Index: chrome/browser/chromeos/drive/resource_metadata.cc |
diff --git a/chrome/browser/chromeos/drive/resource_metadata.cc b/chrome/browser/chromeos/drive/resource_metadata.cc |
index 56c0101280600e39d095ed54a13e7b36462ccf4f..d074e71e8c38db5adea98939a769b60901793448 100644 |
--- a/chrome/browser/chromeos/drive/resource_metadata.cc |
+++ b/chrome/browser/chromeos/drive/resource_metadata.cc |
@@ -38,13 +38,21 @@ std::string GetUniquifiedName(const std::string& name, int uniquifier) { |
// Returns true when there is no entry with the specified name under the parent |
// other than the specified entry. |
-bool EntryCanUseName(ResourceMetadataStorage* storage, |
- const std::string& parent_local_id, |
- const std::string& local_id, |
- const std::string& base_name) { |
- const std::string existing_entry_id = storage->GetChild(parent_local_id, |
- base_name); |
- return existing_entry_id.empty() || existing_entry_id == local_id; |
+FileError EntryCanUseName(ResourceMetadataStorage* storage, |
+ const std::string& parent_local_id, |
+ const std::string& local_id, |
+ const std::string& base_name, |
+ bool* result) { |
+ std::string existing_entry_id; |
+ FileError error = storage->GetChild(parent_local_id, base_name, |
+ &existing_entry_id); |
+ if (error == FILE_ERROR_OK) |
+ *result = existing_entry_id == local_id; |
+ else if (error == FILE_ERROR_NOT_FOUND) |
+ *result = true; |
+ else |
+ return error; |
+ return FILE_ERROR_OK; |
} |
} // namespace |
@@ -59,14 +67,7 @@ ResourceMetadata::ResourceMetadata( |
FileError ResourceMetadata::Initialize() { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
- return FILE_ERROR_NO_LOCAL_SPACE; |
- |
- if (!SetUpDefaultEntries()) |
- return FILE_ERROR_FAILED; |
- |
- return FILE_ERROR_OK; |
+ return SetUpDefaultEntries(); |
} |
void ResourceMetadata::Destroy() { |
@@ -84,84 +85,112 @@ FileError ResourceMetadata::Reset() { |
if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
return FILE_ERROR_NO_LOCAL_SPACE; |
- if (!storage_->SetLargestChangestamp(0)) |
- return FILE_ERROR_FAILED; |
+ FileError error = storage_->SetLargestChangestamp(0); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
// Remove all root entries. |
scoped_ptr<Iterator> it = GetIterator(); |
for (; !it->IsAtEnd(); it->Advance()) { |
if (it->GetValue().parent_local_id().empty()) { |
- if (!RemoveEntryRecursively(it->GetID())) |
- return FILE_ERROR_FAILED; |
+ error = RemoveEntryRecursively(it->GetID()); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
} |
} |
if (it->HasError()) |
return FILE_ERROR_FAILED; |
- if (!SetUpDefaultEntries()) |
- return FILE_ERROR_FAILED; |
- |
- return FILE_ERROR_OK; |
+ return SetUpDefaultEntries(); |
} |
ResourceMetadata::~ResourceMetadata() { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
} |
-bool ResourceMetadata::SetUpDefaultEntries() { |
+FileError ResourceMetadata::SetUpDefaultEntries() { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- // Initialize "/drive", "/drive/other", "drive/trash" and "drive/root". |
+ // Initialize "/drive". |
ResourceEntry entry; |
- if (!storage_->GetEntry(util::kDriveGrandRootLocalId, &entry)) { |
+ FileError error = storage_->GetEntry(util::kDriveGrandRootLocalId, &entry); |
+ if (error == FILE_ERROR_NOT_FOUND) { |
ResourceEntry root; |
root.mutable_file_info()->set_is_directory(true); |
root.set_local_id(util::kDriveGrandRootLocalId); |
root.set_title(util::kDriveGrandRootDirName); |
root.set_base_name(util::kDriveGrandRootDirName); |
- if (!storage_->PutEntry(root)) |
- return false; |
- } else if (!entry.resource_id().empty()) { |
- // Old implementations used kDriveGrandRootLocalId as a resource ID. |
- entry.clear_resource_id(); |
- if (!storage_->PutEntry(entry)) |
- return false; |
+ error = storage_->PutEntry(root); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ } else if (error == FILE_ERROR_OK) { |
+ if (!entry.resource_id().empty()) { |
+ // Old implementations used kDriveGrandRootLocalId as a resource ID. |
+ entry.clear_resource_id(); |
+ error = storage_->PutEntry(entry); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ } |
+ } else { |
+ return error; |
} |
- if (!storage_->GetEntry(util::kDriveOtherDirLocalId, &entry)) { |
+ |
+ // Initialize "/drive/other". |
+ error = storage_->GetEntry(util::kDriveOtherDirLocalId, &entry); |
+ if (error == FILE_ERROR_NOT_FOUND) { |
ResourceEntry other_dir; |
other_dir.mutable_file_info()->set_is_directory(true); |
other_dir.set_local_id(util::kDriveOtherDirLocalId); |
other_dir.set_parent_local_id(util::kDriveGrandRootLocalId); |
other_dir.set_title(util::kDriveOtherDirName); |
- if (!PutEntryUnderDirectory(other_dir)) |
- return false; |
- } else if (!entry.resource_id().empty()) { |
- // Old implementations used kDriveOtherDirLocalId as a resource ID. |
- entry.clear_resource_id(); |
- if (!storage_->PutEntry(entry)) |
- return false; |
+ error = PutEntryUnderDirectory(other_dir); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ } else if (error == FILE_ERROR_OK) { |
+ if (!entry.resource_id().empty()) { |
+ // Old implementations used kDriveOtherDirLocalId as a resource ID. |
+ entry.clear_resource_id(); |
+ error = storage_->PutEntry(entry); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ } |
+ } else { |
+ return error; |
} |
- if (!storage_->GetEntry(util::kDriveTrashDirLocalId, &entry)) { |
+ |
+ // Initialize "drive/trash". |
+ error = storage_->GetEntry(util::kDriveTrashDirLocalId, &entry); |
+ if (error == FILE_ERROR_NOT_FOUND) { |
ResourceEntry trash_dir; |
trash_dir.mutable_file_info()->set_is_directory(true); |
trash_dir.set_local_id(util::kDriveTrashDirLocalId); |
trash_dir.set_parent_local_id(util::kDriveGrandRootLocalId); |
trash_dir.set_title(util::kDriveTrashDirName); |
- if (!PutEntryUnderDirectory(trash_dir)) |
- return false; |
+ error = PutEntryUnderDirectory(trash_dir); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ } else if (error != FILE_ERROR_OK) { |
+ return error; |
} |
- if (storage_->GetChild(util::kDriveGrandRootLocalId, |
- util::kDriveMyDriveRootDirName).empty()) { |
+ |
+ // Initialize "drive/root". |
+ std::string child_id; |
+ error = storage_->GetChild( |
+ util::kDriveGrandRootLocalId, util::kDriveMyDriveRootDirName, &child_id); |
+ if (error == FILE_ERROR_NOT_FOUND) { |
ResourceEntry mydrive; |
mydrive.mutable_file_info()->set_is_directory(true); |
mydrive.set_parent_local_id(util::kDriveGrandRootLocalId); |
mydrive.set_title(util::kDriveMyDriveRootDirName); |
std::string local_id; |
- if (AddEntry(mydrive, &local_id) != FILE_ERROR_OK) |
- return false; |
+ error = AddEntry(mydrive, &local_id); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ } else if (error != FILE_ERROR_OK) { |
+ return error; |
} |
- return true; |
+ return FILE_ERROR_OK; |
} |
void ResourceMetadata::DestroyOnBlockingPool() { |
@@ -171,7 +200,9 @@ void ResourceMetadata::DestroyOnBlockingPool() { |
int64 ResourceMetadata::GetLargestChangestamp() { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- return storage_->GetLargestChangestamp(); |
+ int64 value = 0; |
+ storage_->GetLargestChangestamp(&value); |
+ return value; |
} |
FileError ResourceMetadata::SetLargestChangestamp(int64 value) { |
@@ -180,8 +211,7 @@ FileError ResourceMetadata::SetLargestChangestamp(int64 value) { |
if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
return FILE_ERROR_NO_LOCAL_SPACE; |
- return storage_->SetLargestChangestamp(value) ? |
- FILE_ERROR_OK : FILE_ERROR_FAILED; |
+ return storage_->SetLargestChangestamp(value); |
} |
FileError ResourceMetadata::AddEntry(const ResourceEntry& entry, |
@@ -193,27 +223,37 @@ FileError ResourceMetadata::AddEntry(const ResourceEntry& entry, |
return FILE_ERROR_NO_LOCAL_SPACE; |
ResourceEntry parent; |
- if (!storage_->GetEntry(entry.parent_local_id(), &parent) || |
- !parent.file_info().is_directory()) |
- return FILE_ERROR_NOT_FOUND; |
+ FileError error = storage_->GetEntry(entry.parent_local_id(), &parent); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ if (!parent.file_info().is_directory()) |
+ return FILE_ERROR_NOT_A_DIRECTORY; |
// Multiple entries with the same resource ID should not be present. |
std::string local_id; |
ResourceEntry existing_entry; |
- if (!entry.resource_id().empty() && |
- storage_->GetIdByResourceId(entry.resource_id(), &local_id) && |
- storage_->GetEntry(local_id, &existing_entry)) |
- return FILE_ERROR_EXISTS; |
+ if (!entry.resource_id().empty()) { |
+ error = storage_->GetIdByResourceId(entry.resource_id(), &local_id); |
+ if (error == FILE_ERROR_OK) |
+ error = storage_->GetEntry(local_id, &existing_entry); |
+ |
+ if (error == FILE_ERROR_OK) |
+ return FILE_ERROR_EXISTS; |
+ else if (error != FILE_ERROR_NOT_FOUND) |
+ return error; |
+ } |
// Generate unique local ID when needed. |
- while (local_id.empty() || storage_->GetEntry(local_id, &existing_entry)) |
+ // We don't check for ID collisions as its probability is extremely low. |
+ if (local_id.empty()) |
local_id = base::GenerateGUID(); |
ResourceEntry new_entry(entry); |
new_entry.set_local_id(local_id); |
- if (!PutEntryUnderDirectory(new_entry)) |
- return FILE_ERROR_FAILED; |
+ error = PutEntryUnderDirectory(new_entry); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
*out_id = local_id; |
return FILE_ERROR_OK; |
@@ -232,12 +272,11 @@ FileError ResourceMetadata::RemoveEntry(const std::string& id) { |
return FILE_ERROR_ACCESS_DENIED; |
ResourceEntry entry; |
- if (!storage_->GetEntry(id, &entry)) |
- return FILE_ERROR_NOT_FOUND; |
+ FileError error = storage_->GetEntry(id, &entry); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
- if (!RemoveEntryRecursively(id)) |
- return FILE_ERROR_FAILED; |
- return FILE_ERROR_OK; |
+ return RemoveEntryRecursively(id); |
} |
FileError ResourceMetadata::GetResourceEntryById(const std::string& id, |
@@ -246,8 +285,7 @@ FileError ResourceMetadata::GetResourceEntryById(const std::string& id, |
DCHECK(!id.empty()); |
DCHECK(out_entry); |
- return storage_->GetEntry(id, out_entry) ? |
- FILE_ERROR_OK : FILE_ERROR_NOT_FOUND; |
+ return storage_->GetEntry(id, out_entry); |
} |
FileError ResourceMetadata::GetResourceEntryByPath(const base::FilePath& path, |
@@ -291,12 +329,15 @@ FileError ResourceMetadata::ReadDirectoryById( |
return FILE_ERROR_NOT_A_DIRECTORY; |
std::vector<std::string> children; |
- storage_->GetChildren(id, &children); |
+ error = storage_->GetChildren(id, &children); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
ResourceEntryVector entries(children.size()); |
for (size_t i = 0; i < children.size(); ++i) { |
- if (!storage_->GetEntry(children[i], &entries[i])) |
- return FILE_ERROR_FAILED; |
+ error = storage_->GetEntry(children[i], &entries[i]); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
} |
out_entries->swap(entries); |
return FILE_ERROR_OK; |
@@ -309,8 +350,9 @@ FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) { |
return FILE_ERROR_NO_LOCAL_SPACE; |
ResourceEntry old_entry; |
- if (!storage_->GetEntry(entry.local_id(), &old_entry)) |
- return FILE_ERROR_NOT_FOUND; |
+ FileError error = storage_->GetEntry(entry.local_id(), &old_entry); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
if (old_entry.parent_local_id().empty() || // Reject root. |
old_entry.file_info().is_directory() != // Reject incompatible input. |
@@ -337,16 +379,15 @@ FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) { |
// Make sure that the new parent exists and it is a directory. |
ResourceEntry new_parent; |
- if (!storage_->GetEntry(entry.parent_local_id(), &new_parent)) |
- return FILE_ERROR_NOT_FOUND; |
+ error = storage_->GetEntry(entry.parent_local_id(), &new_parent); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
if (!new_parent.file_info().is_directory()) |
return FILE_ERROR_NOT_A_DIRECTORY; |
// Remove from the old parent and add it to the new parent with the new data. |
- if (!PutEntryUnderDirectory(entry)) |
- return FILE_ERROR_FAILED; |
- return FILE_ERROR_OK; |
+ return PutEntryUnderDirectory(entry); |
} |
void ResourceMetadata::GetSubDirectoriesRecursively( |
@@ -355,11 +396,13 @@ void ResourceMetadata::GetSubDirectoriesRecursively( |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
std::vector<std::string> children; |
- storage_->GetChildren(id, &children); |
+ if (storage_->GetChildren(id, &children) != FILE_ERROR_OK) |
+ return; |
for (size_t i = 0; i < children.size(); ++i) { |
ResourceEntry entry; |
- if (storage_->GetEntry(children[i], &entry) && |
- entry.file_info().is_directory()) { |
+ if (storage_->GetEntry(children[i], &entry) != FILE_ERROR_OK) |
+ return; |
+ if (entry.file_info().is_directory()) { |
sub_directories->insert(GetFilePath(children[i])); |
GetSubDirectoriesRecursively(children[i], sub_directories); |
} |
@@ -369,7 +412,9 @@ void ResourceMetadata::GetSubDirectoriesRecursively( |
std::string ResourceMetadata::GetChildId(const std::string& parent_local_id, |
const std::string& base_name) { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- return storage_->GetChild(parent_local_id, base_name); |
+ std::string child_local_id; |
+ storage_->GetChild(parent_local_id, base_name, &child_local_id); |
+ return child_local_id; |
} |
scoped_ptr<ResourceMetadata::Iterator> ResourceMetadata::GetIterator() { |
@@ -383,7 +428,7 @@ base::FilePath ResourceMetadata::GetFilePath(const std::string& id) { |
base::FilePath path; |
ResourceEntry entry; |
- if (storage_->GetEntry(id, &entry)) { |
+ if (storage_->GetEntry(id, &entry) == FILE_ERROR_OK) { |
if (!entry.parent_local_id().empty()) { |
path = GetFilePath(entry.parent_local_id()); |
} else if (entry.local_id() != util::kDriveGrandRootLocalId) { |
@@ -409,9 +454,11 @@ FileError ResourceMetadata::GetIdByPath(const base::FilePath& file_path, |
std::string id = util::kDriveGrandRootLocalId; |
for (size_t i = 1; i < components.size(); ++i) { |
const std::string component = base::FilePath(components[i]).AsUTF8Unsafe(); |
- id = storage_->GetChild(id, component); |
- if (id.empty()) |
- return FILE_ERROR_NOT_FOUND; |
+ std::string child_id; |
+ FileError error = storage_->GetChild(id, component, &child_id); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ id = child_id; |
} |
*out_id = id; |
return FILE_ERROR_OK; |
@@ -420,23 +467,26 @@ FileError ResourceMetadata::GetIdByPath(const base::FilePath& file_path, |
FileError ResourceMetadata::GetIdByResourceId(const std::string& resource_id, |
std::string* out_local_id) { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- return storage_->GetIdByResourceId(resource_id, out_local_id) ? |
- FILE_ERROR_OK : FILE_ERROR_NOT_FOUND; |
+ return storage_->GetIdByResourceId(resource_id, out_local_id); |
} |
-bool ResourceMetadata::PutEntryUnderDirectory(const ResourceEntry& entry) { |
+FileError ResourceMetadata::PutEntryUnderDirectory(const ResourceEntry& entry) { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
DCHECK(!entry.local_id().empty()); |
DCHECK(!entry.parent_local_id().empty()); |
+ std::string base_name; |
+ FileError error = GetDeduplicatedBaseName(entry, &base_name); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
ResourceEntry updated_entry(entry); |
- updated_entry.set_base_name(GetDeduplicatedBaseName(updated_entry)); |
+ updated_entry.set_base_name(base_name); |
return storage_->PutEntry(updated_entry); |
} |
-std::string ResourceMetadata::GetDeduplicatedBaseName( |
- const ResourceEntry& entry) { |
+FileError ResourceMetadata::GetDeduplicatedBaseName( |
+ const ResourceEntry& entry, |
+ std::string* base_name) { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
DCHECK(!entry.parent_local_id().empty()); |
DCHECK(!entry.title().empty()); |
@@ -444,24 +494,31 @@ std::string ResourceMetadata::GetDeduplicatedBaseName( |
// The entry name may have been changed due to prior name de-duplication. |
// We need to first restore the file name based on the title before going |
// through name de-duplication again when it is added to another directory. |
- std::string base_name = entry.title(); |
+ *base_name = entry.title(); |
if (entry.has_file_specific_info() && |
entry.file_specific_info().is_hosted_document()) { |
- base_name += entry.file_specific_info().document_extension(); |
+ *base_name += entry.file_specific_info().document_extension(); |
} |
- base_name = util::NormalizeFileName(base_name); |
+ *base_name = util::NormalizeFileName(*base_name); |
// If |base_name| is not used, just return it. |
- if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
- base_name)) |
- return base_name; |
+ bool can_use_name = false; |
+ FileError error = EntryCanUseName(storage_, entry.parent_local_id(), |
+ entry.local_id(), *base_name, |
+ &can_use_name); |
+ if (error != FILE_ERROR_OK || can_use_name) |
+ return error; |
// Find an unused number with binary search. |
int smallest_known_unused_modifier = 1; |
while (true) { |
- if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
- GetUniquifiedName(base_name, |
- smallest_known_unused_modifier))) |
+ error = EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
+ GetUniquifiedName(*base_name, |
+ smallest_known_unused_modifier), |
+ &can_use_name); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ if (can_use_name) |
break; |
const int delta = base::RandInt(1, smallest_known_unused_modifier); |
@@ -477,29 +534,36 @@ std::string ResourceMetadata::GetDeduplicatedBaseName( |
const int modifier = largest_known_used_modifier + |
(smallest_known_unused_modifier - largest_known_used_modifier) / 2; |
- if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
- GetUniquifiedName(base_name, modifier))) { |
+ error = EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
+ GetUniquifiedName(*base_name, modifier), |
+ &can_use_name); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
+ if (can_use_name) { |
smallest_known_unused_modifier = modifier; |
} else { |
largest_known_used_modifier = modifier; |
} |
} |
- return GetUniquifiedName(base_name, smallest_known_unused_modifier); |
+ *base_name = GetUniquifiedName(*base_name, smallest_known_unused_modifier); |
+ return FILE_ERROR_OK; |
} |
-bool ResourceMetadata::RemoveEntryRecursively(const std::string& id) { |
+FileError ResourceMetadata::RemoveEntryRecursively(const std::string& id) { |
DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
ResourceEntry entry; |
- if (!storage_->GetEntry(id, &entry)) |
- return false; |
+ FileError error = storage_->GetEntry(id, &entry); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
if (entry.file_info().is_directory()) { |
std::vector<std::string> children; |
storage_->GetChildren(id, &children); |
for (size_t i = 0; i < children.size(); ++i) { |
- if (!RemoveEntryRecursively(children[i])) |
- return false; |
+ error = RemoveEntryRecursively(children[i]); |
+ if (error != FILE_ERROR_OK) |
+ return error; |
} |
} |
return storage_->RemoveEntry(id); |