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() { |
|
hashimoto
2014/05/08 07:58:49
This method is the only method which is expected t
| |
| 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 if (error == FILE_ERROR_OK) | |
| 240 return FILE_ERROR_EXISTS; | |
| 241 else if (error != FILE_ERROR_NOT_FOUND) | |
|
kinaba
2014/05/09 01:57:28
maybe:
error = GetId()
if(OK)
error = GetEntry(
hashimoto
2014/05/09 05:28:48
Thanks, it looks simpler.
Done.
| |
| 242 return error; | |
| 243 } else if (error != FILE_ERROR_NOT_FOUND) { | |
| 244 return error; | |
| 245 } | |
| 246 } | |
| 207 | 247 |
| 208 // Generate unique local ID when needed. | 248 // Generate unique local ID when needed. |
| 209 while (local_id.empty() || storage_->GetEntry(local_id, &existing_entry)) | 249 if (local_id.empty()) |
|
hashimoto
2014/05/08 07:58:49
Retry was omitted as it may become complicated.
kinaba
2014/05/09 01:57:28
Sounds good, but could you leave a comment that th
hashimoto
2014/05/09 05:28:48
Done.
| |
| 210 local_id = base::GenerateGUID(); | 250 local_id = base::GenerateGUID(); |
| 211 | 251 |
| 212 ResourceEntry new_entry(entry); | 252 ResourceEntry new_entry(entry); |
| 213 new_entry.set_local_id(local_id); | 253 new_entry.set_local_id(local_id); |
| 214 | 254 |
| 215 if (!PutEntryUnderDirectory(new_entry)) | 255 error = PutEntryUnderDirectory(new_entry); |
| 216 return FILE_ERROR_FAILED; | 256 if (error != FILE_ERROR_OK) |
| 257 return error; | |
| 217 | 258 |
| 218 *out_id = local_id; | 259 *out_id = local_id; |
| 219 return FILE_ERROR_OK; | 260 return FILE_ERROR_OK; |
| 220 } | 261 } |
| 221 | 262 |
| 222 FileError ResourceMetadata::RemoveEntry(const std::string& id) { | 263 FileError ResourceMetadata::RemoveEntry(const std::string& id) { |
| 223 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 264 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 224 | 265 |
| 225 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) | 266 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
| 226 return FILE_ERROR_NO_LOCAL_SPACE; | 267 return FILE_ERROR_NO_LOCAL_SPACE; |
| 227 | 268 |
| 228 // Disallow deletion of default entries. | 269 // Disallow deletion of default entries. |
| 229 if (id == util::kDriveGrandRootLocalId || | 270 if (id == util::kDriveGrandRootLocalId || |
| 230 id == util::kDriveOtherDirLocalId || | 271 id == util::kDriveOtherDirLocalId || |
| 231 id == util::kDriveTrashDirLocalId) | 272 id == util::kDriveTrashDirLocalId) |
| 232 return FILE_ERROR_ACCESS_DENIED; | 273 return FILE_ERROR_ACCESS_DENIED; |
| 233 | 274 |
| 234 ResourceEntry entry; | 275 ResourceEntry entry; |
| 235 if (!storage_->GetEntry(id, &entry)) | 276 FileError error = storage_->GetEntry(id, &entry); |
| 236 return FILE_ERROR_NOT_FOUND; | 277 if (error != FILE_ERROR_OK) |
| 278 return error; | |
| 237 | 279 |
| 238 if (!RemoveEntryRecursively(id)) | 280 return RemoveEntryRecursively(id); |
| 239 return FILE_ERROR_FAILED; | |
| 240 return FILE_ERROR_OK; | |
| 241 } | 281 } |
| 242 | 282 |
| 243 FileError ResourceMetadata::GetResourceEntryById(const std::string& id, | 283 FileError ResourceMetadata::GetResourceEntryById(const std::string& id, |
| 244 ResourceEntry* out_entry) { | 284 ResourceEntry* out_entry) { |
| 245 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 285 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 246 DCHECK(!id.empty()); | 286 DCHECK(!id.empty()); |
| 247 DCHECK(out_entry); | 287 DCHECK(out_entry); |
| 248 | 288 |
| 249 return storage_->GetEntry(id, out_entry) ? | 289 return storage_->GetEntry(id, out_entry); |
| 250 FILE_ERROR_OK : FILE_ERROR_NOT_FOUND; | |
| 251 } | 290 } |
| 252 | 291 |
| 253 FileError ResourceMetadata::GetResourceEntryByPath(const base::FilePath& path, | 292 FileError ResourceMetadata::GetResourceEntryByPath(const base::FilePath& path, |
| 254 ResourceEntry* out_entry) { | 293 ResourceEntry* out_entry) { |
| 255 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 294 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 256 DCHECK(out_entry); | 295 DCHECK(out_entry); |
| 257 | 296 |
| 258 std::string id; | 297 std::string id; |
| 259 FileError error = GetIdByPath(path, &id); | 298 FileError error = GetIdByPath(path, &id); |
| 260 if (error != FILE_ERROR_OK) | 299 if (error != FILE_ERROR_OK) |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 284 | 323 |
| 285 ResourceEntry entry; | 324 ResourceEntry entry; |
| 286 FileError error = GetResourceEntryById(id, &entry); | 325 FileError error = GetResourceEntryById(id, &entry); |
| 287 if (error != FILE_ERROR_OK) | 326 if (error != FILE_ERROR_OK) |
| 288 return error; | 327 return error; |
| 289 | 328 |
| 290 if (!entry.file_info().is_directory()) | 329 if (!entry.file_info().is_directory()) |
| 291 return FILE_ERROR_NOT_A_DIRECTORY; | 330 return FILE_ERROR_NOT_A_DIRECTORY; |
| 292 | 331 |
| 293 std::vector<std::string> children; | 332 std::vector<std::string> children; |
| 294 storage_->GetChildren(id, &children); | 333 error = storage_->GetChildren(id, &children); |
| 334 if (error != FILE_ERROR_OK) | |
| 335 return error; | |
| 295 | 336 |
| 296 ResourceEntryVector entries(children.size()); | 337 ResourceEntryVector entries(children.size()); |
| 297 for (size_t i = 0; i < children.size(); ++i) { | 338 for (size_t i = 0; i < children.size(); ++i) { |
| 298 if (!storage_->GetEntry(children[i], &entries[i])) | 339 error = storage_->GetEntry(children[i], &entries[i]); |
| 299 return FILE_ERROR_FAILED; | 340 if (error != FILE_ERROR_OK) |
| 341 return error; | |
| 300 } | 342 } |
| 301 out_entries->swap(entries); | 343 out_entries->swap(entries); |
| 302 return FILE_ERROR_OK; | 344 return FILE_ERROR_OK; |
| 303 } | 345 } |
| 304 | 346 |
| 305 FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) { | 347 FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) { |
| 306 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 348 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 307 | 349 |
| 308 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) | 350 if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path())) |
| 309 return FILE_ERROR_NO_LOCAL_SPACE; | 351 return FILE_ERROR_NO_LOCAL_SPACE; |
| 310 | 352 |
| 311 ResourceEntry old_entry; | 353 ResourceEntry old_entry; |
| 312 if (!storage_->GetEntry(entry.local_id(), &old_entry)) | 354 FileError error = storage_->GetEntry(entry.local_id(), &old_entry); |
| 313 return FILE_ERROR_NOT_FOUND; | 355 if (error != FILE_ERROR_OK) |
| 356 return error; | |
| 314 | 357 |
| 315 if (old_entry.parent_local_id().empty() || // Reject root. | 358 if (old_entry.parent_local_id().empty() || // Reject root. |
| 316 old_entry.file_info().is_directory() != // Reject incompatible input. | 359 old_entry.file_info().is_directory() != // Reject incompatible input. |
| 317 entry.file_info().is_directory()) | 360 entry.file_info().is_directory()) |
| 318 return FILE_ERROR_INVALID_OPERATION; | 361 return FILE_ERROR_INVALID_OPERATION; |
| 319 | 362 |
| 320 if (!entry.resource_id().empty()) { | 363 if (!entry.resource_id().empty()) { |
| 321 // Multiple entries cannot share the same resource ID. | 364 // Multiple entries cannot share the same resource ID. |
| 322 std::string local_id; | 365 std::string local_id; |
| 323 FileError error = GetIdByResourceId(entry.resource_id(), &local_id); | 366 FileError error = GetIdByResourceId(entry.resource_id(), &local_id); |
| 324 switch (error) { | 367 switch (error) { |
| 325 case FILE_ERROR_OK: | 368 case FILE_ERROR_OK: |
| 326 if (local_id != entry.local_id()) | 369 if (local_id != entry.local_id()) |
| 327 return FILE_ERROR_INVALID_OPERATION; | 370 return FILE_ERROR_INVALID_OPERATION; |
| 328 break; | 371 break; |
| 329 | 372 |
| 330 case FILE_ERROR_NOT_FOUND: | 373 case FILE_ERROR_NOT_FOUND: |
| 331 break; | 374 break; |
| 332 | 375 |
| 333 default: | 376 default: |
| 334 return error; | 377 return error; |
| 335 } | 378 } |
| 336 } | 379 } |
| 337 | 380 |
| 338 // Make sure that the new parent exists and it is a directory. | 381 // Make sure that the new parent exists and it is a directory. |
| 339 ResourceEntry new_parent; | 382 ResourceEntry new_parent; |
| 340 if (!storage_->GetEntry(entry.parent_local_id(), &new_parent)) | 383 error = storage_->GetEntry(entry.parent_local_id(), &new_parent); |
| 341 return FILE_ERROR_NOT_FOUND; | 384 if (error != FILE_ERROR_OK) |
| 385 return error; | |
| 342 | 386 |
| 343 if (!new_parent.file_info().is_directory()) | 387 if (!new_parent.file_info().is_directory()) |
| 344 return FILE_ERROR_NOT_A_DIRECTORY; | 388 return FILE_ERROR_NOT_A_DIRECTORY; |
| 345 | 389 |
| 346 // Remove from the old parent and add it to the new parent with the new data. | 390 // Remove from the old parent and add it to the new parent with the new data. |
| 347 if (!PutEntryUnderDirectory(entry)) | 391 return PutEntryUnderDirectory(entry); |
| 348 return FILE_ERROR_FAILED; | |
| 349 return FILE_ERROR_OK; | |
| 350 } | 392 } |
| 351 | 393 |
| 352 void ResourceMetadata::GetSubDirectoriesRecursively( | 394 void ResourceMetadata::GetSubDirectoriesRecursively( |
| 353 const std::string& id, | 395 const std::string& id, |
| 354 std::set<base::FilePath>* sub_directories) { | 396 std::set<base::FilePath>* sub_directories) { |
| 355 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 397 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 356 | 398 |
| 357 std::vector<std::string> children; | 399 std::vector<std::string> children; |
| 358 storage_->GetChildren(id, &children); | 400 if (storage_->GetChildren(id, &children) != FILE_ERROR_OK) |
| 401 return; | |
| 359 for (size_t i = 0; i < children.size(); ++i) { | 402 for (size_t i = 0; i < children.size(); ++i) { |
| 360 ResourceEntry entry; | 403 ResourceEntry entry; |
| 361 if (storage_->GetEntry(children[i], &entry) && | 404 if (storage_->GetEntry(children[i], &entry) != FILE_ERROR_OK) |
| 362 entry.file_info().is_directory()) { | 405 return; |
| 406 if (entry.file_info().is_directory()) { | |
| 363 sub_directories->insert(GetFilePath(children[i])); | 407 sub_directories->insert(GetFilePath(children[i])); |
| 364 GetSubDirectoriesRecursively(children[i], sub_directories); | 408 GetSubDirectoriesRecursively(children[i], sub_directories); |
| 365 } | 409 } |
| 366 } | 410 } |
| 367 } | 411 } |
| 368 | 412 |
| 369 std::string ResourceMetadata::GetChildId(const std::string& parent_local_id, | 413 std::string ResourceMetadata::GetChildId(const std::string& parent_local_id, |
| 370 const std::string& base_name) { | 414 const std::string& base_name) { |
| 371 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 415 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 372 return storage_->GetChild(parent_local_id, base_name); | 416 std::string child_local_id; |
| 417 storage_->GetChild(parent_local_id, base_name, &child_local_id); | |
| 418 return child_local_id; | |
| 373 } | 419 } |
| 374 | 420 |
| 375 scoped_ptr<ResourceMetadata::Iterator> ResourceMetadata::GetIterator() { | 421 scoped_ptr<ResourceMetadata::Iterator> ResourceMetadata::GetIterator() { |
| 376 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 422 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 377 | 423 |
| 378 return storage_->GetIterator(); | 424 return storage_->GetIterator(); |
| 379 } | 425 } |
| 380 | 426 |
| 381 base::FilePath ResourceMetadata::GetFilePath(const std::string& id) { | 427 base::FilePath ResourceMetadata::GetFilePath(const std::string& id) { |
| 382 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 428 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 383 | 429 |
| 384 base::FilePath path; | 430 base::FilePath path; |
| 385 ResourceEntry entry; | 431 ResourceEntry entry; |
| 386 if (storage_->GetEntry(id, &entry)) { | 432 if (storage_->GetEntry(id, &entry) == FILE_ERROR_OK) { |
| 387 if (!entry.parent_local_id().empty()) { | 433 if (!entry.parent_local_id().empty()) { |
| 388 path = GetFilePath(entry.parent_local_id()); | 434 path = GetFilePath(entry.parent_local_id()); |
| 389 } else if (entry.local_id() != util::kDriveGrandRootLocalId) { | 435 } else if (entry.local_id() != util::kDriveGrandRootLocalId) { |
| 390 DVLOG(1) << "Entries not under the grand root don't have paths."; | 436 DVLOG(1) << "Entries not under the grand root don't have paths."; |
| 391 return base::FilePath(); | 437 return base::FilePath(); |
| 392 } | 438 } |
| 393 path = path.Append(base::FilePath::FromUTF8Unsafe(entry.base_name())); | 439 path = path.Append(base::FilePath::FromUTF8Unsafe(entry.base_name())); |
| 394 } | 440 } |
| 395 return path; | 441 return path; |
| 396 } | 442 } |
| 397 | 443 |
| 398 FileError ResourceMetadata::GetIdByPath(const base::FilePath& file_path, | 444 FileError ResourceMetadata::GetIdByPath(const base::FilePath& file_path, |
| 399 std::string* out_id) { | 445 std::string* out_id) { |
| 400 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 446 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 401 | 447 |
| 402 // Start from the root. | 448 // Start from the root. |
| 403 std::vector<base::FilePath::StringType> components; | 449 std::vector<base::FilePath::StringType> components; |
| 404 file_path.GetComponents(&components); | 450 file_path.GetComponents(&components); |
| 405 if (components.empty() || components[0] != util::kDriveGrandRootDirName) | 451 if (components.empty() || components[0] != util::kDriveGrandRootDirName) |
| 406 return FILE_ERROR_NOT_FOUND; | 452 return FILE_ERROR_NOT_FOUND; |
| 407 | 453 |
| 408 // Iterate over the remaining components. | 454 // Iterate over the remaining components. |
| 409 std::string id = util::kDriveGrandRootLocalId; | 455 std::string id = util::kDriveGrandRootLocalId; |
| 410 for (size_t i = 1; i < components.size(); ++i) { | 456 for (size_t i = 1; i < components.size(); ++i) { |
| 411 const std::string component = base::FilePath(components[i]).AsUTF8Unsafe(); | 457 const std::string component = base::FilePath(components[i]).AsUTF8Unsafe(); |
| 412 id = storage_->GetChild(id, component); | 458 std::string child_id; |
| 413 if (id.empty()) | 459 FileError error = storage_->GetChild(id, component, &child_id); |
| 414 return FILE_ERROR_NOT_FOUND; | 460 if (error != FILE_ERROR_OK) |
| 461 return error; | |
| 462 id = child_id; | |
| 415 } | 463 } |
| 416 *out_id = id; | 464 *out_id = id; |
| 417 return FILE_ERROR_OK; | 465 return FILE_ERROR_OK; |
| 418 } | 466 } |
| 419 | 467 |
| 420 FileError ResourceMetadata::GetIdByResourceId(const std::string& resource_id, | 468 FileError ResourceMetadata::GetIdByResourceId(const std::string& resource_id, |
| 421 std::string* out_local_id) { | 469 std::string* out_local_id) { |
| 422 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 470 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 423 | 471 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 } | 472 } |
| 427 | 473 |
| 428 bool ResourceMetadata::PutEntryUnderDirectory(const ResourceEntry& entry) { | 474 FileError ResourceMetadata::PutEntryUnderDirectory(const ResourceEntry& entry) { |
| 429 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 475 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 430 DCHECK(!entry.local_id().empty()); | 476 DCHECK(!entry.local_id().empty()); |
| 431 DCHECK(!entry.parent_local_id().empty()); | 477 DCHECK(!entry.parent_local_id().empty()); |
| 432 | 478 |
| 479 std::string base_name; | |
| 480 FileError error = GetDeduplicatedBaseName(entry, &base_name); | |
| 481 if (error != FILE_ERROR_OK) | |
| 482 return error; | |
| 433 ResourceEntry updated_entry(entry); | 483 ResourceEntry updated_entry(entry); |
| 434 updated_entry.set_base_name(GetDeduplicatedBaseName(updated_entry)); | 484 updated_entry.set_base_name(base_name); |
| 435 return storage_->PutEntry(updated_entry); | 485 return storage_->PutEntry(updated_entry); |
| 436 } | 486 } |
| 437 | 487 |
| 438 std::string ResourceMetadata::GetDeduplicatedBaseName( | 488 FileError ResourceMetadata::GetDeduplicatedBaseName( |
| 439 const ResourceEntry& entry) { | 489 const ResourceEntry& entry, |
| 490 std::string* base_name) { | |
| 440 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 491 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 441 DCHECK(!entry.parent_local_id().empty()); | 492 DCHECK(!entry.parent_local_id().empty()); |
| 442 DCHECK(!entry.title().empty()); | 493 DCHECK(!entry.title().empty()); |
| 443 | 494 |
| 444 // The entry name may have been changed due to prior name de-duplication. | 495 // 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 | 496 // 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. | 497 // through name de-duplication again when it is added to another directory. |
| 447 std::string base_name = entry.title(); | 498 *base_name = entry.title(); |
| 448 if (entry.has_file_specific_info() && | 499 if (entry.has_file_specific_info() && |
| 449 entry.file_specific_info().is_hosted_document()) { | 500 entry.file_specific_info().is_hosted_document()) { |
| 450 base_name += entry.file_specific_info().document_extension(); | 501 *base_name += entry.file_specific_info().document_extension(); |
| 451 } | 502 } |
| 452 base_name = util::NormalizeFileName(base_name); | 503 *base_name = util::NormalizeFileName(*base_name); |
| 453 | 504 |
| 454 // If |base_name| is not used, just return it. | 505 // If |base_name| is not used, just return it. |
| 455 if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), | 506 bool can_use_name = false; |
| 456 base_name)) | 507 FileError error = EntryCanUseName(storage_, entry.parent_local_id(), |
| 457 return base_name; | 508 entry.local_id(), *base_name, |
| 509 &can_use_name); | |
| 510 if (error != FILE_ERROR_OK || can_use_name) | |
| 511 return error; | |
| 458 | 512 |
| 459 // Find an unused number with binary search. | 513 // Find an unused number with binary search. |
| 460 int smallest_known_unused_modifier = 1; | 514 int smallest_known_unused_modifier = 1; |
| 461 while (true) { | 515 while (true) { |
| 462 if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), | 516 error = EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
| 463 GetUniquifiedName(base_name, | 517 GetUniquifiedName(*base_name, |
| 464 smallest_known_unused_modifier))) | 518 smallest_known_unused_modifier), |
| 519 &can_use_name); | |
| 520 if (error != FILE_ERROR_OK) | |
| 521 return error; | |
| 522 if (can_use_name) | |
| 465 break; | 523 break; |
| 466 | 524 |
| 467 const int delta = base::RandInt(1, smallest_known_unused_modifier); | 525 const int delta = base::RandInt(1, smallest_known_unused_modifier); |
| 468 if (smallest_known_unused_modifier <= INT_MAX - delta) { | 526 if (smallest_known_unused_modifier <= INT_MAX - delta) { |
| 469 smallest_known_unused_modifier += delta; | 527 smallest_known_unused_modifier += delta; |
| 470 } else { // No luck finding an unused number. Try again. | 528 } else { // No luck finding an unused number. Try again. |
| 471 smallest_known_unused_modifier = 1; | 529 smallest_known_unused_modifier = 1; |
| 472 } | 530 } |
| 473 } | 531 } |
| 474 | 532 |
| 475 int largest_known_used_modifier = 1; | 533 int largest_known_used_modifier = 1; |
| 476 while (smallest_known_unused_modifier - largest_known_used_modifier > 1) { | 534 while (smallest_known_unused_modifier - largest_known_used_modifier > 1) { |
| 477 const int modifier = largest_known_used_modifier + | 535 const int modifier = largest_known_used_modifier + |
| 478 (smallest_known_unused_modifier - largest_known_used_modifier) / 2; | 536 (smallest_known_unused_modifier - largest_known_used_modifier) / 2; |
| 479 | 537 |
| 480 if (EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), | 538 error = EntryCanUseName(storage_, entry.parent_local_id(), entry.local_id(), |
| 481 GetUniquifiedName(base_name, modifier))) { | 539 GetUniquifiedName(*base_name, modifier), |
| 540 &can_use_name); | |
| 541 if (error != FILE_ERROR_OK) | |
| 542 return error; | |
| 543 if (can_use_name) { | |
| 482 smallest_known_unused_modifier = modifier; | 544 smallest_known_unused_modifier = modifier; |
| 483 } else { | 545 } else { |
| 484 largest_known_used_modifier = modifier; | 546 largest_known_used_modifier = modifier; |
| 485 } | 547 } |
| 486 } | 548 } |
| 487 return GetUniquifiedName(base_name, smallest_known_unused_modifier); | 549 *base_name = GetUniquifiedName(*base_name, smallest_known_unused_modifier); |
| 550 return FILE_ERROR_OK; | |
| 488 } | 551 } |
| 489 | 552 |
| 490 bool ResourceMetadata::RemoveEntryRecursively(const std::string& id) { | 553 FileError ResourceMetadata::RemoveEntryRecursively(const std::string& id) { |
| 491 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); | 554 DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread()); |
| 492 | 555 |
| 493 ResourceEntry entry; | 556 ResourceEntry entry; |
| 494 if (!storage_->GetEntry(id, &entry)) | 557 FileError error = storage_->GetEntry(id, &entry); |
| 495 return false; | 558 if (error != FILE_ERROR_OK) |
| 559 return error; | |
| 496 | 560 |
| 497 if (entry.file_info().is_directory()) { | 561 if (entry.file_info().is_directory()) { |
| 498 std::vector<std::string> children; | 562 std::vector<std::string> children; |
| 499 storage_->GetChildren(id, &children); | 563 storage_->GetChildren(id, &children); |
| 500 for (size_t i = 0; i < children.size(); ++i) { | 564 for (size_t i = 0; i < children.size(); ++i) { |
| 501 if (!RemoveEntryRecursively(children[i])) | 565 error = RemoveEntryRecursively(children[i]); |
| 502 return false; | 566 if (error != FILE_ERROR_OK) |
| 567 return error; | |
| 503 } | 568 } |
| 504 } | 569 } |
| 505 return storage_->RemoveEntry(id); | 570 return storage_->RemoveEntry(id); |
| 506 } | 571 } |
| 507 | 572 |
| 508 } // namespace internal | 573 } // namespace internal |
| 509 } // namespace drive | 574 } // namespace drive |
| OLD | NEW |