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 |