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/drive/resource_metadata.h" | 5 #include "chrome/browser/chromeos/drive/resource_metadata.h" |
| 6 | 6 |
| 7 #include "base/guid.h" | 7 #include "base/guid.h" |
| 8 #include "base/rand_util.h" | 8 #include "base/rand_util.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 31 // Returns a file name with a uniquifier appended. (e.g. "File (1).txt") | 31 // Returns a file name with a uniquifier appended. (e.g. "File (1).txt") |
| 32 std::string GetUniquifiedName(const std::string& name, int uniquifier) { | 32 std::string GetUniquifiedName(const std::string& name, int uniquifier) { |
| 33 base::FilePath name_path = base::FilePath::FromUTF8Unsafe(name); | 33 base::FilePath name_path = base::FilePath::FromUTF8Unsafe(name); |
| 34 name_path = name_path.InsertBeforeExtension( | 34 name_path = name_path.InsertBeforeExtension( |
| 35 base::StringPrintf(" (%d)", uniquifier)); | 35 base::StringPrintf(" (%d)", uniquifier)); |
| 36 return name_path.AsUTF8Unsafe(); | 36 return name_path.AsUTF8Unsafe(); |
| 37 } | 37 } |
| 38 | 38 |
| 39 // Returns true when there is no entry with the specified name under the parent | 39 // Returns true when there is no entry with the specified name under the parent |
| 40 // other than the specified entry. | 40 // other than the specified entry. |
| 41 bool EntryCanUseName(ResourceMetadataStorage* storage, | 41 FileError EntryCanUseName(ResourceMetadataStorage* storage, |
| 42 const std::string& parent_local_id, | 42 const std::string& parent_local_id, |
| 43 const std::string& local_id, | 43 const std::string& local_id, |
| 44 const std::string& base_name) { | 44 const std::string& base_name, |
| 45 const std::string existing_entry_id = storage->GetChild(parent_local_id, | 45 bool* result) { |
| 46 base_name); | 46 std::string existing_entry_id; |
| 47 return existing_entry_id.empty() || existing_entry_id == local_id; | 47 FileError error = storage->GetChild(parent_local_id, base_name, |
| 48 &existing_entry_id); | |
| 49 if (error == FILE_ERROR_OK) | |
| 50 *result = existing_entry_id == local_id; | |
| 51 else if (error == FILE_ERROR_NOT_FOUND) | |
| 52 *result = true; | |
| 53 else | |
| 54 return error; | |
| 55 return FILE_ERROR_OK; | |
| 48 } | 56 } |
| 49 | 57 |
| 50 } // namespace | 58 } // namespace |
| 51 | 59 |
| 52 ResourceMetadata::ResourceMetadata( | 60 ResourceMetadata::ResourceMetadata( |
| 53 ResourceMetadataStorage* storage, | 61 ResourceMetadataStorage* storage, |
| 54 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) | 62 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) |
| 55 : blocking_task_runner_(blocking_task_runner), | 63 : blocking_task_runner_(blocking_task_runner), |
| 56 storage_(storage) { | 64 storage_(storage) { |
| 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 58 } | 66 } |
| 59 | 67 |
| 60 FileError ResourceMetadata::Initialize() { | 68 FileError ResourceMetadata::Initialize() { |
| 61 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 69 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 62 | 70 return SetUpDefaultEntries(); |
| 63 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) | |
| 64 return FILE_ERROR_NO_LOCAL_SPACE; | |
| 65 | |
| 66 if (!SetUpDefaultEntries()) | |
| 67 return FILE_ERROR_FAILED; | |
| 68 | |
| 69 return FILE_ERROR_OK; | |
| 70 } | 71 } |
| 71 | 72 |
| 72 void ResourceMetadata::Destroy() { | 73 void ResourceMetadata::Destroy() { |
| 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 74 | 75 |
| 75 blocking_task_runner_->PostTask( | 76 blocking_task_runner_->PostTask( |
| 76 FROM_HERE, | 77 FROM_HERE, |
| 77 base::Bind(&ResourceMetadata::DestroyOnBlockingPool, | 78 base::Bind(&ResourceMetadata::DestroyOnBlockingPool, |
| 78 base::Unretained(this))); | 79 base::Unretained(this))); |
| 79 } | 80 } |
| 80 | 81 |
| 81 FileError ResourceMetadata::Reset() { | 82 FileError ResourceMetadata::Reset() { |
| 82 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 83 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 83 | 84 |
| 84 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) | 85 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
| 85 return FILE_ERROR_NO_LOCAL_SPACE; | 86 return FILE_ERROR_NO_LOCAL_SPACE; |
| 86 | 87 |
| 87 if (!storage_->SetLargestChangestamp(0)) | 88 FileError error = storage_->SetLargestChangestamp(0); |
| 88 return FILE_ERROR_FAILED; | 89 if (error != FILE_ERROR_OK) |
| 90 return error; | |
| 89 | 91 |
| 90 // Remove all root entries. | 92 // Remove all root entries. |
| 91 scoped_ptr<Iterator> it = GetIterator(); | 93 scoped_ptr<Iterator> it = GetIterator(); |
| 92 for (; !it->IsAtEnd(); it->Advance()) { | 94 for (; !it->IsAtEnd(); it->Advance()) { |
| 93 if (it->GetValue().parent_local_id().empty()) { | 95 if (it->GetValue().parent_local_id().empty()) { |
| 94 if (!RemoveEntryRecursively(it->GetID())) | 96 error = RemoveEntryRecursively(it->GetID()); |
| 95 return FILE_ERROR_FAILED; | 97 if (error != FILE_ERROR_OK) |
| 98 return error; | |
| 96 } | 99 } |
| 97 } | 100 } |
| 98 if (it->HasError()) | 101 if (it->HasError()) |
| 99 return FILE_ERROR_FAILED; | 102 return FILE_ERROR_FAILED; |
| 100 | 103 |
| 101 if (!SetUpDefaultEntries()) | 104 return SetUpDefaultEntries(); |
| 102 return FILE_ERROR_FAILED; | |
| 103 | |
| 104 return FILE_ERROR_OK; | |
| 105 } | 105 } |
| 106 | 106 |
| 107 ResourceMetadata::~ResourceMetadata() { | 107 ResourceMetadata::~ResourceMetadata() { |
| 108 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 108 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 109 } | 109 } |
| 110 | 110 |
| 111 bool ResourceMetadata::SetUpDefaultEntries() { | 111 FileError ResourceMetadata::SetUpDefaultEntries() { |
| 112 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 112 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 113 | 113 |
| 114 // Initialize "/drive", "/drive/other", "drive/trash" and "drive/root". | 114 // Initialize "/drive". |
| 115 ResourceEntry entry; | 115 ResourceEntry entry; |
| 116 if (!storage_->GetEntry(util::kDriveGrandRootLocalId, &entry)) { | 116 FileError error = storage_->GetEntry(util::kDriveGrandRootLocalId, &entry); |
| 117 if (error == FILE_ERROR_NOT_FOUND) { | |
| 117 ResourceEntry root; | 118 ResourceEntry root; |
| 118 root.mutable_file_info()->set_is_directory(true); | 119 root.mutable_file_info()->set_is_directory(true); |
| 119 root.set_local_id(util::kDriveGrandRootLocalId); | 120 root.set_local_id(util::kDriveGrandRootLocalId); |
| 120 root.set_title(util::kDriveGrandRootDirName); | 121 root.set_title(util::kDriveGrandRootDirName); |
| 121 root.set_base_name(util::kDriveGrandRootDirName); | 122 root.set_base_name(util::kDriveGrandRootDirName); |
| 122 if (!storage_->PutEntry(root)) | 123 error = storage_->PutEntry(root); |
| 123 return false; | 124 if (error != FILE_ERROR_OK) |
| 124 } else if (!entry.resource_id().empty()) { | 125 return error; |
| 125 // Old implementations used kDriveGrandRootLocalId as a resource ID. | 126 } else if (error == FILE_ERROR_OK) { |
| 126 entry.clear_resource_id(); | 127 if (!entry.resource_id().empty()) { |
| 127 if (!storage_->PutEntry(entry)) | 128 // Old implementations used kDriveGrandRootLocalId as a resource ID. |
| 128 return false; | 129 entry.clear_resource_id(); |
| 130 error = storage_->PutEntry(entry); | |
| 131 if (error != FILE_ERROR_OK) | |
| 132 return error; | |
| 133 } | |
| 134 } else { | |
| 135 return error; | |
| 129 } | 136 } |
| 130 if (!storage_->GetEntry(util::kDriveOtherDirLocalId, &entry)) { | 137 |
| 138 // Initialize "/drive/other". | |
| 139 error = storage_->GetEntry(util::kDriveOtherDirLocalId, &entry); | |
| 140 if (error == FILE_ERROR_NOT_FOUND) { | |
| 131 ResourceEntry other_dir; | 141 ResourceEntry other_dir; |
| 132 other_dir.mutable_file_info()->set_is_directory(true); | 142 other_dir.mutable_file_info()->set_is_directory(true); |
| 133 other_dir.set_local_id(util::kDriveOtherDirLocalId); | 143 other_dir.set_local_id(util::kDriveOtherDirLocalId); |
| 134 other_dir.set_parent_local_id(util::kDriveGrandRootLocalId); | 144 other_dir.set_parent_local_id(util::kDriveGrandRootLocalId); |
| 135 other_dir.set_title(util::kDriveOtherDirName); | 145 other_dir.set_title(util::kDriveOtherDirName); |
| 136 if (!PutEntryUnderDirectory(other_dir)) | 146 error = PutEntryUnderDirectory(other_dir); |
| 137 return false; | 147 if (error != FILE_ERROR_OK) |
| 138 } else if (!entry.resource_id().empty()) { | 148 return error; |
| 139 // Old implementations used kDriveOtherDirLocalId as a resource ID. | 149 } else if (error == FILE_ERROR_OK) { |
| 140 entry.clear_resource_id(); | 150 if (!entry.resource_id().empty()) { |
| 141 if (!storage_->PutEntry(entry)) | 151 // Old implementations used kDriveOtherDirLocalId as a resource ID. |
| 142 return false; | 152 entry.clear_resource_id(); |
| 153 error = storage_->PutEntry(entry); | |
| 154 if (error != FILE_ERROR_OK) | |
| 155 return error; | |
| 156 } | |
| 157 } else { | |
| 158 return error; | |
| 143 } | 159 } |
| 144 if (!storage_->GetEntry(util::kDriveTrashDirLocalId, &entry)) { | 160 |
| 161 // Initialize "drive/trash". | |
| 162 error = storage_->GetEntry(util::kDriveTrashDirLocalId, &entry); | |
| 163 if (error == FILE_ERROR_NOT_FOUND) { | |
| 145 ResourceEntry trash_dir; | 164 ResourceEntry trash_dir; |
| 146 trash_dir.mutable_file_info()->set_is_directory(true); | 165 trash_dir.mutable_file_info()->set_is_directory(true); |
| 147 trash_dir.set_local_id(util::kDriveTrashDirLocalId); | 166 trash_dir.set_local_id(util::kDriveTrashDirLocalId); |
| 148 trash_dir.set_parent_local_id(util::kDriveGrandRootLocalId); | 167 trash_dir.set_parent_local_id(util::kDriveGrandRootLocalId); |
| 149 trash_dir.set_title(util::kDriveTrashDirName); | 168 trash_dir.set_title(util::kDriveTrashDirName); |
| 150 if (!PutEntryUnderDirectory(trash_dir)) | 169 error = PutEntryUnderDirectory(trash_dir); |
| 151 return false; | 170 if (error != FILE_ERROR_OK) |
| 171 return error; | |
| 172 } else if (error != FILE_ERROR_OK) { | |
| 173 return error; | |
| 152 } | 174 } |
| 153 if (storage_->GetChild(util::kDriveGrandRootLocalId, | 175 |
| 154 util::kDriveMyDriveRootDirName).empty()) { | 176 // Initialize "drive/root". |
| 177 std::string child_id; | |
| 178 error = storage_->GetChild( | |
| 179 util::kDriveGrandRootLocalId, util::kDriveMyDriveRootDirName, &child_id); | |
| 180 if (error == FILE_ERROR_NOT_FOUND) { | |
| 155 ResourceEntry mydrive; | 181 ResourceEntry mydrive; |
| 156 mydrive.mutable_file_info()->set_is_directory(true); | 182 mydrive.mutable_file_info()->set_is_directory(true); |
| 157 mydrive.set_parent_local_id(util::kDriveGrandRootLocalId); | 183 mydrive.set_parent_local_id(util::kDriveGrandRootLocalId); |
| 158 mydrive.set_title(util::kDriveMyDriveRootDirName); | 184 mydrive.set_title(util::kDriveMyDriveRootDirName); |
| 159 | 185 |
| 160 std::string local_id; | 186 std::string local_id; |
| 161 if (AddEntry(mydrive, &local_id) != FILE_ERROR_OK) | 187 error = AddEntry(mydrive, &local_id); |
| 162 return false; | 188 if (error != FILE_ERROR_OK) |
| 189 return error; | |
| 190 } else if (error != FILE_ERROR_OK) { | |
| 191 return error; | |
| 163 } | 192 } |
| 164 return true; | 193 return FILE_ERROR_OK; |
| 165 } | 194 } |
| 166 | 195 |
| 167 void ResourceMetadata::DestroyOnBlockingPool() { | 196 void ResourceMetadata::DestroyOnBlockingPool() { |
| 168 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 197 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 169 delete this; | 198 delete this; |
| 170 } | 199 } |
| 171 | 200 |
| 172 int64 ResourceMetadata::GetLargestChangestamp() { | 201 int64 ResourceMetadata::GetLargestChangestamp() { |
| 173 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 202 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 174 return storage_->GetLargestChangestamp(); | 203 int64 value = 0; |
| 204 storage_->GetLargestChangestamp(&value); | |
| 205 return value; | |
| 175 } | 206 } |
| 176 | 207 |
| 177 FileError ResourceMetadata::SetLargestChangestamp(int64 value) { | 208 FileError ResourceMetadata::SetLargestChangestamp(int64 value) { |
| 178 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 209 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 179 | 210 |
| 180 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) | 211 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
| 181 return FILE_ERROR_NO_LOCAL_SPACE; | 212 return FILE_ERROR_NO_LOCAL_SPACE; |
| 182 | 213 |
| 183 return storage_->SetLargestChangestamp(value) ? | 214 return storage_->SetLargestChangestamp(value); |
| 184 FILE_ERROR_OK : FILE_ERROR_FAILED; | |
| 185 } | 215 } |
| 186 | 216 |
| 187 FileError ResourceMetadata::AddEntry(const ResourceEntry& entry, | 217 FileError ResourceMetadata::AddEntry(const ResourceEntry& entry, |
| 188 std::string* out_id) { | 218 std::string* out_id) { |
| 189 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 219 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 190 DCHECK(entry.local_id().empty()); | 220 DCHECK(entry.local_id().empty()); |
| 191 | 221 |
| 192 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) | 222 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
| 193 return FILE_ERROR_NO_LOCAL_SPACE; | 223 return FILE_ERROR_NO_LOCAL_SPACE; |
| 194 | 224 |
| 195 ResourceEntry parent; | 225 ResourceEntry parent; |
| 196 if (!storage_->GetEntry(entry.parent_local_id(), &parent) || | 226 FileError error = storage_->GetEntry(entry.parent_local_id(), &parent); |
| 197 !parent.file_info().is_directory()) | 227 if (error != FILE_ERROR_OK) |
| 198 return FILE_ERROR_NOT_FOUND; | 228 return error; |
| 229 if (!parent.file_info().is_directory()) | |
| 230 return FILE_ERROR_NOT_A_DIRECTORY; | |
| 199 | 231 |
| 200 // Multiple entries with the same resource ID should not be present. | 232 // Multiple entries with the same resource ID should not be present. |
| 201 std::string local_id; | 233 std::string local_id; |
| 202 ResourceEntry existing_entry; | 234 ResourceEntry existing_entry; |
| 203 if (!entry.resource_id().empty() && | 235 if (!entry.resource_id().empty()) { |
| 204 storage_->GetIdByResourceId(entry.resource_id(), &local_id) && | 236 error = storage_->GetIdByResourceId(entry.resource_id(), &local_id); |
| 205 storage_->GetEntry(local_id, &existing_entry)) | 237 if (error == FILE_ERROR_OK) |
| 206 return FILE_ERROR_EXISTS; | 238 error = storage_->GetEntry(local_id, &existing_entry); |
| 239 | |
| 240 if (error == FILE_ERROR_OK) | |
| 241 return FILE_ERROR_EXISTS; | |
| 242 else if (error != FILE_ERROR_NOT_FOUND) | |
| 243 return error; | |
| 244 } | |
| 207 | 245 |
| 208 // Generate unique local ID when needed. | 246 // Generate unique local ID when needed. |
| 209 while (local_id.empty() || storage_->GetEntry(local_id, &existing_entry)) | 247 // We don't check for ID collisions as its probability is extemely low. |
|
kinaba
2014/05/09 05:31:26
nit: ext[r]emely
hashimoto
2014/05/09 05:34:41
Oops, done.
| |
| 248 if (local_id.empty()) | |
| 210 local_id = base::GenerateGUID(); | 249 local_id = base::GenerateGUID(); |
| 211 | 250 |
| 212 ResourceEntry new_entry(entry); | 251 ResourceEntry new_entry(entry); |
| 213 new_entry.set_local_id(local_id); | 252 new_entry.set_local_id(local_id); |
| 214 | 253 |
| 215 if (!PutEntryUnderDirectory(new_entry)) | 254 error = PutEntryUnderDirectory(new_entry); |
| 216 return FILE_ERROR_FAILED; | 255 if (error != FILE_ERROR_OK) |
| 256 return error; | |
| 217 | 257 |
| 218 *out_id = local_id; | 258 *out_id = local_id; |
| 219 return FILE_ERROR_OK; | 259 return FILE_ERROR_OK; |
| 220 } | 260 } |
| 221 | 261 |
| 222 FileError ResourceMetadata::RemoveEntry(const std::string& id) { | 262 FileError ResourceMetadata::RemoveEntry(const std::string& id) { |
| 223 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 263 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 224 | 264 |
| 225 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) | 265 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
| 226 return FILE_ERROR_NO_LOCAL_SPACE; | 266 return FILE_ERROR_NO_LOCAL_SPACE; |
| 227 | 267 |
| 228 // Disallow deletion of default entries. | 268 // Disallow deletion of default entries. |
| 229 if (id == util::kDriveGrandRootLocalId || | 269 if (id == util::kDriveGrandRootLocalId || |
| 230 id == util::kDriveOtherDirLocalId || | 270 id == util::kDriveOtherDirLocalId || |
| 231 id == util::kDriveTrashDirLocalId) | 271 id == util::kDriveTrashDirLocalId) |
| 232 return FILE_ERROR_ACCESS_DENIED; | 272 return FILE_ERROR_ACCESS_DENIED; |
| 233 | 273 |
| 234 ResourceEntry entry; | 274 ResourceEntry entry; |
| 235 if (!storage_->GetEntry(id, &entry)) | 275 FileError error = storage_->GetEntry(id, &entry); |
| 236 return FILE_ERROR_NOT_FOUND; | 276 if (error != FILE_ERROR_OK) |
| 277 return error; | |
| 237 | 278 |
| 238 if (!RemoveEntryRecursively(id)) | 279 return RemoveEntryRecursively(id); |
| 239 return FILE_ERROR_FAILED; | |
| 240 return FILE_ERROR_OK; | |
| 241 } | 280 } |
| 242 | 281 |
| 243 FileError ResourceMetadata::GetResourceEntryById(const std::string& id, | 282 FileError ResourceMetadata::GetResourceEntryById(const std::string& id, |
| 244 ResourceEntry* out_entry) { | 283 ResourceEntry* out_entry) { |
| 245 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 284 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 246 DCHECK(!id.empty()); | 285 DCHECK(!id.empty()); |
| 247 DCHECK(out_entry); | 286 DCHECK(out_entry); |
| 248 | 287 |
| 249 return storage_->GetEntry(id, out_entry) ? | 288 return storage_->GetEntry(id, out_entry); |
| 250 FILE_ERROR_OK : FILE_ERROR_NOT_FOUND; | |
| 251 } | 289 } |
| 252 | 290 |
| 253 FileError ResourceMetadata::GetResourceEntryByPath(const base::FilePath& path, | 291 FileError ResourceMetadata::GetResourceEntryByPath(const base::FilePath& path, |
| 254 ResourceEntry* out_entry) { | 292 ResourceEntry* out_entry) { |
| 255 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 293 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 256 DCHECK(out_entry); | 294 DCHECK(out_entry); |
| 257 | 295 |
| 258 std::string id; | 296 std::string id; |
| 259 FileError error = GetIdByPath(path, &id); | 297 FileError error = GetIdByPath(path, &id); |
| 260 if (error != FILE_ERROR_OK) | 298 if (error != FILE_ERROR_OK) |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 284 | 322 |
| 285 ResourceEntry entry; | 323 ResourceEntry entry; |
| 286 FileError error = GetResourceEntryById(id, &entry); | 324 FileError error = GetResourceEntryById(id, &entry); |
| 287 if (error != FILE_ERROR_OK) | 325 if (error != FILE_ERROR_OK) |
| 288 return error; | 326 return error; |
| 289 | 327 |
| 290 if (!entry.file_info().is_directory()) | 328 if (!entry.file_info().is_directory()) |
| 291 return FILE_ERROR_NOT_A_DIRECTORY; | 329 return FILE_ERROR_NOT_A_DIRECTORY; |
| 292 | 330 |
| 293 std::vector<std::string> children; | 331 std::vector<std::string> children; |
| 294 storage_->GetChildren(id, &children); | 332 error = storage_->GetChildren(id, &children); |
| 333 if (error != FILE_ERROR_OK) | |
| 334 return error; | |
| 295 | 335 |
| 296 ResourceEntryVector entries(children.size()); | 336 ResourceEntryVector entries(children.size()); |
| 297 for (size_t i = 0; i < children.size(); ++i) { | 337 for (size_t i = 0; i < children.size(); ++i) { |
| 298 if (!storage_->GetEntry(children[i], &entries[i])) | 338 error = storage_->GetEntry(children[i], &entries[i]); |
| 299 return FILE_ERROR_FAILED; | 339 if (error != FILE_ERROR_OK) |
| 340 return error; | |
| 300 } | 341 } |
| 301 out_entries->swap(entries); | 342 out_entries->swap(entries); |
| 302 return FILE_ERROR_OK; | 343 return FILE_ERROR_OK; |
| 303 } | 344 } |
| 304 | 345 |
| 305 FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) { | 346 FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) { |
| 306 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 347 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 307 | 348 |
| 308 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) | 349 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
| 309 return FILE_ERROR_NO_LOCAL_SPACE; | 350 return FILE_ERROR_NO_LOCAL_SPACE; |
| 310 | 351 |
| 311 ResourceEntry old_entry; | 352 ResourceEntry old_entry; |
| 312 if (!storage_->GetEntry(entry.local_id(), &old_entry)) | 353 FileError error = storage_->GetEntry(entry.local_id(), &old_entry); |
| 313 return FILE_ERROR_NOT_FOUND; | 354 if (error != FILE_ERROR_OK) |
| 355 return error; | |
| 314 | 356 |
| 315 if (old_entry.parent_local_id().empty() || // Reject root. | 357 if (old_entry.parent_local_id().empty() || // Reject root. |
| 316 old_entry.file_info().is_directory() != // Reject incompatible input. | 358 old_entry.file_info().is_directory() != // Reject incompatible input. |
| 317 entry.file_info().is_directory()) | 359 entry.file_info().is_directory()) |
| 318 return FILE_ERROR_INVALID_OPERATION; | 360 return FILE_ERROR_INVALID_OPERATION; |
| 319 | 361 |
| 320 if (!entry.resource_id().empty()) { | 362 if (!entry.resource_id().empty()) { |
| 321 // Multiple entries cannot share the same resource ID. | 363 // Multiple entries cannot share the same resource ID. |
| 322 std::string local_id; | 364 std::string local_id; |
| 323 FileError error = GetIdByResourceId(entry.resource_id(), &local_id); | 365 FileError error = GetIdByResourceId(entry.resource_id(), &local_id); |
| 324 switch (error) { | 366 switch (error) { |
| 325 case FILE_ERROR_OK: | 367 case FILE_ERROR_OK: |
| 326 if (local_id != entry.local_id()) | 368 if (local_id != entry.local_id()) |
| 327 return FILE_ERROR_INVALID_OPERATION; | 369 return FILE_ERROR_INVALID_OPERATION; |
| 328 break; | 370 break; |
| 329 | 371 |
| 330 case FILE_ERROR_NOT_FOUND: | 372 case FILE_ERROR_NOT_FOUND: |
| 331 break; | 373 break; |
| 332 | 374 |
| 333 default: | 375 default: |
| 334 return error; | 376 return error; |
| 335 } | 377 } |
| 336 } | 378 } |
| 337 | 379 |
| 338 // Make sure that the new parent exists and it is a directory. | 380 // Make sure that the new parent exists and it is a directory. |
| 339 ResourceEntry new_parent; | 381 ResourceEntry new_parent; |
| 340 if (!storage_->GetEntry(entry.parent_local_id(), &new_parent)) | 382 error = storage_->GetEntry(entry.parent_local_id(), &new_parent); |
| 341 return FILE_ERROR_NOT_FOUND; | 383 if (error != FILE_ERROR_OK) |
| 384 return error; | |
| 342 | 385 |
| 343 if (!new_parent.file_info().is_directory()) | 386 if (!new_parent.file_info().is_directory()) |
| 344 return FILE_ERROR_NOT_A_DIRECTORY; | 387 return FILE_ERROR_NOT_A_DIRECTORY; |
| 345 | 388 |
| 346 // Remove from the old parent and add it to the new parent with the new data. | 389 // Remove from the old parent and add it to the new parent with the new data. |
| 347 if (!PutEntryUnderDirectory(entry)) | 390 return PutEntryUnderDirectory(entry); |
| 348 return FILE_ERROR_FAILED; | |
| 349 return FILE_ERROR_OK; | |
| 350 } | 391 } |
| 351 | 392 |
| 352 void ResourceMetadata::GetSubDirectoriesRecursively( | 393 void ResourceMetadata::GetSubDirectoriesRecursively( |
| 353 const std::string& id, | 394 const std::string& id, |
| 354 std::set<base::FilePath>* sub_directories) { | 395 std::set<base::FilePath>* sub_directories) { |
| 355 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 396 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 356 | 397 |
| 357 std::vector<std::string> children; | 398 std::vector<std::string> children; |
| 358 storage_->GetChildren(id, &children); | 399 if (storage_->GetChildren(id, &children) != FILE_ERROR_OK) |
| 400 return; | |
| 359 for (size_t i = 0; i < children.size(); ++i) { | 401 for (size_t i = 0; i < children.size(); ++i) { |
| 360 ResourceEntry entry; | 402 ResourceEntry entry; |
| 361 if (storage_->GetEntry(children[i], &entry) && | 403 if (storage_->GetEntry(children[i], &entry) != FILE_ERROR_OK) |
| 362 entry.file_info().is_directory()) { | 404 return; |
| 405 if (entry.file_info().is_directory()) { | |
| 363 sub_directories->insert(GetFilePath(children[i])); | 406 sub_directories->insert(GetFilePath(children[i])); |
| 364 GetSubDirectoriesRecursively(children[i], sub_directories); | 407 GetSubDirectoriesRecursively(children[i], sub_directories); |
| 365 } | 408 } |
| 366 } | 409 } |
| 367 } | 410 } |
| 368 | 411 |
| 369 std::string ResourceMetadata::GetChildId(const std::string& parent_local_id, | 412 std::string ResourceMetadata::GetChildId(const std::string& parent_local_id, |
| 370 const std::string& base_name) { | 413 const std::string& base_name) { |
| 371 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 414 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 372 return storage_->GetChild(parent_local_id, base_name); | 415 std::string child_local_id; |
| 416 storage_->GetChild(parent_local_id, base_name, &child_local_id); | |
| 417 return child_local_id; | |
| 373 } | 418 } |
| 374 | 419 |
| 375 scoped_ptr<ResourceMetadata::Iterator> ResourceMetadata::GetIterator() { | 420 scoped_ptr<ResourceMetadata::Iterator> ResourceMetadata::GetIterator() { |
| 376 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 421 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 377 | 422 |
| 378 return storage_->GetIterator(); | 423 return storage_->GetIterator(); |
| 379 } | 424 } |
| 380 | 425 |
| 381 base::FilePath ResourceMetadata::GetFilePath(const std::string& id) { | 426 base::FilePath ResourceMetadata::GetFilePath(const std::string& id) { |
| 382 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 427 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 383 | 428 |
| 384 base::FilePath path; | 429 base::FilePath path; |
| 385 ResourceEntry entry; | 430 ResourceEntry entry; |
| 386 if (storage_->GetEntry(id, &entry)) { | 431 if (storage_->GetEntry(id, &entry) == FILE_ERROR_OK) { |
| 387 if (!entry.parent_local_id().empty()) { | 432 if (!entry.parent_local_id().empty()) { |
| 388 path = GetFilePath(entry.parent_local_id()); | 433 path = GetFilePath(entry.parent_local_id()); |
| 389 } else if (entry.local_id() != util::kDriveGrandRootLocalId) { | 434 } else if (entry.local_id() != util::kDriveGrandRootLocalId) { |
| 390 DVLOG(1) << "Entries not under the grand root don't have paths."; | 435 DVLOG(1) << "Entries not under the grand root don't have paths."; |
| 391 return base::FilePath(); | 436 return base::FilePath(); |
| 392 } | 437 } |
| 393 path = path.Append(base::FilePath::FromUTF8Unsafe(entry.base_name())); | 438 path = path.Append(base::FilePath::FromUTF8Unsafe(entry.base_name())); |
| 394 } | 439 } |
| 395 return path; | 440 return path; |
| 396 } | 441 } |
| 397 | 442 |
| 398 FileError ResourceMetadata::GetIdByPath(const base::FilePath& file_path, | 443 FileError ResourceMetadata::GetIdByPath(const base::FilePath& file_path, |
| 399 std::string* out_id) { | 444 std::string* out_id) { |
| 400 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 445 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 401 | 446 |
| 402 // Start from the root. | 447 // Start from the root. |
| 403 std::vector<base::FilePath::StringType> components; | 448 std::vector<base::FilePath::StringType> components; |
| 404 file_path.GetComponents(&components); | 449 file_path.GetComponents(&components); |
| 405 if (components.empty() || components[0] != util::kDriveGrandRootDirName) | 450 if (components.empty() || components[0] != util::kDriveGrandRootDirName) |
| 406 return FILE_ERROR_NOT_FOUND; | 451 return FILE_ERROR_NOT_FOUND; |
| 407 | 452 |
| 408 // Iterate over the remaining components. | 453 // Iterate over the remaining components. |
| 409 std::string id = util::kDriveGrandRootLocalId; | 454 std::string id = util::kDriveGrandRootLocalId; |
| 410 for (size_t i = 1; i < components.size(); ++i) { | 455 for (size_t i = 1; i < components.size(); ++i) { |
| 411 const std::string component = base::FilePath(components[i]).AsUTF8Unsafe(); | 456 const std::string component = base::FilePath(components[i]).AsUTF8Unsafe(); |
| 412 id = storage_->GetChild(id, component); | 457 std::string child_id; |
| 413 if (id.empty()) | 458 FileError error = storage_->GetChild(id, component, &child_id); |
| 414 return FILE_ERROR_NOT_FOUND; | 459 if (error != FILE_ERROR_OK) |
| 460 return error; | |
| 461 id = child_id; | |
| 415 } | 462 } |
| 416 *out_id = id; | 463 *out_id = id; |
| 417 return FILE_ERROR_OK; | 464 return FILE_ERROR_OK; |
| 418 } | 465 } |
| 419 | 466 |
| 420 FileError ResourceMetadata::GetIdByResourceId(const std::string& resource_id, | 467 FileError ResourceMetadata::GetIdByResourceId(const std::string& resource_id, |
| 421 std::string* out_local_id) { | 468 std::string* out_local_id) { |
| 422 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 469 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 423 | 470 return storage_->GetIdByResourceId(resource_id, out_local_id); |
| 424 return storage_->GetIdByResourceId(resource_id, out_local_id) ? | |
| 425 FILE_ERROR_OK : FILE_ERROR_NOT_FOUND; | |
| 426 } | 471 } |
| 427 | 472 |
| 428 bool ResourceMetadata::PutEntryUnderDirectory(const ResourceEntry& entry) { | 473 FileError ResourceMetadata::PutEntryUnderDirectory(const ResourceEntry& entry) { |
| 429 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 474 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 430 DCHECK(!entry.local_id().empty()); | 475 DCHECK(!entry.local_id().empty()); |
| 431 DCHECK(!entry.parent_local_id().empty()); | 476 DCHECK(!entry.parent_local_id().empty()); |
| 432 | 477 |
| 478 std::string base_name; | |
| 479 FileError error = GetDeduplicatedBaseName(entry, &base_name); | |
| 480 if (error != FILE_ERROR_OK) | |
| 481 return error; | |
| 433 ResourceEntry updated_entry(entry); | 482 ResourceEntry updated_entry(entry); |
| 434 updated_entry.set_base_name(GetDeduplicatedBaseName(updated_entry)); | 483 updated_entry.set_base_name(base_name); |
| 435 return storage_->PutEntry(updated_entry); | 484 return storage_->PutEntry(updated_entry); |
| 436 } | 485 } |
| 437 | 486 |
| 438 std::string ResourceMetadata::GetDeduplicatedBaseName( | 487 FileError ResourceMetadata::GetDeduplicatedBaseName( |
| 439 const ResourceEntry& entry) { | 488 const ResourceEntry& entry, |
| 489 std::string* base_name) { | |
| 440 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 490 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 441 DCHECK(!entry.parent_local_id().empty()); | 491 DCHECK(!entry.parent_local_id().empty()); |
| 442 DCHECK(!entry.title().empty()); | 492 DCHECK(!entry.title().empty()); |
| 443 | 493 |
| 444 // The entry name may have been changed due to prior name de-duplication. | 494 // The entry name may have been changed due to prior name de-duplication. |
| 445 // We need to first restore the file name based on the title before going | 495 // We need to first restore the file name based on the title before going |
| 446 // through name de-duplication again when it is added to another directory. | 496 // through name de-duplication again when it is added to another directory. |
| 447 std::string base_name = entry.title(); | 497 *base_name = entry.title(); |
| 448 if (entry.has_file_specific_info() && | 498 if (entry.has_file_specific_info() && |
| 449 entry.file_specific_info().is_hosted_document()) { | 499 entry.file_specific_info().is_hosted_document()) { |
| 450 base_name += entry.file_specific_info().document_extension(); | 500 *base_name += entry.file_specific_info().document_extension(); |
| 451 } | 501 } |
| 452 base_name = util::NormalizeFileName(base_name); | 502 *base_name = util::NormalizeFileName(*base_name); |
| 453 | 503 |
| 454 // If |base_name| is not used, just return it. | 504 // If |base_name| is not used, just return it. |
| 455 if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), | 505 bool can_use_name = false; |
| 456 base_name)) | 506 FileError error = EntryCanUseName(storage_, entry.parent_local_id(), |
| 457 return base_name; | 507 entry.local_id(), *base_name, |
| 508 &can_use_name); | |
| 509 if (error != FILE_ERROR_OK || can_use_name) | |
| 510 return error; | |
| 458 | 511 |
| 459 // Find an unused number with binary search. | 512 // Find an unused number with binary search. |
| 460 int smallest_known_unused_modifier = 1; | 513 int smallest_known_unused_modifier = 1; |
| 461 while (true) { | 514 while (true) { |
| 462 if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), | 515 error = EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
| 463 GetUniquifiedName(base_name, | 516 GetUniquifiedName(*base_name, |
| 464 smallest_known_unused_modifier))) | 517 smallest_known_unused_modifier), |
| 518 &can_use_name); | |
| 519 if (error != FILE_ERROR_OK) | |
| 520 return error; | |
| 521 if (can_use_name) | |
| 465 break; | 522 break; |
| 466 | 523 |
| 467 const int delta = base::RandInt(1, smallest_known_unused_modifier); | 524 const int delta = base::RandInt(1, smallest_known_unused_modifier); |
| 468 if (smallest_known_unused_modifier <= INT_MAX - delta) { | 525 if (smallest_known_unused_modifier <= INT_MAX - delta) { |
| 469 smallest_known_unused_modifier += delta; | 526 smallest_known_unused_modifier += delta; |
| 470 } else { // No luck finding an unused number. Try again. | 527 } else { // No luck finding an unused number. Try again. |
| 471 smallest_known_unused_modifier = 1; | 528 smallest_known_unused_modifier = 1; |
| 472 } | 529 } |
| 473 } | 530 } |
| 474 | 531 |
| 475 int largest_known_used_modifier = 1; | 532 int largest_known_used_modifier = 1; |
| 476 while (smallest_known_unused_modifier - largest_known_used_modifier > 1) { | 533 while (smallest_known_unused_modifier - largest_known_used_modifier > 1) { |
| 477 const int modifier = largest_known_used_modifier + | 534 const int modifier = largest_known_used_modifier + |
| 478 (smallest_known_unused_modifier - largest_known_used_modifier) / 2; | 535 (smallest_known_unused_modifier - largest_known_used_modifier) / 2; |
| 479 | 536 |
| 480 if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), | 537 error = EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
| 481 GetUniquifiedName(base_name, modifier))) { | 538 GetUniquifiedName(*base_name, modifier), |
| 539 &can_use_name); | |
| 540 if (error != FILE_ERROR_OK) | |
| 541 return error; | |
| 542 if (can_use_name) { | |
| 482 smallest_known_unused_modifier = modifier; | 543 smallest_known_unused_modifier = modifier; |
| 483 } else { | 544 } else { |
| 484 largest_known_used_modifier = modifier; | 545 largest_known_used_modifier = modifier; |
| 485 } | 546 } |
| 486 } | 547 } |
| 487 return GetUniquifiedName(base_name, smallest_known_unused_modifier); | 548 *base_name = GetUniquifiedName(*base_name, smallest_known_unused_modifier); |
| 549 return FILE_ERROR_OK; | |
| 488 } | 550 } |
| 489 | 551 |
| 490 bool ResourceMetadata::RemoveEntryRecursively(const std::string& id) { | 552 FileError ResourceMetadata::RemoveEntryRecursively(const std::string& id) { |
| 491 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 553 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 492 | 554 |
| 493 ResourceEntry entry; | 555 ResourceEntry entry; |
| 494 if (!storage_->GetEntry(id, &entry)) | 556 FileError error = storage_->GetEntry(id, &entry); |
| 495 return false; | 557 if (error != FILE_ERROR_OK) |
| 558 return error; | |
| 496 | 559 |
| 497 if (entry.file_info().is_directory()) { | 560 if (entry.file_info().is_directory()) { |
| 498 std::vector<std::string> children; | 561 std::vector<std::string> children; |
| 499 storage_->GetChildren(id, &children); | 562 storage_->GetChildren(id, &children); |
| 500 for (size_t i = 0; i < children.size(); ++i) { | 563 for (size_t i = 0; i < children.size(); ++i) { |
| 501 if (!RemoveEntryRecursively(children[i])) | 564 error = RemoveEntryRecursively(children[i]); |
| 502 return false; | 565 if (error != FILE_ERROR_OK) |
| 566 return error; | |
| 503 } | 567 } |
| 504 } | 568 } |
| 505 return storage_->RemoveEntry(id); | 569 return storage_->RemoveEntry(id); |
| 506 } | 570 } |
| 507 | 571 |
| 508 } // namespace internal | 572 } // namespace internal |
| 509 } // namespace drive | 573 } // namespace drive |
| OLD | NEW |