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 |
deleted file mode 100644 |
index 1842fe5bcd8c77a5fdaba4b85314be91c9ee5c83..0000000000000000000000000000000000000000 |
--- a/chrome/browser/chromeos/drive/resource_metadata.cc |
+++ /dev/null |
@@ -1,607 +0,0 @@ |
-// 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/drive/resource_metadata.h" |
- |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/guid.h" |
-#include "base/location.h" |
-#include "base/rand_util.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/sys_info.h" |
-#include "chrome/browser/chromeos/drive/file_cache.h" |
-#include "chrome/browser/chromeos/drive/file_system_core_util.h" |
-#include "chrome/browser/chromeos/drive/resource_metadata_storage.h" |
-#include "components/drive/drive.pb.h" |
- |
-namespace drive { |
-namespace internal { |
-namespace { |
- |
-// Returns true if enough disk space is available for DB operation. |
-// TODO(hashimoto): Merge this with FileCache's FreeDiskSpaceGetterInterface. |
-bool EnoughDiskSpaceIsAvailableForDBOperation(const base::FilePath& path) { |
- const int64 kRequiredDiskSpaceInMB = 128; // 128 MB seems to be large enough. |
- return base::SysInfo::AmountOfFreeDiskSpace(path) >= |
- kRequiredDiskSpaceInMB * (1 << 20); |
-} |
- |
-// Returns a file name with a uniquifier appended. (e.g. "File (1).txt") |
-std::string GetUniquifiedName(const std::string& name, int uniquifier) { |
- base::FilePath name_path = base::FilePath::FromUTF8Unsafe(name); |
- name_path = name_path.InsertBeforeExtensionASCII( |
- base::StringPrintf(" (%d)", uniquifier)); |
- return name_path.AsUTF8Unsafe(); |
-} |
- |
-// Returns true when there is no entry with the specified name under the parent |
-// other than the specified entry. |
-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; |
-} |
- |
-// Returns true when the ID is used by an immutable entry. |
-bool IsImmutableEntry(const std::string& id) { |
- return id == util::kDriveGrandRootLocalId || |
- id == util::kDriveOtherDirLocalId || |
- id == util::kDriveTrashDirLocalId; |
-} |
- |
-} // namespace |
- |
-ResourceMetadata::ResourceMetadata( |
- ResourceMetadataStorage* storage, |
- FileCache* cache, |
- scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) |
- : blocking_task_runner_(blocking_task_runner), |
- storage_(storage), |
- cache_(cache) { |
-} |
- |
-FileError ResourceMetadata::Initialize() { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- return SetUpDefaultEntries(); |
-} |
- |
-void ResourceMetadata::Destroy() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- blocking_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&ResourceMetadata::DestroyOnBlockingPool, |
- base::Unretained(this))); |
-} |
- |
-FileError ResourceMetadata::Reset() { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
- return FILE_ERROR_NO_LOCAL_SPACE; |
- |
- 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()) { |
- error = RemoveEntryRecursively(it->GetID()); |
- if (error != FILE_ERROR_OK) |
- return error; |
- } |
- } |
- if (it->HasError()) |
- return FILE_ERROR_FAILED; |
- |
- return SetUpDefaultEntries(); |
-} |
- |
-ResourceMetadata::~ResourceMetadata() { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
-} |
- |
-FileError ResourceMetadata::SetUpDefaultEntries() { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- // Initialize "/drive". |
- ResourceEntry 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); |
- 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; |
- } |
- |
- // 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); |
- 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; |
- } |
- |
- // 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); |
- error = PutEntryUnderDirectory(trash_dir); |
- if (error != FILE_ERROR_OK) |
- return error; |
- } else if (error != FILE_ERROR_OK) { |
- return error; |
- } |
- |
- // 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; |
- error = AddEntry(mydrive, &local_id); |
- if (error != FILE_ERROR_OK) |
- return error; |
- } else if (error != FILE_ERROR_OK) { |
- return error; |
- } |
- return FILE_ERROR_OK; |
-} |
- |
-void ResourceMetadata::DestroyOnBlockingPool() { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- delete this; |
-} |
- |
-FileError ResourceMetadata::GetLargestChangestamp(int64* out_value) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- return storage_->GetLargestChangestamp(out_value); |
-} |
- |
-FileError ResourceMetadata::SetLargestChangestamp(int64 value) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
- return FILE_ERROR_NO_LOCAL_SPACE; |
- |
- return storage_->SetLargestChangestamp(value); |
-} |
- |
-FileError ResourceMetadata::AddEntry(const ResourceEntry& entry, |
- std::string* out_id) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(entry.local_id().empty()); |
- |
- if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
- return FILE_ERROR_NO_LOCAL_SPACE; |
- |
- ResourceEntry parent; |
- 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()) { |
- 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. |
- // 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); |
- |
- error = PutEntryUnderDirectory(new_entry); |
- if (error != FILE_ERROR_OK) |
- return error; |
- |
- *out_id = local_id; |
- return FILE_ERROR_OK; |
-} |
- |
-FileError ResourceMetadata::RemoveEntry(const std::string& id) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
- return FILE_ERROR_NO_LOCAL_SPACE; |
- |
- // Disallow deletion of default entries. |
- if (IsImmutableEntry(id)) |
- return FILE_ERROR_ACCESS_DENIED; |
- |
- ResourceEntry entry; |
- FileError error = storage_->GetEntry(id, &entry); |
- if (error != FILE_ERROR_OK) |
- return error; |
- |
- return RemoveEntryRecursively(id); |
-} |
- |
-FileError ResourceMetadata::GetResourceEntryById(const std::string& id, |
- ResourceEntry* out_entry) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(!id.empty()); |
- DCHECK(out_entry); |
- |
- return storage_->GetEntry(id, out_entry); |
-} |
- |
-FileError ResourceMetadata::GetResourceEntryByPath(const base::FilePath& path, |
- ResourceEntry* out_entry) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(out_entry); |
- |
- std::string id; |
- FileError error = GetIdByPath(path, &id); |
- if (error != FILE_ERROR_OK) |
- return error; |
- |
- return GetResourceEntryById(id, out_entry); |
-} |
- |
-FileError ResourceMetadata::ReadDirectoryByPath( |
- const base::FilePath& path, |
- ResourceEntryVector* out_entries) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(out_entries); |
- |
- std::string id; |
- FileError error = GetIdByPath(path, &id); |
- if (error != FILE_ERROR_OK) |
- return error; |
- return ReadDirectoryById(id, out_entries); |
-} |
- |
-FileError ResourceMetadata::ReadDirectoryById( |
- const std::string& id, |
- ResourceEntryVector* out_entries) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- DCHECK(out_entries); |
- |
- ResourceEntry entry; |
- FileError error = GetResourceEntryById(id, &entry); |
- if (error != FILE_ERROR_OK) |
- return error; |
- |
- if (!entry.file_info().is_directory()) |
- return FILE_ERROR_NOT_A_DIRECTORY; |
- |
- std::vector<std::string> 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) { |
- error = storage_->GetEntry(children[i], &entries[i]); |
- if (error != FILE_ERROR_OK) |
- return error; |
- } |
- out_entries->swap(entries); |
- return FILE_ERROR_OK; |
-} |
- |
-FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
- return FILE_ERROR_NO_LOCAL_SPACE; |
- |
- ResourceEntry old_entry; |
- FileError error = storage_->GetEntry(entry.local_id(), &old_entry); |
- if (error != FILE_ERROR_OK) |
- return error; |
- |
- if (IsImmutableEntry(entry.local_id()) || |
- old_entry.file_info().is_directory() != // Reject incompatible input. |
- entry.file_info().is_directory()) |
- return FILE_ERROR_INVALID_OPERATION; |
- |
- if (!entry.resource_id().empty()) { |
- // Multiple entries cannot share the same resource ID. |
- std::string local_id; |
- FileError error = GetIdByResourceId(entry.resource_id(), &local_id); |
- switch (error) { |
- case FILE_ERROR_OK: |
- if (local_id != entry.local_id()) |
- return FILE_ERROR_INVALID_OPERATION; |
- break; |
- |
- case FILE_ERROR_NOT_FOUND: |
- break; |
- |
- default: |
- return error; |
- } |
- } |
- |
- // Make sure that the new parent exists and it is a directory. |
- ResourceEntry new_parent; |
- 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; |
- |
- // Do not overwrite cache states. |
- // Cache state should be changed via FileCache. |
- ResourceEntry updated_entry(entry); |
- if (old_entry.file_specific_info().has_cache_state()) { |
- *updated_entry.mutable_file_specific_info()->mutable_cache_state() = |
- old_entry.file_specific_info().cache_state(); |
- } else if (updated_entry.file_specific_info().has_cache_state()) { |
- updated_entry.mutable_file_specific_info()->clear_cache_state(); |
- } |
- // Remove from the old parent and add it to the new parent with the new data. |
- return PutEntryUnderDirectory(updated_entry); |
-} |
- |
-FileError ResourceMetadata::GetSubDirectoriesRecursively( |
- const std::string& id, |
- std::set<base::FilePath>* sub_directories) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- std::vector<std::string> children; |
- FileError error = storage_->GetChildren(id, &children); |
- if (error != FILE_ERROR_OK) |
- return error; |
- for (size_t i = 0; i < children.size(); ++i) { |
- ResourceEntry entry; |
- error = storage_->GetEntry(children[i], &entry); |
- if (error != FILE_ERROR_OK) |
- return error; |
- if (entry.file_info().is_directory()) { |
- base::FilePath path; |
- error = GetFilePath(children[i], &path); |
- if (error != FILE_ERROR_OK) |
- return error; |
- sub_directories->insert(path); |
- GetSubDirectoriesRecursively(children[i], sub_directories); |
- } |
- } |
- return FILE_ERROR_OK; |
-} |
- |
-FileError ResourceMetadata::GetChildId(const std::string& parent_local_id, |
- const std::string& base_name, |
- std::string* out_child_id) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- return storage_->GetChild(parent_local_id, base_name, out_child_id); |
-} |
- |
-scoped_ptr<ResourceMetadata::Iterator> ResourceMetadata::GetIterator() { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- return storage_->GetIterator(); |
-} |
- |
-FileError ResourceMetadata::GetFilePath(const std::string& id, |
- base::FilePath* out_file_path) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- ResourceEntry entry; |
- FileError error = storage_->GetEntry(id, &entry); |
- if (error != FILE_ERROR_OK) |
- return error; |
- |
- base::FilePath path; |
- if (!entry.parent_local_id().empty()) { |
- error = GetFilePath(entry.parent_local_id(), &path); |
- if (error != FILE_ERROR_OK) |
- return error; |
- } else if (entry.local_id() != util::kDriveGrandRootLocalId) { |
- DVLOG(1) << "Entries not under the grand root don't have paths."; |
- return FILE_ERROR_NOT_FOUND; |
- } |
- path = path.Append(base::FilePath::FromUTF8Unsafe(entry.base_name())); |
- *out_file_path = path; |
- return FILE_ERROR_OK; |
-} |
- |
-FileError ResourceMetadata::GetIdByPath(const base::FilePath& file_path, |
- std::string* out_id) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- // Start from the root. |
- std::vector<base::FilePath::StringType> components; |
- file_path.GetComponents(&components); |
- if (components.empty() || |
- components[0] != util::GetDriveGrandRootPath().value()) |
- return FILE_ERROR_NOT_FOUND; |
- |
- // Iterate over the remaining components. |
- std::string id = util::kDriveGrandRootLocalId; |
- for (size_t i = 1; i < components.size(); ++i) { |
- const std::string component = base::FilePath(components[i]).AsUTF8Unsafe(); |
- 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; |
-} |
- |
-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); |
-} |
- |
-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(base_name); |
- return storage_->PutEntry(updated_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()); |
- |
- // 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. |
- *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 = util::NormalizeFileName(*base_name); |
- |
- // If |base_name| is not used, just return it. |
- 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) { |
- 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); |
- if (smallest_known_unused_modifier <= INT_MAX - delta) { |
- smallest_known_unused_modifier += delta; |
- } else { // No luck finding an unused number. Try again. |
- smallest_known_unused_modifier = 1; |
- } |
- } |
- |
- int largest_known_used_modifier = 1; |
- while (smallest_known_unused_modifier - largest_known_used_modifier > 1) { |
- const int modifier = largest_known_used_modifier + |
- (smallest_known_unused_modifier - largest_known_used_modifier) / 2; |
- |
- 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; |
- } |
- } |
- *base_name = GetUniquifiedName(*base_name, smallest_known_unused_modifier); |
- return FILE_ERROR_OK; |
-} |
- |
-FileError ResourceMetadata::RemoveEntryRecursively(const std::string& id) { |
- DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
- |
- ResourceEntry entry; |
- FileError error = storage_->GetEntry(id, &entry); |
- if (error != FILE_ERROR_OK) |
- return error; |
- |
- if (entry.file_info().is_directory()) { |
- std::vector<std::string> children; |
- error = storage_->GetChildren(id, &children); |
- if (error != FILE_ERROR_OK) |
- return error; |
- for (size_t i = 0; i < children.size(); ++i) { |
- error = RemoveEntryRecursively(children[i]); |
- if (error != FILE_ERROR_OK) |
- return error; |
- } |
- } |
- |
- error = cache_->Remove(id); |
- if (error != FILE_ERROR_OK) |
- return error; |
- |
- return storage_->RemoveEntry(id); |
-} |
- |
-} // namespace internal |
-} // namespace drive |