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 |