Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: webkit/fileapi/obfuscated_file_system_file_util.cc

Issue 7470037: [Refactor] to rename and re-layer the file_util stack layers. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Rebased on the svn tree. Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "webkit/fileapi/obfuscated_file_system_file_util.h"
6
7 #include <queue>
8 #include <string>
9 #include <vector>
10
11 #include "base/file_util.h"
12 #include "base/format_macros.h"
13 #include "base/logging.h"
14 #include "base/message_loop.h"
15 #include "base/stl_util.h"
16 #include "base/string_number_conversions.h"
17 #include "base/stringprintf.h"
18 #include "base/sys_string_conversions.h"
19 #include "googleurl/src/gurl.h"
20 #include "webkit/fileapi/file_system_context.h"
21 #include "webkit/fileapi/file_system_operation_context.h"
22 #include "webkit/fileapi/file_system_path_manager.h"
23 #include "webkit/fileapi/file_system_quota_util.h"
24 #include "webkit/fileapi/file_system_util.h"
25 #include "webkit/fileapi/sandbox_mount_point_provider.h"
26 #include "webkit/quota/quota_manager.h"
27
28 namespace {
29
30 const int64 kFlushDelaySeconds = 10 * 60; // 10 minutes
31
32 const char kOriginDatabaseName[] = "Origins";
33 const char kDirectoryDatabaseName[] = "Paths";
34
35 void InitFileInfo(
36 fileapi::FileSystemDirectoryDatabase::FileInfo* file_info,
37 fileapi::FileSystemDirectoryDatabase::FileId parent_id,
38 const FilePath::StringType& file_name) {
39 DCHECK(file_info);
40 file_info->parent_id = parent_id;
41 file_info->name = file_name;
42 }
43
44 bool IsRootDirectory(const FilePath& virtual_path) {
45 return (virtual_path.empty() ||
46 virtual_path.value() == FILE_PATH_LITERAL("/"));
47 }
48
49 // Costs computed as per crbug.com/86114, based on the LevelDB implementation of
50 // path storage under Linux. It's not clear if that will differ on Windows, on
51 // which FilePath uses wide chars [since they're converted to UTF-8 for storage
52 // anyway], but as long as the cost is high enough that one can't cheat on quota
53 // by storing data in paths, it doesn't need to be all that accurate.
54 const int64 kPathCreationQuotaCost = 146; // Bytes per inode, basically.
55 const int64 kPathByteQuotaCost = 2; // Bytes per byte of path length in UTF-8.
56
57 int64 GetPathQuotaUsage(
58 int growth_in_number_of_paths,
59 int64 growth_in_bytes_of_path_length) {
60 return growth_in_number_of_paths * kPathCreationQuotaCost +
61 growth_in_bytes_of_path_length * kPathByteQuotaCost;
62 }
63
64 bool AllocateQuotaForPath(
65 fileapi::FileSystemOperationContext* context,
66 int growth_in_number_of_paths,
67 int64 growth_in_bytes_of_path_length) {
68 int64 growth = GetPathQuotaUsage(growth_in_number_of_paths,
69 growth_in_bytes_of_path_length);
70 int64 new_quota = context->allowed_bytes_growth() - growth;
71
72 if (growth <= 0 || new_quota >= 0) {
73 context->set_allowed_bytes_growth(new_quota);
74 return true;
75 }
76 return false;
77 }
78
79 void UpdatePathQuotaUsage(
80 fileapi::FileSystemOperationContext* context,
81 const GURL& origin_url,
82 fileapi::FileSystemType type,
83 int growth_in_number_of_paths, // -1, 0, or 1
84 int64 growth_in_bytes_of_path_length) {
85 int64 growth = GetPathQuotaUsage(growth_in_number_of_paths,
86 growth_in_bytes_of_path_length);
87 fileapi::FileSystemQuotaUtil* quota_util =
88 context->file_system_context()->GetQuotaUtil(type);
89 quota::QuotaManagerProxy* quota_manager_proxy =
90 context->file_system_context()->quota_manager_proxy();
91 quota_util->UpdateOriginUsageOnFileThread(quota_manager_proxy, origin_url,
92 type, growth);
93 }
94
95 const FilePath::CharType kLegacyDataDirectory[] = FILE_PATH_LITERAL("Legacy");
96
97 const FilePath::CharType kTemporaryDirectoryName[] = FILE_PATH_LITERAL("t");
98 const FilePath::CharType kPersistentDirectoryName[] = FILE_PATH_LITERAL("p");
99
100 } // namespace
101
102 namespace fileapi {
103
104 using base::PlatformFile;
105 using base::PlatformFileError;
106
107 ObfuscatedFileSystemFileUtil::ObfuscatedFileSystemFileUtil(
108 const FilePath& file_system_directory,
109 FileSystemFileUtil* underlying_file_util)
110 : file_system_directory_(file_system_directory),
111 underlying_file_util_(underlying_file_util) {
112 }
113
114 ObfuscatedFileSystemFileUtil::~ObfuscatedFileSystemFileUtil() {
115 DropDatabases();
116 }
117
118 PlatformFileError ObfuscatedFileSystemFileUtil::CreateOrOpen(
119 FileSystemOperationContext* context,
120 const FilePath& virtual_path, int file_flags,
121 PlatformFile* file_handle, bool* created) {
122 DCHECK(!(file_flags & (base::PLATFORM_FILE_DELETE_ON_CLOSE |
123 base::PLATFORM_FILE_HIDDEN | base::PLATFORM_FILE_EXCLUSIVE_READ |
124 base::PLATFORM_FILE_EXCLUSIVE_WRITE)));
125 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
126 context->src_origin_url(), context->src_type(), true);
127 if (!db)
128 return base::PLATFORM_FILE_ERROR_FAILED;
129 FileId file_id;
130 if (!db->GetFileWithPath(virtual_path, &file_id)) {
131 // The file doesn't exist.
132 if (!(file_flags & (base::PLATFORM_FILE_CREATE |
133 base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_ALWAYS)))
134 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
135 FileId parent_id;
136 if (!db->GetFileWithPath(virtual_path.DirName(), &parent_id))
137 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
138 FileInfo file_info;
139 InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value());
140 if (!AllocateQuotaForPath(context, 1, file_info.name.size()))
141 return base::PLATFORM_FILE_ERROR_NO_SPACE;
142 PlatformFileError error = CreateFile(
143 context, context->src_origin_url(), context->src_type(), FilePath(),
144 &file_info, file_flags, file_handle);
145 if (created && base::PLATFORM_FILE_OK == error)
146 *created = true;
147 return error;
148 }
149 if (file_flags & base::PLATFORM_FILE_CREATE)
150 return base::PLATFORM_FILE_ERROR_EXISTS;
151
152 FileInfo file_info;
153 if (!db->GetFileInfo(file_id, &file_info)) {
154 NOTREACHED();
155 return base::PLATFORM_FILE_ERROR_FAILED;
156 }
157 if (file_info.is_directory())
158 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
159 FilePath local_path = DataPathToLocalPath(context->src_origin_url(),
160 context->src_type(), file_info.data_path);
161 base::PlatformFileError error = underlying_file_util_->CreateOrOpen(
162 context, local_path, file_flags, file_handle, created);
163 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) {
164 // TODO(tzik): Also invalidate on-memory usage cache in UsageTracker.
165 // TODO(tzik): Delete database entry after ensuring the file lost.
166 context->file_system_context()->GetQuotaUtil(context->src_type())->
167 InvalidateUsageCache(context->src_origin_url(),
168 context->src_type());
169 LOG(WARNING) << "Lost a backing file.";
170 error = base::PLATFORM_FILE_ERROR_FAILED;
171 }
172 return error;
173 }
174
175 PlatformFileError ObfuscatedFileSystemFileUtil::EnsureFileExists(
176 FileSystemOperationContext* context,
177 const FilePath& virtual_path,
178 bool* created) {
179 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
180 context->src_origin_url(), context->src_type(), true);
181 if (!db)
182 return base::PLATFORM_FILE_ERROR_FAILED;
183 FileId file_id;
184 if (db->GetFileWithPath(virtual_path, &file_id)) {
185 FileInfo file_info;
186 if (!db->GetFileInfo(file_id, &file_info)) {
187 NOTREACHED();
188 return base::PLATFORM_FILE_ERROR_FAILED;
189 }
190 if (file_info.is_directory())
191 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
192 if (created)
193 *created = false;
194 return base::PLATFORM_FILE_OK;
195 }
196 FileId parent_id;
197 if (!db->GetFileWithPath(virtual_path.DirName(), &parent_id))
198 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
199
200 FileInfo file_info;
201 InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value());
202 if (!AllocateQuotaForPath(context, 1, file_info.name.size()))
203 return base::PLATFORM_FILE_ERROR_NO_SPACE;
204 PlatformFileError error = CreateFile(context, context->src_origin_url(),
205 context->src_type(), FilePath(), &file_info, 0, NULL);
206 if (created && base::PLATFORM_FILE_OK == error)
207 *created = true;
208 return error;
209 }
210
211 PlatformFileError ObfuscatedFileSystemFileUtil::GetLocalFilePath(
212 FileSystemOperationContext* context,
213 const FilePath& virtual_path,
214 FilePath* local_path) {
215 FilePath path =
216 GetLocalPath(context->src_origin_url(), context->src_type(),
217 virtual_path);
218 if (path.empty())
219 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
220
221 *local_path = path;
222 return base::PLATFORM_FILE_OK;
223 }
224
225 PlatformFileError ObfuscatedFileSystemFileUtil::GetFileInfo(
226 FileSystemOperationContext* context,
227 const FilePath& virtual_path,
228 base::PlatformFileInfo* file_info,
229 FilePath* platform_file_path) {
230 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
231 context->src_origin_url(), context->src_type(), false);
232 if (!db)
233 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
234 FileId file_id;
235 if (!db->GetFileWithPath(virtual_path, &file_id))
236 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
237 FileInfo local_info;
238 return GetFileInfoInternal(db, context, file_id,
239 &local_info, file_info, platform_file_path);
240 }
241
242 PlatformFileError ObfuscatedFileSystemFileUtil::ReadDirectory(
243 FileSystemOperationContext* context,
244 const FilePath& virtual_path,
245 std::vector<base::FileUtilProxy::Entry>* entries) {
246 // TODO(kkanetkar): Implement directory read in multiple chunks.
247 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
248 context->src_origin_url(), context->src_type(), false);
249 if (!db) {
250 if (IsRootDirectory(virtual_path)) {
251 // It's the root directory and the database hasn't been initialized yet.
252 entries->clear();
253 return base::PLATFORM_FILE_OK;
254 }
255 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
256 }
257 FileId file_id;
258 if (!db->GetFileWithPath(virtual_path, &file_id))
259 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
260 FileInfo file_info;
261 if (!db->GetFileInfo(file_id, &file_info)) {
262 DCHECK(!file_id);
263 // It's the root directory and the database hasn't been initialized yet.
264 entries->clear();
265 return base::PLATFORM_FILE_OK;
266 }
267 if (!file_info.is_directory())
268 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
269 std::vector<FileId> children;
270 if (!db->ListChildren(file_id, &children)) {
271 NOTREACHED();
272 return base::PLATFORM_FILE_ERROR_FAILED;
273 }
274 std::vector<FileId>::iterator iter;
275 for (iter = children.begin(); iter != children.end(); ++iter) {
276 base::PlatformFileInfo platform_file_info;
277 FilePath file_path;
278 if (GetFileInfoInternal(db, context, *iter,
279 &file_info, &platform_file_info, &file_path) !=
280 base::PLATFORM_FILE_OK) {
281 LOG(WARNING) << "Lost a backing file.";
282 // TODO(tzik): We found a file entry in directory database without
283 // backing file here. Track the inconsistency and remove the database
284 // entry if we can't recover it.
285 continue;
286 }
287
288 base::FileUtilProxy::Entry entry;
289 entry.name = file_info.name;
290 entry.is_directory = file_info.is_directory();
291 entry.size = entry.is_directory ? 0 : platform_file_info.size;
292 entry.last_modified_time = platform_file_info.last_modified;
293 entries->push_back(entry);
294 }
295 return base::PLATFORM_FILE_OK;
296 }
297
298 PlatformFileError ObfuscatedFileSystemFileUtil::CreateDirectory(
299 FileSystemOperationContext* context,
300 const FilePath& virtual_path,
301 bool exclusive,
302 bool recursive) {
303 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
304 context->src_origin_url(), context->src_type(), true);
305 if (!db)
306 return base::PLATFORM_FILE_ERROR_FAILED;
307 FileId file_id;
308 if (db->GetFileWithPath(virtual_path, &file_id)) {
309 FileInfo file_info;
310 if (exclusive)
311 return base::PLATFORM_FILE_ERROR_EXISTS;
312 if (!db->GetFileInfo(file_id, &file_info)) {
313 NOTREACHED();
314 return base::PLATFORM_FILE_ERROR_FAILED;
315 }
316 if (!file_info.is_directory())
317 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
318 return base::PLATFORM_FILE_OK;
319 }
320
321 std::vector<FilePath::StringType> components;
322 virtual_path.GetComponents(&components);
323 FileId parent_id = 0;
324 size_t index;
325 for (index = 0; index < components.size(); ++index) {
326 FilePath::StringType name = components[index];
327 if (name == FILE_PATH_LITERAL("/"))
328 continue;
329 if (!db->GetChildWithName(parent_id, name, &parent_id))
330 break;
331 }
332 if (!recursive && components.size() - index > 1)
333 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
334 for (; index < components.size(); ++index) {
335 FileInfo file_info;
336 file_info.name = components[index];
337 if (file_info.name == FILE_PATH_LITERAL("/"))
338 continue;
339 file_info.modification_time = base::Time::Now();
340 file_info.parent_id = parent_id;
341 if (!AllocateQuotaForPath(context, 1, file_info.name.size()))
342 return base::PLATFORM_FILE_ERROR_NO_SPACE;
343 if (!db->AddFileInfo(file_info, &parent_id)) {
344 NOTREACHED();
345 return base::PLATFORM_FILE_ERROR_FAILED;
346 }
347 UpdatePathQuotaUsage(context, context->src_origin_url(),
348 context->src_type(), 1, file_info.name.size());
349 }
350 return base::PLATFORM_FILE_OK;
351 }
352
353 PlatformFileError ObfuscatedFileSystemFileUtil::CopyOrMoveFile(
354 FileSystemOperationContext* context,
355 const FilePath& src_file_path,
356 const FilePath& dest_file_path,
357 bool copy) {
358 // Cross-filesystem copies and moves should be handled via CopyInForeignFile.
359 DCHECK(context->src_origin_url() == context->dest_origin_url());
360 DCHECK(context->src_type() == context->dest_type());
361
362 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
363 context->src_origin_url(), context->src_type(), true);
364 if (!db)
365 return base::PLATFORM_FILE_ERROR_FAILED;
366 FileId src_file_id;
367 if (!db->GetFileWithPath(src_file_path, &src_file_id))
368 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
369 FileId dest_file_id;
370 bool overwrite = db->GetFileWithPath(dest_file_path, &dest_file_id);
371 FileInfo src_file_info;
372 FileInfo dest_file_info;
373 if (!db->GetFileInfo(src_file_id, &src_file_info) ||
374 src_file_info.is_directory()) {
375 NOTREACHED();
376 return base::PLATFORM_FILE_ERROR_FAILED;
377 }
378 if (overwrite) {
379 if (!db->GetFileInfo(dest_file_id, &dest_file_info) ||
380 dest_file_info.is_directory()) {
381 NOTREACHED();
382 return base::PLATFORM_FILE_ERROR_FAILED;
383 }
384 }
385 /*
386 * Copy-with-overwrite
387 * Just overwrite data file
388 * Copy-without-overwrite
389 * Copy backing file
390 * Create new metadata pointing to new backing file.
391 * Move-with-overwrite
392 * transaction:
393 * Remove source entry.
394 * Point target entry to source entry's backing file.
395 * Delete target entry's old backing file
396 * Move-without-overwrite
397 * Just update metadata
398 */
399 if (copy) {
400 FilePath src_data_path = DataPathToLocalPath(context->src_origin_url(),
401 context->src_type(), src_file_info.data_path);
402 if (!underlying_file_util_->PathExists(context, src_data_path)) {
403 // TODO(tzik): Also invalidate on-memory usage cache in UsageTracker.
404 context->file_system_context()->GetQuotaUtil(context->src_type())->
405 InvalidateUsageCache(context->src_origin_url(),
406 context->src_type());
407 LOG(WARNING) << "Lost a backing file.";
408 return base::PLATFORM_FILE_ERROR_FAILED;
409 }
410
411 if (overwrite) {
412 FilePath dest_data_path = DataPathToLocalPath(context->src_origin_url(),
413 context->src_type(), dest_file_info.data_path);
414 return underlying_file_util_->CopyOrMoveFile(context,
415 src_data_path, dest_data_path, copy);
416 } else {
417 FileId dest_parent_id;
418 if (!db->GetFileWithPath(dest_file_path.DirName(), &dest_parent_id)) {
419 NOTREACHED(); // We shouldn't be called in this case.
420 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
421 }
422 InitFileInfo(&dest_file_info, dest_parent_id,
423 dest_file_path.BaseName().value());
424 if (!AllocateQuotaForPath(context, 1, dest_file_info.name.size()))
425 return base::PLATFORM_FILE_ERROR_NO_SPACE;
426 return CreateFile(context, context->dest_origin_url(),
427 context->dest_type(), src_data_path, &dest_file_info, 0,
428 NULL);
429 }
430 } else { // It's a move.
431 if (overwrite) {
432 AllocateQuotaForPath(context, -1,
433 -static_cast<int64>(src_file_info.name.size()));
434 if (!db->OverwritingMoveFile(src_file_id, dest_file_id))
435 return base::PLATFORM_FILE_ERROR_FAILED;
436 FilePath dest_data_path = DataPathToLocalPath(context->src_origin_url(),
437 context->src_type(), dest_file_info.data_path);
438 if (base::PLATFORM_FILE_OK !=
439 underlying_file_util_->DeleteFile(context, dest_data_path))
440 LOG(WARNING) << "Leaked a backing file.";
441 UpdatePathQuotaUsage(context, context->src_origin_url(),
442 context->src_type(), -1,
443 -static_cast<int64>(src_file_info.name.size()));
444 return base::PLATFORM_FILE_OK;
445 } else {
446 FileId dest_parent_id;
447 if (!db->GetFileWithPath(dest_file_path.DirName(), &dest_parent_id)) {
448 NOTREACHED();
449 return base::PLATFORM_FILE_ERROR_FAILED;
450 }
451 if (!AllocateQuotaForPath(
452 context, 0,
453 static_cast<int64>(dest_file_path.BaseName().value().size())
454 - static_cast<int64>(src_file_info.name.size())))
455 return base::PLATFORM_FILE_ERROR_NO_SPACE;
456 src_file_info.parent_id = dest_parent_id;
457 src_file_info.name = dest_file_path.BaseName().value();
458 if (!db->UpdateFileInfo(src_file_id, src_file_info))
459 return base::PLATFORM_FILE_ERROR_FAILED;
460 UpdatePathQuotaUsage(
461 context, context->src_origin_url(), context->src_type(), 0,
462 static_cast<int64>(dest_file_path.BaseName().value().size()) -
463 static_cast<int64>(src_file_path.BaseName().value().size()));
464 return base::PLATFORM_FILE_OK;
465 }
466 }
467 NOTREACHED();
468 return base::PLATFORM_FILE_ERROR_FAILED;
469 }
470
471 PlatformFileError ObfuscatedFileSystemFileUtil::CopyInForeignFile(
472 FileSystemOperationContext* context,
473 const FilePath& src_file_path,
474 const FilePath& dest_file_path) {
475 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
476 context->dest_origin_url(), context->dest_type(), true);
477 if (!db)
478 return base::PLATFORM_FILE_ERROR_FAILED;
479 FileId dest_file_id;
480 bool overwrite = db->GetFileWithPath(dest_file_path, &dest_file_id);
481 FileInfo dest_file_info;
482 if (overwrite) {
483 if (!db->GetFileInfo(dest_file_id, &dest_file_info) ||
484 dest_file_info.is_directory()) {
485 NOTREACHED();
486 return base::PLATFORM_FILE_ERROR_FAILED;
487 }
488 FilePath dest_data_path = DataPathToLocalPath(context->dest_origin_url(),
489 context->dest_type(), dest_file_info.data_path);
490 return underlying_file_util_->CopyOrMoveFile(context,
491 src_file_path, dest_data_path, true /* copy */);
492 } else {
493 FileId dest_parent_id;
494 if (!db->GetFileWithPath(dest_file_path.DirName(), &dest_parent_id)) {
495 NOTREACHED(); // We shouldn't be called in this case.
496 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
497 }
498 InitFileInfo(&dest_file_info, dest_parent_id,
499 dest_file_path.BaseName().value());
500 if (!AllocateQuotaForPath(context, 1, dest_file_info.name.size()))
501 return base::PLATFORM_FILE_ERROR_NO_SPACE;
502 return CreateFile(context, context->dest_origin_url(),
503 context->dest_type(), src_file_path, &dest_file_info, 0, NULL);
504 }
505 return base::PLATFORM_FILE_ERROR_FAILED;
506 }
507
508 PlatformFileError ObfuscatedFileSystemFileUtil::DeleteFile(
509 FileSystemOperationContext* context,
510 const FilePath& virtual_path) {
511 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
512 context->src_origin_url(), context->src_type(), true);
513 if (!db)
514 return base::PLATFORM_FILE_ERROR_FAILED;
515 FileId file_id;
516 if (!db->GetFileWithPath(virtual_path, &file_id))
517 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
518 FileInfo file_info;
519 if (!db->GetFileInfo(file_id, &file_info) || file_info.is_directory()) {
520 NOTREACHED();
521 return base::PLATFORM_FILE_ERROR_FAILED;
522 }
523 if (!db->RemoveFileInfo(file_id)) {
524 NOTREACHED();
525 return base::PLATFORM_FILE_ERROR_FAILED;
526 }
527 AllocateQuotaForPath(context, -1, -static_cast<int64>(file_info.name.size()));
528 UpdatePathQuotaUsage(context, context->src_origin_url(), context->src_type(),
529 -1, -static_cast<int64>(file_info.name.size()));
530 FilePath data_path = DataPathToLocalPath(context->src_origin_url(),
531 context->src_type(), file_info.data_path);
532 if (base::PLATFORM_FILE_OK !=
533 underlying_file_util_->DeleteFile(context, data_path))
534 LOG(WARNING) << "Leaked a backing file.";
535 return base::PLATFORM_FILE_OK;
536 }
537
538 PlatformFileError ObfuscatedFileSystemFileUtil::DeleteSingleDirectory(
539 FileSystemOperationContext* context,
540 const FilePath& virtual_path) {
541 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
542 context->src_origin_url(), context->src_type(), true);
543 if (!db)
544 return base::PLATFORM_FILE_ERROR_FAILED;
545 FileId file_id;
546 if (!db->GetFileWithPath(virtual_path, &file_id))
547 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
548 FileInfo file_info;
549 if (!db->GetFileInfo(file_id, &file_info) || !file_info.is_directory()) {
550 NOTREACHED();
551 return base::PLATFORM_FILE_ERROR_FAILED;
552 }
553 if (!db->RemoveFileInfo(file_id))
554 return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
555 AllocateQuotaForPath(context, -1, -static_cast<int64>(file_info.name.size()));
556 UpdatePathQuotaUsage(context, context->src_origin_url(), context->src_type(),
557 -1, -static_cast<int64>(file_info.name.size()));
558 return base::PLATFORM_FILE_OK;
559 }
560
561 PlatformFileError ObfuscatedFileSystemFileUtil::Touch(
562 FileSystemOperationContext* context,
563 const FilePath& virtual_path,
564 const base::Time& last_access_time,
565 const base::Time& last_modified_time) {
566 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
567 context->src_origin_url(), context->src_type(), false);
568 if (!db)
569 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
570 FileId file_id;
571 if (!db->GetFileWithPath(virtual_path, &file_id))
572 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
573
574 FileInfo file_info;
575 if (!db->GetFileInfo(file_id, &file_info)) {
576 NOTREACHED();
577 return base::PLATFORM_FILE_ERROR_FAILED;
578 }
579 if (file_info.is_directory()) {
580 file_info.modification_time = last_modified_time;
581 if (!db->UpdateFileInfo(file_id, file_info))
582 return base::PLATFORM_FILE_ERROR_FAILED;
583 return base::PLATFORM_FILE_OK;
584 }
585 FilePath data_path = DataPathToLocalPath(context->src_origin_url(),
586 context->src_type(), file_info.data_path);
587 return underlying_file_util_->Touch(
588 context, data_path, last_access_time, last_modified_time);
589 }
590
591 PlatformFileError ObfuscatedFileSystemFileUtil::Truncate(
592 FileSystemOperationContext* context,
593 const FilePath& virtual_path,
594 int64 length) {
595 FilePath local_path =
596 GetLocalPath(context->src_origin_url(), context->src_type(),
597 virtual_path);
598 if (local_path.empty())
599 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
600 return underlying_file_util_->Truncate(
601 context, local_path, length);
602 }
603
604 bool ObfuscatedFileSystemFileUtil::PathExists(
605 FileSystemOperationContext* context,
606 const FilePath& virtual_path) {
607 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
608 context->src_origin_url(), context->src_type(), false);
609 if (!db)
610 return false;
611 FileId file_id;
612 return db->GetFileWithPath(virtual_path, &file_id);
613 }
614
615 bool ObfuscatedFileSystemFileUtil::DirectoryExists(
616 FileSystemOperationContext* context,
617 const FilePath& virtual_path) {
618 if (IsRootDirectory(virtual_path)) {
619 // It's questionable whether we should return true or false for the
620 // root directory of nonexistent origin, but here we return true
621 // as the current implementation of ReadDirectory always returns an empty
622 // array (rather than erroring out with NOT_FOUND_ERR even) for
623 // nonexistent origins.
624 // Note: if you're going to change this behavior please also consider
625 // changiing the ReadDirectory's behavior!
626 return true;
627 }
628 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
629 context->src_origin_url(), context->src_type(), false);
630 if (!db)
631 return false;
632 FileId file_id;
633 if (!db->GetFileWithPath(virtual_path, &file_id))
634 return false;
635 FileInfo file_info;
636 if (!db->GetFileInfo(file_id, &file_info)) {
637 NOTREACHED();
638 return false;
639 }
640 return file_info.is_directory();
641 }
642
643 bool ObfuscatedFileSystemFileUtil::IsDirectoryEmpty(
644 FileSystemOperationContext* context,
645 const FilePath& virtual_path) {
646 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
647 context->src_origin_url(), context->src_type(), false);
648 if (!db)
649 return true; // Not a great answer, but it's what others do.
650 FileId file_id;
651 if (!db->GetFileWithPath(virtual_path, &file_id))
652 return true; // Ditto.
653 FileInfo file_info;
654 if (!db->GetFileInfo(file_id, &file_info)) {
655 DCHECK(!file_id);
656 // It's the root directory and the database hasn't been initialized yet.
657 return true;
658 }
659 if (!file_info.is_directory())
660 return true;
661 std::vector<FileId> children;
662 // TODO(ericu): This could easily be made faster with help from the database.
663 if (!db->ListChildren(file_id, &children))
664 return true;
665 return children.empty();
666 }
667
668 class ObfuscatedFileSystemFileEnumerator
669 : public FileSystemFileUtil::AbstractFileEnumerator {
670 public:
671 ObfuscatedFileSystemFileEnumerator(
672 const FilePath& base_path,
673 FileSystemDirectoryDatabase* db,
674 FileSystemOperationContext* context,
675 FileSystemFileUtil* underlying_file_util,
676 const FilePath& virtual_root_path)
677 : base_path_(base_path),
678 db_(db),
679 context_(context),
680 underlying_file_util_(underlying_file_util) {
681 DCHECK(db_);
682 DCHECK(context_);
683 DCHECK(underlying_file_util_);
684
685 FileId file_id;
686 FileInfo file_info;
687 if (!db_->GetFileWithPath(virtual_root_path, &file_id))
688 return;
689 if (!db_->GetFileInfo(file_id, &file_info))
690 return;
691 if (!file_info.is_directory())
692 return;
693 FileRecord record = { file_id, file_info, virtual_root_path };
694 display_queue_.push(record);
695 Next(); // Enumerators don't include the directory itself.
696 }
697
698 ~ObfuscatedFileSystemFileEnumerator() {}
699
700 virtual FilePath Next() OVERRIDE {
701 ProcessRecurseQueue();
702 if (display_queue_.empty())
703 return FilePath();
704 current_ = display_queue_.front();
705 display_queue_.pop();
706 if (current_.file_info.is_directory())
707 recurse_queue_.push(current_);
708 return current_.file_path;
709 }
710
711 virtual int64 Size() OVERRIDE {
712 if (IsDirectory())
713 return 0;
714
715 base::PlatformFileInfo file_info;
716 FilePath platform_file_path;
717
718 FilePath local_path = base_path_.Append(current_.file_info.data_path);
719 base::PlatformFileError error = underlying_file_util_->GetFileInfo(
720 context_, local_path, &file_info, &platform_file_path);
721 if (error != base::PLATFORM_FILE_OK) {
722 LOG(WARNING) << "Lost a backing file.";
723 return 0;
724 }
725 return file_info.size;
726 }
727
728 virtual bool IsDirectory() OVERRIDE {
729 return current_.file_info.is_directory();
730 }
731
732 private:
733 typedef FileSystemDirectoryDatabase::FileId FileId;
734 typedef FileSystemDirectoryDatabase::FileInfo FileInfo;
735
736 struct FileRecord {
737 FileId file_id;
738 FileInfo file_info;
739 FilePath file_path;
740 };
741
742 void ProcessRecurseQueue() {
743 while (display_queue_.empty() && !recurse_queue_.empty()) {
744 FileRecord directory = recurse_queue_.front();
745 std::vector<FileId> children;
746 recurse_queue_.pop();
747 if (!db_->ListChildren(directory.file_id, &children))
748 return;
749 std::vector<FileId>::iterator iter;
750 for (iter = children.begin(); iter != children.end(); ++iter) {
751 FileRecord child;
752 child.file_id = *iter;
753 if (!db_->GetFileInfo(child.file_id, &child.file_info))
754 return;
755 child.file_path = directory.file_path.Append(child.file_info.name);
756 display_queue_.push(child);
757 }
758 }
759 }
760
761 std::queue<FileRecord> display_queue_;
762 std::queue<FileRecord> recurse_queue_;
763 FileRecord current_;
764 FilePath base_path_;
765 FileSystemDirectoryDatabase* db_;
766 FileSystemOperationContext* context_;
767 FileSystemFileUtil* underlying_file_util_;
768 };
769
770 class ObfuscatedFileSystemOriginEnumerator
771 : public ObfuscatedFileSystemFileUtil::AbstractOriginEnumerator {
772 public:
773 typedef FileSystemOriginDatabase::OriginRecord OriginRecord;
774 ObfuscatedFileSystemOriginEnumerator(
775 FileSystemOriginDatabase* origin_database,
776 const FilePath& base_path)
777 : base_path_(base_path) {
778 if (origin_database)
779 origin_database->ListAllOrigins(&origins_);
780 }
781
782 ~ObfuscatedFileSystemOriginEnumerator() {}
783
784 // Returns the next origin. Returns empty if there are no more origins.
785 virtual GURL Next() OVERRIDE {
786 OriginRecord record;
787 if (!origins_.empty()) {
788 record = origins_.back();
789 origins_.pop_back();
790 }
791 current_ = record;
792 return GetOriginURLFromIdentifier(record.origin);
793 }
794
795 // Returns the current origin's information.
796 virtual bool HasFileSystemType(FileSystemType type) const OVERRIDE {
797 if (current_.path.empty())
798 return false;
799 FilePath::StringType type_string =
800 ObfuscatedFileSystemFileUtil::GetDirectoryNameForType(type);
801 if (type_string.empty()) {
802 NOTREACHED();
803 return false;
804 }
805 FilePath path = base_path_.Append(current_.path).Append(type_string);
806 return file_util::DirectoryExists(path);
807 }
808
809 private:
810 std::vector<OriginRecord> origins_;
811 OriginRecord current_;
812 FilePath base_path_;
813 };
814
815 ObfuscatedFileSystemFileUtil::AbstractOriginEnumerator*
816 ObfuscatedFileSystemFileUtil::CreateOriginEnumerator() {
817 std::vector<FileSystemOriginDatabase::OriginRecord> origins;
818
819 InitOriginDatabase(false);
820 return new ObfuscatedFileSystemOriginEnumerator(
821 origin_database_.get(), file_system_directory_);
822 }
823
824 FileSystemFileUtil::AbstractFileEnumerator*
825 ObfuscatedFileSystemFileUtil::CreateFileEnumerator(
826 FileSystemOperationContext* context,
827 const FilePath& root_path) {
828 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
829 context->src_origin_url(), context->src_type(), false);
830 if (!db)
831 return new FileSystemFileUtil::EmptyFileEnumerator();
832 return new ObfuscatedFileSystemFileEnumerator(
833 GetDirectoryForOriginAndType(context->src_origin_url(),
834 context->src_type(), false),
835 db,
836 context,
837 underlying_file_util_.get(),
838 root_path);
839 }
840
841 PlatformFileError ObfuscatedFileSystemFileUtil::GetFileInfoInternal(
842 FileSystemDirectoryDatabase* db,
843 FileSystemOperationContext* context,
844 FileId file_id,
845 FileInfo* local_info,
846 base::PlatformFileInfo* file_info,
847 FilePath* platform_file_path) {
848 DCHECK(db);
849 DCHECK(context);
850 DCHECK(file_info);
851 DCHECK(platform_file_path);
852
853 if (!db->GetFileInfo(file_id, local_info)) {
854 NOTREACHED();
855 return base::PLATFORM_FILE_ERROR_FAILED;
856 }
857
858 if (local_info->is_directory()) {
859 file_info->is_directory = true;
860 file_info->is_symbolic_link = false;
861 file_info->last_modified = local_info->modification_time;
862 *platform_file_path = FilePath();
863 // We don't fill in ctime or atime.
864 return base::PLATFORM_FILE_OK;
865 }
866 if (local_info->data_path.empty())
867 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
868 FilePath data_path = DataPathToLocalPath(context->src_origin_url(),
869 context->src_type(), local_info->data_path);
870 return underlying_file_util_->GetFileInfo(
871 context, data_path, file_info, platform_file_path);
872 }
873
874 PlatformFileError ObfuscatedFileSystemFileUtil::CreateFile(
875 FileSystemOperationContext* context,
876 const GURL& origin_url, FileSystemType type, const FilePath& source_path,
877 FileInfo* file_info, int file_flags, PlatformFile* handle) {
878 if (handle)
879 *handle = base::kInvalidPlatformFileValue;
880 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
881 origin_url, type, true);
882 int64 number;
883 if (!db || !db->GetNextInteger(&number))
884 return base::PLATFORM_FILE_ERROR_FAILED;
885 // We use the third- and fourth-to-last digits as the directory.
886 int64 directory_number = number % 10000 / 100;
887 // TODO(ericu): local_path is an OS path; underlying_file_util_ isn't
888 // guaranteed to understand OS paths.
889 FilePath local_path =
890 GetDirectoryForOriginAndType(origin_url, type, false);
891 if (local_path.empty())
892 return base::PLATFORM_FILE_ERROR_FAILED;
893
894 local_path = local_path.AppendASCII(StringPrintf("%02" PRIu64,
895 directory_number));
896 PlatformFileError error;
897 error = underlying_file_util_->CreateDirectory(
898 context, local_path, false /* exclusive */, false /* recursive */);
899 if (base::PLATFORM_FILE_OK != error)
900 return error;
901 local_path = local_path.AppendASCII(StringPrintf("%08" PRIu64, number));
902 FilePath data_path = LocalPathToDataPath(origin_url, type, local_path);
903 if (data_path.empty())
904 return base::PLATFORM_FILE_ERROR_FAILED;
905 bool created = false;
906 if (!source_path.empty()) {
907 DCHECK(!file_flags);
908 DCHECK(!handle);
909 error = underlying_file_util_->CopyOrMoveFile(
910 context, source_path, local_path, true /* copy */);
911 created = true;
912 } else {
913 FilePath path;
914 underlying_file_util_->GetLocalFilePath(context, local_path, &path);
915 if (file_util::PathExists(path)) {
916 if (!file_util::Delete(path, true)) {
917 NOTREACHED();
918 return base::PLATFORM_FILE_ERROR_FAILED;
919 }
920 LOG(WARNING) << "A stray file detected";
921 context->file_system_context()->GetQuotaUtil(context->src_type())->
922 InvalidateUsageCache(context->src_origin_url(), context->src_type());
923 }
924
925 if (handle) {
926 error = underlying_file_util_->CreateOrOpen(
927 context, local_path, file_flags, handle, &created);
928 // If this succeeds, we must close handle on any subsequent error.
929 } else {
930 DCHECK(!file_flags); // file_flags is only used by CreateOrOpen.
931 error = underlying_file_util_->EnsureFileExists(
932 context, local_path, &created);
933 }
934 }
935 if (error != base::PLATFORM_FILE_OK)
936 return error;
937
938 if (!created) {
939 NOTREACHED();
940 if (handle) {
941 DCHECK_NE(base::kInvalidPlatformFileValue, *handle);
942 base::ClosePlatformFile(*handle);
943 underlying_file_util_->DeleteFile(context, local_path);
944 }
945 return base::PLATFORM_FILE_ERROR_FAILED;
946 }
947 file_info->data_path = data_path;
948 FileId file_id;
949 if (!db->AddFileInfo(*file_info, &file_id)) {
950 if (handle) {
951 DCHECK_NE(base::kInvalidPlatformFileValue, *handle);
952 base::ClosePlatformFile(*handle);
953 }
954 underlying_file_util_->DeleteFile(context, local_path);
955 return base::PLATFORM_FILE_ERROR_FAILED;
956 }
957 UpdatePathQuotaUsage(context, origin_url, type, 1, file_info->name.size());
958
959 return base::PLATFORM_FILE_OK;
960 }
961
962 FilePath ObfuscatedFileSystemFileUtil::GetLocalPath(
963 const GURL& origin_url,
964 FileSystemType type,
965 const FilePath& virtual_path) {
966 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
967 origin_url, type, false);
968 if (!db)
969 return FilePath();
970 FileId file_id;
971 if (!db->GetFileWithPath(virtual_path, &file_id))
972 return FilePath();
973 FileInfo file_info;
974 if (!db->GetFileInfo(file_id, &file_info) || file_info.is_directory()) {
975 NOTREACHED();
976 return FilePath(); // Directories have no local path.
977 }
978 return DataPathToLocalPath(origin_url, type, file_info.data_path);
979 }
980
981 FilePath ObfuscatedFileSystemFileUtil::GetDirectoryForOriginAndType(
982 const GURL& origin, FileSystemType type, bool create) {
983 FilePath origin_dir = GetDirectoryForOrigin(origin, create);
984 if (origin_dir.empty())
985 return FilePath();
986 FilePath::StringType type_string = GetDirectoryNameForType(type);
987 if (type_string.empty()) {
988 LOG(WARNING) << "Unknown filesystem type requested:" << type;
989 return FilePath();
990 }
991 FilePath path = origin_dir.Append(type_string);
992 if (!file_util::DirectoryExists(path) &&
993 (!create || !file_util::CreateDirectory(path)))
994 return FilePath();
995 return path;
996 }
997
998 bool ObfuscatedFileSystemFileUtil::DeleteDirectoryForOriginAndType(
999 const GURL& origin, FileSystemType type) {
1000 FilePath origin_type_path = GetDirectoryForOriginAndType(origin, type, false);
1001 if (!file_util::PathExists(origin_type_path))
1002 return true;
1003
1004 // TODO(dmikurube): Consider the return value of DestroyDirectoryDatabase.
1005 // We ignore its error now since 1) it doesn't matter the final result, and
1006 // 2) it always returns false in Windows because of LevelDB's implementation.
1007 // Information about failure would be useful for debugging.
1008 DestroyDirectoryDatabase(origin, type);
1009 if (!file_util::Delete(origin_type_path, true /* recursive */))
1010 return false;
1011
1012 FilePath origin_path = origin_type_path.DirName();
1013 DCHECK_EQ(origin_path.value(), GetDirectoryForOrigin(origin, false).value());
1014
1015 // Delete the origin directory if the deleted one was the last remaining
1016 // type for the origin.
1017 if (file_util::Delete(origin_path, false /* recursive */)) {
1018 InitOriginDatabase(false);
1019 if (origin_database_.get())
1020 origin_database_->RemovePathForOrigin(GetOriginIdentifierFromURL(origin));
1021 }
1022
1023 // At this point we are sure we had successfully deleted the origin/type
1024 // directory, so just returning true here.
1025 return true;
1026 }
1027
1028 bool ObfuscatedFileSystemFileUtil::MigrateFromOldSandbox(
1029 const GURL& origin_url, FileSystemType type, const FilePath& src_root) {
1030 if (!DestroyDirectoryDatabase(origin_url, type))
1031 return false;
1032 FilePath dest_root = GetDirectoryForOriginAndType(origin_url, type, true);
1033 if (dest_root.empty())
1034 return false;
1035 FileSystemDirectoryDatabase* db = GetDirectoryDatabase(
1036 origin_url, type, true);
1037 if (!db)
1038 return false;
1039
1040 file_util::FileEnumerator file_enum(src_root, true,
1041 static_cast<file_util::FileEnumerator::FileType>(
1042 file_util::FileEnumerator::FILES |
1043 file_util::FileEnumerator::DIRECTORIES));
1044 FilePath src_full_path;
1045 size_t root_path_length = src_root.value().length() + 1; // +1 for the slash
1046 while (!(src_full_path = file_enum.Next()).empty()) {
1047 file_util::FileEnumerator::FindInfo info;
1048 file_enum.GetFindInfo(&info);
1049 FilePath relative_virtual_path =
1050 FilePath(src_full_path.value().substr(root_path_length));
1051 if (relative_virtual_path.empty()) {
1052 LOG(WARNING) << "Failed to convert path to relative: " <<
1053 src_full_path.value();
1054 return false;
1055 }
1056 FileId file_id;
1057 if (db->GetFileWithPath(relative_virtual_path, &file_id)) {
1058 NOTREACHED(); // File already exists.
1059 return false;
1060 }
1061 if (!db->GetFileWithPath(relative_virtual_path.DirName(), &file_id)) {
1062 NOTREACHED(); // Parent doesn't exist.
1063 return false;
1064 }
1065
1066 FileInfo file_info;
1067 file_info.name = src_full_path.BaseName().value();
1068 if (file_util::FileEnumerator::IsDirectory(info)) {
1069 #if defined(OS_WIN)
1070 file_info.modification_time =
1071 base::Time::FromFileTime(info.ftLastWriteTime);
1072 #elif defined(OS_POSIX)
1073 file_info.modification_time = base::Time::FromTimeT(info.stat.st_mtime);
1074 #endif
1075 } else {
1076 file_info.data_path =
1077 FilePath(kLegacyDataDirectory).Append(relative_virtual_path);
1078 }
1079 file_info.parent_id = file_id;
1080 if (!db->AddFileInfo(file_info, &file_id)) {
1081 NOTREACHED();
1082 return false;
1083 }
1084 }
1085 // TODO(ericu): Should we adjust the mtime of the root directory to match as
1086 // well?
1087 FilePath legacy_dest_dir = dest_root.Append(kLegacyDataDirectory);
1088
1089 if (!file_util::Move(src_root, legacy_dest_dir)) {
1090 LOG(WARNING) <<
1091 "The final step of a migration failed; I'll try to clean up.";
1092 db = NULL;
1093 DestroyDirectoryDatabase(origin_url, type);
1094 return false;
1095 }
1096 return true;
1097 }
1098
1099 // static
1100 FilePath::StringType ObfuscatedFileSystemFileUtil::GetDirectoryNameForType(
1101 FileSystemType type) {
1102 switch (type) {
1103 case kFileSystemTypeTemporary:
1104 return kTemporaryDirectoryName;
1105 case kFileSystemTypePersistent:
1106 return kPersistentDirectoryName;
1107 case kFileSystemTypeUnknown:
1108 default:
1109 return FilePath::StringType();
1110 }
1111 }
1112
1113 FilePath ObfuscatedFileSystemFileUtil::DataPathToLocalPath(
1114 const GURL& origin, FileSystemType type, const FilePath& data_path) {
1115 FilePath root = GetDirectoryForOriginAndType(origin, type, false);
1116 if (root.empty())
1117 return root;
1118 return root.Append(data_path);
1119 }
1120
1121 FilePath ObfuscatedFileSystemFileUtil::LocalPathToDataPath(
1122 const GURL& origin, FileSystemType type, const FilePath& local_path) {
1123 FilePath root = GetDirectoryForOriginAndType(origin, type, false);
1124 if (root.empty())
1125 return root;
1126 // This removes the root, including the trailing slash, leaving a relative
1127 // path.
1128 return FilePath(local_path.value().substr(root.value().length() + 1));
1129 }
1130
1131 // TODO: How to do the whole validation-without-creation thing? We may not have
1132 // quota even to create the database. Ah, in that case don't even get here?
1133 // Still doesn't answer the quota issue, though.
1134 FileSystemDirectoryDatabase* ObfuscatedFileSystemFileUtil::GetDirectoryDatabase(
1135 const GURL& origin, FileSystemType type, bool create) {
1136 std::string type_string =
1137 FileSystemPathManager::GetFileSystemTypeString(type);
1138 if (type_string.empty()) {
1139 LOG(WARNING) << "Unknown filesystem type requested:" << type;
1140 return NULL;
1141 }
1142 std::string key = GetOriginIdentifierFromURL(origin) + type_string;
1143 DirectoryMap::iterator iter = directories_.find(key);
1144 if (iter != directories_.end()) {
1145 MarkUsed();
1146 return iter->second;
1147 }
1148
1149 FilePath path = GetDirectoryForOriginAndType(origin, type, create);
1150 if (path.empty())
1151 return NULL;
1152 if (!file_util::DirectoryExists(path)) {
1153 if (!file_util::CreateDirectory(path)) {
1154 LOG(WARNING) << "Failed to origin+type directory: " << path.value();
1155 return NULL;
1156 }
1157 }
1158 MarkUsed();
1159 path = path.AppendASCII(kDirectoryDatabaseName);
1160 FileSystemDirectoryDatabase* database = new FileSystemDirectoryDatabase(path);
1161 directories_[key] = database;
1162 return database;
1163 }
1164
1165 FilePath ObfuscatedFileSystemFileUtil::GetDirectoryForOrigin(
1166 const GURL& origin, bool create) {
1167 if (!InitOriginDatabase(create))
1168 return FilePath();
1169 FilePath directory_name;
1170 std::string id = GetOriginIdentifierFromURL(origin);
1171
1172 bool exists_in_db = origin_database_->HasOriginPath(id);
1173 if (!exists_in_db && !create)
1174 return FilePath();
1175 if (!origin_database_->GetPathForOrigin(id, &directory_name))
1176 return FilePath();
1177
1178 FilePath path = file_system_directory_.Append(directory_name);
1179 bool exists_in_fs = file_util::DirectoryExists(path);
1180 if (!exists_in_db && exists_in_fs) {
1181 if (!file_util::Delete(path, true))
1182 return FilePath();
1183 exists_in_fs = false;
1184 }
1185
1186 if (!exists_in_fs) {
1187 if (!create || !file_util::CreateDirectory(path))
1188 return FilePath();
1189 }
1190
1191 return path;
1192 }
1193
1194 void ObfuscatedFileSystemFileUtil::MarkUsed() {
1195 if (timer_.IsRunning())
1196 timer_.Reset();
1197 else
1198 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kFlushDelaySeconds),
1199 this, &ObfuscatedFileSystemFileUtil::DropDatabases);
1200 }
1201
1202 void ObfuscatedFileSystemFileUtil::DropDatabases() {
1203 origin_database_.reset();
1204 STLDeleteContainerPairSecondPointers(
1205 directories_.begin(), directories_.end());
1206 directories_.clear();
1207 }
1208
1209 // static
1210 int64 ObfuscatedFileSystemFileUtil::ComputeFilePathCost(const FilePath& path) {
1211 return GetPathQuotaUsage(1, path.BaseName().value().size());
1212 }
1213
1214 bool ObfuscatedFileSystemFileUtil::DestroyDirectoryDatabase(
1215 const GURL& origin, FileSystemType type) {
1216 std::string type_string =
1217 FileSystemPathManager::GetFileSystemTypeString(type);
1218 if (type_string.empty()) {
1219 LOG(WARNING) << "Unknown filesystem type requested:" << type;
1220 return true;
1221 }
1222 std::string key = GetOriginIdentifierFromURL(origin) + type_string;
1223 DirectoryMap::iterator iter = directories_.find(key);
1224 if (iter != directories_.end()) {
1225 FileSystemDirectoryDatabase* database = iter->second;
1226 directories_.erase(iter);
1227 delete database;
1228 }
1229
1230 FilePath path = GetDirectoryForOriginAndType(origin, type, false);
1231 if (path.empty())
1232 return true;
1233 if (!file_util::DirectoryExists(path))
1234 return true;
1235 path = path.AppendASCII(kDirectoryDatabaseName);
1236 return FileSystemDirectoryDatabase::DestroyDatabase(path);
1237 }
1238
1239 bool ObfuscatedFileSystemFileUtil::InitOriginDatabase(bool create) {
1240 if (!origin_database_.get()) {
1241 if (!create && !file_util::DirectoryExists(file_system_directory_))
1242 return false;
1243 if (!file_util::CreateDirectory(file_system_directory_)) {
1244 LOG(WARNING) << "Failed to create FileSystem directory: " <<
1245 file_system_directory_.value();
1246 return false;
1247 }
1248 origin_database_.reset(
1249 new FileSystemOriginDatabase(
1250 file_system_directory_.AppendASCII(kOriginDatabaseName)));
1251 }
1252 return true;
1253 }
1254
1255 } // namespace fileapi
OLDNEW
« no previous file with comments | « webkit/fileapi/obfuscated_file_system_file_util.h ('k') | webkit/fileapi/obfuscated_file_system_file_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698