Chromium Code Reviews| 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 <leveldb/db.h> | |
| 7 #include <vector> | 8 #include <vector> |
| 8 | 9 |
| 9 #include "base/message_loop_proxy.h" | 10 #include "base/message_loop_proxy.h" |
| 10 #include "base/platform_file.h" | 11 #include "base/platform_file.h" |
| 12 #include "base/string_number_conversions.h" | |
| 11 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 12 #include "base/stringprintf.h" | 14 #include "base/stringprintf.h" |
| 15 #include "base/sequenced_task_runner.h" | |
| 13 #include "base/tracked_objects.h" | 16 #include "base/tracked_objects.h" |
| 14 #include "base/utf_string_conversions.h" | 17 #include "base/utf_string_conversions.h" |
| 15 #include "chrome/browser/chromeos/gdata/gdata.pb.h" | 18 #include "chrome/browser/chromeos/gdata/gdata.pb.h" |
| 16 #include "chrome/browser/chromeos/gdata/gdata_util.h" | 19 #include "chrome/browser/chromeos/gdata/gdata_util.h" |
| 17 #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h" | 20 #include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h" |
| 21 #include "content/public/browser/browser_thread.h" | |
| 18 #include "net/base/escape.h" | 22 #include "net/base/escape.h" |
| 19 | 23 |
| 24 using content::BrowserThread; | |
| 25 | |
| 20 namespace gdata { | 26 namespace gdata { |
| 21 namespace { | 27 namespace { |
| 22 | 28 |
| 23 const char kSlash[] = "/"; | 29 const char kSlash[] = "/"; |
| 24 const char kEscapedSlash[] = "\xE2\x88\x95"; | 30 const char kEscapedSlash[] = "\xE2\x88\x95"; |
| 31 const char kDBKeyLargestChangestamp[] = "m:largest_changestamp"; | |
|
satorux1
2012/08/03 20:19:16
Maybe add
// m: prefix is used for global metadat
achuithb
2012/08/03 21:41:04
Done.
| |
| 32 const char kDBKeyVersion[] = "m:version"; | |
| 33 const char kDBKeyResourceIdPrefix[] = "r:"; | |
| 25 | 34 |
| 26 // Extracts resource_id out of edit url. | 35 // Extracts resource_id out of edit url. |
| 27 std::string ExtractResourceId(const GURL& url) { | 36 std::string ExtractResourceId(const GURL& url) { |
| 28 return net::UnescapeURLComponent(url.ExtractFileName(), | 37 return net::UnescapeURLComponent(url.ExtractFileName(), |
| 29 net::UnescapeRule::URL_SPECIAL_CHARS); | 38 net::UnescapeRule::URL_SPECIAL_CHARS); |
| 30 } | 39 } |
| 31 | 40 |
| 32 // Returns true if |proto| is a valid proto as the root directory. | 41 // Returns true if |proto| is a valid proto as the root directory. |
| 33 // Used to reject incompatible proto. | 42 // Used to reject incompatible proto. |
| 34 bool IsValidRootDirectoryProto(const GDataDirectoryProto& proto) { | 43 bool IsValidRootDirectoryProto(const GDataDirectoryProto& proto) { |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 416 GDataDirectory* dir = iter->second; | 425 GDataDirectory* dir = iter->second; |
| 417 // Remove directories recursively. | 426 // Remove directories recursively. |
| 418 dir->RemoveChildren(); | 427 dir->RemoveChildren(); |
| 419 if (directory_service_) | 428 if (directory_service_) |
| 420 directory_service_->RemoveEntryFromResourceMap(dir); | 429 directory_service_->RemoveEntryFromResourceMap(dir); |
| 421 } | 430 } |
| 422 STLDeleteValues(&child_directories_); | 431 STLDeleteValues(&child_directories_); |
| 423 child_directories_.clear(); | 432 child_directories_.clear(); |
| 424 } | 433 } |
| 425 | 434 |
| 435 // ResourceMetadataDB implementation. | |
| 436 | |
| 437 // Params for GDatadirectoryServiceDB::Create. | |
| 438 struct CreateDBParams { | |
| 439 CreateDBParams(const FilePath& db_path, | |
| 440 base::SequencedTaskRunner* blocking_task_runner) | |
| 441 : db_path(db_path), | |
| 442 blocking_task_runner(blocking_task_runner) { | |
| 443 } | |
| 444 | |
| 445 FilePath db_path; | |
| 446 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner; | |
| 447 scoped_ptr<ResourceMetadataDB> db; | |
| 448 GDataDirectoryService::SerializedMap serialized_resources; | |
| 449 }; | |
| 450 | |
| 451 // Wrapper for level db. All methods must be called on blocking thread. | |
| 452 class ResourceMetadataDB { | |
| 453 public: | |
| 454 ResourceMetadataDB(const FilePath& db_path, | |
| 455 base::SequencedTaskRunner* blocking_task_runner); | |
| 456 | |
| 457 // Initializes the database. | |
| 458 void Init(); | |
| 459 | |
| 460 // Reads the database into |serialized_resources|. | |
| 461 void Read(GDataDirectoryService::SerializedMap* serialized_resources); | |
| 462 | |
| 463 // Saves |serialized_resources| to the database. | |
| 464 void Save(const GDataDirectoryService::SerializedMap& serialized_resources); | |
| 465 | |
| 466 private: | |
| 467 // Clears the database. | |
| 468 void Clear(); | |
| 469 | |
| 470 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; | |
| 471 scoped_ptr<leveldb::DB> level_db_; | |
| 472 FilePath db_path_; | |
| 473 }; | |
| 474 | |
| 475 ResourceMetadataDB::ResourceMetadataDB(const FilePath& db_path, | |
| 476 base::SequencedTaskRunner* blocking_task_runner) | |
| 477 : blocking_task_runner_(blocking_task_runner), | |
| 478 db_path_(db_path) { | |
| 479 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | |
| 480 } | |
| 481 | |
| 482 // Creates, initializes and reads from the database. | |
| 483 // This must be defined after ResourceMetadataDB and CreateDBParams. | |
| 484 static void CreateResourceMetadataDBOnBlockingPool( | |
| 485 CreateDBParams* params) { | |
| 486 DCHECK(params->blocking_task_runner->RunsTasksOnCurrentThread()); | |
| 487 DCHECK(!params->db_path.empty()); | |
| 488 | |
| 489 params->db.reset(new ResourceMetadataDB(params->db_path, | |
| 490 params->blocking_task_runner)); | |
| 491 params->db->Init(); | |
| 492 params->db->Read(¶ms->serialized_resources); | |
| 493 } | |
| 494 | |
| 495 void ResourceMetadataDB::Init() { | |
| 496 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | |
| 497 DCHECK(!db_path_.empty()); | |
| 498 | |
| 499 DVLOG(1) << "Init " << db_path_.value(); | |
| 500 | |
| 501 leveldb::DB* level_db = NULL; | |
| 502 leveldb::Options options; | |
| 503 options.create_if_missing = true; | |
| 504 leveldb::Status db_status = leveldb::DB::Open(options, db_path_.value(), | |
| 505 &level_db); | |
| 506 DCHECK(level_db); | |
| 507 DCHECK(db_status.ok()); | |
| 508 level_db_.reset(level_db); | |
| 509 } | |
| 510 | |
| 511 void ResourceMetadataDB::Read( | |
| 512 GDataDirectoryService::SerializedMap* serialized_resources) { | |
| 513 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | |
| 514 DCHECK(serialized_resources); | |
| 515 DVLOG(1) << "Read " << db_path_.value(); | |
| 516 | |
| 517 scoped_ptr<leveldb::Iterator> iter(level_db_->NewIterator( | |
| 518 leveldb::ReadOptions())); | |
| 519 for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { | |
| 520 DVLOG(1) << "Read, resource " << iter->key().ToString(); | |
| 521 serialized_resources->insert(std::make_pair(iter->key().ToString(), | |
| 522 iter->value().ToString())); | |
| 523 } | |
| 524 } | |
| 525 | |
| 526 void ResourceMetadataDB::Save( | |
| 527 const GDataDirectoryService::SerializedMap& serialized_resources) { | |
| 528 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | |
| 529 | |
| 530 Clear(); | |
| 531 for (GDataDirectoryService::SerializedMap::const_iterator iter = | |
| 532 serialized_resources.begin(); | |
| 533 iter != serialized_resources.end(); ++iter) { | |
| 534 DVLOG(1) << "Saving resource " << iter->first << " to db"; | |
| 535 leveldb::Status status = level_db_->Put(leveldb::WriteOptions(), | |
| 536 leveldb::Slice(iter->first), | |
| 537 leveldb::Slice(iter->second)); | |
| 538 if (!status.ok()) { | |
| 539 LOG(ERROR) << "leveldb Put failed of " << iter->first | |
| 540 << ", with " << status.ToString(); | |
| 541 NOTREACHED(); | |
| 542 } | |
| 543 } | |
| 544 } | |
| 545 | |
| 546 void ResourceMetadataDB::Clear() { | |
| 547 level_db_.reset(); | |
| 548 leveldb::DestroyDB(db_path_.value(), leveldb::Options()); | |
| 549 Init(); | |
| 550 } | |
| 551 | |
| 426 // GDataDirectoryService class implementation. | 552 // GDataDirectoryService class implementation. |
| 427 | 553 |
| 428 GDataDirectoryService::GDataDirectoryService() | 554 GDataDirectoryService::GDataDirectoryService() |
| 429 : serialized_size_(0), | 555 : blocking_task_runner_(NULL), |
| 556 serialized_size_(0), | |
| 430 largest_changestamp_(0), | 557 largest_changestamp_(0), |
| 431 origin_(UNINITIALIZED) { | 558 origin_(UNINITIALIZED), |
| 559 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
| 432 root_.reset(new GDataDirectory(NULL, this)); | 560 root_.reset(new GDataDirectory(NULL, this)); |
| 433 root_->set_title(kGDataRootDirectory); | 561 root_->set_title(kGDataRootDirectory); |
| 434 root_->SetBaseNameFromTitle(); | 562 root_->SetBaseNameFromTitle(); |
| 435 root_->set_resource_id(kGDataRootDirectoryResourceId); | 563 root_->set_resource_id(kGDataRootDirectoryResourceId); |
| 436 AddEntryToResourceMap(root_.get()); | 564 AddEntryToResourceMap(root_.get()); |
| 437 } | 565 } |
| 438 | 566 |
| 439 GDataDirectoryService::~GDataDirectoryService() { | 567 GDataDirectoryService::~GDataDirectoryService() { |
| 568 ClearRoot(); | |
| 569 | |
| 570 // Ensure db is closed on the blocking pool. | |
| 571 if (blocking_task_runner_ && directory_service_db_.get()) | |
| 572 blocking_task_runner_->DeleteSoon(FROM_HERE, | |
| 573 directory_service_db_.release()); | |
| 574 } | |
| 575 | |
| 576 void GDataDirectoryService::ClearRoot() { | |
| 440 // Note that children have a reference to root_, | 577 // Note that children have a reference to root_, |
| 441 // so we need to delete them here. | 578 // so we need to delete them here. |
| 442 root_->RemoveChildren(); | 579 root_->RemoveChildren(); |
| 443 RemoveEntryFromResourceMap(root_.get()); | 580 RemoveEntryFromResourceMap(root_.get()); |
| 444 DCHECK(resource_map_.empty()); | 581 DCHECK(resource_map_.empty()); |
| 445 resource_map_.clear(); | 582 resource_map_.clear(); |
| 583 root_.reset(); | |
| 446 } | 584 } |
| 447 | 585 |
| 448 void GDataDirectoryService::AddEntryToDirectory( | 586 void GDataDirectoryService::AddEntryToDirectory( |
| 449 const FilePath& directory_path, | 587 const FilePath& directory_path, |
| 450 GDataEntry* entry, | 588 GDataEntry* entry, |
| 451 const FileOperationCallback& callback) { | 589 const FileOperationCallback& callback) { |
| 452 GDataEntry* destination = FindEntryByPathSync(directory_path); | 590 GDataEntry* destination = FindEntryByPathSync(directory_path); |
| 453 GDataFileError error = GDATA_FILE_ERROR_FAILED; | 591 GDataFileError error = GDATA_FILE_ERROR_FAILED; |
| 454 if (!destination) { | 592 if (!destination) { |
| 455 error = GDATA_FILE_ERROR_NOT_FOUND; | 593 error = GDATA_FILE_ERROR_NOT_FOUND; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 554 GDataDirectory* entry_parent = old_entry ? old_entry->parent() : NULL; | 692 GDataDirectory* entry_parent = old_entry ? old_entry->parent() : NULL; |
| 555 if (entry_parent) { | 693 if (entry_parent) { |
| 556 DCHECK_EQ(fresh_file->resource_id(), old_entry->resource_id()); | 694 DCHECK_EQ(fresh_file->resource_id(), old_entry->resource_id()); |
| 557 DCHECK(old_entry->AsGDataFile()); | 695 DCHECK(old_entry->AsGDataFile()); |
| 558 | 696 |
| 559 entry_parent->RemoveEntry(old_entry); | 697 entry_parent->RemoveEntry(old_entry); |
| 560 entry_parent->AddEntry(fresh_file.release()); | 698 entry_parent->AddEntry(fresh_file.release()); |
| 561 } | 699 } |
| 562 } | 700 } |
| 563 | 701 |
| 702 void GDataDirectoryService::InitFromDB( | |
| 703 const FilePath& db_path, | |
| 704 base::SequencedTaskRunner* blocking_task_runner, | |
| 705 LoadRootFeedParams* load_params, | |
| 706 const base::Closure& callback) { | |
| 707 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 708 DCHECK(!db_path.empty()); | |
| 709 DCHECK(blocking_task_runner); | |
| 710 | |
| 711 if (directory_service_db_.get()) { | |
| 712 NOTREACHED(); | |
| 713 if (!callback.is_null()) | |
| 714 callback.Run(); | |
| 715 } | |
| 716 | |
| 717 blocking_task_runner_ = blocking_task_runner; | |
| 718 | |
| 719 DVLOG(1) << "InitFromDB " << db_path.value(); | |
| 720 | |
| 721 CreateDBParams* create_params = | |
| 722 new CreateDBParams(db_path, blocking_task_runner); | |
| 723 blocking_task_runner_->PostTaskAndReply( | |
| 724 FROM_HERE, | |
| 725 base::Bind(&CreateResourceMetadataDBOnBlockingPool, | |
| 726 create_params), | |
| 727 base::Bind(&GDataDirectoryService::InitResourceMap, | |
| 728 weak_ptr_factory_.GetWeakPtr(), | |
| 729 base::Owned(create_params), | |
| 730 load_params, | |
| 731 callback)); | |
| 732 } | |
| 733 | |
| 734 void GDataDirectoryService::InitResourceMap( | |
| 735 CreateDBParams* create_params, | |
| 736 LoadRootFeedParams* load_params, | |
| 737 const base::Closure& callback) { | |
| 738 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 739 DCHECK(create_params); | |
| 740 // Ensure this callback is run before we return. | |
| 741 base::ScopedClosureRunner callback_runner(callback); | |
| 742 | |
| 743 SerializedMap* serialized_resources = &create_params->serialized_resources; | |
| 744 directory_service_db_ = create_params->db.Pass(); | |
| 745 if (serialized_resources->empty()) { | |
| 746 origin_ = INITIALIZING; | |
| 747 if (load_params) | |
| 748 load_params->load_error = GDATA_FILE_ERROR_NOT_FOUND; | |
| 749 return; | |
| 750 } | |
| 751 | |
| 752 ClearRoot(); | |
| 753 | |
| 754 // Version check. | |
| 755 int32 version = 0; | |
| 756 SerializedMap::iterator iter = serialized_resources->find(kDBKeyVersion); | |
| 757 if (iter == serialized_resources->end() || | |
| 758 !base::StringToInt(iter->second, &version) || | |
| 759 version != kProtoVersion) { | |
| 760 if (load_params) | |
|
satorux1
2012/08/03 20:19:16
can it be NULL? Can we add DCHECK(load_params) at
achuithb
2012/08/03 21:41:04
It can be NULL for tests.
I'm going to change th
| |
| 761 load_params->load_error = GDATA_FILE_ERROR_NOT_FOUND; | |
|
satorux1
2012/08/03 20:19:16
maybe GDATA_FILE_ERROR_FAILED?
achuithb
2012/08/03 21:41:04
Done.
| |
| 762 return; | |
| 763 } | |
| 764 serialized_resources->erase(iter); | |
| 765 | |
| 766 // Get the largest changestamp. | |
| 767 iter = serialized_resources->find(kDBKeyLargestChangestamp); | |
| 768 if (iter != serialized_resources->end()) { | |
| 769 base::StringToInt(iter->second, &largest_changestamp_); | |
| 770 DVLOG(1) << "InitResourceMap largest_changestamp_" | |
| 771 << largest_changestamp_; | |
| 772 serialized_resources->erase(iter); | |
| 773 } else { | |
| 774 NOTREACHED() << "Could not find largest_changestamp"; | |
|
satorux1
2012/08/03 20:19:16
Add this?
load_params->load_error = GDATA_FILE_ER
achuithb
2012/08/03 21:41:04
Done.
| |
| 775 } | |
| 776 | |
| 777 ResourceMap resource_map; | |
| 778 for (SerializedMap::const_iterator iter = serialized_resources->begin(); | |
| 779 iter != serialized_resources->end(); ++iter) { | |
| 780 if (iter->first.find(kDBKeyResourceIdPrefix) != 0) { | |
| 781 NOTREACHED() << "Incorrect prefix for db key " << iter->first; | |
| 782 continue; | |
| 783 } | |
| 784 | |
| 785 const std::string resource_id = | |
| 786 iter->first.substr(strlen(kDBKeyResourceIdPrefix)); | |
| 787 scoped_ptr<GDataEntry> entry = FromProtoString(iter->second); | |
| 788 if (entry.get()) { | |
| 789 DVLOG(1) << "Inserting resource " << resource_id | |
| 790 << " into resource_map"; | |
| 791 resource_map.insert(std::make_pair(resource_id, entry.release())); | |
| 792 } else { | |
| 793 NOTREACHED() << "Failed to parse GDataEntry for resource " << resource_id; | |
| 794 } | |
| 795 } | |
| 796 | |
| 797 // Fix up parent-child relations. | |
| 798 for (ResourceMap::iterator iter = resource_map.begin(); | |
| 799 iter != resource_map.end(); ++iter) { | |
| 800 GDataEntry* entry = iter->second; | |
| 801 ResourceMap::iterator parent_it = | |
| 802 resource_map.find(entry->parent_resource_id()); | |
| 803 if (parent_it != resource_map.end()) { | |
| 804 GDataDirectory* parent = parent_it->second->AsGDataDirectory(); | |
| 805 if (parent) { | |
| 806 DVLOG(1) << "Adding " << entry->resource_id() | |
| 807 << " as a child of " << parent->resource_id(); | |
| 808 parent->AddEntry(entry); | |
| 809 } else { | |
| 810 NOTREACHED() << "Parent is not a directory " << parent->resource_id(); | |
| 811 } | |
| 812 } else if (entry->resource_id() == kGDataRootDirectoryResourceId) { | |
| 813 root_.reset(entry->AsGDataDirectory()); | |
| 814 DCHECK(root_.get()); | |
| 815 AddEntryToResourceMap(root_.get()); | |
| 816 } else { | |
| 817 NOTREACHED() << "Missing parent id " << entry->parent_resource_id() | |
| 818 << " for resource " << entry->resource_id(); | |
| 819 } | |
| 820 } | |
| 821 | |
| 822 DCHECK(root_.get()); | |
| 823 DCHECK_EQ(resource_map.size(), resource_map_.size()); | |
| 824 DCHECK_EQ(resource_map.size(), serialized_resources->size()); | |
| 825 | |
| 826 origin_ = FROM_CACHE; | |
| 827 } | |
| 828 | |
| 829 void GDataDirectoryService::SaveToDB() { | |
| 830 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 831 | |
| 832 if (!blocking_task_runner_ || !directory_service_db_.get()) { | |
| 833 NOTREACHED(); | |
| 834 return; | |
| 835 } | |
| 836 | |
| 837 size_t serialized_size = 0; | |
| 838 SerializedMap serialized_resources; | |
| 839 for (ResourceMap::const_iterator iter = resource_map_.begin(); | |
| 840 iter != resource_map_.end(); ++iter) { | |
| 841 GDataEntryProto proto; | |
| 842 iter->second->ToProtoFull(&proto); | |
| 843 std::string serialized_string; | |
| 844 const bool ok = proto.SerializeToString(&serialized_string); | |
| 845 DCHECK(ok); | |
| 846 if (ok) { | |
| 847 serialized_resources.insert( | |
| 848 std::make_pair(std::string(kDBKeyResourceIdPrefix) + iter->first, | |
| 849 serialized_string)); | |
| 850 serialized_size += serialized_string.size(); | |
| 851 } | |
| 852 } | |
| 853 | |
| 854 serialized_resources.insert(std::make_pair(kDBKeyVersion, | |
| 855 base::IntToString(kProtoVersion))); | |
| 856 serialized_resources.insert(std::make_pair(kDBKeyLargestChangestamp, | |
| 857 base::IntToString(largest_changestamp_))); | |
| 858 set_last_serialized(base::Time::Now()); | |
| 859 set_serialized_size(serialized_size); | |
| 860 | |
| 861 blocking_task_runner_->PostTask( | |
| 862 FROM_HERE, | |
| 863 base::Bind(&ResourceMetadataDB::Save, | |
| 864 base::Unretained(directory_service_db_.get()), | |
| 865 serialized_resources)); | |
| 866 } | |
| 867 | |
| 564 // Convert to/from proto. | 868 // Convert to/from proto. |
| 565 | 869 |
| 566 // static | 870 // static |
| 567 void GDataEntry::ConvertProtoToPlatformFileInfo( | 871 void GDataEntry::ConvertProtoToPlatformFileInfo( |
| 568 const PlatformFileInfoProto& proto, | 872 const PlatformFileInfoProto& proto, |
| 569 base::PlatformFileInfo* file_info) { | 873 base::PlatformFileInfo* file_info) { |
| 570 file_info->size = proto.size(); | 874 file_info->size = proto.size(); |
| 571 file_info->is_directory = proto.is_directory(); | 875 file_info->is_directory = proto.is_directory(); |
| 572 file_info->is_symbolic_link = proto.is_symbolic_link(); | 876 file_info->is_symbolic_link = proto.is_symbolic_link(); |
| 573 file_info->last_modified = base::Time::FromInternalValue( | 877 file_info->last_modified = base::Time::FromInternalValue( |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 788 | 1092 |
| 789 if (!root_->FromProto(proto.gdata_directory())) | 1093 if (!root_->FromProto(proto.gdata_directory())) |
| 790 return false; | 1094 return false; |
| 791 | 1095 |
| 792 origin_ = FROM_CACHE; | 1096 origin_ = FROM_CACHE; |
| 793 largest_changestamp_ = proto.largest_changestamp(); | 1097 largest_changestamp_ = proto.largest_changestamp(); |
| 794 | 1098 |
| 795 return true; | 1099 return true; |
| 796 } | 1100 } |
| 797 | 1101 |
| 1102 scoped_ptr<GDataEntry> GDataDirectoryService::FromProtoString( | |
| 1103 const std::string& serialized_proto) { | |
| 1104 GDataEntryProto entry_proto; | |
| 1105 if (!entry_proto.ParseFromString(serialized_proto)) | |
| 1106 return scoped_ptr<GDataEntry>(); | |
| 1107 | |
| 1108 scoped_ptr<GDataEntry> entry; | |
| 1109 if (entry_proto.file_info().is_directory()) { | |
| 1110 entry.reset(new GDataDirectory(NULL, this)); | |
| 1111 // Call GDataEntry::FromProto instead of GDataDirectory::FromProto because | |
| 1112 // the proto does not include children. | |
| 1113 if (!entry->FromProto(entry_proto)) { | |
| 1114 NOTREACHED() << "FromProto (directory) failed"; | |
| 1115 entry.reset(); | |
| 1116 } | |
| 1117 } else { | |
| 1118 scoped_ptr<GDataFile> file(new GDataFile(NULL, this)); | |
| 1119 // Call GDataFile::FromProto. | |
| 1120 if (file->FromProto(entry_proto)) { | |
| 1121 entry.reset(file.release()); | |
| 1122 } else { | |
| 1123 NOTREACHED() << "FromProto (file) failed"; | |
| 1124 } | |
| 1125 } | |
| 1126 return entry.Pass(); | |
| 1127 } | |
| 1128 | |
| 798 } // namespace gdata | 1129 } // namespace gdata |
| OLD | NEW |