| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/chromeos/gdata/gdata_files.h" | 5 #include "chrome/browser/chromeos/gdata/gdata_files.h" |
| 6 | 6 |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/utf_string_conversions.h" | 7 #include "base/utf_string_conversions.h" |
| 10 #include "base/platform_file.h" | 8 #include "base/platform_file.h" |
| 11 #include "base/stringprintf.h" | 9 #include "base/stringprintf.h" |
| 12 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 13 #include "chrome/browser/chromeos/gdata/find_entry_delegate.h" | 11 #include "chrome/browser/chromeos/gdata/find_entry_delegate.h" |
| 14 #include "chrome/browser/chromeos/gdata/gdata.pb.h" | 12 #include "chrome/browser/chromeos/gdata/gdata.pb.h" |
| 15 #include "chrome/browser/chromeos/gdata/gdata_parser.h" | 13 #include "chrome/browser/chromeos/gdata/gdata_parser.h" |
| 14 #include "chrome/browser/chromeos/gdata/gdata_util.h" |
| 16 #include "net/base/escape.h" | 15 #include "net/base/escape.h" |
| 17 | 16 |
| 18 namespace gdata { | 17 namespace gdata { |
| 19 namespace { | 18 namespace { |
| 20 | 19 |
| 21 const char kSlash[] = "/"; | 20 const char kSlash[] = "/"; |
| 22 const char kEscapedSlash[] = "\xE2\x88\x95"; | 21 const char kEscapedSlash[] = "\xE2\x88\x95"; |
| 23 const FilePath::CharType kGDataRootDirectory[] = FILE_PATH_LITERAL("gdata"); | 22 const FilePath::CharType kGDataRootDirectory[] = FILE_PATH_LITERAL("gdata"); |
| 24 | 23 |
| 25 std::string CacheSubDirectoryTypeToString( | 24 std::string CacheSubDirectoryTypeToString( |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 } | 287 } |
| 289 entry->set_file_name(full_file_name.value()); | 288 entry->set_file_name(full_file_name.value()); |
| 290 | 289 |
| 291 DVLOG(1) << "AddEntry: dir = " << GetFilePath().value() | 290 DVLOG(1) << "AddEntry: dir = " << GetFilePath().value() |
| 292 << ", file = " + entry->file_name() | 291 << ", file = " + entry->file_name() |
| 293 << ", parent resource = " << entry->parent_resource_id() | 292 << ", parent resource = " << entry->parent_resource_id() |
| 294 << ", resource = " + entry->resource_id(); | 293 << ", resource = " + entry->resource_id(); |
| 295 | 294 |
| 296 | 295 |
| 297 // Add entry to resource map. | 296 // Add entry to resource map. |
| 298 root_->AddEntryToResourceMap(entry); | 297 if (root_) |
| 298 root_->AddEntryToResourceMap(entry); |
| 299 |
| 299 // Setup child and parent links. | 300 // Setup child and parent links. |
| 300 AddChild(entry); | 301 AddChild(entry); |
| 301 entry->SetParent(this); | 302 entry->SetParent(this); |
| 302 } | 303 } |
| 303 | 304 |
| 304 bool GDataDirectory::TakeEntry(GDataEntry* entry) { | 305 bool GDataDirectory::TakeEntry(GDataEntry* entry) { |
| 305 DCHECK(entry); | 306 DCHECK(entry); |
| 306 DCHECK(entry->parent()); | 307 DCHECK(entry->parent()); |
| 307 | 308 |
| 308 entry->parent()->RemoveChild(entry); | 309 entry->parent()->RemoveChild(entry); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 DCHECK(entry); | 368 DCHECK(entry); |
| 368 | 369 |
| 369 const std::string file_name(entry->file_name()); | 370 const std::string file_name(entry->file_name()); |
| 370 GDataEntry* found_entry = FindChild(file_name); | 371 GDataEntry* found_entry = FindChild(file_name); |
| 371 if (!found_entry) | 372 if (!found_entry) |
| 372 return false; | 373 return false; |
| 373 | 374 |
| 374 DCHECK_EQ(entry, found_entry); | 375 DCHECK_EQ(entry, found_entry); |
| 375 | 376 |
| 376 // Remove entry from resource map first. | 377 // Remove entry from resource map first. |
| 377 root_->RemoveEntryFromResourceMap(entry); | 378 if (root_) |
| 379 root_->RemoveEntryFromResourceMap(entry); |
| 378 | 380 |
| 379 // Then delete it from tree. | 381 // Then delete it from tree. |
| 380 child_files_.erase(file_name); | 382 child_files_.erase(file_name); |
| 381 child_directories_.erase(file_name); | 383 child_directories_.erase(file_name); |
| 382 | 384 |
| 383 return true; | 385 return true; |
| 384 } | 386 } |
| 385 | 387 |
| 386 void GDataDirectory::RemoveChildren() { | 388 void GDataDirectory::RemoveChildren() { |
| 387 // Remove child files first. | 389 // Remove child files first. |
| 388 for (GDataFileCollection::const_iterator iter = child_files_.begin(); | 390 for (GDataFileCollection::const_iterator iter = child_files_.begin(); |
| 389 iter != child_files_.end(); ++iter) { | 391 iter != child_files_.end(); ++iter) { |
| 390 root_->RemoveEntryFromResourceMap(iter->second); | 392 if (root_) |
| 393 root_->RemoveEntryFromResourceMap(iter->second); |
| 391 } | 394 } |
| 392 STLDeleteValues(&child_files_); | 395 STLDeleteValues(&child_files_); |
| 393 child_files_.clear(); | 396 child_files_.clear(); |
| 394 | 397 |
| 395 for (GDataDirectoryCollection::iterator iter = child_directories_.begin(); | 398 for (GDataDirectoryCollection::iterator iter = child_directories_.begin(); |
| 396 iter != child_directories_.end(); ++iter) { | 399 iter != child_directories_.end(); ++iter) { |
| 397 GDataDirectory* dir = iter->second; | 400 GDataDirectory* dir = iter->second; |
| 398 // Remove directories recursively. | 401 // Remove directories recursively. |
| 399 dir->RemoveChildren(); | 402 dir->RemoveChildren(); |
| 400 root_->RemoveEntryFromResourceMap(dir); | 403 if (root_) |
| 404 root_->RemoveEntryFromResourceMap(dir); |
| 401 } | 405 } |
| 402 STLDeleteValues(&child_directories_); | 406 STLDeleteValues(&child_directories_); |
| 403 child_directories_.clear(); | 407 child_directories_.clear(); |
| 404 } | 408 } |
| 405 | 409 |
| 406 // GDataRootDirectory::CacheEntry struct implementation. | 410 // GDataRootDirectory::CacheEntry struct implementation. |
| 407 | 411 |
| 408 std::string GDataRootDirectory::CacheEntry::ToString() const { | 412 std::string GDataRootDirectory::CacheEntry::ToString() const { |
| 409 std::vector<std::string> cache_states; | 413 std::vector<std::string> cache_states; |
| 410 if (GDataFile::IsCachePresent(cache_state)) | 414 if (GDataFile::IsCachePresent(cache_state)) |
| 411 cache_states.push_back("present"); | 415 cache_states.push_back("present"); |
| 412 if (GDataFile::IsCachePinned(cache_state)) | 416 if (GDataFile::IsCachePinned(cache_state)) |
| 413 cache_states.push_back("pinned"); | 417 cache_states.push_back("pinned"); |
| 414 if (GDataFile::IsCacheDirty(cache_state)) | 418 if (GDataFile::IsCacheDirty(cache_state)) |
| 415 cache_states.push_back("dirty"); | 419 cache_states.push_back("dirty"); |
| 416 | 420 |
| 417 return base::StringPrintf("md5=%s, subdir=%s, cache_state=%s", | 421 return base::StringPrintf("md5=%s, subdir=%s, cache_state=%s", |
| 418 md5.c_str(), | 422 md5.c_str(), |
| 419 CacheSubDirectoryTypeToString(sub_dir_type).c_str(), | 423 CacheSubDirectoryTypeToString(sub_dir_type).c_str(), |
| 420 JoinString(cache_states, ',').c_str()); | 424 JoinString(cache_states, ',').c_str()); |
| 421 } | 425 } |
| 422 | 426 |
| 423 // GDataRootDirectory class implementation. | 427 // GDataRootDirectory class implementation. |
| 424 | 428 |
| 425 GDataRootDirectory::GDataRootDirectory() | 429 GDataRootDirectory::GDataRootDirectory() |
| 426 : ALLOW_THIS_IN_INITIALIZER_LIST(GDataDirectory(NULL, this)), | 430 : ALLOW_THIS_IN_INITIALIZER_LIST(GDataDirectory(NULL, this)), |
| 431 fake_search_directory_(new GDataDirectory(NULL, NULL)), |
| 427 largest_changestamp_(0), serialized_size_(0) { | 432 largest_changestamp_(0), serialized_size_(0) { |
| 428 title_ = kGDataRootDirectory; | 433 title_ = kGDataRootDirectory; |
| 429 SetFileNameFromTitle(); | 434 SetFileNameFromTitle(); |
| 430 } | 435 } |
| 431 | 436 |
| 432 GDataRootDirectory::~GDataRootDirectory() { | 437 GDataRootDirectory::~GDataRootDirectory() { |
| 433 STLDeleteValues(&cache_map_); | 438 STLDeleteValues(&cache_map_); |
| 434 cache_map_.clear(); | 439 cache_map_.clear(); |
| 435 | 440 |
| 436 resource_map_.clear(); | 441 resource_map_.clear(); |
| 437 } | 442 } |
| 438 | 443 |
| 439 GDataRootDirectory* GDataRootDirectory::AsGDataRootDirectory() { | 444 GDataRootDirectory* GDataRootDirectory::AsGDataRootDirectory() { |
| 440 return this; | 445 return this; |
| 441 } | 446 } |
| 442 | 447 |
| 443 void GDataRootDirectory::AddEntryToResourceMap(GDataEntry* entry) { | 448 void GDataRootDirectory::AddEntryToResourceMap(GDataEntry* entry) { |
| 444 // GDataFileSystem has already locked. | 449 // GDataFileSystem has already locked. |
| 445 DVLOG(1) << "AddEntryToResourceMap " << entry->resource_id(); | 450 DVLOG(1) << "AddEntryToResourceMap " << entry->resource_id(); |
| 446 resource_map_.insert(std::make_pair(entry->resource_id(), entry)); | 451 resource_map_.insert(std::make_pair(entry->resource_id(), entry)); |
| 447 } | 452 } |
| 448 | 453 |
| 449 void GDataRootDirectory::RemoveEntryFromResourceMap(GDataEntry* entry) { | 454 void GDataRootDirectory::RemoveEntryFromResourceMap(GDataEntry* entry) { |
| 450 // GDataFileSystem has already locked. | 455 // GDataFileSystem has already locked. |
| 451 resource_map_.erase(entry->resource_id()); | 456 resource_map_.erase(entry->resource_id()); |
| 452 } | 457 } |
| 453 | 458 |
| 459 bool GDataRootDirectory::ModifyFindEntryParamsForSearchPath( |
| 460 const FilePath& file_path, |
| 461 std::vector<FilePath::StringType>* components, |
| 462 GDataDirectory** current_dir, |
| 463 FilePath* directory_path) { |
| 464 DCHECK(current_dir); |
| 465 DCHECK(components); |
| 466 // |components| should contain at least 4 members. |
| 467 // "gdata", ".search", query_name and query_result_name. Additionally, |
| 468 // if query result is a directory, it may contain subdirectories and files, |
| 469 // in which case the number of components may be bigger than 4. |
| 470 DCHECK_GT(components->size(), 3u); |
| 471 DCHECK(components->at(0) == "gdata" && components->at(1) == ".search"); |
| 472 |
| 473 FilePath::StringType resource_id; |
| 474 FilePath::StringType file_name; |
| 475 if (!util::ParseSearchFileName((*components)[3], &resource_id, &file_name)) |
| 476 return false; |
| 477 |
| 478 GDataEntry* file_entry = GetEntryByResourceId(resource_id); |
| 479 if (!file_entry) |
| 480 return false; |
| 481 |
| 482 // We should continue search from the entry's parent dir (|current_dir|), so |
| 483 // we have to ammend |components| to be relative to the |current_dir| |
| 484 // (including the dir itself). |
| 485 // We continue the search with the entry's parent instead of the entry itself |
| 486 // to make sure that the returned file really has the name |file_name|. Note |
| 487 // that we may end up with finding an entry even if entry with |resource_id| |
| 488 // has a name different from |file_name|. This is intended, and enables us to |
| 489 // test that new file name is unique (in file manager) when renaming the |
| 490 // entry. |
| 491 DCHECK(file_entry->parent()); |
| 492 *current_dir = file_entry->parent(); |
| 493 |
| 494 if ((*current_dir)->parent()) { |
| 495 *directory_path = (*current_dir)->parent()->GetFilePath(); |
| 496 } else { |
| 497 *directory_path = FilePath(); |
| 498 } |
| 499 |
| 500 // Remove "gdata/.search" from path. |
| 501 components->erase(components->begin(), components->begin() + 2); |
| 502 (*components)[0] = (*current_dir)->file_name(); |
| 503 (*components)[1] = file_name; |
| 504 return true; |
| 505 } |
| 506 |
| 454 void GDataRootDirectory::FindEntryByPath( | 507 void GDataRootDirectory::FindEntryByPath( |
| 455 const FilePath& file_path, | 508 const FilePath& file_path, |
| 456 FindEntryDelegate* delegate) { | 509 FindEntryDelegate* delegate) { |
| 457 // GDataFileSystem has already locked. | 510 // GDataFileSystem has already locked. |
| 458 DCHECK(delegate); | 511 DCHECK(delegate); |
| 459 | 512 |
| 460 std::vector<FilePath::StringType> components; | 513 std::vector<FilePath::StringType> components; |
| 461 file_path.GetComponents(&components); | 514 file_path.GetComponents(&components); |
| 462 | 515 |
| 463 GDataDirectory* current_dir = this; | 516 GDataDirectory* current_dir = this; |
| 464 FilePath directory_path; | 517 FilePath directory_path; |
| 518 |
| 519 util::GDataSearchPathType path_type = |
| 520 util::GetSearchPathStatusForPathComponents(components); |
| 521 |
| 522 if (path_type == util::GDATA_SEARCH_PATH_ROOT || |
| 523 path_type == util::GDATA_SEARCH_PATH_QUERY) { |
| 524 delegate->OnDone(base::PLATFORM_FILE_OK, file_path.DirName(), |
| 525 fake_search_directory_.get()); |
| 526 return; |
| 527 } |
| 528 |
| 529 // If the path is under search path, we have to modify paremeters for finding |
| 530 // the entry. |
| 531 if (path_type != util::GDATA_SEARCH_PATH_INVALID) { |
| 532 if (!ModifyFindEntryParamsForSearchPath(file_path, |
| 533 &components, ¤t_dir, &directory_path)) { |
| 534 delegate->OnDone(base::PLATFORM_FILE_ERROR_NOT_FOUND, FilePath(), NULL); |
| 535 return; |
| 536 } |
| 537 } |
| 538 |
| 465 for (size_t i = 0; i < components.size() && current_dir; i++) { | 539 for (size_t i = 0; i < components.size() && current_dir; i++) { |
| 466 directory_path = directory_path.Append(current_dir->file_name()); | 540 directory_path = directory_path.Append(current_dir->file_name()); |
| 467 | 541 |
| 468 // Last element must match, if not last then it must be a directory. | 542 // Last element must match, if not last then it must be a directory. |
| 469 if (i == components.size() - 1) { | 543 if (i == components.size() - 1) { |
| 470 if (current_dir->file_name() == components[i]) | 544 if (current_dir->file_name() == components[i]) { |
| 471 delegate->OnDone(base::PLATFORM_FILE_OK, directory_path, current_dir); | 545 delegate->OnDone(base::PLATFORM_FILE_OK, directory_path, current_dir); |
| 472 else | 546 } else { |
| 473 delegate->OnDone(base::PLATFORM_FILE_ERROR_NOT_FOUND, FilePath(), NULL); | 547 delegate->OnDone(base::PLATFORM_FILE_ERROR_NOT_FOUND, FilePath(), NULL); |
| 474 | 548 } |
| 475 return; | 549 return; |
| 476 } | 550 } |
| 477 | 551 |
| 478 // Not the last part of the path, search for the next segment. | 552 // Not the last part of the path, search for the next segment. |
| 479 GDataEntry* entry = current_dir->FindChild(components[i + 1]); | 553 GDataEntry* entry = current_dir->FindChild(components[i + 1]); |
| 480 if (!entry) { | 554 if (!entry) { |
| 481 delegate->OnDone(base::PLATFORM_FILE_ERROR_NOT_FOUND, FilePath(), NULL); | 555 delegate->OnDone(base::PLATFORM_FILE_ERROR_NOT_FOUND, FilePath(), NULL); |
| 482 return; | 556 return; |
| 483 } | 557 } |
| 484 | 558 |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 bool ok = proto->ParseFromString(serialized_proto); | 873 bool ok = proto->ParseFromString(serialized_proto); |
| 800 if (ok) { | 874 if (ok) { |
| 801 FromProto(*proto.get()); | 875 FromProto(*proto.get()); |
| 802 set_origin(FROM_CACHE); | 876 set_origin(FROM_CACHE); |
| 803 set_refresh_time(base::Time::Now()); | 877 set_refresh_time(base::Time::Now()); |
| 804 } | 878 } |
| 805 return ok; | 879 return ok; |
| 806 } | 880 } |
| 807 | 881 |
| 808 } // namespace gdata | 882 } // namespace gdata |
| OLD | NEW |