| 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 <set> | 25 #include <set> |
| 26 #include <string> | 26 #include <string> |
| 27 | 27 |
| 28 #include "base/hash_tables.h" | 28 #include "base/hash_tables.h" |
| 29 #include "base/file_util.h" |
| 29 #include "base/logging.h" | 30 #include "base/logging.h" |
| 30 #include "base/perftimer.h" | 31 #include "base/perftimer.h" |
| 31 #include "base/scoped_ptr.h" | 32 #include "base/scoped_ptr.h" |
| 33 #include "base/string_util.h" |
| 32 #include "base/time.h" | 34 #include "base/time.h" |
| 33 #include "chrome/browser/sync/engine/syncer.h" | 35 #include "chrome/browser/sync/engine/syncer.h" |
| 34 #include "chrome/browser/sync/engine/syncer_util.h" | 36 #include "chrome/browser/sync/engine/syncer_util.h" |
| 35 #include "chrome/browser/sync/protocol/service_constants.h" | 37 #include "chrome/browser/sync/protocol/service_constants.h" |
| 36 #include "chrome/browser/sync/syncable/directory_backing_store.h" | 38 #include "chrome/browser/sync/syncable/directory_backing_store.h" |
| 37 #include "chrome/browser/sync/syncable/directory_manager.h" | 39 #include "chrome/browser/sync/syncable/directory_manager.h" |
| 38 #include "chrome/browser/sync/syncable/syncable-inl.h" | 40 #include "chrome/browser/sync/syncable/syncable-inl.h" |
| 39 #include "chrome/browser/sync/syncable/syncable_changes_version.h" | 41 #include "chrome/browser/sync/syncable/syncable_changes_version.h" |
| 40 #include "chrome/browser/sync/syncable/syncable_columns.h" | 42 #include "chrome/browser/sync/syncable/syncable_columns.h" |
| 41 #include "chrome/browser/sync/util/character_set_converters.h" | |
| 42 #include "chrome/browser/sync/util/compat_file.h" | |
| 43 #include "chrome/browser/sync/util/crypto_helpers.h" | 43 #include "chrome/browser/sync/util/crypto_helpers.h" |
| 44 #include "chrome/browser/sync/util/event_sys-inl.h" | 44 #include "chrome/browser/sync/util/event_sys-inl.h" |
| 45 #include "chrome/browser/sync/util/fast_dump.h" | 45 #include "chrome/browser/sync/util/fast_dump.h" |
| 46 #include "chrome/browser/sync/util/path_helpers.h" | 46 #include "chrome/browser/sync/util/path_helpers.h" |
| 47 | 47 |
| 48 namespace { | 48 namespace { |
| 49 enum InvariantCheckLevel { | 49 enum InvariantCheckLevel { |
| 50 OFF = 0, | 50 OFF = 0, |
| 51 VERIFY_IN_MEMORY = 1, | 51 VERIFY_IN_MEMORY = 1, |
| 52 FULL_DB_VERIFICATION = 2 | 52 FULL_DB_VERIFICATION = 2 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 83 #error NEED OS SPECIFIC Now() implementation | 83 #error NEED OS SPECIFIC Now() implementation |
| 84 #endif | 84 #endif |
| 85 } | 85 } |
| 86 | 86 |
| 87 /////////////////////////////////////////////////////////////////////////// | 87 /////////////////////////////////////////////////////////////////////////// |
| 88 // Compare functions and hashes for the indices. | 88 // Compare functions and hashes for the indices. |
| 89 | 89 |
| 90 // Callback for sqlite3 | 90 // Callback for sqlite3 |
| 91 int ComparePathNames16(void*, int a_bytes, const void* a, int b_bytes, | 91 int ComparePathNames16(void*, int a_bytes, const void* a, int b_bytes, |
| 92 const void* b) { | 92 const void* b) { |
| 93 #if defined(OS_WIN) | |
| 94 DCHECK_EQ(0, a_bytes % 2); | |
| 95 DCHECK_EQ(0, b_bytes % 2); | |
| 96 int result = CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, | |
| 97 static_cast<const PathChar*>(a), a_bytes / 2, | |
| 98 static_cast<const PathChar*>(b), b_bytes / 2); | |
| 99 CHECK(0 != result) << "Error comparing strings: " << GetLastError(); | |
| 100 return result - 2; // Convert to -1, 0, 1 | |
| 101 #elif defined(OS_LINUX) | |
| 102 int result = base::strncasecmp(reinterpret_cast<const char *>(a), | 93 int result = base::strncasecmp(reinterpret_cast<const char *>(a), |
| 103 reinterpret_cast<const char *>(b), | 94 reinterpret_cast<const char *>(b), |
| 104 std::min(a_bytes, b_bytes)); | 95 std::min(a_bytes, b_bytes)); |
| 105 if (result != 0) { | 96 if (result != 0) { |
| 106 return result; | 97 return result; |
| 107 } else { | 98 } else { |
| 108 return a_bytes > b_bytes ? 1 : b_bytes > a_bytes ? -1 : 0; | 99 return a_bytes > b_bytes ? 1 : b_bytes > a_bytes ? -1 : 0; |
| 109 } | 100 } |
| 110 #elif defined(OS_MACOSX) | |
| 111 CFStringRef a_str; | |
| 112 CFStringRef b_str; | |
| 113 a_str = CFStringCreateWithBytes(NULL, reinterpret_cast<const UInt8*>(a), | |
| 114 a_bytes, kCFStringEncodingUTF8, FALSE); | |
| 115 b_str = CFStringCreateWithBytes(NULL, reinterpret_cast<const UInt8*>(b), | |
| 116 b_bytes, kCFStringEncodingUTF8, FALSE); | |
| 117 CFComparisonResult res; | |
| 118 res = CFStringCompare(a_str, b_str, kCFCompareCaseInsensitive); | |
| 119 CFRelease(a_str); | |
| 120 CFRelease(b_str); | |
| 121 return res; | |
| 122 #else | |
| 123 #error no ComparePathNames16() for your OS | |
| 124 #endif | |
| 125 } | 101 } |
| 126 | 102 |
| 127 template <Int64Field field_index> | 103 template <Int64Field field_index> |
| 128 class SameField { | 104 class SameField { |
| 129 public: | 105 public: |
| 130 inline bool operator()(const syncable::EntryKernel* a, | 106 inline bool operator()(const syncable::EntryKernel* a, |
| 131 const syncable::EntryKernel* b) const { | 107 const syncable::EntryKernel* b) const { |
| 132 return a->ref(field_index) == b->ref(field_index); | 108 return a->ref(field_index) == b->ref(field_index); |
| 133 } | 109 } |
| 134 }; | 110 }; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 kernel->ref(NAME) : kernel->ref(UNSANITIZED_NAME); | 146 kernel->ref(NAME) : kernel->ref(UNSANITIZED_NAME); |
| 171 return Name(kernel->ref(NAME), sync_name_ref, kernel->ref(NON_UNIQUE_NAME)); | 147 return Name(kernel->ref(NAME), sync_name_ref, kernel->ref(NON_UNIQUE_NAME)); |
| 172 } | 148 } |
| 173 | 149 |
| 174 /////////////////////////////////////////////////////////////////////////// | 150 /////////////////////////////////////////////////////////////////////////// |
| 175 // Directory | 151 // Directory |
| 176 | 152 |
| 177 static const DirectoryChangeEvent kShutdownChangesEvent = | 153 static const DirectoryChangeEvent kShutdownChangesEvent = |
| 178 { DirectoryChangeEvent::SHUTDOWN, 0, 0 }; | 154 { DirectoryChangeEvent::SHUTDOWN, 0, 0 }; |
| 179 | 155 |
| 180 Directory::Kernel::Kernel(const PathString& db_path, | 156 Directory::Kernel::Kernel(const FilePath& db_path, |
| 181 const PathString& name, | 157 const PathString& name, |
| 182 const KernelLoadInfo& info) | 158 const KernelLoadInfo& info) |
| 183 : db_path(db_path), | 159 : db_path(db_path), |
| 184 refcount(1), | 160 refcount(1), |
| 185 name_(name), | 161 name_(name), |
| 186 metahandles_index(new Directory::MetahandlesIndex), | 162 metahandles_index(new Directory::MetahandlesIndex), |
| 187 ids_index(new Directory::IdsIndex), | 163 ids_index(new Directory::IdsIndex), |
| 188 parent_id_and_names_index(new Directory::ParentIdAndNamesIndex), | 164 parent_id_and_names_index(new Directory::ParentIdAndNamesIndex), |
| 189 extended_attributes(new ExtendedAttributes), | 165 extended_attributes(new ExtendedAttributes), |
| 190 unapplied_update_metahandles(new MetahandleSet), | 166 unapplied_update_metahandles(new MetahandleSet), |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 | 216 |
| 241 // PathMatchSpec strips spaces from the start of pathspec, so we compare those | 217 // PathMatchSpec strips spaces from the start of pathspec, so we compare those |
| 242 // ourselves. | 218 // ourselves. |
| 243 const PathChar* pathname_ptr = pathname.c_str(); | 219 const PathChar* pathname_ptr = pathname.c_str(); |
| 244 const PathChar* pathspec_ptr = pathspec.c_str(); | 220 const PathChar* pathspec_ptr = pathspec.c_str(); |
| 245 | 221 |
| 246 while (*pathname_ptr == ' ' && *pathspec_ptr == ' ') | 222 while (*pathname_ptr == ' ' && *pathspec_ptr == ' ') |
| 247 ++pathname_ptr, ++pathspec_ptr; | 223 ++pathname_ptr, ++pathspec_ptr; |
| 248 | 224 |
| 249 // If we have more inital spaces in the pathspec than in the pathname then the | 225 // If we have more inital spaces in the pathspec than in the pathname then the |
| 250 // result from PathMatchSpec will be erronous. | 226 // result from PathMatchSpec will be erroneous. |
| 251 if (*pathspec_ptr == ' ') | 227 if (*pathspec_ptr == ' ') |
| 252 return FALSE; | 228 return FALSE; |
| 253 | 229 |
| 254 // PathMatchSpec also gets "confused" when there are ';' characters in name or | 230 // PathMatchSpec also gets "confused" when there are ';' characters in name or |
| 255 // in spec. So, if we match (f.i.) ";" with ";" PathMatchSpec will return | 231 // in spec. So, if we match (f.i.) ";" with ";" PathMatchSpec will return |
| 256 // FALSE (which is wrong). Luckily for us, we can easily fix this by | 232 // FALSE (which is wrong). Luckily for us, we can easily fix this by |
| 257 // substituting ';' with ':' which is illegal character in file name and | 233 // substituting ';' with ':' which is illegal character in file name and |
| 258 // we're not going to see it there. With ':' in path name and spec | 234 // we're not going to see it there. With ':' in path name and spec |
| 259 // PathMatchSpec works fine. | 235 // PathMatchSpec works fine. |
| 260 if ((NULL == wcschr(pathname_ptr, L';')) && | 236 if ((NULL == strchr(pathname_ptr, ';')) && |
| 261 (NULL == wcschr(pathspec_ptr, L';'))) { | 237 (NULL == strchr(pathspec_ptr, ';'))) { |
| 262 // No ';' in file name and in spec. Just pass it as it is. | 238 // No ';' in file name and in spec. Just pass it as it is. |
| 263 return ::PathMatchSpec(pathname_ptr, pathspec_ptr); | 239 return ::PathMatchSpecA(pathname_ptr, pathspec_ptr); |
| 264 } | 240 } |
| 265 | 241 |
| 266 // We need to subst ';' with ':' in both, name and spec. | 242 // We need to subst ';' with ':' in both, name and spec. |
| 267 PathString name_subst(pathname_ptr); | 243 PathString name_subst(pathname_ptr); |
| 268 PathString spec_subst(pathspec_ptr); | 244 PathString spec_subst(pathspec_ptr); |
| 269 | 245 |
| 270 PathString::size_type index = name_subst.find(L';'); | 246 PathString::size_type index = name_subst.find(L';'); |
| 271 while (PathString::npos != index) { | 247 while (PathString::npos != index) { |
| 272 name_subst[index] = L':'; | 248 name_subst[index] = ':'; |
| 273 index = name_subst.find(L';', index + 1); | 249 index = name_subst.find(';', index + 1); |
| 274 } | 250 } |
| 275 | 251 |
| 276 index = spec_subst.find(L';'); | 252 index = spec_subst.find(L';'); |
| 277 while (PathString::npos != index) { | 253 while (PathString::npos != index) { |
| 278 spec_subst[index] = L':'; | 254 spec_subst[index] = ':'; |
| 279 index = spec_subst.find(L';', index + 1); | 255 index = spec_subst.find(';', index + 1); |
| 280 } | 256 } |
| 281 | 257 |
| 282 return ::PathMatchSpec(name_subst.c_str(), spec_subst.c_str()); | 258 return ::PathMatchSpecA(name_subst.c_str(), spec_subst.c_str()); |
| 283 #else | 259 #else |
| 284 return 0 == ComparePathNames(pathname, pathspec); | 260 return 0 == ComparePathNames(pathname, pathspec); |
| 285 #endif | 261 #endif |
| 286 } | 262 } |
| 287 | 263 |
| 288 DirOpenResult Directory::Open(const PathString& file_path, | 264 DirOpenResult Directory::Open(const FilePath& file_path, |
| 289 const PathString& name) { | 265 const PathString& name) { |
| 290 const DirOpenResult result = OpenImpl(file_path, name); | 266 const DirOpenResult result = OpenImpl(file_path, name); |
| 291 if (OPENED != result) | 267 if (OPENED != result) |
| 292 Close(); | 268 Close(); |
| 293 return result; | 269 return result; |
| 294 } | 270 } |
| 295 | 271 |
| 296 void Directory::InitializeIndices() { | 272 void Directory::InitializeIndices() { |
| 297 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); | 273 MetahandlesIndex::iterator it = kernel_->metahandles_index->begin(); |
| 298 for (; it != kernel_->metahandles_index->end(); ++it) { | 274 for (; it != kernel_->metahandles_index->end(); ++it) { |
| 299 EntryKernel* entry = *it; | 275 EntryKernel* entry = *it; |
| 300 if (!entry->ref(IS_DEL)) | 276 if (!entry->ref(IS_DEL)) |
| 301 kernel_->parent_id_and_names_index->insert(entry); | 277 kernel_->parent_id_and_names_index->insert(entry); |
| 302 kernel_->ids_index->insert(entry); | 278 kernel_->ids_index->insert(entry); |
| 303 if (entry->ref(IS_UNSYNCED)) | 279 if (entry->ref(IS_UNSYNCED)) |
| 304 kernel_->unsynced_metahandles->insert(entry->ref(META_HANDLE)); | 280 kernel_->unsynced_metahandles->insert(entry->ref(META_HANDLE)); |
| 305 if (entry->ref(IS_UNAPPLIED_UPDATE)) | 281 if (entry->ref(IS_UNAPPLIED_UPDATE)) |
| 306 kernel_->unapplied_update_metahandles->insert(entry->ref(META_HANDLE)); | 282 kernel_->unapplied_update_metahandles->insert(entry->ref(META_HANDLE)); |
| 307 } | 283 } |
| 308 } | 284 } |
| 309 | 285 |
| 310 DirectoryBackingStore* Directory::CreateBackingStore( | 286 DirectoryBackingStore* Directory::CreateBackingStore( |
| 311 const PathString& dir_name, const PathString& backing_filepath) { | 287 const PathString& dir_name, const FilePath& backing_filepath) { |
| 312 return new DirectoryBackingStore(dir_name, backing_filepath); | 288 return new DirectoryBackingStore(dir_name, backing_filepath); |
| 313 } | 289 } |
| 314 | 290 |
| 315 DirOpenResult Directory::OpenImpl(const PathString& file_path, | 291 DirOpenResult Directory::OpenImpl(const FilePath& file_path, |
| 316 const PathString& name) { | 292 const PathString& name) { |
| 317 DCHECK_EQ(static_cast<DirectoryBackingStore*>(NULL), store_); | 293 DCHECK_EQ(static_cast<DirectoryBackingStore*>(NULL), store_); |
| 318 const PathString db_path = ::GetFullPath(file_path); | 294 FilePath db_path(file_path); |
| 295 file_util::AbsolutePath(&db_path); |
| 319 store_ = CreateBackingStore(name, db_path); | 296 store_ = CreateBackingStore(name, db_path); |
| 320 | 297 |
| 321 KernelLoadInfo info; | 298 KernelLoadInfo info; |
| 322 // Temporary indicies before kernel_ initialized in case Load fails. We 0(1) | 299 // Temporary indices before kernel_ initialized in case Load fails. We 0(1) |
| 323 // swap these later. | 300 // swap these later. |
| 324 MetahandlesIndex metas_bucket; | 301 MetahandlesIndex metas_bucket; |
| 325 ExtendedAttributes xattrs_bucket; | 302 ExtendedAttributes xattrs_bucket; |
| 326 DirOpenResult result = store_->Load(&metas_bucket, &xattrs_bucket, &info); | 303 DirOpenResult result = store_->Load(&metas_bucket, &xattrs_bucket, &info); |
| 327 if (OPENED != result) | 304 if (OPENED != result) |
| 328 return result; | 305 return result; |
| 329 | 306 |
| 330 kernel_ = new Kernel(db_path, name, info); | 307 kernel_ = new Kernel(db_path, name, info); |
| 331 kernel_->metahandles_index->swap(metas_bucket); | 308 kernel_->metahandles_index->swap(metas_bucket); |
| 332 kernel_->extended_attributes->swap(xattrs_bucket); | 309 kernel_->extended_attributes->swap(xattrs_bucket); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 return index->lower_bound(&needle_); | 476 return index->lower_bound(&needle_); |
| 500 } | 477 } |
| 501 virtual Index::iterator upper_bound(Index* index) { | 478 virtual Index::iterator upper_bound(Index* index) { |
| 502 needle_.ref(PARENT_ID) = parent_id_; | 479 needle_.ref(PARENT_ID) = parent_id_; |
| 503 needle_.ref(NAME) = pathspec_; | 480 needle_.ref(NAME) = pathspec_; |
| 504 return index->upper_bound(&needle_); | 481 return index->upper_bound(&needle_); |
| 505 } | 482 } |
| 506 const PathString pathspec_; | 483 const PathString pathspec_; |
| 507 }; | 484 }; |
| 508 | 485 |
| 509 // Matches a pathspec with wildcards. | |
| 510 struct PartialPathMatcher : public PathMatcher { | |
| 511 PartialPathMatcher(const PathString& pathspec, | |
| 512 PathString::size_type wildcard, const Id& parent_id) | |
| 513 : PathMatcher(parent_id), pathspec_(pathspec) { | |
| 514 if (0 == wildcard) | |
| 515 return; | |
| 516 lesser_.assign(pathspec_.data(), wildcard); | |
| 517 greater_.assign(pathspec_.data(), wildcard); | |
| 518 // Increment the last letter of greater so we can then less than | |
| 519 // compare to it. | |
| 520 PathString::size_type i = greater_.size() - 1; | |
| 521 do { | |
| 522 if (greater_[i] == std::numeric_limits<PathString::value_type>::max()) { | |
| 523 greater_.resize(i); // Try the preceding character. | |
| 524 if (0 == i--) | |
| 525 break; | |
| 526 } else { | |
| 527 greater_[i] += 1; | |
| 528 } | |
| 529 // Yes, there are cases where incrementing a character | |
| 530 // actually decreases its position in the sort. Example: 9 -> : | |
| 531 } while (ComparePathNames(lesser_, greater_) >= 0); | |
| 532 } | |
| 533 | |
| 534 virtual MatchType PathMatches(const PathString& path) { | |
| 535 return PathNameMatch(path, pathspec_) ? MATCH : NO_MATCH; | |
| 536 } | |
| 537 | |
| 538 virtual Index::iterator lower_bound(Index* index) { | |
| 539 needle_.ref(PARENT_ID) = parent_id_; | |
| 540 needle_.ref(NAME) = lesser_; | |
| 541 return index->lower_bound(&needle_); | |
| 542 } | |
| 543 virtual Index::iterator upper_bound(Index* index) { | |
| 544 if (greater_.empty()) { | |
| 545 needle_.ref(PARENT_ID) = parent_id_; | |
| 546 needle_.ref(NAME).clear(); | |
| 547 Index::iterator i = index->upper_bound(&needle_), | |
| 548 end = index->end(); | |
| 549 while (i != end && (*i)->ref(PARENT_ID) == parent_id_) | |
| 550 ++i; | |
| 551 return i; | |
| 552 } else { | |
| 553 needle_.ref(PARENT_ID) = parent_id_; | |
| 554 needle_.ref(NAME) = greater_; | |
| 555 return index->lower_bound(&needle_); | |
| 556 } | |
| 557 } | |
| 558 | |
| 559 const PathString pathspec_; | |
| 560 PathString lesser_; | |
| 561 PathString greater_; | |
| 562 }; | |
| 563 | |
| 564 | |
| 565 void Directory::GetChildHandles(BaseTransaction* trans, const Id& parent_id, | 486 void Directory::GetChildHandles(BaseTransaction* trans, const Id& parent_id, |
| 566 Directory::ChildHandles* result) { | 487 Directory::ChildHandles* result) { |
| 567 AllPathsMatcher matcher(parent_id); | 488 AllPathsMatcher matcher(parent_id); |
| 568 return GetChildHandlesImpl(trans, parent_id, &matcher, result); | 489 return GetChildHandlesImpl(trans, parent_id, &matcher, result); |
| 569 } | 490 } |
| 570 | 491 |
| 571 void Directory::GetChildHandlesImpl(BaseTransaction* trans, const Id& parent_id, | 492 void Directory::GetChildHandlesImpl(BaseTransaction* trans, const Id& parent_id, |
| 572 PathMatcher* matcher, | 493 PathMatcher* matcher, |
| 573 Directory::ChildHandles* result) { | 494 Directory::ChildHandles* result) { |
| 574 CHECK(this == trans->directory()); | 495 CHECK(this == trans->directory()); |
| (...skipping 1076 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1651 return true; | 1572 return true; |
| 1652 } | 1573 } |
| 1653 | 1574 |
| 1654 // returns -1 if s contains any non [0-9] characters | 1575 // returns -1 if s contains any non [0-9] characters |
| 1655 static int PathStringToInteger(PathString s) { | 1576 static int PathStringToInteger(PathString s) { |
| 1656 PathString::const_iterator i = s.begin(); | 1577 PathString::const_iterator i = s.begin(); |
| 1657 for (; i != s.end(); ++i) { | 1578 for (; i != s.end(); ++i) { |
| 1658 if (PathString::npos == PathString(PSTR("0123456789")).find(*i)) | 1579 if (PathString::npos == PathString(PSTR("0123456789")).find(*i)) |
| 1659 return -1; | 1580 return -1; |
| 1660 } | 1581 } |
| 1661 return | 1582 return atoi(s.c_str()); |
| 1662 #if !PATHSTRING_IS_STD_STRING | |
| 1663 _wtoi | |
| 1664 #else | |
| 1665 atoi | |
| 1666 #endif | |
| 1667 (s.c_str()); | |
| 1668 } | |
| 1669 | |
| 1670 static PathString IntegerToPathString(int i) { | |
| 1671 const size_t kBufSize = 25; | |
| 1672 PathChar buf[kBufSize]; | |
| 1673 #if !PATHSTRING_IS_STD_STRING | |
| 1674 const int radix = 10; | |
| 1675 _itow(i, buf, radix); | |
| 1676 #else | |
| 1677 snprintf(buf, kBufSize, "%d", i); | |
| 1678 #endif | |
| 1679 return buf; | |
| 1680 } | 1583 } |
| 1681 | 1584 |
| 1682 // appends ~1 to the end of 's' unless there is already ~#, in which case | 1585 // appends ~1 to the end of 's' unless there is already ~#, in which case |
| 1683 // it just increments the number | 1586 // it just increments the number |
| 1684 static PathString FixBasenameInCollision(const PathString s) { | 1587 static PathString FixBasenameInCollision(const PathString s) { |
| 1685 PathString::size_type last_tilde = s.find_last_of(PSTR('~')); | 1588 PathString::size_type last_tilde = s.find_last_of(PSTR('~')); |
| 1686 if (PathString::npos == last_tilde) return s + PSTR("~1"); | 1589 if (PathString::npos == last_tilde) return s + PSTR("~1"); |
| 1687 if (s.size() == (last_tilde + 1)) return s + PSTR("1"); | 1590 if (s.size() == (last_tilde + 1)) return s + PSTR("1"); |
| 1688 // we have ~, but not necessarily ~# (for some number >= 0). check for that | 1591 // we have ~, but not necessarily ~# (for some number >= 0). check for that |
| 1689 int n; | 1592 int n; |
| 1690 if ((n = PathStringToInteger(s.substr(last_tilde + 1))) != -1) { | 1593 if ((n = PathStringToInteger(s.substr(last_tilde + 1))) != -1) { |
| 1691 n++; | 1594 n++; |
| 1692 PathString pre_number = s.substr(0, last_tilde + 1); | 1595 PathString pre_number = s.substr(0, last_tilde + 1); |
| 1693 return pre_number + IntegerToPathString(n); | 1596 return pre_number + IntToString(n); |
| 1694 } else { | 1597 } else { |
| 1695 // we have a ~, but not a number following it, so we'll add another | 1598 // we have a ~, but not a number following it, so we'll add another |
| 1696 // ~ and this time, a number | 1599 // ~ and this time, a number |
| 1697 return s + PSTR("~1"); | 1600 return s + PSTR("~1"); |
| 1698 } | 1601 } |
| 1699 } | 1602 } |
| 1700 | 1603 |
| 1701 void DBName::MakeNoncollidingForEntry(BaseTransaction* trans, | 1604 void DBName::MakeNoncollidingForEntry(BaseTransaction* trans, |
| 1702 const Id& parent_id, | 1605 const Id& parent_id, |
| 1703 Entry* e) { | 1606 Entry* e) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1717 if (!same_path_entry.good() || (e && same_path_entry.Get(ID) == e->Get(ID))) | 1620 if (!same_path_entry.good() || (e && same_path_entry.Get(ID) == e->Get(ID))) |
| 1718 break; | 1621 break; |
| 1719 // There was a collision, so fix the name. | 1622 // There was a collision, so fix the name. |
| 1720 basename = FixBasenameInCollision(basename); | 1623 basename = FixBasenameInCollision(basename); |
| 1721 } | 1624 } |
| 1722 // Set our value to the new value. This invalidates desired_name. | 1625 // Set our value to the new value. This invalidates desired_name. |
| 1723 PathString new_value = basename + dotextension; | 1626 PathString new_value = basename + dotextension; |
| 1724 swap(new_value); | 1627 swap(new_value); |
| 1725 } | 1628 } |
| 1726 | 1629 |
| 1727 PathString GetFullPath(BaseTransaction* trans, const Entry& e) { | |
| 1728 PathString result; | |
| 1729 #if defined(COMPILER_MSVC) | |
| 1730 result.reserve(MAX_PATH); | |
| 1731 #endif | |
| 1732 ReverseAppend(e.Get(NAME), &result); | |
| 1733 Id id = e.Get(PARENT_ID); | |
| 1734 while (!id.IsRoot()) { | |
| 1735 result.push_back(kPathSeparator[0]); | |
| 1736 Entry ancestor(trans, GET_BY_ID, id); | |
| 1737 if (!ancestor.good()) { | |
| 1738 // This can happen if the parent folder got deleted before the entry. | |
| 1739 LOG(WARNING) << "Cannot get full path of " << e | |
| 1740 << "\nbecause an ancestor folder has been deleted."; | |
| 1741 result.clear(); | |
| 1742 return result; | |
| 1743 } | |
| 1744 ReverseAppend(ancestor.Get(NAME), &result); | |
| 1745 id = ancestor.Get(PARENT_ID); | |
| 1746 } | |
| 1747 result.push_back(kPathSeparator[0]); | |
| 1748 reverse(result.begin(), result.end()); | |
| 1749 return result; | |
| 1750 } | |
| 1751 | |
| 1752 const Blob* GetExtendedAttributeValue(const Entry& e, | 1630 const Blob* GetExtendedAttributeValue(const Entry& e, |
| 1753 const PathString& attribute_name) { | 1631 const PathString& attribute_name) { |
| 1754 ExtendedAttributeKey key(e.Get(META_HANDLE), attribute_name); | 1632 ExtendedAttributeKey key(e.Get(META_HANDLE), attribute_name); |
| 1755 ExtendedAttribute extended_attribute(e.trans(), GET_BY_HANDLE, key); | 1633 ExtendedAttribute extended_attribute(e.trans(), GET_BY_HANDLE, key); |
| 1756 if (extended_attribute.good() && !extended_attribute.is_deleted()) | 1634 if (extended_attribute.good() && !extended_attribute.is_deleted()) |
| 1757 return &extended_attribute.value(); | 1635 return &extended_attribute.value(); |
| 1758 return NULL; | 1636 return NULL; |
| 1759 } | 1637 } |
| 1760 | 1638 |
| 1761 // This function sets only the flags needed to get this entry to sync. | 1639 // This function sets only the flags needed to get this entry to sync. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1781 } | 1659 } |
| 1782 | 1660 |
| 1783 inline FastDump& operator<<(FastDump& dump, const DumpColon&) { | 1661 inline FastDump& operator<<(FastDump& dump, const DumpColon&) { |
| 1784 dump.out_->sputn(": ", 2); | 1662 dump.out_->sputn(": ", 2); |
| 1785 return dump; | 1663 return dump; |
| 1786 } | 1664 } |
| 1787 | 1665 |
| 1788 std::ostream& operator<<(std::ostream& stream, const syncable::Entry& entry) { | 1666 std::ostream& operator<<(std::ostream& stream, const syncable::Entry& entry) { |
| 1789 // Using ostreams directly here is dreadfully slow, because a mutex is | 1667 // Using ostreams directly here is dreadfully slow, because a mutex is |
| 1790 // acquired for every <<. Users noticed it spiking CPU. | 1668 // acquired for every <<. Users noticed it spiking CPU. |
| 1791 using browser_sync::ToUTF8; | |
| 1792 using syncable::BitField; | 1669 using syncable::BitField; |
| 1793 using syncable::BitTemp; | 1670 using syncable::BitTemp; |
| 1794 using syncable::BlobField; | 1671 using syncable::BlobField; |
| 1795 using syncable::EntryKernel; | 1672 using syncable::EntryKernel; |
| 1796 using syncable::g_metas_columns; | 1673 using syncable::g_metas_columns; |
| 1797 using syncable::IdField; | 1674 using syncable::IdField; |
| 1798 using syncable::Int64Field; | 1675 using syncable::Int64Field; |
| 1799 using syncable::StringField; | 1676 using syncable::StringField; |
| 1800 using syncable::BEGIN_FIELDS; | 1677 using syncable::BEGIN_FIELDS; |
| 1801 using syncable::BIT_FIELDS_END; | 1678 using syncable::BIT_FIELDS_END; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1816 for ( ; i < ID_FIELDS_END; ++i) { | 1693 for ( ; i < ID_FIELDS_END; ++i) { |
| 1817 s << g_metas_columns[i].name << colon | 1694 s << g_metas_columns[i].name << colon |
| 1818 << kernel->ref(static_cast<IdField>(i)) << separator; | 1695 << kernel->ref(static_cast<IdField>(i)) << separator; |
| 1819 } | 1696 } |
| 1820 s << "Flags: "; | 1697 s << "Flags: "; |
| 1821 for ( ; i < BIT_FIELDS_END; ++i) { | 1698 for ( ; i < BIT_FIELDS_END; ++i) { |
| 1822 if (kernel->ref(static_cast<BitField>(i))) | 1699 if (kernel->ref(static_cast<BitField>(i))) |
| 1823 s << g_metas_columns[i].name << separator; | 1700 s << g_metas_columns[i].name << separator; |
| 1824 } | 1701 } |
| 1825 for ( ; i < STRING_FIELDS_END; ++i) { | 1702 for ( ; i < STRING_FIELDS_END; ++i) { |
| 1826 ToUTF8 field(kernel->ref(static_cast<StringField>(i))); | 1703 const PathString& field = kernel->ref(static_cast<StringField>(i)); |
| 1827 s << g_metas_columns[i].name << colon << field.get_string() << separator; | 1704 s << g_metas_columns[i].name << colon << field << separator; |
| 1828 } | 1705 } |
| 1829 for ( ; i < BLOB_FIELDS_END; ++i) { | 1706 for ( ; i < BLOB_FIELDS_END; ++i) { |
| 1830 s << g_metas_columns[i].name << colon | 1707 s << g_metas_columns[i].name << colon |
| 1831 << kernel->ref(static_cast<BlobField>(i)) << separator; | 1708 << kernel->ref(static_cast<BlobField>(i)) << separator; |
| 1832 } | 1709 } |
| 1833 s << "TempFlags: "; | 1710 s << "TempFlags: "; |
| 1834 for ( ; i < BIT_TEMPS_END; ++i) { | 1711 for ( ; i < BIT_TEMPS_END; ++i) { |
| 1835 if (kernel->ref(static_cast<BitTemp>(i))) | 1712 if (kernel->ref(static_cast<BitTemp>(i))) |
| 1836 s << "#" << i - BIT_TEMPS_BEGIN << separator; | 1713 s << "#" << i - BIT_TEMPS_BEGIN << separator; |
| 1837 } | 1714 } |
| 1838 return stream; | 1715 return stream; |
| 1839 } | 1716 } |
| 1840 | 1717 |
| 1841 std::ostream& operator<<(std::ostream& s, const syncable::Blob& blob) { | 1718 std::ostream& operator<<(std::ostream& s, const syncable::Blob& blob) { |
| 1842 for (syncable::Blob::const_iterator i = blob.begin(); i != blob.end(); ++i) | 1719 for (syncable::Blob::const_iterator i = blob.begin(); i != blob.end(); ++i) |
| 1843 s << std::hex << std::setw(2) | 1720 s << std::hex << std::setw(2) |
| 1844 << std::setfill('0') << static_cast<unsigned int>(*i); | 1721 << std::setfill('0') << static_cast<unsigned int>(*i); |
| 1845 return s << std::dec; | 1722 return s << std::dec; |
| 1846 } | 1723 } |
| 1847 | 1724 |
| 1848 FastDump& operator<<(FastDump& dump, const syncable::Blob& blob) { | 1725 FastDump& operator<<(FastDump& dump, const syncable::Blob& blob) { |
| 1849 if (blob.empty()) | 1726 if (blob.empty()) |
| 1850 return dump; | 1727 return dump; |
| 1851 string buffer(HexEncode(&blob[0], blob.size())); | 1728 string buffer(HexEncode(&blob[0], blob.size())); |
| 1852 dump.out_->sputn(buffer.c_str(), buffer.size()); | 1729 dump.out_->sputn(buffer.c_str(), buffer.size()); |
| 1853 return dump; | 1730 return dump; |
| 1854 } | 1731 } |
| OLD | NEW |