| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/syncable/syncable.h" | 5 #include "chrome/browser/sync/syncable/syncable.h" |
| 6 | 6 |
| 7 #include "build/build_config.h" | 7 #include "build/build_config.h" |
| 8 | 8 |
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 10 #if defined(OS_POSIX) | 10 #if defined(OS_POSIX) |
| 11 #include <sys/time.h> | 11 #include <sys/time.h> |
| 12 #endif | 12 #endif |
| 13 #include <sys/types.h> | 13 #include <sys/types.h> |
| 14 #include <time.h> | 14 #include <time.h> |
| 15 #if defined(OS_MACOSX) | 15 #if defined(OS_MACOSX) |
| 16 #include <CoreFoundation/CoreFoundation.h> | 16 #include <CoreFoundation/CoreFoundation.h> |
| 17 #elif defined(OS_WIN) | 17 #elif defined(OS_WIN) |
| 18 #include <shlwapi.h> // for PathMatchSpec | 18 #include <shlwapi.h> // for PathMatchSpec |
| 19 #endif | 19 #endif |
| 20 | 20 |
| 21 #include <algorithm> | 21 #include <algorithm> |
| 22 #include <functional> | 22 #include <functional> |
| 23 #include <iomanip> | 23 #include <iomanip> |
| 24 #include <iterator> | 24 #include <iterator> |
| 25 #include <limits> |
| 25 #include <set> | 26 #include <set> |
| 26 #include <string> | 27 #include <string> |
| 27 | 28 |
| 28 #include "base/hash_tables.h" | 29 #include "base/hash_tables.h" |
| 29 #include "base/file_util.h" | 30 #include "base/file_util.h" |
| 30 #include "base/logging.h" | 31 #include "base/logging.h" |
| 31 #include "base/perftimer.h" | 32 #include "base/perftimer.h" |
| 32 #include "base/scoped_ptr.h" | 33 #include "base/scoped_ptr.h" |
| 33 #include "base/string_util.h" | 34 #include "base/string_util.h" |
| 34 #include "base/time.h" | 35 #include "base/time.h" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 return static_cast<int64>(tv.tv_sec); | 82 return static_cast<int64>(tv.tv_sec); |
| 82 #else | 83 #else |
| 83 #error NEED OS SPECIFIC Now() implementation | 84 #error NEED OS SPECIFIC Now() implementation |
| 84 #endif | 85 #endif |
| 85 } | 86 } |
| 86 | 87 |
| 87 /////////////////////////////////////////////////////////////////////////// | 88 /////////////////////////////////////////////////////////////////////////// |
| 88 // Compare functions and hashes for the indices. | 89 // Compare functions and hashes for the indices. |
| 89 | 90 |
| 90 // Callback for sqlite3 | 91 // Callback for sqlite3 |
| 92 // TODO(chron): This should be somewhere else |
| 91 int ComparePathNames16(void*, int a_bytes, const void* a, int b_bytes, | 93 int ComparePathNames16(void*, int a_bytes, const void* a, int b_bytes, |
| 92 const void* b) { | 94 const void* b) { |
| 93 int result = base::strncasecmp(reinterpret_cast<const char *>(a), | 95 int result = base::strncasecmp(reinterpret_cast<const char *>(a), |
| 94 reinterpret_cast<const char *>(b), | 96 reinterpret_cast<const char *>(b), |
| 95 std::min(a_bytes, b_bytes)); | 97 std::min(a_bytes, b_bytes)); |
| 96 if (result != 0) { | 98 if (result != 0) { |
| 97 return result; | 99 return result; |
| 98 } else { | 100 } else { |
| 99 return a_bytes > b_bytes ? 1 : b_bytes > a_bytes ? -1 : 0; | 101 return a_bytes > b_bytes ? 1 : b_bytes > a_bytes ? -1 : 0; |
| 100 } | 102 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 111 | 113 |
| 112 template <Int64Field field_index> | 114 template <Int64Field field_index> |
| 113 class HashField { | 115 class HashField { |
| 114 public: | 116 public: |
| 115 inline size_t operator()(const syncable::EntryKernel* a) const { | 117 inline size_t operator()(const syncable::EntryKernel* a) const { |
| 116 return hasher_(a->ref(field_index)); | 118 return hasher_(a->ref(field_index)); |
| 117 } | 119 } |
| 118 base::hash_set<int64> hasher_; | 120 base::hash_set<int64> hasher_; |
| 119 }; | 121 }; |
| 120 | 122 |
| 121 // TODO(ncarter): Rename! | 123 // TODO(chron): Remove this function. |
| 122 int ComparePathNames(const PathString& a, const PathString& b) { | 124 int ComparePathNames(const PathString& a, const PathString& b) { |
| 123 const size_t val_size = sizeof(PathString::value_type); | 125 const size_t val_size = sizeof(PathString::value_type); |
| 124 return ComparePathNames16(NULL, a.size() * val_size, a.data(), | 126 return ComparePathNames16(NULL, a.size() * val_size, a.data(), |
| 125 b.size() * val_size, b.data()); | 127 b.size() * val_size, b.data()); |
| 126 } | 128 } |
| 127 | 129 |
| 128 class LessParentIdAndNames { | 130 class LessParentIdAndHandle { |
| 129 public: | 131 public: |
| 130 bool operator() (const syncable::EntryKernel* a, | 132 bool operator() (const syncable::EntryKernel* a, |
| 131 const syncable::EntryKernel* b) const { | 133 const syncable::EntryKernel* b) const { |
| 132 if (a->ref(PARENT_ID) != b->ref(PARENT_ID)) | 134 if (a->ref(PARENT_ID) != b->ref(PARENT_ID)) { |
| 133 return a->ref(PARENT_ID) < b->ref(PARENT_ID); | 135 return a->ref(PARENT_ID) < b->ref(PARENT_ID); |
| 134 return ComparePathNames(a->ref(NAME), b->ref(NAME)) < 0; | 136 } |
| 137 |
| 138 // Meta handles are immutable per entry so this is ideal. |
| 139 return a->ref(META_HANDLE) < b->ref(META_HANDLE); |
| 135 } | 140 } |
| 136 }; | 141 }; |
| 137 | 142 |
| 143 // TODO(chron): Remove this function. |
| 138 bool LessPathNames::operator() (const PathString& a, | 144 bool LessPathNames::operator() (const PathString& a, |
| 139 const PathString& b) const { | 145 const PathString& b) const { |
| 140 return ComparePathNames(a, b) < 0; | 146 return ComparePathNames(a, b) < 0; |
| 141 } | 147 } |
| 142 | 148 |
| 143 // static | |
| 144 Name Name::FromEntryKernel(EntryKernel* kernel) { | |
| 145 PathString& sync_name_ref = kernel->ref(UNSANITIZED_NAME).empty() ? | |
| 146 kernel->ref(NAME) : kernel->ref(UNSANITIZED_NAME); | |
| 147 return Name(kernel->ref(NAME), sync_name_ref, kernel->ref(NON_UNIQUE_NAME)); | |
| 148 } | |
| 149 | |
| 150 /////////////////////////////////////////////////////////////////////////// | 149 /////////////////////////////////////////////////////////////////////////// |
| 151 // Directory | 150 // Directory |
| 152 | 151 |
| 153 static const DirectoryChangeEvent kShutdownChangesEvent = | 152 static const DirectoryChangeEvent kShutdownChangesEvent = |
| 154 { DirectoryChangeEvent::SHUTDOWN, 0, 0 }; | 153 { DirectoryChangeEvent::SHUTDOWN, 0, 0 }; |
| 155 | 154 |
| 156 Directory::Kernel::Kernel(const FilePath& db_path, | 155 Directory::Kernel::Kernel(const FilePath& db_path, |
| 157 const PathString& name, | 156 const PathString& name, |
| 158 const KernelLoadInfo& info) | 157 const KernelLoadInfo& info) |
| 159 : db_path(db_path), | 158 : db_path(db_path), |
| 160 refcount(1), | 159 refcount(1), |
| 161 name_(name), | 160 name_(name), |
| 162 metahandles_index(new Directory::MetahandlesIndex), | 161 metahandles_index(new Directory::MetahandlesIndex), |
| 163 ids_index(new Directory::IdsIndex), | 162 ids_index(new Directory::IdsIndex), |
| 164 parent_id_and_names_index(new Directory::ParentIdAndNamesIndex), | 163 parent_id_child_index(new Directory::ParentIdChildIndex), |
| 165 extended_attributes(new ExtendedAttributes), | 164 extended_attributes(new ExtendedAttributes), |
| 166 unapplied_update_metahandles(new MetahandleSet), | 165 unapplied_update_metahandles(new MetahandleSet), |
| 167 unsynced_metahandles(new MetahandleSet), | 166 unsynced_metahandles(new MetahandleSet), |
| 168 channel(new Directory::Channel(syncable::DIRECTORY_DESTROYED)), | 167 channel(new Directory::Channel(syncable::DIRECTORY_DESTROYED)), |
| 169 changes_channel(new Directory::ChangesChannel(kShutdownChangesEvent)), | 168 changes_channel(new Directory::ChangesChannel(kShutdownChangesEvent)), |
| 170 last_sync_timestamp_(info.kernel_info.last_sync_timestamp), | 169 last_sync_timestamp_(info.kernel_info.last_sync_timestamp), |
| 171 initial_sync_ended_(info.kernel_info.initial_sync_ended), | 170 initial_sync_ended_(info.kernel_info.initial_sync_ended), |
| 172 store_birthday_(info.kernel_info.store_birthday), | 171 store_birthday_(info.kernel_info.store_birthday), |
| 173 cache_guid_(info.cache_guid), | 172 cache_guid_(info.cache_guid), |
| 174 next_metahandle(info.max_metahandle + 1), | 173 next_metahandle(info.max_metahandle + 1), |
| (...skipping 14 matching lines...) Expand all Loading... |
| 189 delete this; | 188 delete this; |
| 190 } | 189 } |
| 191 | 190 |
| 192 Directory::Kernel::~Kernel() { | 191 Directory::Kernel::~Kernel() { |
| 193 CHECK(0 == refcount); | 192 CHECK(0 == refcount); |
| 194 delete channel; | 193 delete channel; |
| 195 delete changes_channel; | 194 delete changes_channel; |
| 196 delete unsynced_metahandles; | 195 delete unsynced_metahandles; |
| 197 delete unapplied_update_metahandles; | 196 delete unapplied_update_metahandles; |
| 198 delete extended_attributes; | 197 delete extended_attributes; |
| 199 delete parent_id_and_names_index; | 198 delete parent_id_child_index; |
| 200 delete ids_index; | 199 delete ids_index; |
| 201 for_each(metahandles_index->begin(), metahandles_index->end(), DeleteEntry); | 200 for_each(metahandles_index->begin(), metahandles_index->end(), DeleteEntry); |
| 202 delete metahandles_index; | 201 delete metahandles_index; |
| 203 } | 202 } |
| 204 | 203 |
| 205 Directory::Directory() : kernel_(NULL), store_(NULL) { | 204 Directory::Directory() : kernel_(NULL), store_(NULL) { |
| 206 } | 205 } |
| 207 | 206 |
| 208 Directory::~Directory() { | 207 Directory::~Directory() { |
| 209 Close(); | 208 Close(); |
| 210 } | 209 } |
| 211 | 210 |
| 212 BOOL PathNameMatch(const PathString& pathname, const PathString& pathspec) { | |
| 213 #if defined(OS_WIN) | |
| 214 // Note that if we go Vista only this is easier: | |
| 215 // http://msdn2.microsoft.com/en-us/library/ms628611.aspx | |
| 216 | |
| 217 // PathMatchSpec strips spaces from the start of pathspec, so we compare those | |
| 218 // ourselves. | |
| 219 const PathChar* pathname_ptr = pathname.c_str(); | |
| 220 const PathChar* pathspec_ptr = pathspec.c_str(); | |
| 221 | |
| 222 while (*pathname_ptr == ' ' && *pathspec_ptr == ' ') | |
| 223 ++pathname_ptr, ++pathspec_ptr; | |
| 224 | |
| 225 // If we have more inital spaces in the pathspec than in the pathname then the | |
| 226 // result from PathMatchSpec will be erroneous. | |
| 227 if (*pathspec_ptr == ' ') | |
| 228 return FALSE; | |
| 229 | |
| 230 // PathMatchSpec also gets "confused" when there are ';' characters in name or | |
| 231 // in spec. So, if we match (f.i.) ";" with ";" PathMatchSpec will return | |
| 232 // FALSE (which is wrong). Luckily for us, we can easily fix this by | |
| 233 // substituting ';' with ':' which is illegal character in file name and | |
| 234 // we're not going to see it there. With ':' in path name and spec | |
| 235 // PathMatchSpec works fine. | |
| 236 if ((NULL == strchr(pathname_ptr, ';')) && | |
| 237 (NULL == strchr(pathspec_ptr, ';'))) { | |
| 238 // No ';' in file name and in spec. Just pass it as it is. | |
| 239 return ::PathMatchSpecA(pathname_ptr, pathspec_ptr); | |
| 240 } | |
| 241 | |
| 242 // We need to subst ';' with ':' in both, name and spec. | |
| 243 PathString name_subst(pathname_ptr); | |
| 244 PathString spec_subst(pathspec_ptr); | |
| 245 | |
| 246 PathString::size_type index = name_subst.find(L';'); | |
| 247 while (PathString::npos != index) { | |
| 248 name_subst[index] = ':'; | |
| 249 index = name_subst.find(';', index + 1); | |
| 250 } | |
| 251 | |
| 252 index = spec_subst.find(L';'); | |
| 253 while (PathString::npos != index) { | |
| 254 spec_subst[index] = ':'; | |
| 255 index = spec_subst.find(';', index + 1); | |
| 256 } | |
| 257 | |
| 258 return ::PathMatchSpecA(name_subst.c_str(), spec_subst.c_str()); | |
| 259 #else | |
| 260 return 0 == ComparePathNames(pathname, pathspec); | |
| 261 #endif | |
| 262 } | |
| 263 | |
| 264 DirOpenResult Directory::Open(const FilePath& file_path, | 211 DirOpenResult Directory::Open(const FilePath& file_path, |
| 265 const PathString& name) { | 212 const PathString& name) { |
| 266 const DirOpenResult result = OpenImpl(file_path, name); | 213 const DirOpenResult result = OpenImpl(file_path, name); |
| 267 if (OPENED != result) | 214 if (OPENED != result) |
| 268 Close(); | 215 Close(); |
| 269 return result; | 216 return result; |
| 270 } | 217 } |
| 271 | 218 |
| 272 void Directory::InitializeIndices() { | 219 void Directory::InitializeIndices() { |
| 273 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); | 220 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); |
| 274 for (; it != kernel_->metahandles_index->end(); ++it) { | 221 for (; it != kernel_->metahandles_index->end(); ++it) { |
| 275 EntryKernel* entry = *it; | 222 EntryKernel* entry = *it; |
| 276 if (!entry->ref(IS_DEL)) | 223 if (!entry->ref(IS_DEL)) |
| 277 kernel_->parent_id_and_names_index->insert(entry); | 224 kernel_->parent_id_child_index->insert(entry); |
| 278 kernel_->ids_index->insert(entry); | 225 kernel_->ids_index->insert(entry); |
| 279 if (entry->ref(IS_UNSYNCED)) | 226 if (entry->ref(IS_UNSYNCED)) |
| 280 kernel_->unsynced_metahandles->insert(entry->ref(META_HANDLE)); | 227 kernel_->unsynced_metahandles->insert(entry->ref(META_HANDLE)); |
| 281 if (entry->ref(IS_UNAPPLIED_UPDATE)) | 228 if (entry->ref(IS_UNAPPLIED_UPDATE)) |
| 282 kernel_->unapplied_update_metahandles->insert(entry->ref(META_HANDLE)); | 229 kernel_->unapplied_update_metahandles->insert(entry->ref(META_HANDLE)); |
| 283 } | 230 } |
| 284 } | 231 } |
| 285 | 232 |
| 286 DirectoryBackingStore* Directory::CreateBackingStore( | 233 DirectoryBackingStore* Directory::CreateBackingStore( |
| 287 const PathString& dir_name, const FilePath& backing_filepath) { | 234 const PathString& dir_name, const FilePath& backing_filepath) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 kernel_->needle.ref(META_HANDLE) = metahandle; | 317 kernel_->needle.ref(META_HANDLE) = metahandle; |
| 371 MetahandlesIndex::iterator found = | 318 MetahandlesIndex::iterator found = |
| 372 kernel_->metahandles_index->find(&kernel_->needle); | 319 kernel_->metahandles_index->find(&kernel_->needle); |
| 373 if (found != kernel_->metahandles_index->end()) { | 320 if (found != kernel_->metahandles_index->end()) { |
| 374 // Found it in memory. Easy. | 321 // Found it in memory. Easy. |
| 375 return *found; | 322 return *found; |
| 376 } | 323 } |
| 377 return NULL; | 324 return NULL; |
| 378 } | 325 } |
| 379 | 326 |
| 380 EntryKernel* Directory::GetChildWithName(const Id& parent_id, | |
| 381 const PathString& name) { | |
| 382 ScopedKernelLock lock(this); | |
| 383 return GetChildWithName(parent_id, name, &lock); | |
| 384 } | |
| 385 | |
| 386 // Will return child entry if the folder is opened, | |
| 387 // otherwise it will return NULL. | |
| 388 EntryKernel* Directory::GetChildWithName(const Id& parent_id, | |
| 389 const PathString& name, | |
| 390 ScopedKernelLock* const lock) { | |
| 391 PathString dbname = name; | |
| 392 EntryKernel* parent = GetEntryById(parent_id, lock); | |
| 393 if (parent == NULL) | |
| 394 return NULL; | |
| 395 return GetChildWithNameImpl(parent_id, dbname, lock); | |
| 396 } | |
| 397 | |
| 398 // Will return child entry even when the folder is not opened. This is used by | |
| 399 // syncer to apply update when folder is closed. | |
| 400 EntryKernel* Directory::GetChildWithDBName(const Id& parent_id, | |
| 401 const PathString& name) { | |
| 402 ScopedKernelLock lock(this); | |
| 403 return GetChildWithNameImpl(parent_id, name, &lock); | |
| 404 } | |
| 405 | |
| 406 EntryKernel* Directory::GetChildWithNameImpl(const Id& parent_id, | |
| 407 const PathString& name, | |
| 408 ScopedKernelLock* const lock) { | |
| 409 // First look up in memory: | |
| 410 kernel_->needle.ref(NAME) = name; | |
| 411 kernel_->needle.ref(PARENT_ID) = parent_id; | |
| 412 ParentIdAndNamesIndex::iterator found = | |
| 413 kernel_->parent_id_and_names_index->find(&kernel_->needle); | |
| 414 if (found != kernel_->parent_id_and_names_index->end()) { | |
| 415 // Found it in memory. Easy. | |
| 416 return *found; | |
| 417 } | |
| 418 return NULL; | |
| 419 } | |
| 420 | |
| 421 // An interface to specify the details of which children | 327 // An interface to specify the details of which children |
| 422 // GetChildHandles() is looking for. | 328 // GetChildHandles() is looking for. |
| 329 // TODO(chron): Clean this up into one function to get child handles |
| 423 struct PathMatcher { | 330 struct PathMatcher { |
| 424 explicit PathMatcher(const Id& parent_id) : parent_id_(parent_id) { } | 331 explicit PathMatcher(const Id& parent_id) : parent_id_(parent_id) { } |
| 425 virtual ~PathMatcher() { } | 332 virtual ~PathMatcher() { } |
| 426 enum MatchType { | 333 |
| 427 NO_MATCH, | 334 typedef Directory::ParentIdChildIndex Index; |
| 428 MATCH, | |
| 429 // Means we found the only entry we're looking for in | |
| 430 // memory so we don't need to check the DB. | |
| 431 EXACT_MATCH | |
| 432 }; | |
| 433 virtual MatchType PathMatches(const PathString& path) = 0; | |
| 434 typedef Directory::ParentIdAndNamesIndex Index; | |
| 435 virtual Index::iterator lower_bound(Index* index) = 0; | 335 virtual Index::iterator lower_bound(Index* index) = 0; |
| 436 virtual Index::iterator upper_bound(Index* index) = 0; | 336 virtual Index::iterator upper_bound(Index* index) = 0; |
| 437 const Id parent_id_; | 337 const Id parent_id_; |
| 438 EntryKernel needle_; | 338 EntryKernel needle_; |
| 439 }; | 339 }; |
| 440 | 340 |
| 441 // Matches all children. | 341 // Matches all children. |
| 342 // TODO(chron): Unit test this by itself |
| 442 struct AllPathsMatcher : public PathMatcher { | 343 struct AllPathsMatcher : public PathMatcher { |
| 443 explicit AllPathsMatcher(const Id& parent_id) : PathMatcher(parent_id) { | 344 explicit AllPathsMatcher(const Id& parent_id) : PathMatcher(parent_id) { |
| 444 } | 345 } |
| 445 virtual MatchType PathMatches(const PathString& path) { | 346 |
| 446 return MATCH; | |
| 447 } | |
| 448 virtual Index::iterator lower_bound(Index* index) { | 347 virtual Index::iterator lower_bound(Index* index) { |
| 449 needle_.ref(PARENT_ID) = parent_id_; | 348 needle_.ref(PARENT_ID) = parent_id_; |
| 450 needle_.ref(NAME).clear(); | 349 needle_.ref(META_HANDLE) = std::numeric_limits<int64>::min(); |
| 451 return index->lower_bound(&needle_); | 350 return index->lower_bound(&needle_); |
| 452 } | 351 } |
| 453 | 352 |
| 454 virtual Index::iterator upper_bound(Index* index) { | 353 virtual Index::iterator upper_bound(Index* index) { |
| 455 needle_.ref(PARENT_ID) = parent_id_; | 354 needle_.ref(PARENT_ID) = parent_id_; |
| 456 needle_.ref(NAME).clear(); | 355 needle_.ref(META_HANDLE) = std::numeric_limits<int64>::max(); |
| 457 Index::iterator i = index->upper_bound(&needle_), | 356 return index->upper_bound(&needle_); |
| 458 end = index->end(); | |
| 459 while (i != end && (*i)->ref(PARENT_ID) == parent_id_) | |
| 460 ++i; | |
| 461 return i; | |
| 462 } | 357 } |
| 463 }; | 358 }; |
| 464 | 359 |
| 465 // Matches an exact filename only; no wildcards. | |
| 466 struct ExactPathMatcher : public PathMatcher { | |
| 467 ExactPathMatcher(const PathString& pathspec, const Id& parent_id) | |
| 468 : PathMatcher(parent_id), pathspec_(pathspec) { | |
| 469 } | |
| 470 virtual MatchType PathMatches(const PathString& path) { | |
| 471 return 0 == ComparePathNames(path, pathspec_) ? EXACT_MATCH : NO_MATCH; | |
| 472 } | |
| 473 virtual Index::iterator lower_bound(Index* index) { | |
| 474 needle_.ref(PARENT_ID) = parent_id_; | |
| 475 needle_.ref(NAME) = pathspec_; | |
| 476 return index->lower_bound(&needle_); | |
| 477 } | |
| 478 virtual Index::iterator upper_bound(Index* index) { | |
| 479 needle_.ref(PARENT_ID) = parent_id_; | |
| 480 needle_.ref(NAME) = pathspec_; | |
| 481 return index->upper_bound(&needle_); | |
| 482 } | |
| 483 const PathString pathspec_; | |
| 484 }; | |
| 485 | |
| 486 void Directory::GetChildHandles(BaseTransaction* trans, const Id& parent_id, | 360 void Directory::GetChildHandles(BaseTransaction* trans, const Id& parent_id, |
| 487 Directory::ChildHandles* result) { | 361 Directory::ChildHandles* result) { |
| 488 AllPathsMatcher matcher(parent_id); | 362 AllPathsMatcher matcher(parent_id); |
| 489 return GetChildHandlesImpl(trans, parent_id, &matcher, result); | 363 return GetChildHandlesImpl(trans, parent_id, &matcher, result); |
| 490 } | 364 } |
| 491 | 365 |
| 492 void Directory::GetChildHandlesImpl(BaseTransaction* trans, const Id& parent_id, | 366 void Directory::GetChildHandlesImpl(BaseTransaction* trans, const Id& parent_id, |
| 493 PathMatcher* matcher, | 367 PathMatcher* matcher, |
| 494 Directory::ChildHandles* result) { | 368 Directory::ChildHandles* result) { |
| 495 CHECK(this == trans->directory()); | 369 CHECK(this == trans->directory()); |
| 496 result->clear(); | 370 result->clear(); |
| 497 { | 371 { |
| 498 ScopedKernelLock lock(this); | 372 ScopedKernelLock lock(this); |
| 499 ParentIdAndNamesIndex* const index = | 373 |
| 500 kernel_->parent_id_and_names_index; | 374 // This index is sorted by parent id and metahandle. |
| 501 typedef ParentIdAndNamesIndex::iterator iterator; | 375 ParentIdChildIndex* const index = kernel_->parent_id_child_index; |
| 376 typedef ParentIdChildIndex::iterator iterator; |
| 502 for (iterator i = matcher->lower_bound(index), | 377 for (iterator i = matcher->lower_bound(index), |
| 503 end = matcher->upper_bound(index); i != end; ++i) { | 378 end = matcher->upper_bound(index); i != end; ++i) { |
| 504 // root's parent_id is NULL in the db but 0 in memory, so | 379 // root's parent_id is NULL in the db but 0 in memory, so |
| 505 // have avoid listing the root as its own child. | 380 // have avoid listing the root as its own child. |
| 506 if ((*i)->ref(ID) == (*i)->ref(PARENT_ID)) | 381 if ((*i)->ref(ID) == (*i)->ref(PARENT_ID)) |
| 507 continue; | 382 continue; |
| 508 PathMatcher::MatchType match = matcher->PathMatches((*i)->ref(NAME)); | |
| 509 if (PathMatcher::NO_MATCH == match) | |
| 510 continue; | |
| 511 result->push_back((*i)->ref(META_HANDLE)); | 383 result->push_back((*i)->ref(META_HANDLE)); |
| 512 if (PathMatcher::EXACT_MATCH == match) | |
| 513 return; | |
| 514 } | 384 } |
| 515 } | 385 } |
| 516 } | 386 } |
| 517 | 387 |
| 518 EntryKernel* Directory::GetRootEntry() { | 388 EntryKernel* Directory::GetRootEntry() { |
| 519 return GetEntryById(Id()); | 389 return GetEntryById(Id()); |
| 520 } | 390 } |
| 521 | 391 |
| 522 EntryKernel* Directory::GetEntryByPath(const PathString& path) { | |
| 523 CHECK(kernel_); | |
| 524 EntryKernel* result = GetRootEntry(); | |
| 525 CHECK(result) << "There should always be a root node."; | |
| 526 for (PathSegmentIterator<PathString> i(path), end; | |
| 527 i != end && NULL != result; ++i) { | |
| 528 result = GetChildWithName(result->ref(ID), *i); | |
| 529 } | |
| 530 return result; | |
| 531 } | |
| 532 | |
| 533 void ZeroFields(EntryKernel* entry, int first_field) { | 392 void ZeroFields(EntryKernel* entry, int first_field) { |
| 534 int i = first_field; | 393 int i = first_field; |
| 535 // Note that bitset<> constructor sets all bits to zero, and strings | 394 // Note that bitset<> constructor sets all bits to zero, and strings |
| 536 // initialize to empty. | 395 // initialize to empty. |
| 537 for ( ; i < INT64_FIELDS_END; ++i) | 396 for ( ; i < INT64_FIELDS_END; ++i) |
| 538 entry->ref(static_cast<Int64Field>(i)) = 0; | 397 entry->ref(static_cast<Int64Field>(i)) = 0; |
| 539 for ( ; i < ID_FIELDS_END; ++i) | 398 for ( ; i < ID_FIELDS_END; ++i) |
| 540 entry->ref(static_cast<IdField>(i)).Clear(); | 399 entry->ref(static_cast<IdField>(i)).Clear(); |
| 541 for ( ; i < BIT_FIELDS_END; ++i) | 400 for ( ; i < BIT_FIELDS_END; ++i) |
| 542 entry->ref(static_cast<BitField>(i)) = false; | 401 entry->ref(static_cast<BitField>(i)) = false; |
| 543 if (i < BLOB_FIELDS_END) | 402 if (i < BLOB_FIELDS_END) |
| 544 i = BLOB_FIELDS_END; | 403 i = BLOB_FIELDS_END; |
| 545 } | 404 } |
| 546 | 405 |
| 547 void Directory::InsertEntry(EntryKernel* entry) { | 406 void Directory::InsertEntry(EntryKernel* entry) { |
| 548 ScopedKernelLock lock(this); | 407 ScopedKernelLock lock(this); |
| 549 InsertEntry(entry, &lock); | 408 InsertEntry(entry, &lock); |
| 550 } | 409 } |
| 551 | 410 |
| 552 void Directory::InsertEntry(EntryKernel* entry, ScopedKernelLock* lock) { | 411 void Directory::InsertEntry(EntryKernel* entry, ScopedKernelLock* lock) { |
| 553 DCHECK(NULL != lock); | 412 DCHECK(NULL != lock); |
| 554 CHECK(NULL != entry); | 413 CHECK(NULL != entry); |
| 555 static const char error[] = "Entry already in memory index."; | 414 static const char error[] = "Entry already in memory index."; |
| 556 CHECK(kernel_->metahandles_index->insert(entry).second) << error; | 415 CHECK(kernel_->metahandles_index->insert(entry).second) << error; |
| 557 if (!entry->ref(IS_DEL)) | 416 |
| 558 CHECK(kernel_->parent_id_and_names_index->insert(entry).second) << error; | 417 if (!entry->ref(IS_DEL)) { |
| 418 CHECK(kernel_->parent_id_child_index->insert(entry).second) << error; |
| 419 } |
| 559 CHECK(kernel_->ids_index->insert(entry).second) << error; | 420 CHECK(kernel_->ids_index->insert(entry).second) << error; |
| 560 } | 421 } |
| 561 | 422 |
| 562 bool Directory::Undelete(EntryKernel* const entry) { | 423 void Directory::Undelete(EntryKernel* const entry) { |
| 563 DCHECK(entry->ref(IS_DEL)); | 424 DCHECK(entry->ref(IS_DEL)); |
| 564 ScopedKernelLock lock(this); | 425 ScopedKernelLock lock(this); |
| 565 if (NULL != GetChildWithName(entry->ref(PARENT_ID), entry->ref(NAME), &lock)) | |
| 566 return false; // Would have duplicated existing entry. | |
| 567 entry->ref(IS_DEL) = false; | 426 entry->ref(IS_DEL) = false; |
| 568 entry->dirty[IS_DEL] = true; | 427 entry->dirty[IS_DEL] = true; |
| 569 CHECK(kernel_->parent_id_and_names_index->insert(entry).second); | 428 CHECK(kernel_->parent_id_child_index->insert(entry).second); |
| 570 return true; | |
| 571 } | 429 } |
| 572 | 430 |
| 573 bool Directory::Delete(EntryKernel* const entry) { | 431 void Directory::Delete(EntryKernel* const entry) { |
| 574 DCHECK(!entry->ref(IS_DEL)); | 432 DCHECK(!entry->ref(IS_DEL)); |
| 575 entry->ref(IS_DEL) = true; | 433 entry->ref(IS_DEL) = true; |
| 576 entry->dirty[IS_DEL] = true; | 434 entry->dirty[IS_DEL] = true; |
| 577 ScopedKernelLock lock(this); | 435 ScopedKernelLock lock(this); |
| 578 CHECK(1 == kernel_->parent_id_and_names_index->erase(entry)); | 436 CHECK(1 == kernel_->parent_id_child_index->erase(entry)); |
| 579 return true; | |
| 580 } | 437 } |
| 581 | 438 |
| 582 bool Directory::ReindexId(EntryKernel* const entry, const Id& new_id) { | 439 bool Directory::ReindexId(EntryKernel* const entry, const Id& new_id) { |
| 583 ScopedKernelLock lock(this); | 440 ScopedKernelLock lock(this); |
| 584 if (NULL != GetEntryById(new_id, &lock)) | 441 if (NULL != GetEntryById(new_id, &lock)) |
| 585 return false; | 442 return false; |
| 586 CHECK(1 == kernel_->ids_index->erase(entry)); | 443 CHECK(1 == kernel_->ids_index->erase(entry)); |
| 587 entry->ref(ID) = new_id; | 444 entry->ref(ID) = new_id; |
| 588 CHECK(kernel_->ids_index->insert(entry).second); | 445 CHECK(kernel_->ids_index->insert(entry).second); |
| 589 return true; | 446 return true; |
| 590 } | 447 } |
| 591 | 448 |
| 592 bool Directory::ReindexParentIdAndName(EntryKernel* const entry, | 449 void Directory::ReindexParentId(EntryKernel* const entry, |
| 593 const Id& new_parent_id, | 450 const Id& new_parent_id) { |
| 594 const PathString& new_name) { | 451 |
| 595 ScopedKernelLock lock(this); | 452 ScopedKernelLock lock(this); |
| 596 PathString new_indexed_name = new_name; | |
| 597 if (entry->ref(IS_DEL)) { | 453 if (entry->ref(IS_DEL)) { |
| 598 entry->ref(PARENT_ID) = new_parent_id; | 454 entry->ref(PARENT_ID) = new_parent_id; |
| 599 entry->ref(NAME) = new_indexed_name; | 455 return; |
| 600 return true; | |
| 601 } | 456 } |
| 602 | 457 |
| 603 // check for a case changing rename | 458 if (entry->ref(PARENT_ID) == new_parent_id) { |
| 604 if (entry->ref(PARENT_ID) == new_parent_id && | 459 return; |
| 605 0 == ComparePathNames(entry->ref(NAME), new_indexed_name)) { | |
| 606 entry->ref(NAME) = new_indexed_name; | |
| 607 } else { | |
| 608 if (NULL != GetChildWithName(new_parent_id, new_indexed_name, &lock)) | |
| 609 return false; | |
| 610 CHECK(1 == kernel_->parent_id_and_names_index->erase(entry)); | |
| 611 entry->ref(PARENT_ID) = new_parent_id; | |
| 612 entry->ref(NAME) = new_indexed_name; | |
| 613 CHECK(kernel_->parent_id_and_names_index->insert(entry).second); | |
| 614 } | 460 } |
| 615 return true; | 461 |
| 462 CHECK(1 == kernel_->parent_id_child_index->erase(entry)); |
| 463 entry->ref(PARENT_ID) = new_parent_id; |
| 464 CHECK(kernel_->parent_id_child_index->insert(entry).second); |
| 616 } | 465 } |
| 617 | 466 |
| 618 // static | 467 // static |
| 619 bool Directory::SafeToPurgeFromMemory(const EntryKernel* const entry) { | 468 bool Directory::SafeToPurgeFromMemory(const EntryKernel* const entry) { |
| 620 return entry->ref(IS_DEL) && !entry->dirty.any() && !entry->ref(SYNCING) && | 469 return entry->ref(IS_DEL) && !entry->dirty.any() && !entry->ref(SYNCING) && |
| 621 !entry->ref(IS_UNAPPLIED_UPDATE) && !entry->ref(IS_UNSYNCED); | 470 !entry->ref(IS_UNAPPLIED_UPDATE) && !entry->ref(IS_UNSYNCED); |
| 622 } | 471 } |
| 623 | 472 |
| 624 void Directory::TakeSnapshotForSaveChanges(SaveChangesSnapshot* snapshot) { | 473 void Directory::TakeSnapshotForSaveChanges(SaveChangesSnapshot* snapshot) { |
| 625 ReadTransaction trans(this, __FILE__, __LINE__); | 474 ReadTransaction trans(this, __FILE__, __LINE__); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 964 | 813 |
| 965 if (id.IsRoot()) { | 814 if (id.IsRoot()) { |
| 966 CHECK(e.Get(IS_DIR)) << e; | 815 CHECK(e.Get(IS_DIR)) << e; |
| 967 CHECK(parentid.IsRoot()) << e; | 816 CHECK(parentid.IsRoot()) << e; |
| 968 CHECK(!e.Get(IS_UNSYNCED)) << e; | 817 CHECK(!e.Get(IS_UNSYNCED)) << e; |
| 969 ++entries_done; | 818 ++entries_done; |
| 970 continue; | 819 continue; |
| 971 } | 820 } |
| 972 if (!e.Get(IS_DEL)) { | 821 if (!e.Get(IS_DEL)) { |
| 973 CHECK(id != parentid) << e; | 822 CHECK(id != parentid) << e; |
| 974 CHECK(!e.Get(NAME).empty()) << e; | 823 CHECK(!e.Get(NON_UNIQUE_NAME).empty()) << e; |
| 975 int safety_count = handles.size() + 1; | 824 int safety_count = handles.size() + 1; |
| 976 while (!parentid.IsRoot()) { | 825 while (!parentid.IsRoot()) { |
| 977 if (!idfilter.ShouldConsider(parentid)) | 826 if (!idfilter.ShouldConsider(parentid)) |
| 978 break; | 827 break; |
| 979 Entry parent(trans, GET_BY_ID, parentid); | 828 Entry parent(trans, GET_BY_ID, parentid); |
| 980 CHECK(parent.good()) << e; | 829 CHECK(parent.good()) << e; |
| 981 CHECK(parent.Get(IS_DIR)) << parent << e; | 830 CHECK(parent.Get(IS_DIR)) << parent << e; |
| 982 CHECK(!parent.Get(IS_DEL)) << parent << e; | 831 CHECK(!parent.Get(IS_DEL)) << parent << e; |
| 983 CHECK(handles.end() != handles.find(parent.Get(META_HANDLE))) | 832 CHECK(handles.end() != handles.find(parent.Get(META_HANDLE))) |
| 984 << e << parent; | 833 << e << parent; |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1141 Entry::Entry(BaseTransaction* trans, GetByTag, const PathString& tag) | 990 Entry::Entry(BaseTransaction* trans, GetByTag, const PathString& tag) |
| 1142 : basetrans_(trans) { | 991 : basetrans_(trans) { |
| 1143 kernel_ = trans->directory()->GetEntryByTag(tag); | 992 kernel_ = trans->directory()->GetEntryByTag(tag); |
| 1144 } | 993 } |
| 1145 | 994 |
| 1146 Entry::Entry(BaseTransaction* trans, GetByHandle, int64 metahandle) | 995 Entry::Entry(BaseTransaction* trans, GetByHandle, int64 metahandle) |
| 1147 : basetrans_(trans) { | 996 : basetrans_(trans) { |
| 1148 kernel_ = trans->directory()->GetEntryByHandle(metahandle); | 997 kernel_ = trans->directory()->GetEntryByHandle(metahandle); |
| 1149 } | 998 } |
| 1150 | 999 |
| 1151 Entry::Entry(BaseTransaction* trans, GetByPath, const PathString& path) | |
| 1152 : basetrans_(trans) { | |
| 1153 kernel_ = trans->directory()->GetEntryByPath(path); | |
| 1154 } | |
| 1155 | |
| 1156 Entry::Entry(BaseTransaction* trans, GetByParentIdAndName, const Id& parentid, | |
| 1157 const PathString& name) | |
| 1158 : basetrans_(trans) { | |
| 1159 kernel_ = trans->directory()->GetChildWithName(parentid, name); | |
| 1160 } | |
| 1161 | |
| 1162 Entry::Entry(BaseTransaction* trans, GetByParentIdAndDBName, const Id& parentid, | |
| 1163 const PathString& name) | |
| 1164 : basetrans_(trans) { | |
| 1165 kernel_ = trans->directory()->GetChildWithDBName(parentid, name); | |
| 1166 } | |
| 1167 | |
| 1168 | |
| 1169 Directory* Entry::dir() const { | 1000 Directory* Entry::dir() const { |
| 1170 return basetrans_->directory(); | 1001 return basetrans_->directory(); |
| 1171 } | 1002 } |
| 1172 | 1003 |
| 1173 PathString Entry::Get(StringField field) const { | 1004 PathString Entry::Get(StringField field) const { |
| 1174 DCHECK(kernel_); | 1005 DCHECK(kernel_); |
| 1175 return kernel_->ref(field); | 1006 return kernel_->ref(field); |
| 1176 } | 1007 } |
| 1177 | 1008 |
| 1178 void Entry::GetAllExtendedAttributes(BaseTransaction* trans, | 1009 void Entry::GetAllExtendedAttributes(BaseTransaction* trans, |
| 1179 std::set<ExtendedAttribute> *result) { | 1010 std::set<ExtendedAttribute> *result) { |
| 1180 dir()->GetAllExtendedAttributes(trans, kernel_->ref(META_HANDLE), result); | 1011 dir()->GetAllExtendedAttributes(trans, kernel_->ref(META_HANDLE), result); |
| 1181 } | 1012 } |
| 1182 | 1013 |
| 1183 void Entry::GetExtendedAttributesList(BaseTransaction* trans, | 1014 void Entry::GetExtendedAttributesList(BaseTransaction* trans, |
| 1184 AttributeKeySet* result) { | 1015 AttributeKeySet* result) { |
| 1185 dir()->GetExtendedAttributesList(trans, kernel_->ref(META_HANDLE), result); | 1016 dir()->GetExtendedAttributesList(trans, kernel_->ref(META_HANDLE), result); |
| 1186 } | 1017 } |
| 1187 | 1018 |
| 1188 void Entry::DeleteAllExtendedAttributes(WriteTransaction *trans) { | 1019 void Entry::DeleteAllExtendedAttributes(WriteTransaction *trans) { |
| 1189 dir()->DeleteAllExtendedAttributes(trans, kernel_->ref(META_HANDLE)); | 1020 dir()->DeleteAllExtendedAttributes(trans, kernel_->ref(META_HANDLE)); |
| 1190 } | 1021 } |
| 1191 | 1022 |
| 1192 /////////////////////////////////////////////////////////////////////////// | 1023 /////////////////////////////////////////////////////////////////////////// |
| 1193 // MutableEntry | 1024 // MutableEntry |
| 1194 | 1025 |
| 1195 MutableEntry::MutableEntry(WriteTransaction* trans, Create, | 1026 MutableEntry::MutableEntry(WriteTransaction* trans, Create, |
| 1196 const Id& parent_id, const PathString& name) | 1027 const Id& parent_id, const PathString& name) |
| 1197 : Entry(trans), write_transaction_(trans) { | 1028 : Entry(trans), |
| 1198 if (NULL != trans->directory()->GetChildWithName(parent_id, name)) { | 1029 write_transaction_(trans) { |
| 1199 kernel_ = NULL; // would have duplicated an existing entry. | |
| 1200 return; | |
| 1201 } | |
| 1202 Init(trans, parent_id, name); | 1030 Init(trans, parent_id, name); |
| 1203 } | 1031 } |
| 1204 | 1032 |
| 1205 | 1033 |
| 1206 void MutableEntry::Init(WriteTransaction* trans, const Id& parent_id, | 1034 void MutableEntry::Init(WriteTransaction* trans, const Id& parent_id, |
| 1207 const PathString& name) { | 1035 const PathString& name) { |
| 1208 kernel_ = new EntryKernel; | 1036 kernel_ = new EntryKernel; |
| 1209 ZeroFields(kernel_, BEGIN_FIELDS); | 1037 ZeroFields(kernel_, BEGIN_FIELDS); |
| 1210 kernel_->ref(ID) = trans->directory_->NextId(); | 1038 kernel_->ref(ID) = trans->directory_->NextId(); |
| 1211 kernel_->dirty[ID] = true; | 1039 kernel_->dirty[ID] = true; |
| 1212 kernel_->ref(META_HANDLE) = trans->directory_->NextMetahandle(); | 1040 kernel_->ref(META_HANDLE) = trans->directory_->NextMetahandle(); |
| 1213 kernel_->dirty[META_HANDLE] = true; | 1041 kernel_->dirty[META_HANDLE] = true; |
| 1214 kernel_->ref(PARENT_ID) = parent_id; | 1042 kernel_->ref(PARENT_ID) = parent_id; |
| 1215 kernel_->dirty[PARENT_ID] = true; | 1043 kernel_->dirty[PARENT_ID] = true; |
| 1216 kernel_->ref(NAME) = name; | |
| 1217 kernel_->dirty[NAME] = true; | |
| 1218 kernel_->ref(NON_UNIQUE_NAME) = name; | 1044 kernel_->ref(NON_UNIQUE_NAME) = name; |
| 1219 kernel_->dirty[NON_UNIQUE_NAME] = true; | 1045 kernel_->dirty[NON_UNIQUE_NAME] = true; |
| 1220 kernel_->ref(IS_NEW) = true; | 1046 kernel_->ref(IS_NEW) = true; |
| 1221 const int64 now = Now(); | 1047 const int64 now = Now(); |
| 1222 kernel_->ref(CTIME) = now; | 1048 kernel_->ref(CTIME) = now; |
| 1223 kernel_->dirty[CTIME] = true; | 1049 kernel_->dirty[CTIME] = true; |
| 1224 kernel_->ref(MTIME) = now; | 1050 kernel_->ref(MTIME) = now; |
| 1225 kernel_->dirty[MTIME] = true; | 1051 kernel_->dirty[MTIME] = true; |
| 1226 // We match the database defaults here | 1052 // We match the database defaults here |
| 1227 kernel_->ref(BASE_VERSION) = CHANGES_VERSION; | 1053 kernel_->ref(BASE_VERSION) = CHANGES_VERSION; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1259 : Entry(trans, GET_BY_ID, id), write_transaction_(trans) { | 1085 : Entry(trans, GET_BY_ID, id), write_transaction_(trans) { |
| 1260 trans->SaveOriginal(kernel_); | 1086 trans->SaveOriginal(kernel_); |
| 1261 } | 1087 } |
| 1262 | 1088 |
| 1263 MutableEntry::MutableEntry(WriteTransaction* trans, GetByHandle, | 1089 MutableEntry::MutableEntry(WriteTransaction* trans, GetByHandle, |
| 1264 int64 metahandle) | 1090 int64 metahandle) |
| 1265 : Entry(trans, GET_BY_HANDLE, metahandle), write_transaction_(trans) { | 1091 : Entry(trans, GET_BY_HANDLE, metahandle), write_transaction_(trans) { |
| 1266 trans->SaveOriginal(kernel_); | 1092 trans->SaveOriginal(kernel_); |
| 1267 } | 1093 } |
| 1268 | 1094 |
| 1269 MutableEntry::MutableEntry(WriteTransaction* trans, GetByPath, | |
| 1270 const PathString& path) | |
| 1271 : Entry(trans, GET_BY_PATH, path), write_transaction_(trans) { | |
| 1272 trans->SaveOriginal(kernel_); | |
| 1273 } | |
| 1274 | |
| 1275 MutableEntry::MutableEntry(WriteTransaction* trans, GetByParentIdAndName, | |
| 1276 const Id& parentid, const PathString& name) | |
| 1277 : Entry(trans, GET_BY_PARENTID_AND_NAME, parentid, name), | |
| 1278 write_transaction_(trans) { | |
| 1279 trans->SaveOriginal(kernel_); | |
| 1280 } | |
| 1281 | |
| 1282 MutableEntry::MutableEntry(WriteTransaction* trans, GetByParentIdAndDBName, | |
| 1283 const Id& parentid, const PathString& name) | |
| 1284 : Entry(trans, GET_BY_PARENTID_AND_DBNAME, parentid, name), | |
| 1285 write_transaction_(trans) { | |
| 1286 trans->SaveOriginal(kernel_); | |
| 1287 } | |
| 1288 | |
| 1289 bool MutableEntry::PutIsDel(bool is_del) { | 1095 bool MutableEntry::PutIsDel(bool is_del) { |
| 1290 DCHECK(kernel_); | 1096 DCHECK(kernel_); |
| 1291 if (is_del == kernel_->ref(IS_DEL)) | 1097 if (is_del == kernel_->ref(IS_DEL)) { |
| 1292 return true; | 1098 return true; |
| 1099 } |
| 1293 if (is_del) { | 1100 if (is_del) { |
| 1294 UnlinkFromOrder(); | 1101 UnlinkFromOrder(); |
| 1295 if (!dir()->Delete(kernel_)) | 1102 dir()->Delete(kernel_); |
| 1296 return false; | |
| 1297 return true; | 1103 return true; |
| 1298 } else { | 1104 } else { |
| 1299 if (!dir()->Undelete(kernel_)) | 1105 dir()->Undelete(kernel_); |
| 1300 return false; | |
| 1301 PutPredecessor(Id()); // Restores position to the 0th index. | 1106 PutPredecessor(Id()); // Restores position to the 0th index. |
| 1302 return true; | 1107 return true; |
| 1303 } | 1108 } |
| 1304 } | 1109 } |
| 1305 | 1110 |
| 1306 bool MutableEntry::Put(Int64Field field, const int64& value) { | 1111 bool MutableEntry::Put(Int64Field field, const int64& value) { |
| 1307 DCHECK(kernel_); | 1112 DCHECK(kernel_); |
| 1308 if (kernel_->ref(field) != value) { | 1113 if (kernel_->ref(field) != value) { |
| 1309 kernel_->ref(field) = value; | 1114 kernel_->ref(field) = value; |
| 1310 kernel_->dirty[static_cast<int>(field)] = true; | 1115 kernel_->dirty[static_cast<int>(field)] = true; |
| 1311 } | 1116 } |
| 1312 return true; | 1117 return true; |
| 1313 } | 1118 } |
| 1314 | 1119 |
| 1315 bool MutableEntry::Put(IdField field, const Id& value) { | 1120 bool MutableEntry::Put(IdField field, const Id& value) { |
| 1316 DCHECK(kernel_); | 1121 DCHECK(kernel_); |
| 1317 if (kernel_->ref(field) != value) { | 1122 if (kernel_->ref(field) != value) { |
| 1318 if (ID == field) { | 1123 if (ID == field) { |
| 1319 if (!dir()->ReindexId(kernel_, value)) | 1124 if (!dir()->ReindexId(kernel_, value)) |
| 1320 return false; | 1125 return false; |
| 1321 } else if (PARENT_ID == field) { | 1126 } else if (PARENT_ID == field) { |
| 1322 if (!dir()->ReindexParentIdAndName(kernel_, value, kernel_->ref(NAME))) | 1127 dir()->ReindexParentId(kernel_, value); |
| 1323 return false; | 1128 PutPredecessor(Id()); |
| 1324 } else { | 1129 } else { |
| 1325 kernel_->ref(field) = value; | 1130 kernel_->ref(field) = value; |
| 1326 } | 1131 } |
| 1327 kernel_->dirty[static_cast<int>(field)] = true; | 1132 kernel_->dirty[static_cast<int>(field)] = true; |
| 1328 } | 1133 } |
| 1329 return true; | 1134 return true; |
| 1330 } | 1135 } |
| 1331 | 1136 |
| 1332 bool MutableEntry::Put(BaseVersion field, int64 value) { | 1137 bool MutableEntry::Put(BaseVersion field, int64 value) { |
| 1333 DCHECK(kernel_); | 1138 DCHECK(kernel_); |
| 1334 if (kernel_->ref(field) != value) { | 1139 if (kernel_->ref(field) != value) { |
| 1335 kernel_->ref(field) = value; | 1140 kernel_->ref(field) = value; |
| 1336 kernel_->dirty[static_cast<int>(field)] = true; | 1141 kernel_->dirty[static_cast<int>(field)] = true; |
| 1337 } | 1142 } |
| 1338 return true; | 1143 return true; |
| 1339 } | 1144 } |
| 1340 | 1145 |
| 1341 bool MutableEntry::Put(StringField field, const PathString& value) { | 1146 bool MutableEntry::Put(StringField field, const PathString& value) { |
| 1342 return PutImpl(field, value); | 1147 return PutImpl(field, value); |
| 1343 } | 1148 } |
| 1344 | 1149 |
| 1345 bool MutableEntry::PutImpl(StringField field, const PathString& value) { | 1150 bool MutableEntry::PutImpl(StringField field, const PathString& value) { |
| 1346 DCHECK(kernel_); | 1151 DCHECK(kernel_); |
| 1347 if (kernel_->ref(field) != value) { | 1152 if (kernel_->ref(field) != value) { |
| 1348 if (NAME == field) { | 1153 kernel_->ref(field) = value; |
| 1349 if (!dir()->ReindexParentIdAndName(kernel_, kernel_->ref(PARENT_ID), | |
| 1350 value)) | |
| 1351 return false; | |
| 1352 } else { | |
| 1353 kernel_->ref(field) = value; | |
| 1354 } | |
| 1355 kernel_->dirty[static_cast<int>(field)] = true; | 1154 kernel_->dirty[static_cast<int>(field)] = true; |
| 1356 } | 1155 } |
| 1357 return true; | 1156 return true; |
| 1358 } | 1157 } |
| 1359 | 1158 |
| 1360 bool MutableEntry::Put(IndexedBitField field, bool value) { | 1159 bool MutableEntry::Put(IndexedBitField field, bool value) { |
| 1361 DCHECK(kernel_); | 1160 DCHECK(kernel_); |
| 1362 if (kernel_->ref(field) != value) { | 1161 if (kernel_->ref(field) != value) { |
| 1363 MetahandleSet* index; | 1162 MetahandleSet* index; |
| 1364 if (IS_UNSYNCED == field) | 1163 if (IS_UNSYNCED == field) |
| 1365 index = dir()->kernel_->unsynced_metahandles; | 1164 index = dir()->kernel_->unsynced_metahandles; |
| 1366 else | 1165 else |
| 1367 index = dir()->kernel_->unapplied_update_metahandles; | 1166 index = dir()->kernel_->unapplied_update_metahandles; |
| 1368 | 1167 |
| 1369 ScopedKernelLock lock(dir()); | 1168 ScopedKernelLock lock(dir()); |
| 1370 if (value) | 1169 if (value) |
| 1371 CHECK(index->insert(kernel_->ref(META_HANDLE)).second); | 1170 CHECK(index->insert(kernel_->ref(META_HANDLE)).second); |
| 1372 else | 1171 else |
| 1373 CHECK(1 == index->erase(kernel_->ref(META_HANDLE))); | 1172 CHECK(1 == index->erase(kernel_->ref(META_HANDLE))); |
| 1374 kernel_->ref(field) = value; | 1173 kernel_->ref(field) = value; |
| 1375 kernel_->dirty[static_cast<int>(field)] = true; | 1174 kernel_->dirty[static_cast<int>(field)] = true; |
| 1376 } | 1175 } |
| 1377 return true; | 1176 return true; |
| 1378 } | 1177 } |
| 1379 | 1178 |
| 1380 // Avoids temporary collision in index when renaming a bookmark to another | |
| 1381 // folder. | |
| 1382 bool MutableEntry::PutParentIdAndName(const Id& parent_id, | |
| 1383 const Name& name) { | |
| 1384 DCHECK(kernel_); | |
| 1385 const bool parent_id_changes = parent_id != kernel_->ref(PARENT_ID); | |
| 1386 bool db_name_changes = name.db_value() != kernel_->ref(NAME); | |
| 1387 if (parent_id_changes || db_name_changes) { | |
| 1388 if (!dir()->ReindexParentIdAndName(kernel_, parent_id, | |
| 1389 name.db_value())) | |
| 1390 return false; | |
| 1391 } | |
| 1392 Put(UNSANITIZED_NAME, name.GetUnsanitizedName()); | |
| 1393 Put(NON_UNIQUE_NAME, name.non_unique_value()); | |
| 1394 if (db_name_changes) | |
| 1395 kernel_->dirty[NAME] = true; | |
| 1396 if (parent_id_changes) { | |
| 1397 kernel_->dirty[PARENT_ID] = true; | |
| 1398 PutPredecessor(Id()); // Put in the 0th position. | |
| 1399 } | |
| 1400 return true; | |
| 1401 } | |
| 1402 | |
| 1403 void MutableEntry::UnlinkFromOrder() { | 1179 void MutableEntry::UnlinkFromOrder() { |
| 1404 Id old_previous = Get(PREV_ID); | 1180 Id old_previous = Get(PREV_ID); |
| 1405 Id old_next = Get(NEXT_ID); | 1181 Id old_next = Get(NEXT_ID); |
| 1406 | 1182 |
| 1407 // Self-looping signifies that this item is not in the order. If we were to | 1183 // Self-looping signifies that this item is not in the order. If we were to |
| 1408 // set these to 0, we could get into trouble because this node might look | 1184 // set these to 0, we could get into trouble because this node might look |
| 1409 // like the first node in the ordering. | 1185 // like the first node in the ordering. |
| 1410 Put(NEXT_ID, Get(ID)); | 1186 Put(NEXT_ID, Get(ID)); |
| 1411 Put(PREV_ID, Get(ID)); | 1187 Put(PREV_ID, Get(ID)); |
| 1412 | 1188 |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1565 while (!ancestor_id.IsRoot()) { | 1341 while (!ancestor_id.IsRoot()) { |
| 1566 if (entry_id == ancestor_id) | 1342 if (entry_id == ancestor_id) |
| 1567 return false; | 1343 return false; |
| 1568 Entry new_parent(trans, GET_BY_ID, ancestor_id); | 1344 Entry new_parent(trans, GET_BY_ID, ancestor_id); |
| 1569 CHECK(new_parent.good()); | 1345 CHECK(new_parent.good()); |
| 1570 ancestor_id = new_parent.Get(PARENT_ID); | 1346 ancestor_id = new_parent.Get(PARENT_ID); |
| 1571 } | 1347 } |
| 1572 return true; | 1348 return true; |
| 1573 } | 1349 } |
| 1574 | 1350 |
| 1575 // returns -1 if s contains any non [0-9] characters | |
| 1576 static int PathStringToInteger(PathString s) { | |
| 1577 PathString::const_iterator i = s.begin(); | |
| 1578 for (; i != s.end(); ++i) { | |
| 1579 if (PathString::npos == PathString(PSTR("0123456789")).find(*i)) | |
| 1580 return -1; | |
| 1581 } | |
| 1582 return atoi(s.c_str()); | |
| 1583 } | |
| 1584 | |
| 1585 // appends ~1 to the end of 's' unless there is already ~#, in which case | |
| 1586 // it just increments the number | |
| 1587 static PathString FixBasenameInCollision(const PathString s) { | |
| 1588 PathString::size_type last_tilde = s.find_last_of(PSTR('~')); | |
| 1589 if (PathString::npos == last_tilde) return s + PSTR("~1"); | |
| 1590 if (s.size() == (last_tilde + 1)) return s + PSTR("1"); | |
| 1591 // we have ~, but not necessarily ~# (for some number >= 0). check for that | |
| 1592 int n; | |
| 1593 if ((n = PathStringToInteger(s.substr(last_tilde + 1))) != -1) { | |
| 1594 n++; | |
| 1595 PathString pre_number = s.substr(0, last_tilde + 1); | |
| 1596 return pre_number + IntToString(n); | |
| 1597 } else { | |
| 1598 // we have a ~, but not a number following it, so we'll add another | |
| 1599 // ~ and this time, a number | |
| 1600 return s + PSTR("~1"); | |
| 1601 } | |
| 1602 } | |
| 1603 | |
| 1604 void DBName::MakeNoncollidingForEntry(BaseTransaction* trans, | |
| 1605 const Id& parent_id, | |
| 1606 Entry* e) { | |
| 1607 const PathString& desired_name = *this; | |
| 1608 CHECK(!desired_name.empty()); | |
| 1609 PathString::size_type first_dot = desired_name.find_first_of(PSTR('.')); | |
| 1610 if (PathString::npos == first_dot) | |
| 1611 first_dot = desired_name.size(); | |
| 1612 PathString basename = desired_name.substr(0, first_dot); | |
| 1613 PathString dotextension = desired_name.substr(first_dot); | |
| 1614 CHECK(basename + dotextension == desired_name); | |
| 1615 for (;;) { | |
| 1616 // Check for collision. | |
| 1617 PathString testname = basename + dotextension; | |
| 1618 Entry same_path_entry(trans, GET_BY_PARENTID_AND_DBNAME, | |
| 1619 parent_id, testname); | |
| 1620 if (!same_path_entry.good() || (e && same_path_entry.Get(ID) == e->Get(ID))) | |
| 1621 break; | |
| 1622 // There was a collision, so fix the name. | |
| 1623 basename = FixBasenameInCollision(basename); | |
| 1624 } | |
| 1625 // Set our value to the new value. This invalidates desired_name. | |
| 1626 PathString new_value = basename + dotextension; | |
| 1627 swap(new_value); | |
| 1628 } | |
| 1629 | |
| 1630 const Blob* GetExtendedAttributeValue(const Entry& e, | 1351 const Blob* GetExtendedAttributeValue(const Entry& e, |
| 1631 const PathString& attribute_name) { | 1352 const PathString& attribute_name) { |
| 1632 ExtendedAttributeKey key(e.Get(META_HANDLE), attribute_name); | 1353 ExtendedAttributeKey key(e.Get(META_HANDLE), attribute_name); |
| 1633 ExtendedAttribute extended_attribute(e.trans(), GET_BY_HANDLE, key); | 1354 ExtendedAttribute extended_attribute(e.trans(), GET_BY_HANDLE, key); |
| 1634 if (extended_attribute.good() && !extended_attribute.is_deleted()) | 1355 if (extended_attribute.good() && !extended_attribute.is_deleted()) |
| 1635 return &extended_attribute.value(); | 1356 return &extended_attribute.value(); |
| 1636 return NULL; | 1357 return NULL; |
| 1637 } | 1358 } |
| 1638 | 1359 |
| 1639 // This function sets only the flags needed to get this entry to sync. | 1360 // This function sets only the flags needed to get this entry to sync. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1722 return s << std::dec; | 1443 return s << std::dec; |
| 1723 } | 1444 } |
| 1724 | 1445 |
| 1725 FastDump& operator<<(FastDump& dump, const syncable::Blob& blob) { | 1446 FastDump& operator<<(FastDump& dump, const syncable::Blob& blob) { |
| 1726 if (blob.empty()) | 1447 if (blob.empty()) |
| 1727 return dump; | 1448 return dump; |
| 1728 string buffer(HexEncode(&blob[0], blob.size())); | 1449 string buffer(HexEncode(&blob[0], blob.size())); |
| 1729 dump.out_->sputn(buffer.c_str(), buffer.size()); | 1450 dump.out_->sputn(buffer.c_str(), buffer.size()); |
| 1730 return dump; | 1451 return dump; |
| 1731 } | 1452 } |
| OLD | NEW |