Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Side by Side Diff: chrome/browser/chromeos/gdata/gdata_files.cc

Issue 10827343: Split out gdata_directory_service* (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: rebase Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <leveldb/db.h>
8
9 #include "base/message_loop_proxy.h" 7 #include "base/message_loop_proxy.h"
10 #include "base/platform_file.h" 8 #include "base/platform_file.h"
11 #include "base/string_number_conversions.h" 9 #include "base/string_number_conversions.h"
12 #include "base/string_util.h" 10 #include "base/string_util.h"
13 #include "base/stringprintf.h" 11 #include "base/stringprintf.h"
14 #include "base/sequenced_task_runner.h" 12 #include "base/sequenced_task_runner.h"
15 #include "base/tracked_objects.h" 13 #include "base/tracked_objects.h"
16 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
17 #include "chrome/browser/chromeos/gdata/gdata.pb.h" 15 #include "chrome/browser/chromeos/gdata/gdata.pb.h"
16 #include "chrome/browser/chromeos/gdata/gdata_directory_service.h"
18 #include "chrome/browser/chromeos/gdata/gdata_util.h" 17 #include "chrome/browser/chromeos/gdata/gdata_util.h"
19 #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h" 18 #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h"
20 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
21 #include "net/base/escape.h" 20 #include "net/base/escape.h"
22 21
23 using content::BrowserThread; 22 using content::BrowserThread;
24 23
25 namespace gdata { 24 namespace gdata {
26 namespace { 25 namespace {
27 26
28 const char kSlash[] = "/"; 27 const char kSlash[] = "/";
29 const char kEscapedSlash[] = "\xE2\x88\x95"; 28 const char kEscapedSlash[] = "\xE2\x88\x95";
30 29
31 // m: prefix for filesystem metadata db keys, version and largest_changestamp.
32 // r: prefix for resource id db keys.
33 const char kDBKeyLargestChangestamp[] = "m:largest_changestamp";
34 const char kDBKeyVersion[] = "m:version";
35 const char kDBKeyResourceIdPrefix[] = "r:";
36
37 // Extracts resource_id out of edit url. 30 // Extracts resource_id out of edit url.
38 std::string ExtractResourceId(const GURL& url) { 31 std::string ExtractResourceId(const GURL& url) {
39 return net::UnescapeURLComponent(url.ExtractFileName(), 32 return net::UnescapeURLComponent(url.ExtractFileName(),
40 net::UnescapeRule::URL_SPECIAL_CHARS); 33 net::UnescapeRule::URL_SPECIAL_CHARS);
41 } 34 }
42 35
43 // Returns true if |proto| is a valid proto as the root directory.
44 // Used to reject incompatible proto.
45 bool IsValidRootDirectoryProto(const GDataDirectoryProto& proto) {
46 const GDataEntryProto& entry_proto = proto.gdata_entry();
47 // The title field for the root directory was originally empty, then
48 // changed to "gdata", then changed to "drive". Discard the proto data if
49 // the older formats are detected. See crbug.com/128133 for details.
50 if (entry_proto.title() != "drive") {
51 LOG(ERROR) << "Incompatible proto detected (bad title): "
52 << entry_proto.title();
53 return false;
54 }
55 // The title field for the root directory was originally empty. Discard
56 // the proto data if the older format is detected.
57 if (entry_proto.resource_id() != kGDataRootDirectoryResourceId) {
58 LOG(ERROR) << "Incompatible proto detected (bad resource ID): "
59 << entry_proto.resource_id();
60 return false;
61 }
62
63 return true;
64 }
65
66 } // namespace 36 } // namespace
67 37
68 EntryInfoResult::EntryInfoResult() : error(GDATA_FILE_ERROR_FAILED) {
69 }
70
71 EntryInfoResult::~EntryInfoResult() {
72 }
73
74 EntryInfoPairResult::EntryInfoPairResult() {
75 }
76
77 EntryInfoPairResult::~EntryInfoPairResult() {
78 }
79
80 // GDataEntry class. 38 // GDataEntry class.
81 39
82 GDataEntry::GDataEntry(GDataDirectoryService* directory_service) 40 GDataEntry::GDataEntry(GDataDirectoryService* directory_service)
83 : parent_(NULL), 41 : parent_(NULL),
84 directory_service_(directory_service), 42 directory_service_(directory_service),
85 deleted_(false) { 43 deleted_(false) {
86 } 44 }
87 45
88 GDataEntry::~GDataEntry() { 46 GDataEntry::~GDataEntry() {
89 } 47 }
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 GDataDirectory* dir = iter->second; 343 GDataDirectory* dir = iter->second;
386 // Remove directories recursively. 344 // Remove directories recursively.
387 dir->RemoveChildren(); 345 dir->RemoveChildren();
388 if (directory_service_) 346 if (directory_service_)
389 directory_service_->RemoveEntryFromResourceMap(dir); 347 directory_service_->RemoveEntryFromResourceMap(dir);
390 } 348 }
391 STLDeleteValues(&child_directories_); 349 STLDeleteValues(&child_directories_);
392 child_directories_.clear(); 350 child_directories_.clear();
393 } 351 }
394 352
395 // ResourceMetadataDB implementation.
396
397 // Params for GDatadirectoryServiceDB::Create.
398 struct CreateDBParams {
399 CreateDBParams(const FilePath& db_path,
400 base::SequencedTaskRunner* blocking_task_runner)
401 : db_path(db_path),
402 blocking_task_runner(blocking_task_runner) {
403 }
404
405 FilePath db_path;
406 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner;
407 scoped_ptr<ResourceMetadataDB> db;
408 GDataDirectoryService::SerializedMap serialized_resources;
409 };
410
411 // Wrapper for level db. All methods must be called on blocking thread.
412 class ResourceMetadataDB {
413 public:
414 ResourceMetadataDB(const FilePath& db_path,
415 base::SequencedTaskRunner* blocking_task_runner);
416
417 // Initializes the database.
418 void Init();
419
420 // Reads the database into |serialized_resources|.
421 void Read(GDataDirectoryService::SerializedMap* serialized_resources);
422
423 // Saves |serialized_resources| to the database.
424 void Save(const GDataDirectoryService::SerializedMap& serialized_resources);
425
426 private:
427 // Clears the database.
428 void Clear();
429
430 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
431 scoped_ptr<leveldb::DB> level_db_;
432 FilePath db_path_;
433 };
434
435 ResourceMetadataDB::ResourceMetadataDB(const FilePath& db_path,
436 base::SequencedTaskRunner* blocking_task_runner)
437 : blocking_task_runner_(blocking_task_runner),
438 db_path_(db_path) {
439 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
440 }
441
442 // Creates, initializes and reads from the database.
443 // This must be defined after ResourceMetadataDB and CreateDBParams.
444 static void CreateResourceMetadataDBOnBlockingPool(
445 CreateDBParams* params) {
446 DCHECK(params->blocking_task_runner->RunsTasksOnCurrentThread());
447 DCHECK(!params->db_path.empty());
448
449 params->db.reset(new ResourceMetadataDB(params->db_path,
450 params->blocking_task_runner));
451 params->db->Init();
452 params->db->Read(&params->serialized_resources);
453 }
454
455 void ResourceMetadataDB::Init() {
456 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
457 DCHECK(!db_path_.empty());
458
459 DVLOG(1) << "Init " << db_path_.value();
460
461 leveldb::DB* level_db = NULL;
462 leveldb::Options options;
463 options.create_if_missing = true;
464 leveldb::Status db_status = leveldb::DB::Open(options, db_path_.value(),
465 &level_db);
466 DCHECK(level_db);
467 DCHECK(db_status.ok());
468 level_db_.reset(level_db);
469 }
470
471 void ResourceMetadataDB::Read(
472 GDataDirectoryService::SerializedMap* serialized_resources) {
473 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
474 DCHECK(serialized_resources);
475 DVLOG(1) << "Read " << db_path_.value();
476
477 scoped_ptr<leveldb::Iterator> iter(level_db_->NewIterator(
478 leveldb::ReadOptions()));
479 for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
480 DVLOG(1) << "Read, resource " << iter->key().ToString();
481 serialized_resources->insert(std::make_pair(iter->key().ToString(),
482 iter->value().ToString()));
483 }
484 }
485
486 void ResourceMetadataDB::Save(
487 const GDataDirectoryService::SerializedMap& serialized_resources) {
488 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
489
490 Clear();
491 for (GDataDirectoryService::SerializedMap::const_iterator iter =
492 serialized_resources.begin();
493 iter != serialized_resources.end(); ++iter) {
494 DVLOG(1) << "Saving resource " << iter->first << " to db";
495 leveldb::Status status = level_db_->Put(leveldb::WriteOptions(),
496 leveldb::Slice(iter->first),
497 leveldb::Slice(iter->second));
498 if (!status.ok()) {
499 LOG(ERROR) << "leveldb Put failed of " << iter->first
500 << ", with " << status.ToString();
501 NOTREACHED();
502 }
503 }
504 }
505
506 void ResourceMetadataDB::Clear() {
507 level_db_.reset();
508 leveldb::DestroyDB(db_path_.value(), leveldb::Options());
509 Init();
510 }
511
512 // GDataDirectoryService class implementation.
513
514 GDataDirectoryService::GDataDirectoryService()
515 : blocking_task_runner_(NULL),
516 serialized_size_(0),
517 largest_changestamp_(0),
518 origin_(UNINITIALIZED),
519 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
520 root_.reset(CreateGDataDirectory());
521 if (!util::IsDriveV2ApiEnabled())
522 InitializeRootEntry(kGDataRootDirectoryResourceId);
523 }
524
525 GDataDirectoryService::~GDataDirectoryService() {
526 ClearRoot();
527
528 // Ensure db is closed on the blocking pool.
529 if (blocking_task_runner_ && directory_service_db_.get())
530 blocking_task_runner_->DeleteSoon(FROM_HERE,
531 directory_service_db_.release());
532 }
533
534 GDataEntry* GDataDirectoryService::FromDocumentEntry(DocumentEntry* doc) {
535 DCHECK(doc);
536 GDataEntry* entry = NULL;
537 if (doc->is_folder())
538 entry = CreateGDataDirectory();
539 else if (doc->is_hosted_document() || doc->is_file())
540 entry = CreateGDataFile();
541
542 if (entry)
543 entry->InitFromDocumentEntry(doc);
544 return entry;
545 }
546
547 GDataFile* GDataDirectoryService::CreateGDataFile() {
548 return new GDataFile(this);
549 }
550
551 GDataDirectory* GDataDirectoryService::CreateGDataDirectory() {
552 return new GDataDirectory(this);
553 }
554
555 void GDataDirectoryService::InitializeRootEntry(const std::string& root_id) {
556 root_.reset(CreateGDataDirectory());
557 root_->set_title(kGDataRootDirectory);
558 root_->SetBaseNameFromTitle();
559 root_->set_resource_id(root_id);
560 AddEntryToResourceMap(root_.get());
561 }
562
563 void GDataDirectoryService::ClearRoot() {
564 // Note that children have a reference to root_,
565 // so we need to delete them here.
566 root_->RemoveChildren();
567 RemoveEntryFromResourceMap(root_.get());
568 DCHECK(resource_map_.empty());
569 resource_map_.clear();
570 root_.reset();
571 }
572
573 void GDataDirectoryService::AddEntryToDirectory(
574 GDataDirectory* directory,
575 GDataEntry* new_entry,
576 const FileMoveCallback& callback) {
577 DCHECK(directory);
578 DCHECK(new_entry);
579 DCHECK(!callback.is_null());
580
581 directory->AddEntry(new_entry);
582 DVLOG(1) << "AddEntryToDirectory " << new_entry->GetFilePath().value();
583 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
584 base::Bind(callback, GDATA_FILE_OK, new_entry->GetFilePath()));
585 }
586
587 void GDataDirectoryService::MoveEntryToDirectory(
588 const FilePath& directory_path,
589 GDataEntry* entry,
590 const FileMoveCallback& callback) {
591 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
592 DCHECK(entry);
593 DCHECK(!callback.is_null());
594
595 if (entry->parent())
596 entry->parent()->RemoveChild(entry);
597
598 GDataEntry* destination = FindEntryByPathSync(directory_path);
599 FilePath moved_file_path;
600 GDataFileError error = GDATA_FILE_ERROR_FAILED;
601 if (!destination) {
602 error = GDATA_FILE_ERROR_NOT_FOUND;
603 } else if (!destination->AsGDataDirectory()) {
604 error = GDATA_FILE_ERROR_NOT_A_DIRECTORY;
605 } else {
606 destination->AsGDataDirectory()->AddEntry(entry);
607 moved_file_path = entry->GetFilePath();
608 error = GDATA_FILE_OK;
609 }
610 DVLOG(1) << "MoveEntryToDirectory " << moved_file_path.value();
611 base::MessageLoopProxy::current()->PostTask(
612 FROM_HERE, base::Bind(callback, error, moved_file_path));
613 }
614
615 void GDataDirectoryService::RemoveEntryFromParent(
616 GDataEntry* entry,
617 const FileMoveCallback& callback) {
618 GDataDirectory* parent = entry->parent();
619 DCHECK(parent);
620 DCHECK(!callback.is_null());
621 DVLOG(1) << "RemoveEntryFromParent " << entry->GetFilePath().value();
622
623 parent->RemoveEntry(entry);
624 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
625 base::Bind(callback, GDATA_FILE_OK, parent->GetFilePath()));
626 }
627
628 void GDataDirectoryService::AddEntryToResourceMap(GDataEntry* entry) {
629 // GDataFileSystem has already locked.
630 DVLOG(1) << "AddEntryToResourceMap " << entry->resource_id();
631 resource_map_.insert(std::make_pair(entry->resource_id(), entry));
632 }
633
634 void GDataDirectoryService::RemoveEntryFromResourceMap(GDataEntry* entry) {
635 // GDataFileSystem has already locked.
636 resource_map_.erase(entry->resource_id());
637 }
638
639 GDataEntry* GDataDirectoryService::FindEntryByPathSync(
640 const FilePath& file_path) {
641 if (file_path == root_->GetFilePath())
642 return root_.get();
643
644 std::vector<FilePath::StringType> components;
645 file_path.GetComponents(&components);
646 GDataDirectory* current_dir = root_.get();
647
648 for (size_t i = 1; i < components.size() && current_dir; ++i) {
649 GDataEntry* entry = current_dir->FindChild(components[i]);
650 if (!entry)
651 return NULL;
652
653 if (i == components.size() - 1) // Last component.
654 return entry;
655 else
656 current_dir = entry->AsGDataDirectory();
657 }
658 return NULL;
659 }
660
661 void GDataDirectoryService::FindEntryByPathAndRunSync(
662 const FilePath& search_file_path,
663 const FindEntryCallback& callback) {
664 GDataEntry* entry = FindEntryByPathSync(search_file_path);
665 callback.Run(entry ? GDATA_FILE_OK : GDATA_FILE_ERROR_NOT_FOUND, entry);
666 }
667
668 GDataEntry* GDataDirectoryService::GetEntryByResourceId(
669 const std::string& resource) {
670 // GDataFileSystem has already locked.
671 ResourceMap::const_iterator iter = resource_map_.find(resource);
672 return iter == resource_map_.end() ? NULL : iter->second;
673 }
674
675 void GDataDirectoryService::GetEntryByResourceIdAsync(
676 const std::string& resource_id,
677 const GetEntryByResourceIdCallback& callback) {
678 GDataEntry* entry = GetEntryByResourceId(resource_id);
679 callback.Run(entry);
680 }
681
682 void GDataDirectoryService::GetEntryInfoByPath(
683 const FilePath& path,
684 const GetEntryInfoCallback& callback) {
685 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
686 DCHECK(!callback.is_null());
687
688 scoped_ptr<GDataEntryProto> entry_proto;
689 GDataFileError error = GDATA_FILE_ERROR_FAILED;
690
691 GDataEntry* entry = FindEntryByPathSync(path);
692 if (entry) {
693 entry_proto.reset(new GDataEntryProto);
694 entry->ToProtoFull(entry_proto.get());
695 error = GDATA_FILE_OK;
696 } else {
697 error = GDATA_FILE_ERROR_NOT_FOUND;
698 }
699
700 base::MessageLoopProxy::current()->PostTask(
701 FROM_HERE,
702 base::Bind(callback, error, base::Passed(&entry_proto)));
703 }
704
705 void GDataDirectoryService::ReadDirectoryByPath(
706 const FilePath& path,
707 const ReadDirectoryCallback& callback) {
708 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
709 DCHECK(!callback.is_null());
710
711 scoped_ptr<GDataEntryProtoVector> entries;
712 GDataFileError error = GDATA_FILE_ERROR_FAILED;
713
714 GDataEntry* entry = FindEntryByPathSync(path);
715 if (entry && entry->AsGDataDirectory()) {
716 entries = entry->AsGDataDirectory()->ToProtoVector();
717 error = GDATA_FILE_OK;
718 } else if (entry && !entry->AsGDataDirectory()) {
719 error = GDATA_FILE_ERROR_NOT_A_DIRECTORY;
720 } else {
721 error = GDATA_FILE_ERROR_NOT_FOUND;
722 }
723
724 base::MessageLoopProxy::current()->PostTask(
725 FROM_HERE,
726 base::Bind(callback, error, base::Passed(&entries)));
727 }
728
729 void GDataDirectoryService::GetEntryInfoPairByPaths(
730 const FilePath& first_path,
731 const FilePath& second_path,
732 const GetEntryInfoPairCallback& callback) {
733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
734 DCHECK(!callback.is_null());
735
736 // Get the first entry.
737 GetEntryInfoByPath(
738 first_path,
739 base::Bind(&GDataDirectoryService::GetEntryInfoPairByPathsAfterGetFirst,
740 weak_ptr_factory_.GetWeakPtr(),
741 first_path,
742 second_path,
743 callback));
744 }
745
746 void GDataDirectoryService::RefreshFile(scoped_ptr<GDataFile> fresh_file) {
747 DCHECK(fresh_file.get());
748
749 // Need to get a reference here because Passed() could get evaluated first.
750 const std::string& resource_id = fresh_file->resource_id();
751 GetEntryByResourceIdAsync(
752 resource_id,
753 base::Bind(&GDataDirectoryService::RefreshFileInternal,
754 base::Passed(&fresh_file)));
755 }
756
757 // static
758 void GDataDirectoryService::RefreshFileInternal(
759 scoped_ptr<GDataFile> fresh_file,
760 GDataEntry* old_entry) {
761 GDataDirectory* entry_parent = old_entry ? old_entry->parent() : NULL;
762 if (entry_parent) {
763 DCHECK_EQ(fresh_file->resource_id(), old_entry->resource_id());
764 DCHECK(old_entry->AsGDataFile());
765
766 entry_parent->RemoveEntry(old_entry);
767 entry_parent->AddEntry(fresh_file.release());
768 }
769 }
770
771 void GDataDirectoryService::RefreshDirectory(
772 const std::string& directory_resource_id,
773 const ResourceMap& file_map,
774 const FileMoveCallback& callback) {
775 DCHECK(!callback.is_null());
776 GetEntryByResourceIdAsync(
777 directory_resource_id,
778 base::Bind(&GDataDirectoryService::RefreshDirectoryInternal,
779 file_map,
780 callback));
781 }
782
783 // static
784 void GDataDirectoryService::RefreshDirectoryInternal(
785 const ResourceMap& file_map,
786 const FileMoveCallback& callback,
787 GDataEntry* directory_entry) {
788 DCHECK(!callback.is_null());
789
790 if (!directory_entry) {
791 callback.Run(GDATA_FILE_ERROR_NOT_FOUND, FilePath());
792 return;
793 }
794
795 GDataDirectory* directory = directory_entry->AsGDataDirectory();
796 if (!directory) {
797 callback.Run(GDATA_FILE_ERROR_NOT_A_DIRECTORY, FilePath());
798 return;
799 }
800
801 directory->RemoveChildFiles();
802 // Add files from file_map.
803 for (ResourceMap::const_iterator it = file_map.begin();
804 it != file_map.end(); ++it) {
805 scoped_ptr<GDataEntry> entry(it->second);
806 // Skip if it's not a file (i.e. directory).
807 if (!entry->AsGDataFile())
808 continue;
809 directory->AddEntry(entry.release());
810 }
811
812 callback.Run(GDATA_FILE_OK, directory->GetFilePath());
813 }
814
815 void GDataDirectoryService::InitFromDB(
816 const FilePath& db_path,
817 base::SequencedTaskRunner* blocking_task_runner,
818 const FileOperationCallback& callback) {
819 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
820 DCHECK(!db_path.empty());
821 DCHECK(blocking_task_runner);
822
823 if (directory_service_db_.get()) {
824 if (!callback.is_null())
825 callback.Run(GDATA_FILE_ERROR_FAILED);
826 return;
827 }
828
829 blocking_task_runner_ = blocking_task_runner;
830
831 DVLOG(1) << "InitFromDB " << db_path.value();
832
833 CreateDBParams* create_params =
834 new CreateDBParams(db_path, blocking_task_runner);
835 blocking_task_runner_->PostTaskAndReply(
836 FROM_HERE,
837 base::Bind(&CreateResourceMetadataDBOnBlockingPool,
838 create_params),
839 base::Bind(&GDataDirectoryService::InitResourceMap,
840 weak_ptr_factory_.GetWeakPtr(),
841 base::Owned(create_params),
842 callback));
843 }
844
845 void GDataDirectoryService::InitResourceMap(
846 CreateDBParams* create_params,
847 const FileOperationCallback& callback) {
848 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
849 DCHECK(create_params);
850 DCHECK(!directory_service_db_.get());
851
852 SerializedMap* serialized_resources = &create_params->serialized_resources;
853 directory_service_db_ = create_params->db.Pass();
854 if (serialized_resources->empty()) {
855 origin_ = INITIALIZING;
856 if (!callback.is_null())
857 callback.Run(GDATA_FILE_ERROR_NOT_FOUND);
858 return;
859 }
860
861 ClearRoot();
862
863 // Version check.
864 int32 version = 0;
865 SerializedMap::iterator iter = serialized_resources->find(kDBKeyVersion);
866 if (iter == serialized_resources->end() ||
867 !base::StringToInt(iter->second, &version) ||
868 version != kProtoVersion) {
869 if (!callback.is_null())
870 callback.Run(GDATA_FILE_ERROR_FAILED);
871 return;
872 }
873 serialized_resources->erase(iter);
874
875 // Get the largest changestamp.
876 iter = serialized_resources->find(kDBKeyLargestChangestamp);
877 if (iter == serialized_resources->end() ||
878 !base::StringToInt64(iter->second, &largest_changestamp_)) {
879 NOTREACHED() << "Could not find/parse largest_changestamp";
880 if (!callback.is_null())
881 callback.Run(GDATA_FILE_ERROR_FAILED);
882 return;
883 } else {
884 DVLOG(1) << "InitResourceMap largest_changestamp_" << largest_changestamp_;
885 serialized_resources->erase(iter);
886 }
887
888 ResourceMap resource_map;
889 for (SerializedMap::const_iterator iter = serialized_resources->begin();
890 iter != serialized_resources->end(); ++iter) {
891 if (iter->first.find(kDBKeyResourceIdPrefix) != 0) {
892 NOTREACHED() << "Incorrect prefix for db key " << iter->first;
893 continue;
894 }
895
896 const std::string resource_id =
897 iter->first.substr(strlen(kDBKeyResourceIdPrefix));
898 scoped_ptr<GDataEntry> entry = FromProtoString(iter->second);
899 if (entry.get()) {
900 DVLOG(1) << "Inserting resource " << resource_id
901 << " into resource_map";
902 resource_map.insert(std::make_pair(resource_id, entry.release()));
903 } else {
904 NOTREACHED() << "Failed to parse GDataEntry for resource " << resource_id;
905 }
906 }
907
908 // Fix up parent-child relations.
909 for (ResourceMap::iterator iter = resource_map.begin();
910 iter != resource_map.end(); ++iter) {
911 GDataEntry* entry = iter->second;
912 ResourceMap::iterator parent_it =
913 resource_map.find(entry->parent_resource_id());
914 if (parent_it != resource_map.end()) {
915 GDataDirectory* parent = parent_it->second->AsGDataDirectory();
916 if (parent) {
917 DVLOG(1) << "Adding " << entry->resource_id()
918 << " as a child of " << parent->resource_id();
919 parent->AddEntry(entry);
920 } else {
921 NOTREACHED() << "Parent is not a directory " << parent->resource_id();
922 }
923 } else if (entry->resource_id() == kGDataRootDirectoryResourceId) {
924 root_.reset(entry->AsGDataDirectory());
925 DCHECK(root_.get());
926 AddEntryToResourceMap(root_.get());
927 } else {
928 NOTREACHED() << "Missing parent id " << entry->parent_resource_id()
929 << " for resource " << entry->resource_id();
930 }
931 }
932
933 DCHECK(root_.get());
934 DCHECK_EQ(resource_map.size(), resource_map_.size());
935 DCHECK_EQ(resource_map.size(), serialized_resources->size());
936
937 origin_ = FROM_CACHE;
938
939 if (!callback.is_null())
940 callback.Run(GDATA_FILE_OK);
941 }
942
943 void GDataDirectoryService::SaveToDB() {
944 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
945
946 if (!blocking_task_runner_ || !directory_service_db_.get()) {
947 NOTREACHED();
948 return;
949 }
950
951 size_t serialized_size = 0;
952 SerializedMap serialized_resources;
953 for (ResourceMap::const_iterator iter = resource_map_.begin();
954 iter != resource_map_.end(); ++iter) {
955 GDataEntryProto proto;
956 iter->second->ToProtoFull(&proto);
957 std::string serialized_string;
958 const bool ok = proto.SerializeToString(&serialized_string);
959 DCHECK(ok);
960 if (ok) {
961 serialized_resources.insert(
962 std::make_pair(std::string(kDBKeyResourceIdPrefix) + iter->first,
963 serialized_string));
964 serialized_size += serialized_string.size();
965 }
966 }
967
968 serialized_resources.insert(std::make_pair(kDBKeyVersion,
969 base::IntToString(kProtoVersion)));
970 serialized_resources.insert(std::make_pair(kDBKeyLargestChangestamp,
971 base::IntToString(largest_changestamp_)));
972 set_last_serialized(base::Time::Now());
973 set_serialized_size(serialized_size);
974
975 blocking_task_runner_->PostTask(
976 FROM_HERE,
977 base::Bind(&ResourceMetadataDB::Save,
978 base::Unretained(directory_service_db_.get()),
979 serialized_resources));
980 }
981
982 // Convert to/from proto. 353 // Convert to/from proto.
983 354
984 // static 355 // static
985 void GDataEntry::ConvertProtoToPlatformFileInfo( 356 void GDataEntry::ConvertProtoToPlatformFileInfo(
986 const PlatformFileInfoProto& proto, 357 const PlatformFileInfoProto& proto,
987 base::PlatformFileInfo* file_info) { 358 base::PlatformFileInfo* file_info) {
988 file_info->size = proto.size(); 359 file_info->size = proto.size();
989 file_info->is_directory = proto.is_directory(); 360 file_info->is_directory = proto.is_directory();
990 file_info->is_symbolic_link = proto.is_symbolic_link(); 361 file_info->is_symbolic_link = proto.is_symbolic_link();
991 file_info->last_modified = base::Time::FromInternalValue( 362 file_info->last_modified = base::Time::FromInternalValue(
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1163 const bool ok = entry_proto.SerializeToString(serialized_proto); 534 const bool ok = entry_proto.SerializeToString(serialized_proto);
1164 DCHECK(ok); 535 DCHECK(ok);
1165 } else if (dir) { 536 } else if (dir) {
1166 GDataDirectoryProto dir_proto; 537 GDataDirectoryProto dir_proto;
1167 dir->ToProto(&dir_proto); 538 dir->ToProto(&dir_proto);
1168 const bool ok = dir_proto.SerializeToString(serialized_proto); 539 const bool ok = dir_proto.SerializeToString(serialized_proto);
1169 DCHECK(ok); 540 DCHECK(ok);
1170 } 541 }
1171 } 542 }
1172 543
1173 void GDataDirectoryService::SerializeToString(
1174 std::string* serialized_proto) const {
1175 GDataRootDirectoryProto proto;
1176 root_->ToProto(proto.mutable_gdata_directory());
1177 proto.set_largest_changestamp(largest_changestamp_);
1178 proto.set_version(kProtoVersion);
1179
1180 const bool ok = proto.SerializeToString(serialized_proto);
1181 DCHECK(ok);
1182 }
1183
1184 bool GDataDirectoryService::ParseFromString(
1185 const std::string& serialized_proto) {
1186 GDataRootDirectoryProto proto;
1187 if (!proto.ParseFromString(serialized_proto))
1188 return false;
1189
1190 if (proto.version() != kProtoVersion) {
1191 LOG(ERROR) << "Incompatible proto detected (incompatible version): "
1192 << proto.version();
1193 return false;
1194 }
1195
1196 if (!IsValidRootDirectoryProto(proto.gdata_directory()))
1197 return false;
1198
1199 if (!root_->FromProto(proto.gdata_directory()))
1200 return false;
1201
1202 origin_ = FROM_CACHE;
1203 largest_changestamp_ = proto.largest_changestamp();
1204
1205 return true;
1206 }
1207
1208 scoped_ptr<GDataEntry> GDataDirectoryService::FromProtoString(
1209 const std::string& serialized_proto) {
1210 GDataEntryProto entry_proto;
1211 if (!entry_proto.ParseFromString(serialized_proto))
1212 return scoped_ptr<GDataEntry>();
1213
1214 scoped_ptr<GDataEntry> entry;
1215 if (entry_proto.file_info().is_directory()) {
1216 entry.reset(CreateGDataDirectory());
1217 // Call GDataEntry::FromProto instead of GDataDirectory::FromProto because
1218 // the proto does not include children.
1219 if (!entry->FromProto(entry_proto)) {
1220 NOTREACHED() << "FromProto (directory) failed";
1221 entry.reset();
1222 }
1223 } else {
1224 scoped_ptr<GDataFile> file(CreateGDataFile());
1225 // Call GDataFile::FromProto.
1226 if (file->FromProto(entry_proto)) {
1227 entry.reset(file.release());
1228 } else {
1229 NOTREACHED() << "FromProto (file) failed";
1230 }
1231 }
1232 return entry.Pass();
1233 }
1234
1235 void GDataDirectoryService::GetEntryInfoPairByPathsAfterGetFirst(
1236 const FilePath& first_path,
1237 const FilePath& second_path,
1238 const GetEntryInfoPairCallback& callback,
1239 GDataFileError error,
1240 scoped_ptr<GDataEntryProto> entry_proto) {
1241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1242 DCHECK(!callback.is_null());
1243
1244 scoped_ptr<EntryInfoPairResult> result(new EntryInfoPairResult);
1245 result->first.path = first_path;
1246 result->first.error = error;
1247 result->first.proto = entry_proto.Pass();
1248
1249 // If the first one is not found, don't continue.
1250 if (error != GDATA_FILE_OK) {
1251 callback.Run(result.Pass());
1252 return;
1253 }
1254
1255 // Get the second entry.
1256 GetEntryInfoByPath(
1257 second_path,
1258 base::Bind(&GDataDirectoryService::GetEntryInfoPairByPathsAfterGetSecond,
1259 weak_ptr_factory_.GetWeakPtr(),
1260 second_path,
1261 callback,
1262 base::Passed(&result)));
1263 }
1264
1265 void GDataDirectoryService::GetEntryInfoPairByPathsAfterGetSecond(
1266 const FilePath& second_path,
1267 const GetEntryInfoPairCallback& callback,
1268 scoped_ptr<EntryInfoPairResult> result,
1269 GDataFileError error,
1270 scoped_ptr<GDataEntryProto> entry_proto) {
1271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1272 DCHECK(!callback.is_null());
1273 DCHECK(result.get());
1274
1275 result->second.path = second_path;
1276 result->second.error = error;
1277 result->second.proto = entry_proto.Pass();
1278
1279 callback.Run(result.Pass());
1280 }
1281
1282 } // namespace gdata 544 } // namespace gdata
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/gdata/gdata_files.h ('k') | chrome/browser/chromeos/gdata/gdata_files_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698