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 |