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 |