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

Unified Diff: chrome/browser/chromeos/gdata/gdata_directory_service.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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/gdata/gdata_directory_service.cc
===================================================================
--- chrome/browser/chromeos/gdata/gdata_directory_service.cc (revision 0)
+++ chrome/browser/chromeos/gdata/gdata_directory_service.cc (revision 0)
@@ -0,0 +1,767 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/gdata/gdata_directory_service.h"
+
+#include <leveldb/db.h>
+
+#include "base/message_loop_proxy.h"
+#include "base/platform_file.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/sequenced_task_runner.h"
+#include "base/tracked_objects.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/gdata/gdata.pb.h"
+#include "chrome/browser/chromeos/gdata/gdata_util.h"
+#include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/escape.h"
+
+using content::BrowserThread;
+
+namespace gdata {
+namespace {
+
+// m: prefix for filesystem metadata db keys, version and largest_changestamp.
+// r: prefix for resource id db keys.
+const char kDBKeyLargestChangestamp[] = "m:largest_changestamp";
+const char kDBKeyVersion[] = "m:version";
+const char kDBKeyResourceIdPrefix[] = "r:";
+
+// Returns true if |proto| is a valid proto as the root directory.
+// Used to reject incompatible proto.
+bool IsValidRootDirectoryProto(const GDataDirectoryProto& proto) {
+ const GDataEntryProto& entry_proto = proto.gdata_entry();
+ // The title field for the root directory was originally empty, then
+ // changed to "gdata", then changed to "drive". Discard the proto data if
+ // the older formats are detected. See crbug.com/128133 for details.
+ if (entry_proto.title() != "drive") {
+ LOG(ERROR) << "Incompatible proto detected (bad title): "
+ << entry_proto.title();
+ return false;
+ }
+ // The title field for the root directory was originally empty. Discard
+ // the proto data if the older format is detected.
+ if (entry_proto.resource_id() != kGDataRootDirectoryResourceId) {
+ LOG(ERROR) << "Incompatible proto detected (bad resource ID): "
+ << entry_proto.resource_id();
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+EntryInfoResult::EntryInfoResult() : error(GDATA_FILE_ERROR_FAILED) {
+}
+
+EntryInfoResult::~EntryInfoResult() {
+}
+
+EntryInfoPairResult::EntryInfoPairResult() {
+}
+
+EntryInfoPairResult::~EntryInfoPairResult() {
+}
+
+// ResourceMetadataDB implementation.
+
+// Params for GDatadirectoryServiceDB::Create.
+struct CreateDBParams {
+ CreateDBParams(const FilePath& db_path,
+ base::SequencedTaskRunner* blocking_task_runner)
+ : db_path(db_path),
+ blocking_task_runner(blocking_task_runner) {
+ }
+
+ FilePath db_path;
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner;
+ scoped_ptr<ResourceMetadataDB> db;
+ GDataDirectoryService::SerializedMap serialized_resources;
+};
+
+// Wrapper for level db. All methods must be called on blocking thread.
+class ResourceMetadataDB {
+ public:
+ ResourceMetadataDB(const FilePath& db_path,
+ base::SequencedTaskRunner* blocking_task_runner);
+
+ // Initializes the database.
+ void Init();
+
+ // Reads the database into |serialized_resources|.
+ void Read(GDataDirectoryService::SerializedMap* serialized_resources);
+
+ // Saves |serialized_resources| to the database.
+ void Save(const GDataDirectoryService::SerializedMap& serialized_resources);
+
+ private:
+ // Clears the database.
+ void Clear();
+
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+ scoped_ptr<leveldb::DB> level_db_;
+ FilePath db_path_;
+};
+
+ResourceMetadataDB::ResourceMetadataDB(const FilePath& db_path,
+ base::SequencedTaskRunner* blocking_task_runner)
+ : blocking_task_runner_(blocking_task_runner),
+ db_path_(db_path) {
+ DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
+}
+
+// Creates, initializes and reads from the database.
+// This must be defined after ResourceMetadataDB and CreateDBParams.
+static void CreateResourceMetadataDBOnBlockingPool(
+ CreateDBParams* params) {
+ DCHECK(params->blocking_task_runner->RunsTasksOnCurrentThread());
+ DCHECK(!params->db_path.empty());
+
+ params->db.reset(new ResourceMetadataDB(params->db_path,
+ params->blocking_task_runner));
+ params->db->Init();
+ params->db->Read(&params->serialized_resources);
+}
+
+void ResourceMetadataDB::Init() {
+ DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(!db_path_.empty());
+
+ DVLOG(1) << "Init " << db_path_.value();
+
+ leveldb::DB* level_db = NULL;
+ leveldb::Options options;
+ options.create_if_missing = true;
+ leveldb::Status db_status = leveldb::DB::Open(options, db_path_.value(),
+ &level_db);
+ DCHECK(level_db);
+ DCHECK(db_status.ok());
+ level_db_.reset(level_db);
+}
+
+void ResourceMetadataDB::Read(
+ GDataDirectoryService::SerializedMap* serialized_resources) {
+ DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(serialized_resources);
+ DVLOG(1) << "Read " << db_path_.value();
+
+ scoped_ptr<leveldb::Iterator> iter(level_db_->NewIterator(
+ leveldb::ReadOptions()));
+ for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
+ DVLOG(1) << "Read, resource " << iter->key().ToString();
+ serialized_resources->insert(std::make_pair(iter->key().ToString(),
+ iter->value().ToString()));
+ }
+}
+
+void ResourceMetadataDB::Save(
+ const GDataDirectoryService::SerializedMap& serialized_resources) {
+ DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
+
+ Clear();
+ for (GDataDirectoryService::SerializedMap::const_iterator iter =
+ serialized_resources.begin();
+ iter != serialized_resources.end(); ++iter) {
+ DVLOG(1) << "Saving resource " << iter->first << " to db";
+ leveldb::Status status = level_db_->Put(leveldb::WriteOptions(),
+ leveldb::Slice(iter->first),
+ leveldb::Slice(iter->second));
+ if (!status.ok()) {
+ LOG(ERROR) << "leveldb Put failed of " << iter->first
+ << ", with " << status.ToString();
+ NOTREACHED();
+ }
+ }
+}
+
+void ResourceMetadataDB::Clear() {
+ level_db_.reset();
+ leveldb::DestroyDB(db_path_.value(), leveldb::Options());
+ Init();
+}
+
+// GDataDirectoryService class implementation.
+
+GDataDirectoryService::GDataDirectoryService()
+ : blocking_task_runner_(NULL),
+ serialized_size_(0),
+ largest_changestamp_(0),
+ origin_(UNINITIALIZED),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+ root_.reset(CreateGDataDirectory());
+ if (!util::IsDriveV2ApiEnabled())
+ InitializeRootEntry(kGDataRootDirectoryResourceId);
+}
+
+GDataDirectoryService::~GDataDirectoryService() {
+ ClearRoot();
+
+ // Ensure db is closed on the blocking pool.
+ if (blocking_task_runner_ && directory_service_db_.get())
+ blocking_task_runner_->DeleteSoon(FROM_HERE,
+ directory_service_db_.release());
+}
+
+GDataEntry* GDataDirectoryService::FromDocumentEntry(DocumentEntry* doc) {
+ DCHECK(doc);
+ GDataEntry* entry = NULL;
+ if (doc->is_folder())
+ entry = CreateGDataDirectory();
+ else if (doc->is_hosted_document() || doc->is_file())
+ entry = CreateGDataFile();
+
+ if (entry)
+ entry->InitFromDocumentEntry(doc);
+ return entry;
+}
+
+GDataFile* GDataDirectoryService::CreateGDataFile() {
+ return new GDataFile(this);
+}
+
+GDataDirectory* GDataDirectoryService::CreateGDataDirectory() {
+ return new GDataDirectory(this);
+}
+
+void GDataDirectoryService::InitializeRootEntry(const std::string& root_id) {
+ root_.reset(CreateGDataDirectory());
+ root_->set_title(kGDataRootDirectory);
+ root_->SetBaseNameFromTitle();
+ root_->set_resource_id(root_id);
+ AddEntryToResourceMap(root_.get());
+}
+
+void GDataDirectoryService::ClearRoot() {
+ // Note that children have a reference to root_,
+ // so we need to delete them here.
+ root_->RemoveChildren();
+ RemoveEntryFromResourceMap(root_.get());
+ DCHECK(resource_map_.empty());
+ resource_map_.clear();
+ root_.reset();
+}
+
+void GDataDirectoryService::AddEntryToDirectory(
+ GDataDirectory* directory,
+ GDataEntry* new_entry,
+ const FileMoveCallback& callback) {
+ DCHECK(directory);
+ DCHECK(new_entry);
+ DCHECK(!callback.is_null());
+
+ directory->AddEntry(new_entry);
+ DVLOG(1) << "AddEntryToDirectory " << new_entry->GetFilePath().value();
+ base::MessageLoopProxy::current()->PostTask(FROM_HERE,
+ base::Bind(callback, GDATA_FILE_OK, new_entry->GetFilePath()));
+}
+
+void GDataDirectoryService::MoveEntryToDirectory(
+ const FilePath& directory_path,
+ GDataEntry* entry,
+ const FileMoveCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(entry);
+ DCHECK(!callback.is_null());
+
+ if (entry->parent())
+ entry->parent()->RemoveChild(entry);
+
+ GDataEntry* destination = FindEntryByPathSync(directory_path);
+ FilePath moved_file_path;
+ GDataFileError error = GDATA_FILE_ERROR_FAILED;
+ if (!destination) {
+ error = GDATA_FILE_ERROR_NOT_FOUND;
+ } else if (!destination->AsGDataDirectory()) {
+ error = GDATA_FILE_ERROR_NOT_A_DIRECTORY;
+ } else {
+ destination->AsGDataDirectory()->AddEntry(entry);
+ moved_file_path = entry->GetFilePath();
+ error = GDATA_FILE_OK;
+ }
+ DVLOG(1) << "MoveEntryToDirectory " << moved_file_path.value();
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE, base::Bind(callback, error, moved_file_path));
+}
+
+void GDataDirectoryService::RemoveEntryFromParent(
+ GDataEntry* entry,
+ const FileMoveCallback& callback) {
+ GDataDirectory* parent = entry->parent();
+ DCHECK(parent);
+ DCHECK(!callback.is_null());
+ DVLOG(1) << "RemoveEntryFromParent " << entry->GetFilePath().value();
+
+ parent->RemoveEntry(entry);
+ base::MessageLoopProxy::current()->PostTask(FROM_HERE,
+ base::Bind(callback, GDATA_FILE_OK, parent->GetFilePath()));
+}
+
+void GDataDirectoryService::AddEntryToResourceMap(GDataEntry* entry) {
+ // GDataFileSystem has already locked.
+ DVLOG(1) << "AddEntryToResourceMap " << entry->resource_id();
+ resource_map_.insert(std::make_pair(entry->resource_id(), entry));
+}
+
+void GDataDirectoryService::RemoveEntryFromResourceMap(GDataEntry* entry) {
+ // GDataFileSystem has already locked.
+ resource_map_.erase(entry->resource_id());
+}
+
+GDataEntry* GDataDirectoryService::FindEntryByPathSync(
+ const FilePath& file_path) {
+ if (file_path == root_->GetFilePath())
+ return root_.get();
+
+ std::vector<FilePath::StringType> components;
+ file_path.GetComponents(&components);
+ GDataDirectory* current_dir = root_.get();
+
+ for (size_t i = 1; i < components.size() && current_dir; ++i) {
+ GDataEntry* entry = current_dir->FindChild(components[i]);
+ if (!entry)
+ return NULL;
+
+ if (i == components.size() - 1) // Last component.
+ return entry;
+ else
+ current_dir = entry->AsGDataDirectory();
+ }
+ return NULL;
+}
+
+void GDataDirectoryService::FindEntryByPathAndRunSync(
+ const FilePath& search_file_path,
+ const FindEntryCallback& callback) {
+ GDataEntry* entry = FindEntryByPathSync(search_file_path);
+ callback.Run(entry ? GDATA_FILE_OK : GDATA_FILE_ERROR_NOT_FOUND, entry);
+}
+
+GDataEntry* GDataDirectoryService::GetEntryByResourceId(
+ const std::string& resource) {
+ // GDataFileSystem has already locked.
+ ResourceMap::const_iterator iter = resource_map_.find(resource);
+ return iter == resource_map_.end() ? NULL : iter->second;
+}
+
+void GDataDirectoryService::GetEntryByResourceIdAsync(
+ const std::string& resource_id,
+ const GetEntryByResourceIdCallback& callback) {
+ GDataEntry* entry = GetEntryByResourceId(resource_id);
+ callback.Run(entry);
+}
+
+void GDataDirectoryService::GetEntryInfoByPath(
+ const FilePath& path,
+ const GetEntryInfoCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!callback.is_null());
+
+ scoped_ptr<GDataEntryProto> entry_proto;
+ GDataFileError error = GDATA_FILE_ERROR_FAILED;
+
+ GDataEntry* entry = FindEntryByPathSync(path);
+ if (entry) {
+ entry_proto.reset(new GDataEntryProto);
+ entry->ToProtoFull(entry_proto.get());
+ error = GDATA_FILE_OK;
+ } else {
+ error = GDATA_FILE_ERROR_NOT_FOUND;
+ }
+
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, error, base::Passed(&entry_proto)));
+}
+
+void GDataDirectoryService::ReadDirectoryByPath(
+ const FilePath& path,
+ const ReadDirectoryCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!callback.is_null());
+
+ scoped_ptr<GDataEntryProtoVector> entries;
+ GDataFileError error = GDATA_FILE_ERROR_FAILED;
+
+ GDataEntry* entry = FindEntryByPathSync(path);
+ if (entry && entry->AsGDataDirectory()) {
+ entries = entry->AsGDataDirectory()->ToProtoVector();
+ error = GDATA_FILE_OK;
+ } else if (entry && !entry->AsGDataDirectory()) {
+ error = GDATA_FILE_ERROR_NOT_A_DIRECTORY;
+ } else {
+ error = GDATA_FILE_ERROR_NOT_FOUND;
+ }
+
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, error, base::Passed(&entries)));
+}
+
+void GDataDirectoryService::GetEntryInfoPairByPaths(
+ const FilePath& first_path,
+ const FilePath& second_path,
+ const GetEntryInfoPairCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!callback.is_null());
+
+ // Get the first entry.
+ GetEntryInfoByPath(
+ first_path,
+ base::Bind(&GDataDirectoryService::GetEntryInfoPairByPathsAfterGetFirst,
+ weak_ptr_factory_.GetWeakPtr(),
+ first_path,
+ second_path,
+ callback));
+}
+
+void GDataDirectoryService::RefreshFile(scoped_ptr<GDataFile> fresh_file) {
+ DCHECK(fresh_file.get());
+
+ // Need to get a reference here because Passed() could get evaluated first.
+ const std::string& resource_id = fresh_file->resource_id();
+ GetEntryByResourceIdAsync(
+ resource_id,
+ base::Bind(&GDataDirectoryService::RefreshFileInternal,
+ base::Passed(&fresh_file)));
+}
+
+// static
+void GDataDirectoryService::RefreshFileInternal(
+ scoped_ptr<GDataFile> fresh_file,
+ GDataEntry* old_entry) {
+ GDataDirectory* entry_parent = old_entry ? old_entry->parent() : NULL;
+ if (entry_parent) {
+ DCHECK_EQ(fresh_file->resource_id(), old_entry->resource_id());
+ DCHECK(old_entry->AsGDataFile());
+
+ entry_parent->RemoveEntry(old_entry);
+ entry_parent->AddEntry(fresh_file.release());
+ }
+}
+
+void GDataDirectoryService::RefreshDirectory(
+ const std::string& directory_resource_id,
+ const ResourceMap& file_map,
+ const FileMoveCallback& callback) {
+ DCHECK(!callback.is_null());
+ GetEntryByResourceIdAsync(
+ directory_resource_id,
+ base::Bind(&GDataDirectoryService::RefreshDirectoryInternal,
+ file_map,
+ callback));
+}
+
+// static
+void GDataDirectoryService::RefreshDirectoryInternal(
+ const ResourceMap& file_map,
+ const FileMoveCallback& callback,
+ GDataEntry* directory_entry) {
+ DCHECK(!callback.is_null());
+
+ if (!directory_entry) {
+ callback.Run(GDATA_FILE_ERROR_NOT_FOUND, FilePath());
+ return;
+ }
+
+ GDataDirectory* directory = directory_entry->AsGDataDirectory();
+ if (!directory) {
+ callback.Run(GDATA_FILE_ERROR_NOT_A_DIRECTORY, FilePath());
+ return;
+ }
+
+ directory->RemoveChildFiles();
+ // Add files from file_map.
+ for (ResourceMap::const_iterator it = file_map.begin();
+ it != file_map.end(); ++it) {
+ scoped_ptr<GDataEntry> entry(it->second);
+ // Skip if it's not a file (i.e. directory).
+ if (!entry->AsGDataFile())
+ continue;
+ directory->AddEntry(entry.release());
+ }
+
+ callback.Run(GDATA_FILE_OK, directory->GetFilePath());
+}
+
+void GDataDirectoryService::InitFromDB(
+ const FilePath& db_path,
+ base::SequencedTaskRunner* blocking_task_runner,
+ const FileOperationCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!db_path.empty());
+ DCHECK(blocking_task_runner);
+
+ if (directory_service_db_.get()) {
+ if (!callback.is_null())
+ callback.Run(GDATA_FILE_ERROR_FAILED);
+ return;
+ }
+
+ blocking_task_runner_ = blocking_task_runner;
+
+ DVLOG(1) << "InitFromDB " << db_path.value();
+
+ CreateDBParams* create_params =
+ new CreateDBParams(db_path, blocking_task_runner);
+ blocking_task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&CreateResourceMetadataDBOnBlockingPool,
+ create_params),
+ base::Bind(&GDataDirectoryService::InitResourceMap,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(create_params),
+ callback));
+}
+
+void GDataDirectoryService::InitResourceMap(
+ CreateDBParams* create_params,
+ const FileOperationCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(create_params);
+ DCHECK(!directory_service_db_.get());
+
+ SerializedMap* serialized_resources = &create_params->serialized_resources;
+ directory_service_db_ = create_params->db.Pass();
+ if (serialized_resources->empty()) {
+ origin_ = INITIALIZING;
+ if (!callback.is_null())
+ callback.Run(GDATA_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+
+ ClearRoot();
+
+ // Version check.
+ int32 version = 0;
+ SerializedMap::iterator iter = serialized_resources->find(kDBKeyVersion);
+ if (iter == serialized_resources->end() ||
+ !base::StringToInt(iter->second, &version) ||
+ version != kProtoVersion) {
+ if (!callback.is_null())
+ callback.Run(GDATA_FILE_ERROR_FAILED);
+ return;
+ }
+ serialized_resources->erase(iter);
+
+ // Get the largest changestamp.
+ iter = serialized_resources->find(kDBKeyLargestChangestamp);
+ if (iter == serialized_resources->end() ||
+ !base::StringToInt64(iter->second, &largest_changestamp_)) {
+ NOTREACHED() << "Could not find/parse largest_changestamp";
+ if (!callback.is_null())
+ callback.Run(GDATA_FILE_ERROR_FAILED);
+ return;
+ } else {
+ DVLOG(1) << "InitResourceMap largest_changestamp_" << largest_changestamp_;
+ serialized_resources->erase(iter);
+ }
+
+ ResourceMap resource_map;
+ for (SerializedMap::const_iterator iter = serialized_resources->begin();
+ iter != serialized_resources->end(); ++iter) {
+ if (iter->first.find(kDBKeyResourceIdPrefix) != 0) {
+ NOTREACHED() << "Incorrect prefix for db key " << iter->first;
+ continue;
+ }
+
+ const std::string resource_id =
+ iter->first.substr(strlen(kDBKeyResourceIdPrefix));
+ scoped_ptr<GDataEntry> entry = FromProtoString(iter->second);
+ if (entry.get()) {
+ DVLOG(1) << "Inserting resource " << resource_id
+ << " into resource_map";
+ resource_map.insert(std::make_pair(resource_id, entry.release()));
+ } else {
+ NOTREACHED() << "Failed to parse GDataEntry for resource " << resource_id;
+ }
+ }
+
+ // Fix up parent-child relations.
+ for (ResourceMap::iterator iter = resource_map.begin();
+ iter != resource_map.end(); ++iter) {
+ GDataEntry* entry = iter->second;
+ ResourceMap::iterator parent_it =
+ resource_map.find(entry->parent_resource_id());
+ if (parent_it != resource_map.end()) {
+ GDataDirectory* parent = parent_it->second->AsGDataDirectory();
+ if (parent) {
+ DVLOG(1) << "Adding " << entry->resource_id()
+ << " as a child of " << parent->resource_id();
+ parent->AddEntry(entry);
+ } else {
+ NOTREACHED() << "Parent is not a directory " << parent->resource_id();
+ }
+ } else if (entry->resource_id() == kGDataRootDirectoryResourceId) {
+ root_.reset(entry->AsGDataDirectory());
+ DCHECK(root_.get());
+ AddEntryToResourceMap(root_.get());
+ } else {
+ NOTREACHED() << "Missing parent id " << entry->parent_resource_id()
+ << " for resource " << entry->resource_id();
+ }
+ }
+
+ DCHECK(root_.get());
+ DCHECK_EQ(resource_map.size(), resource_map_.size());
+ DCHECK_EQ(resource_map.size(), serialized_resources->size());
+
+ origin_ = FROM_CACHE;
+
+ if (!callback.is_null())
+ callback.Run(GDATA_FILE_OK);
+}
+
+void GDataDirectoryService::SaveToDB() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (!blocking_task_runner_ || !directory_service_db_.get()) {
+ NOTREACHED();
+ return;
+ }
+
+ size_t serialized_size = 0;
+ SerializedMap serialized_resources;
+ for (ResourceMap::const_iterator iter = resource_map_.begin();
+ iter != resource_map_.end(); ++iter) {
+ GDataEntryProto proto;
+ iter->second->ToProtoFull(&proto);
+ std::string serialized_string;
+ const bool ok = proto.SerializeToString(&serialized_string);
+ DCHECK(ok);
+ if (ok) {
+ serialized_resources.insert(
+ std::make_pair(std::string(kDBKeyResourceIdPrefix) + iter->first,
+ serialized_string));
+ serialized_size += serialized_string.size();
+ }
+ }
+
+ serialized_resources.insert(std::make_pair(kDBKeyVersion,
+ base::IntToString(kProtoVersion)));
+ serialized_resources.insert(std::make_pair(kDBKeyLargestChangestamp,
+ base::IntToString(largest_changestamp_)));
+ set_last_serialized(base::Time::Now());
+ set_serialized_size(serialized_size);
+
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ResourceMetadataDB::Save,
+ base::Unretained(directory_service_db_.get()),
+ serialized_resources));
+}
+
+void GDataDirectoryService::SerializeToString(
+ std::string* serialized_proto) const {
+ GDataRootDirectoryProto proto;
+ root_->ToProto(proto.mutable_gdata_directory());
+ proto.set_largest_changestamp(largest_changestamp_);
+ proto.set_version(kProtoVersion);
+
+ const bool ok = proto.SerializeToString(serialized_proto);
+ DCHECK(ok);
+}
+
+bool GDataDirectoryService::ParseFromString(
+ const std::string& serialized_proto) {
+ GDataRootDirectoryProto proto;
+ if (!proto.ParseFromString(serialized_proto))
+ return false;
+
+ if (proto.version() != kProtoVersion) {
+ LOG(ERROR) << "Incompatible proto detected (incompatible version): "
+ << proto.version();
+ return false;
+ }
+
+ if (!IsValidRootDirectoryProto(proto.gdata_directory()))
+ return false;
+
+ if (!root_->FromProto(proto.gdata_directory()))
+ return false;
+
+ origin_ = FROM_CACHE;
+ largest_changestamp_ = proto.largest_changestamp();
+
+ return true;
+}
+
+scoped_ptr<GDataEntry> GDataDirectoryService::FromProtoString(
+ const std::string& serialized_proto) {
+ GDataEntryProto entry_proto;
+ if (!entry_proto.ParseFromString(serialized_proto))
+ return scoped_ptr<GDataEntry>();
+
+ scoped_ptr<GDataEntry> entry;
+ if (entry_proto.file_info().is_directory()) {
+ entry.reset(CreateGDataDirectory());
+ // Call GDataEntry::FromProto instead of GDataDirectory::FromProto because
+ // the proto does not include children.
+ if (!entry->FromProto(entry_proto)) {
+ NOTREACHED() << "FromProto (directory) failed";
+ entry.reset();
+ }
+ } else {
+ scoped_ptr<GDataFile> file(CreateGDataFile());
+ // Call GDataFile::FromProto.
+ if (file->FromProto(entry_proto)) {
+ entry.reset(file.release());
+ } else {
+ NOTREACHED() << "FromProto (file) failed";
+ }
+ }
+ return entry.Pass();
+}
+
+void GDataDirectoryService::GetEntryInfoPairByPathsAfterGetFirst(
+ const FilePath& first_path,
+ const FilePath& second_path,
+ const GetEntryInfoPairCallback& callback,
+ GDataFileError error,
+ scoped_ptr<GDataEntryProto> entry_proto) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!callback.is_null());
+
+ scoped_ptr<EntryInfoPairResult> result(new EntryInfoPairResult);
+ result->first.path = first_path;
+ result->first.error = error;
+ result->first.proto = entry_proto.Pass();
+
+ // If the first one is not found, don't continue.
+ if (error != GDATA_FILE_OK) {
+ callback.Run(result.Pass());
+ return;
+ }
+
+ // Get the second entry.
+ GetEntryInfoByPath(
+ second_path,
+ base::Bind(&GDataDirectoryService::GetEntryInfoPairByPathsAfterGetSecond,
+ weak_ptr_factory_.GetWeakPtr(),
+ second_path,
+ callback,
+ base::Passed(&result)));
+}
+
+void GDataDirectoryService::GetEntryInfoPairByPathsAfterGetSecond(
+ const FilePath& second_path,
+ const GetEntryInfoPairCallback& callback,
+ scoped_ptr<EntryInfoPairResult> result,
+ GDataFileError error,
+ scoped_ptr<GDataEntryProto> entry_proto) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(!callback.is_null());
+ DCHECK(result.get());
+
+ result->second.path = second_path;
+ result->second.error = error;
+ result->second.proto = entry_proto.Pass();
+
+ callback.Run(result.Pass());
+}
+
+} // namespace gdata
Property changes on: chrome/browser/chromeos/gdata/gdata_directory_service.cc
___________________________________________________________________
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698