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

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

Powered by Google App Engine
This is Rietveld 408576698