diff options
author | Andras Becsi <andras.becsi@digia.com> | 2013-12-11 21:33:03 +0100 |
---|---|---|
committer | Andras Becsi <andras.becsi@digia.com> | 2013-12-13 12:34:07 +0100 |
commit | f2a33ff9cbc6d19943f1c7fbddd1f23d23975577 (patch) | |
tree | 0586a32aa390ade8557dfd6b4897f43a07449578 /chromium/webkit/browser/fileapi | |
parent | 5362912cdb5eea702b68ebe23702468d17c3017a (diff) | |
download | qtwebengine-chromium-f2a33ff9cbc6d19943f1c7fbddd1f23d23975577.tar.gz |
Update Chromium to branch 1650 (31.0.1650.63)
Change-Id: I57d8c832eaec1eb2364e0a8e7352a6dd354db99f
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
Diffstat (limited to 'chromium/webkit/browser/fileapi')
78 files changed, 3083 insertions, 1689 deletions
diff --git a/chromium/webkit/browser/fileapi/async_file_test_helper.cc b/chromium/webkit/browser/fileapi/async_file_test_helper.cc index 8a01fd2a474..e3343d51935 100644 --- a/chromium/webkit/browser/fileapi/async_file_test_helper.cc +++ b/chromium/webkit/browser/fileapi/async_file_test_helper.cc @@ -3,6 +3,8 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/file_util.h" +#include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/browser/fileapi/async_file_test_helper.h" @@ -92,10 +94,19 @@ base::PlatformFileError AsyncFileTestHelper::Copy( FileSystemContext* context, const FileSystemURL& src, const FileSystemURL& dest) { + return CopyWithProgress(context, src, dest, CopyProgressCallback()); +} + +base::PlatformFileError AsyncFileTestHelper::CopyWithProgress( + FileSystemContext* context, + const FileSystemURL& src, + const FileSystemURL& dest, + const CopyProgressCallback& progress_callback) { base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED; base::RunLoop run_loop; context->operation_runner()->Copy( - src, dest, AssignAndQuitCallback(&run_loop, &result)); + src, dest, progress_callback, + AssignAndQuitCallback(&run_loop, &result)); run_loop.Run(); return result; } @@ -164,6 +175,25 @@ base::PlatformFileError AsyncFileTestHelper::CreateFile( return result; } +base::PlatformFileError AsyncFileTestHelper::CreateFileWithData( + FileSystemContext* context, + const FileSystemURL& url, + const char* buf, + int buf_size) { + base::ScopedTempDir dir; + if (!dir.CreateUniqueTempDir()) + return base::PLATFORM_FILE_ERROR_FAILED; + base::FilePath local_path = dir.path().AppendASCII("tmp"); + if (buf_size != file_util::WriteFile(local_path, buf, buf_size)) + return base::PLATFORM_FILE_ERROR_FAILED; + base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED; + base::RunLoop run_loop; + context->operation_runner()->CopyInForeignFile( + local_path, url, AssignAndQuitCallback(&run_loop, &result)); + run_loop.Run(); + return result; +} + base::PlatformFileError AsyncFileTestHelper::TruncateFile( FileSystemContext* context, const FileSystemURL& url, @@ -232,7 +262,7 @@ quota::QuotaStatusCode AsyncFileTestHelper::GetUsageAndQuota( origin, FileSystemTypeToQuotaStorageType(type), base::Bind(&DidGetUsageAndQuota, &status, usage, quota)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); return status; } diff --git a/chromium/webkit/browser/fileapi/async_file_test_helper.h b/chromium/webkit/browser/fileapi/async_file_test_helper.h index cfa7981e03e..168400fd0ef 100644 --- a/chromium/webkit/browser/fileapi/async_file_test_helper.h +++ b/chromium/webkit/browser/fileapi/async_file_test_helper.h @@ -23,6 +23,7 @@ class FileSystemURL; class AsyncFileTestHelper { public: typedef FileSystemOperation::FileEntryList FileEntryList; + typedef FileSystemOperation::CopyProgressCallback CopyProgressCallback; static const int64 kDontCheckSize; @@ -31,6 +32,13 @@ class AsyncFileTestHelper { const FileSystemURL& src, const FileSystemURL& dest); + // Same as Copy, but this supports |progress_callback|. + static base::PlatformFileError CopyWithProgress( + FileSystemContext* context, + const FileSystemURL& src, + const FileSystemURL& dest, + const CopyProgressCallback& progress_callback); + // Performs Move from |src| to |dest| and returns the status code. static base::PlatformFileError Move(FileSystemContext* context, const FileSystemURL& src, @@ -54,6 +62,13 @@ class AsyncFileTestHelper { static base::PlatformFileError CreateFile(FileSystemContext* context, const FileSystemURL& url); + // Creates a file at |url| and fills with |buf|. + static base::PlatformFileError CreateFileWithData( + FileSystemContext* context, + const FileSystemURL& url, + const char* buf, + int buf_size); + // Truncates the file |url| to |size|. static base::PlatformFileError TruncateFile(FileSystemContext* context, const FileSystemURL& url, diff --git a/chromium/webkit/browser/fileapi/async_file_util.h b/chromium/webkit/browser/fileapi/async_file_util.h index dc8216eaac0..84a033b7a4e 100644 --- a/chromium/webkit/browser/fileapi/async_file_util.h +++ b/chromium/webkit/browser/fileapi/async_file_util.h @@ -42,7 +42,7 @@ class FileSystemURL; // It is NOT valid to give null callback to this class, and implementors // can assume that they don't get any null callbacks. // -class WEBKIT_STORAGE_BROWSER_EXPORT AsyncFileUtil { +class AsyncFileUtil { public: typedef base::Callback< void(base::PlatformFileError result)> StatusCallback; @@ -76,6 +76,15 @@ class WEBKIT_STORAGE_BROWSER_EXPORT AsyncFileUtil { const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref )> CreateSnapshotFileCallback; + + typedef base::Callback<void(int64 size)> CopyFileProgressCallback; + + // Creates an AsyncFileUtil instance which performs file operations on + // local native file system. The created instance assumes + // FileSystemURL::path() has the target platform path. + WEBKIT_STORAGE_BROWSER_EXPORT static AsyncFileUtil* + CreateForLocalFileSystem(); + AsyncFileUtil() {} virtual ~AsyncFileUtil() {} @@ -198,6 +207,12 @@ class WEBKIT_STORAGE_BROWSER_EXPORT AsyncFileUtil { // Copies a file from |src_url| to |dest_url|. // This must be called for files that belong to the same filesystem // (i.e. type() and origin() of the |src_url| and |dest_url| must match). + // |progress_callback| is a callback to report the progress update. + // See file_system_operations.h for details. This should be called on the + // same thread as where the method's called (IO thread). Calling this + // is optional. It is recommended to use this callback for heavier operations + // (such as file network downloading), so that, e.g., clients (UIs) can + // update its state to show progress to users. This may be a null callback. // // FileSystemOperationImpl::Copy calls this for same-filesystem copy case. // @@ -214,6 +229,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT AsyncFileUtil { scoped_ptr<FileSystemOperationContext> context, const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, const StatusCallback& callback) = 0; // Moves a local file from |src_url| to |dest_url|. diff --git a/chromium/webkit/browser/fileapi/async_file_util_adapter.cc b/chromium/webkit/browser/fileapi/async_file_util_adapter.cc index 807c2e20227..54d67976dc7 100644 --- a/chromium/webkit/browser/fileapi/async_file_util_adapter.cc +++ b/chromium/webkit/browser/fileapi/async_file_util_adapter.cc @@ -253,7 +253,9 @@ void AsyncFileUtilAdapter::CopyFileLocal( scoped_ptr<FileSystemOperationContext> context, const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, const StatusCallback& callback) { + // TODO(hidehiko): Support progress_callback. FileSystemOperationContext* context_ptr = context.release(); const bool success = base::PostTaskAndReplyWithResult( context_ptr->task_runner(), FROM_HERE, diff --git a/chromium/webkit/browser/fileapi/async_file_util_adapter.h b/chromium/webkit/browser/fileapi/async_file_util_adapter.h index 9da3db9eac7..0122b11b9d5 100644 --- a/chromium/webkit/browser/fileapi/async_file_util_adapter.h +++ b/chromium/webkit/browser/fileapi/async_file_util_adapter.h @@ -22,8 +22,8 @@ class FileSystemFileUtil; // // This instance (as thus this->sync_file_util_) is guaranteed to be alive // as far as FileSystemOperationContext given to each operation is kept alive. -class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE AsyncFileUtilAdapter - : public AsyncFileUtil { +class WEBKIT_STORAGE_BROWSER_EXPORT AsyncFileUtilAdapter + : public NON_EXPORTED_BASE(AsyncFileUtil) { public: // Creates a new AsyncFileUtil for |sync_file_util|. This takes the // ownership of |sync_file_util|. (This doesn't take scoped_ptr<> just @@ -76,6 +76,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE AsyncFileUtilAdapter scoped_ptr<FileSystemOperationContext> context, const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, const StatusCallback& callback) OVERRIDE; virtual void MoveFileLocal( scoped_ptr<FileSystemOperationContext> context, diff --git a/chromium/webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc b/chromium/webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc index caecccfddfb..366efa3dad5 100644 --- a/chromium/webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc +++ b/chromium/webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc @@ -6,7 +6,7 @@ #include "base/bind.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/browser/fileapi/async_file_test_helper.h" #include "webkit/browser/fileapi/copy_or_move_file_validator.h" @@ -46,7 +46,7 @@ class CopyOrMoveFileValidatorTestHelper { ~CopyOrMoveFileValidatorTestHelper() { file_system_context_ = NULL; - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } void SetUp() { @@ -68,7 +68,7 @@ class CopyOrMoveFileValidatorTestHelper { origin_, src_type_, OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, base::Bind(&ExpectOk)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); ASSERT_EQ(base::PLATFORM_FILE_OK, CreateDirectory(SourceURL(""))); // Sets up dest. diff --git a/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate.cc b/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate.cc index da1ef97b984..aba17b55d75 100644 --- a/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate.cc +++ b/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate.cc @@ -16,22 +16,293 @@ namespace fileapi { +class CopyOrMoveOperationDelegate::CopyOrMoveImpl { + public: + virtual ~CopyOrMoveImpl() {} + virtual void Run( + const CopyOrMoveOperationDelegate::StatusCallback& callback) = 0; + protected: + CopyOrMoveImpl() {} + DISALLOW_COPY_AND_ASSIGN(CopyOrMoveImpl); +}; + +namespace { + +// Copies a file on a (same) file system. Just delegate the operation to +// |operation_runner|. +class CopyOrMoveOnSameFileSystemImpl + : public CopyOrMoveOperationDelegate::CopyOrMoveImpl { + public: + CopyOrMoveOnSameFileSystemImpl( + FileSystemOperationRunner* operation_runner, + CopyOrMoveOperationDelegate::OperationType operation_type, + const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const FileSystemOperation::CopyFileProgressCallback& + file_progress_callback) + : operation_runner_(operation_runner), + operation_type_(operation_type), + src_url_(src_url), + dest_url_(dest_url), + file_progress_callback_(file_progress_callback) { + } + + virtual void Run( + const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE { + if (operation_type_ == CopyOrMoveOperationDelegate::OPERATION_MOVE) { + operation_runner_->MoveFileLocal(src_url_, dest_url_, callback); + } else { + operation_runner_->CopyFileLocal( + src_url_, dest_url_, file_progress_callback_, callback); + } + } + + private: + FileSystemOperationRunner* operation_runner_; + CopyOrMoveOperationDelegate::OperationType operation_type_; + FileSystemURL src_url_; + FileSystemURL dest_url_; + FileSystemOperation::CopyFileProgressCallback file_progress_callback_; + DISALLOW_COPY_AND_ASSIGN(CopyOrMoveOnSameFileSystemImpl); +}; + +// Specifically for cross file system copy/move operation, this class creates +// a snapshot file, validates it if necessary, runs copying process, +// validates the created file, and removes source file for move (noop for +// copy). +class SnapshotCopyOrMoveImpl + : public CopyOrMoveOperationDelegate::CopyOrMoveImpl { + public: + SnapshotCopyOrMoveImpl( + FileSystemOperationRunner* operation_runner, + CopyOrMoveOperationDelegate::OperationType operation_type, + const FileSystemURL& src_url, + const FileSystemURL& dest_url, + CopyOrMoveFileValidatorFactory* validator_factory, + const FileSystemOperation::CopyFileProgressCallback& + file_progress_callback) + : operation_runner_(operation_runner), + operation_type_(operation_type), + src_url_(src_url), + dest_url_(dest_url), + validator_factory_(validator_factory), + file_progress_callback_(file_progress_callback), + weak_factory_(this) { + } + + virtual void Run( + const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE { + file_progress_callback_.Run(0); + operation_runner_->CreateSnapshotFile( + src_url_, + base::Bind(&SnapshotCopyOrMoveImpl::RunAfterCreateSnapshot, + weak_factory_.GetWeakPtr(), callback)); + } + + private: + void RunAfterCreateSnapshot( + const CopyOrMoveOperationDelegate::StatusCallback& callback, + base::PlatformFileError error, + const base::PlatformFileInfo& file_info, + const base::FilePath& platform_path, + const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { + if (error != base::PLATFORM_FILE_OK) { + callback.Run(error); + return; + } + + // For now we assume CreateSnapshotFile always return a valid local file + // path. + DCHECK(!platform_path.empty()); + + if (!validator_factory_) { + // No validation is needed. + RunAfterPreWriteValidation(platform_path, file_info, file_ref, callback, + base::PLATFORM_FILE_OK); + return; + } + + // Run pre write validation. + PreWriteValidation( + platform_path, + base::Bind(&SnapshotCopyOrMoveImpl::RunAfterPreWriteValidation, + weak_factory_.GetWeakPtr(), + platform_path, file_info, file_ref, callback)); + } + + void RunAfterPreWriteValidation( + const base::FilePath& platform_path, + const base::PlatformFileInfo& file_info, + const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref, + const CopyOrMoveOperationDelegate::StatusCallback& callback, + base::PlatformFileError error) { + if (error != base::PLATFORM_FILE_OK) { + callback.Run(error); + return; + } + + // |file_ref| is unused but necessary to keep the file alive until + // CopyInForeignFile() is completed. + operation_runner_->CopyInForeignFile( + platform_path, dest_url_, + base::Bind(&SnapshotCopyOrMoveImpl::RunAfterCopyInForeignFile, + weak_factory_.GetWeakPtr(), file_info, file_ref, callback)); + } + + void RunAfterCopyInForeignFile( + const base::PlatformFileInfo& file_info, + const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref, + const CopyOrMoveOperationDelegate::StatusCallback& callback, + base::PlatformFileError error) { + if (error != base::PLATFORM_FILE_OK) { + callback.Run(error); + return; + } + + file_progress_callback_.Run(file_info.size); + + // |validator_| is NULL when the destination filesystem does not do + // validation. + if (!validator_) { + // No validation is needed. + RunAfterPostWriteValidation(callback, base::PLATFORM_FILE_OK); + return; + } + + PostWriteValidation( + base::Bind(&SnapshotCopyOrMoveImpl::RunAfterPostWriteValidation, + weak_factory_.GetWeakPtr(), callback)); + } + + void RunAfterPostWriteValidation( + const CopyOrMoveOperationDelegate::StatusCallback& callback, + base::PlatformFileError error) { + if (error != base::PLATFORM_FILE_OK) { + // Failed to validate. Remove the destination file. + operation_runner_->Remove( + dest_url_, true /* recursive */, + base::Bind(&SnapshotCopyOrMoveImpl::DidRemoveDestForError, + weak_factory_.GetWeakPtr(), error, callback)); + return; + } + + if (operation_type_ == CopyOrMoveOperationDelegate::OPERATION_COPY) { + callback.Run(base::PLATFORM_FILE_OK); + return; + } + + DCHECK_EQ(CopyOrMoveOperationDelegate::OPERATION_MOVE, operation_type_); + + // Remove the source for finalizing move operation. + operation_runner_->Remove( + src_url_, true /* recursive */, + base::Bind(&SnapshotCopyOrMoveImpl::RunAfterRemoveSourceForMove, + weak_factory_.GetWeakPtr(), callback)); + } + + void RunAfterRemoveSourceForMove( + const CopyOrMoveOperationDelegate::StatusCallback& callback, + base::PlatformFileError error) { + if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) + error = base::PLATFORM_FILE_OK; + callback.Run(error); + } + + void DidRemoveDestForError( + base::PlatformFileError prior_error, + const CopyOrMoveOperationDelegate::StatusCallback& callback, + base::PlatformFileError error) { + if (error != base::PLATFORM_FILE_OK) { + VLOG(1) << "Error removing destination file after validation error: " + << error; + } + callback.Run(prior_error); + } + + // Runs pre-write validation. + void PreWriteValidation( + const base::FilePath& platform_path, + const CopyOrMoveOperationDelegate::StatusCallback& callback) { + DCHECK(validator_factory_); + validator_.reset( + validator_factory_->CreateCopyOrMoveFileValidator( + src_url_, platform_path)); + validator_->StartPreWriteValidation(callback); + } + + // Runs post-write validation. + void PostWriteValidation( + const CopyOrMoveOperationDelegate::StatusCallback& callback) { + operation_runner_->CreateSnapshotFile( + dest_url_, + base::Bind( + &SnapshotCopyOrMoveImpl::PostWriteValidationAfterCreateSnapshotFile, + weak_factory_.GetWeakPtr(), callback)); + } + + void PostWriteValidationAfterCreateSnapshotFile( + const CopyOrMoveOperationDelegate::StatusCallback& callback, + base::PlatformFileError error, + const base::PlatformFileInfo& file_info, + const base::FilePath& platform_path, + const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { + if (error != base::PLATFORM_FILE_OK) { + callback.Run(error); + return; + } + + DCHECK(validator_); + // Note: file_ref passed here to keep the file alive until after + // the StartPostWriteValidation operation finishes. + validator_->StartPostWriteValidation( + platform_path, + base::Bind(&SnapshotCopyOrMoveImpl::DidPostWriteValidation, + weak_factory_.GetWeakPtr(), file_ref, callback)); + } + + // |file_ref| is unused; it is passed here to make sure the reference is + // alive until after post-write validation is complete. + void DidPostWriteValidation( + const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref, + const CopyOrMoveOperationDelegate::StatusCallback& callback, + base::PlatformFileError error) { + callback.Run(error); + } + + FileSystemOperationRunner* operation_runner_; + CopyOrMoveOperationDelegate::OperationType operation_type_; + FileSystemURL src_url_; + FileSystemURL dest_url_; + CopyOrMoveFileValidatorFactory* validator_factory_; + scoped_ptr<CopyOrMoveFileValidator> validator_; + FileSystemOperation::CopyFileProgressCallback file_progress_callback_; + + base::WeakPtrFactory<SnapshotCopyOrMoveImpl> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(SnapshotCopyOrMoveImpl); +}; + +} // namespace + + CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( FileSystemContext* file_system_context, const FileSystemURL& src_root, const FileSystemURL& dest_root, OperationType operation_type, + const CopyProgressCallback& progress_callback, const StatusCallback& callback) : RecursiveOperationDelegate(file_system_context), src_root_(src_root), dest_root_(dest_root), operation_type_(operation_type), + progress_callback_(progress_callback), callback_(callback), weak_factory_(this) { same_file_system_ = src_root_.IsInSameFileSystem(dest_root_); } CopyOrMoveOperationDelegate::~CopyOrMoveOperationDelegate() { + STLDeleteElements(&running_copy_set_); } void CopyOrMoveOperationDelegate::Run() { @@ -54,239 +325,154 @@ void CopyOrMoveOperationDelegate::RunRecursively() { return; } - // First try to copy/move it as a file. - CopyOrMoveFile(URLPair(src_root_, dest_root_), - base::Bind(&CopyOrMoveOperationDelegate::DidTryCopyOrMoveFile, - weak_factory_.GetWeakPtr())); -} - -void CopyOrMoveOperationDelegate::ProcessFile(const FileSystemURL& src_url, - const StatusCallback& callback) { - CopyOrMoveFile(URLPair(src_url, CreateDestURL(src_url)), callback); -} - -void CopyOrMoveOperationDelegate::ProcessDirectory(const FileSystemURL& src_url, - const StatusCallback& callback) { - FileSystemURL dest_url = CreateDestURL(src_url); - - // If operation_type == Move we may need to record directories and - // restore directory timestamps in the end, though it may have - // negative performance impact. - // See http://crbug.com/171284 for more details. - operation_runner()->CreateDirectory( - dest_url, false /* exclusive */, false /* recursive */, callback); -} - -void CopyOrMoveOperationDelegate::DidTryCopyOrMoveFile( - base::PlatformFileError error) { - if (error == base::PLATFORM_FILE_OK || - error != base::PLATFORM_FILE_ERROR_NOT_A_FILE) { - callback_.Run(error); - return; - } - - // The src_root_ looks to be a directory. - // Try removing the dest_root_ to see if it exists and/or it is an - // empty directory. - operation_runner()->RemoveDirectory( - dest_root_, - base::Bind(&CopyOrMoveOperationDelegate::DidTryRemoveDestRoot, - weak_factory_.GetWeakPtr())); -} - -void CopyOrMoveOperationDelegate::DidTryRemoveDestRoot( - base::PlatformFileError error) { - if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) { - callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); - return; - } - if (error != base::PLATFORM_FILE_OK && - error != base::PLATFORM_FILE_ERROR_NOT_FOUND) { - callback_.Run(error); - return; - } - // Start to process the source directory recursively. // TODO(kinuko): This could be too expensive for same_file_system_==true // and operation==MOVE case, probably we can just rename the root directory. // http://crbug.com/172187 - StartRecursiveOperation( - src_root_, - base::Bind(&CopyOrMoveOperationDelegate::DidFinishRecursiveCopyDir, - weak_factory_.GetWeakPtr(), src_root_, callback_)); + StartRecursiveOperation(src_root_, callback_); } -void CopyOrMoveOperationDelegate::CopyOrMoveFile( - const URLPair& url_pair, +void CopyOrMoveOperationDelegate::ProcessFile( + const FileSystemURL& src_url, const StatusCallback& callback) { - // Same filesystem case. - if (same_file_system_) { - if (operation_type_ == OPERATION_MOVE) { - operation_runner()->MoveFileLocal(url_pair.src, url_pair.dest, callback); - } else { - operation_runner()->CopyFileLocal(url_pair.src, url_pair.dest, callback); - } - return; + if (!progress_callback_.is_null()) { + progress_callback_.Run( + FileSystemOperation::BEGIN_COPY_ENTRY, src_url, FileSystemURL(), 0); } - // Cross filesystem case. - // Perform CreateSnapshotFile, CopyInForeignFile and then calls - // copy_callback which removes the source file if operation_type == MOVE. - StatusCallback copy_callback = - base::Bind(&CopyOrMoveOperationDelegate::DidFinishCopy, - weak_factory_.GetWeakPtr(), url_pair, callback); - operation_runner()->CreateSnapshotFile( - url_pair.src, - base::Bind(&CopyOrMoveOperationDelegate::DidCreateSnapshot, - weak_factory_.GetWeakPtr(), url_pair, copy_callback)); -} + FileSystemURL dest_url = CreateDestURL(src_url); + CopyOrMoveImpl* impl = NULL; + if (same_file_system_) { + impl = new CopyOrMoveOnSameFileSystemImpl( + operation_runner(), operation_type_, src_url, dest_url, + base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, + weak_factory_.GetWeakPtr(), src_url)); + } else { + // Cross filesystem case. + // TODO(hidehiko): Support stream based copy. crbug.com/279287. + base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; + CopyOrMoveFileValidatorFactory* validator_factory = + file_system_context()->GetCopyOrMoveFileValidatorFactory( + dest_root_.type(), &error); + if (error != base::PLATFORM_FILE_OK) { + callback.Run(error); + return; + } -void CopyOrMoveOperationDelegate::DidCreateSnapshot( - const URLPair& url_pair, - const StatusCallback& callback, - base::PlatformFileError error, - const base::PlatformFileInfo& file_info, - const base::FilePath& platform_path, - const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { - if (error != base::PLATFORM_FILE_OK) { - callback.Run(error); - return; + impl = new SnapshotCopyOrMoveImpl( + operation_runner(), operation_type_, src_url, dest_url, + validator_factory, + base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, + weak_factory_.GetWeakPtr(), src_url)); } - current_file_ref_ = file_ref; - // For now we assume CreateSnapshotFile always return a valid local file path. - // TODO(kinuko): Otherwise create a FileStreamReader to perform a copy/move. - DCHECK(!platform_path.empty()); + // Register the running task. + running_copy_set_.insert(impl); + impl->Run(base::Bind( + &CopyOrMoveOperationDelegate::DidCopyOrMoveFile, + weak_factory_.GetWeakPtr(), src_url, dest_url, callback, impl)); +} - CopyOrMoveFileValidatorFactory* factory = - file_system_context()->GetCopyOrMoveFileValidatorFactory( - dest_root_.type(), &error); - if (error != base::PLATFORM_FILE_OK) { - callback.Run(error); - return; - } - if (!factory) { - DidValidateFile(url_pair.dest, callback, file_info, platform_path, error); +void CopyOrMoveOperationDelegate::ProcessDirectory( + const FileSystemURL& src_url, + const StatusCallback& callback) { + if (src_url == src_root_) { + // The src_root_ looks to be a directory. + // Try removing the dest_root_ to see if it exists and/or it is an + // empty directory. + // We do not invoke |progress_callback_| for source root, because it is + // already called in ProcessFile(). + operation_runner()->RemoveDirectory( + dest_root_, + base::Bind(&CopyOrMoveOperationDelegate::DidTryRemoveDestRoot, + weak_factory_.GetWeakPtr(), callback)); return; } - validator_.reset( - factory->CreateCopyOrMoveFileValidator(url_pair.src, platform_path)); - validator_->StartPreWriteValidation( - base::Bind(&CopyOrMoveOperationDelegate::DidValidateFile, - weak_factory_.GetWeakPtr(), - url_pair.dest, callback, file_info, platform_path)); -} - -void CopyOrMoveOperationDelegate::DidValidateFile( - const FileSystemURL& dest, - const StatusCallback& callback, - const base::PlatformFileInfo& file_info, - const base::FilePath& platform_path, - base::PlatformFileError error) { - if (error != base::PLATFORM_FILE_OK) { - callback.Run(error); - return; + if (!progress_callback_.is_null()) { + progress_callback_.Run( + FileSystemOperation::BEGIN_COPY_ENTRY, src_url, FileSystemURL(), 0); } - operation_runner()->CopyInForeignFile(platform_path, dest, callback); + ProcessDirectoryInternal(src_url, CreateDestURL(src_url), callback); } -void CopyOrMoveOperationDelegate::DidFinishRecursiveCopyDir( - const FileSystemURL& src, - const StatusCallback& callback, - base::PlatformFileError error) { - if (error != base::PLATFORM_FILE_OK || - operation_type_ == OPERATION_COPY) { - callback.Run(error); +void CopyOrMoveOperationDelegate::PostProcessDirectory( + const FileSystemURL& src_url, + const StatusCallback& callback) { + if (operation_type_ == OPERATION_COPY) { + callback.Run(base::PLATFORM_FILE_OK); return; } DCHECK_EQ(OPERATION_MOVE, operation_type_); - // Remove the source for finalizing move operation. + // All files and subdirectories in the directory should be moved here, + // so remove the source directory for finalizing move operation. operation_runner()->Remove( - src, true /* recursive */, + src_url, false /* recursive */, base::Bind(&CopyOrMoveOperationDelegate::DidRemoveSourceForMove, weak_factory_.GetWeakPtr(), callback)); } -void CopyOrMoveOperationDelegate::DidFinishCopy( - const URLPair& url_pair, +void CopyOrMoveOperationDelegate::DidCopyOrMoveFile( + const FileSystemURL& src_url, + const FileSystemURL& dest_url, const StatusCallback& callback, + CopyOrMoveImpl* impl, base::PlatformFileError error) { - if (error != base::PLATFORM_FILE_OK) { - callback.Run(error); - return; - } + running_copy_set_.erase(impl); + delete impl; - // |validator_| is NULL in the same-filesystem case or when the destination - // filesystem does not do validation. - if (!validator_.get()) { - scoped_refptr<webkit_blob::ShareableFileReference> file_ref; - DidPostWriteValidation(url_pair, callback, file_ref, - base::PLATFORM_FILE_OK); - return; + if (!progress_callback_.is_null() && error == base::PLATFORM_FILE_OK) { + progress_callback_.Run( + FileSystemOperation::END_COPY_ENTRY, src_url, dest_url, 0); } - DCHECK(!same_file_system_); - operation_runner()->CreateSnapshotFile( - url_pair.dest, - base::Bind(&CopyOrMoveOperationDelegate::DoPostWriteValidation, - weak_factory_.GetWeakPtr(), url_pair, callback)); + callback.Run(error); } -void CopyOrMoveOperationDelegate::DoPostWriteValidation( - const URLPair& url_pair, +void CopyOrMoveOperationDelegate::DidTryRemoveDestRoot( const StatusCallback& callback, - base::PlatformFileError error, - const base::PlatformFileInfo& file_info, - const base::FilePath& platform_path, - const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { - if (error != base::PLATFORM_FILE_OK) { - operation_runner()->Remove( - url_pair.dest, true, - base::Bind(&CopyOrMoveOperationDelegate::DidRemoveDestForError, - weak_factory_.GetWeakPtr(), error, callback)); + base::PlatformFileError error) { + if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) { + callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); + return; + } + if (error != base::PLATFORM_FILE_OK && + error != base::PLATFORM_FILE_ERROR_NOT_FOUND) { + callback_.Run(error); return; } - DCHECK(validator_.get()); - // Note: file_ref passed here to keep the file alive until after - // the StartPostWriteValidation operation finishes. - validator_->StartPostWriteValidation( - platform_path, - base::Bind(&CopyOrMoveOperationDelegate::DidPostWriteValidation, - weak_factory_.GetWeakPtr(), url_pair, callback, file_ref)); + ProcessDirectoryInternal(src_root_, dest_root_, callback); +} + +void CopyOrMoveOperationDelegate::ProcessDirectoryInternal( + const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback) { + // If operation_type == Move we may need to record directories and + // restore directory timestamps in the end, though it may have + // negative performance impact. + // See http://crbug.com/171284 for more details. + operation_runner()->CreateDirectory( + dest_url, false /* exclusive */, false /* recursive */, + base::Bind(&CopyOrMoveOperationDelegate::DidCreateDirectory, + weak_factory_.GetWeakPtr(), src_url, dest_url, callback)); } -// |file_ref| is unused; it is passed here to make sure the reference is -// alive until after post-write validation is complete. -void CopyOrMoveOperationDelegate::DidPostWriteValidation( - const URLPair& url_pair, +void CopyOrMoveOperationDelegate::DidCreateDirectory( + const FileSystemURL& src_url, + const FileSystemURL& dest_url, const StatusCallback& callback, - const scoped_refptr<webkit_blob::ShareableFileReference>& /*file_ref*/, base::PlatformFileError error) { - if (error != base::PLATFORM_FILE_OK) { - operation_runner()->Remove( - url_pair.dest, true, - base::Bind(&CopyOrMoveOperationDelegate::DidRemoveDestForError, - weak_factory_.GetWeakPtr(), error, callback)); - return; + if (!progress_callback_.is_null() && error == base::PLATFORM_FILE_OK) { + progress_callback_.Run( + FileSystemOperation::END_COPY_ENTRY, src_url, dest_url, 0); } - if (operation_type_ == OPERATION_COPY) { - callback.Run(error); - return; - } - - DCHECK_EQ(OPERATION_MOVE, operation_type_); - - // Remove the source for finalizing move operation. - operation_runner()->Remove( - url_pair.src, true /* recursive */, - base::Bind(&CopyOrMoveOperationDelegate::DidRemoveSourceForMove, - weak_factory_.GetWeakPtr(), callback)); + callback.Run(error); } void CopyOrMoveOperationDelegate::DidRemoveSourceForMove( @@ -297,6 +483,14 @@ void CopyOrMoveOperationDelegate::DidRemoveSourceForMove( callback.Run(error); } +void CopyOrMoveOperationDelegate::OnCopyFileProgress( + const FileSystemURL& src_url, int64 size) { + if (!progress_callback_.is_null()) { + progress_callback_.Run( + FileSystemOperation::PROGRESS, src_url, FileSystemURL(), size); + } +} + FileSystemURL CopyOrMoveOperationDelegate::CreateDestURL( const FileSystemURL& src_url) const { DCHECK_EQ(src_root_.type(), src_url.type()); @@ -311,15 +505,4 @@ FileSystemURL CopyOrMoveOperationDelegate::CreateDestURL( relative); } -void CopyOrMoveOperationDelegate::DidRemoveDestForError( - base::PlatformFileError prior_error, - const StatusCallback& callback, - base::PlatformFileError error) { - if (error != base::PLATFORM_FILE_OK) { - VLOG(1) << "Error removing destination file after validation error: " - << error; - } - callback.Run(prior_error); -} - } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate.h b/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate.h index ceceb971367..77d1a76efc6 100644 --- a/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate.h +++ b/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate.h @@ -23,6 +23,9 @@ class CopyOrMoveFileValidator; class CopyOrMoveOperationDelegate : public RecursiveOperationDelegate { public: + class CopyOrMoveImpl; + typedef FileSystemOperation::CopyProgressCallback CopyProgressCallback; + enum OperationType { OPERATION_COPY, OPERATION_MOVE @@ -33,6 +36,7 @@ class CopyOrMoveOperationDelegate const FileSystemURL& src_root, const FileSystemURL& dest_root, OperationType operation_type, + const CopyProgressCallback& progress_callback, const StatusCallback& callback); virtual ~CopyOrMoveOperationDelegate(); @@ -43,75 +47,38 @@ class CopyOrMoveOperationDelegate const StatusCallback& callback) OVERRIDE; virtual void ProcessDirectory(const FileSystemURL& url, const StatusCallback& callback) OVERRIDE; + virtual void PostProcessDirectory(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE; private: - struct URLPair { - URLPair(const FileSystemURL& src, const FileSystemURL& dest) - : src(src), - dest(dest) { - } - FileSystemURL src; - FileSystemURL dest; - }; - - void DidTryCopyOrMoveFile(base::PlatformFileError error); - void DidTryRemoveDestRoot(base::PlatformFileError error); - void CopyOrMoveFile( - const URLPair& url_pair, - const StatusCallback& callback); - void DidCreateSnapshot( - const URLPair& url_pair, - const StatusCallback& callback, - base::PlatformFileError error, - const base::PlatformFileInfo& file_info, - const base::FilePath& platform_path, - const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref); - void DidValidateFile( - const FileSystemURL& dest, - const StatusCallback& callback, - const base::PlatformFileInfo& file_info, - const base::FilePath& platform_path, - base::PlatformFileError error); - void DidFinishRecursiveCopyDir( - const FileSystemURL& src, - const StatusCallback& callback, - base::PlatformFileError error); - void DidFinishCopy( - const URLPair& url_pair, - const StatusCallback& callback, - base::PlatformFileError error); - void DoPostWriteValidation( - const URLPair& url_pair, - const StatusCallback& callback, - base::PlatformFileError error, - const base::PlatformFileInfo& file_info, - const base::FilePath& platform_path, - const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref); - void DidPostWriteValidation( - const URLPair& url_pair, - const StatusCallback& callback, - const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref, - base::PlatformFileError error); - void DidRemoveSourceForMove( - const StatusCallback& callback, - base::PlatformFileError error); - void DidRemoveDestForError( - base::PlatformFileError prior_error, - const StatusCallback& callback, - base::PlatformFileError error); - + void DidCopyOrMoveFile(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback, + CopyOrMoveImpl* impl, + base::PlatformFileError error); + void DidTryRemoveDestRoot(const StatusCallback& callback, + base::PlatformFileError error); + void ProcessDirectoryInternal(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback); + void DidCreateDirectory(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback, + base::PlatformFileError error); + void DidRemoveSourceForMove(const StatusCallback& callback, + base::PlatformFileError error); + + void OnCopyFileProgress(const FileSystemURL& src_url, int64 size); FileSystemURL CreateDestURL(const FileSystemURL& src_url) const; FileSystemURL src_root_; FileSystemURL dest_root_; bool same_file_system_; OperationType operation_type_; + CopyProgressCallback progress_callback_; StatusCallback callback_; - scoped_refptr<webkit_blob::ShareableFileReference> current_file_ref_; - - scoped_ptr<CopyOrMoveFileValidator> validator_; - + std::set<CopyOrMoveImpl*> running_copy_set_; base::WeakPtrFactory<CopyOrMoveOperationDelegate> weak_factory_; DISALLOW_COPY_AND_ASSIGN(CopyOrMoveOperationDelegate); diff --git a/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate_unittest.cc b/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate_unittest.cc index 183becd7dbf..322341dc40f 100644 --- a/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate_unittest.cc +++ b/chromium/webkit/browser/fileapi/copy_or_move_operation_delegate_unittest.cc @@ -93,6 +93,27 @@ class TestValidatorFactory : public CopyOrMoveFileValidatorFactory { }; }; +// Records CopyProgressCallback invocations. +struct ProgressRecord { + FileSystemOperation::CopyProgressType type; + FileSystemURL source_url; + FileSystemURL dest_url; + int64 size; +}; + +void RecordProgressCallback(std::vector<ProgressRecord>* records, + FileSystemOperation::CopyProgressType type, + const FileSystemURL& source_url, + const FileSystemURL& dest_url, + int64 size) { + ProgressRecord record; + record.type = type; + record.source_url = source_url; + record.dest_url = dest_url; + record.size = size; + records->push_back(record); +} + } // namespace class CopyOrMoveOperationTestHelper { @@ -110,7 +131,7 @@ class CopyOrMoveOperationTestHelper { quota_manager_proxy_->SimulateQuotaManagerDestroyed(); quota_manager_ = NULL; quota_manager_proxy_ = NULL; - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } void SetUp() { @@ -156,7 +177,7 @@ class CopyOrMoveOperationTestHelper { backend->OpenFileSystem(origin_, dest_type_, OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, base::Bind(&ExpectOk)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); // Grant relatively big quota initially. quota_manager_->SetQuota(origin_, @@ -194,6 +215,14 @@ class CopyOrMoveOperationTestHelper { return AsyncFileTestHelper::Copy(file_system_context_.get(), src, dest); } + base::PlatformFileError CopyWithProgress( + const FileSystemURL& src, + const FileSystemURL& dest, + const AsyncFileTestHelper::CopyProgressCallback& progress_callback) { + return AsyncFileTestHelper::CopyWithProgress( + file_system_context_.get(), src, dest, progress_callback); + } + base::PlatformFileError Move(const FileSystemURL& src, const FileSystemURL& dest) { return AsyncFileTestHelper::Move(file_system_context_.get(), src, dest); @@ -453,7 +482,10 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopyDirectory) { int64 src_increase = helper.GetSourceUsage() - src_initial_usage; // Copy it. - ASSERT_EQ(base::PLATFORM_FILE_OK, helper.Copy(src, dest)); + ASSERT_EQ(base::PLATFORM_FILE_OK, + helper.CopyWithProgress( + src, dest, + AsyncFileTestHelper::CopyProgressCallback())); // Verify. ASSERT_TRUE(helper.DirectoryExists(src)); @@ -559,4 +591,75 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFileNoValidator) { ASSERT_EQ(base::PLATFORM_FILE_ERROR_SECURITY, helper.Copy(src, dest)); } +TEST(LocalFileSystemCopyOrMoveOperationTest, ProgressCallback) { + CopyOrMoveOperationTestHelper helper(GURL("http://foo"), + kFileSystemTypeTemporary, + kFileSystemTypePersistent); + helper.SetUp(); + + FileSystemURL src = helper.SourceURL("a"); + FileSystemURL dest = helper.DestURL("b"); + + // Set up a source directory. + ASSERT_EQ(base::PLATFORM_FILE_OK, helper.CreateDirectory(src)); + ASSERT_EQ(base::PLATFORM_FILE_OK, + helper.SetUpTestCaseFiles(src, + test::kRegularTestCases, + test::kRegularTestCaseSize)); + + std::vector<ProgressRecord> records; + ASSERT_EQ(base::PLATFORM_FILE_OK, + helper.CopyWithProgress(src, dest, + base::Bind(&RecordProgressCallback, + base::Unretained(&records)))); + + // Verify progress callback. + for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) { + const test::TestCaseRecord& test_case = test::kRegularTestCases[i]; + + FileSystemURL src_url = helper.SourceURL( + std::string("a/") + base::FilePath(test_case.path).AsUTF8Unsafe()); + FileSystemURL dest_url = helper.DestURL( + std::string("b/") + base::FilePath(test_case.path).AsUTF8Unsafe()); + + // Find the first and last progress record. + size_t begin_index = records.size(); + size_t end_index = records.size(); + for (size_t j = 0; j < records.size(); ++j) { + if (records[j].source_url == src_url) { + if (begin_index == records.size()) + begin_index = j; + end_index = j; + } + } + + // The record should be found. + ASSERT_NE(begin_index, records.size()); + ASSERT_NE(end_index, records.size()); + ASSERT_NE(begin_index, end_index); + + EXPECT_EQ(FileSystemOperation::BEGIN_COPY_ENTRY, + records[begin_index].type); + EXPECT_FALSE(records[begin_index].dest_url.is_valid()); + EXPECT_EQ(FileSystemOperation::END_COPY_ENTRY, records[end_index].type); + EXPECT_EQ(dest_url, records[end_index].dest_url); + + if (test_case.is_directory) { + // For directory copy, the progress shouldn't be interlaced. + EXPECT_EQ(begin_index + 1, end_index); + } else { + // PROGRESS event's size should be assending order. + int64 current_size = 0; + for (size_t j = begin_index + 1; j < end_index; ++j) { + if (records[j].source_url == src_url) { + EXPECT_EQ(FileSystemOperation::PROGRESS, records[j].type); + EXPECT_FALSE(records[j].dest_url.is_valid()); + EXPECT_GE(records[j].size, current_size); + current_size = records[j].size; + } + } + } + } +} + } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/isolated_file_util.cc b/chromium/webkit/browser/fileapi/dragged_file_util.cc index bd2dffc009e..b4536a70f9a 100644 --- a/chromium/webkit/browser/fileapi/isolated_file_util.cc +++ b/chromium/webkit/browser/fileapi/dragged_file_util.cc @@ -1,8 +1,8 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "webkit/browser/fileapi/isolated_file_util.h" +#include "webkit/browser/fileapi/dragged_file_util.h" #include <string> #include <vector> @@ -58,24 +58,6 @@ class SetFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { //------------------------------------------------------------------------- -IsolatedFileUtil::IsolatedFileUtil() {} - -PlatformFileError IsolatedFileUtil::GetLocalFilePath( - FileSystemOperationContext* context, - const FileSystemURL& url, - base::FilePath* local_file_path) { - DCHECK(local_file_path); - DCHECK(url.is_valid()); - if (url.path().empty()) { - // Root direcory case, which should not be accessed. - return base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - } - *local_file_path = url.path(); - return base::PLATFORM_FILE_OK; -} - -//------------------------------------------------------------------------- - DraggedFileUtil::DraggedFileUtil() {} PlatformFileError DraggedFileUtil::GetFileInfo( diff --git a/chromium/webkit/browser/fileapi/isolated_file_util.h b/chromium/webkit/browser/fileapi/dragged_file_util.h index e6f595572c4..22c538e1b34 100644 --- a/chromium/webkit/browser/fileapi/isolated_file_util.h +++ b/chromium/webkit/browser/fileapi/dragged_file_util.h @@ -1,9 +1,9 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef WEBKIT_BROWSER_FILEAPI_ISOLATED_FILE_UTIL_H_ -#define WEBKIT_BROWSER_FILEAPI_ISOLATED_FILE_UTIL_H_ +#ifndef WEBKIT_BROWSER_FILEAPI_DRAGGED_FILE_UTIL_H_ +#define WEBKIT_BROWSER_FILEAPI_DRAGGED_FILE_UTIL_H_ #include "base/memory/scoped_ptr.h" #include "webkit/browser/fileapi/local_file_util.h" @@ -13,24 +13,11 @@ namespace fileapi { class FileSystemOperationContext; -class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE IsolatedFileUtil - : public LocalFileUtil { - public: - IsolatedFileUtil(); - virtual ~IsolatedFileUtil() {} - - // LocalFileUtil overrides. - virtual base::PlatformFileError GetLocalFilePath( - FileSystemOperationContext* context, - const FileSystemURL& file_system_url, - base::FilePath* local_file_path) OVERRIDE; -}; - -// Dragged file system is a specialized IsolatedFileUtil where read access to +// Dragged file system is a specialized LocalFileUtil where read access to // the virtual root directory (i.e. empty cracked path case) is allowed // and single isolated context may be associated with multiple file paths. class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE DraggedFileUtil - : public IsolatedFileUtil { + : public LocalFileUtil { public: DraggedFileUtil(); virtual ~DraggedFileUtil() {} @@ -51,4 +38,4 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE DraggedFileUtil } // namespace fileapi -#endif // WEBKIT_BROWSER_FILEAPI_ISOLATED_FILE_UTIL_H_ +#endif // WEBKIT_BROWSER_FILEAPI_DRAGGED_FILE_UTIL_H_ diff --git a/chromium/webkit/browser/fileapi/isolated_file_util_unittest.cc b/chromium/webkit/browser/fileapi/dragged_file_util_unittest.cc index fee8ed1497d..af15af8f9fd 100644 --- a/chromium/webkit/browser/fileapi/isolated_file_util_unittest.cc +++ b/chromium/webkit/browser/fileapi/dragged_file_util_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -17,10 +17,10 @@ #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/browser/fileapi/async_file_test_helper.h" +#include "webkit/browser/fileapi/dragged_file_util.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/isolated_context.h" -#include "webkit/browser/fileapi/isolated_file_util.h" #include "webkit/browser/fileapi/local_file_util.h" #include "webkit/browser/fileapi/mock_file_system_context.h" #include "webkit/browser/fileapi/native_file_util.h" @@ -32,7 +32,7 @@ namespace { typedef AsyncFileTestHelper::FileEntryList FileEntryList; -// Used in IsolatedFileUtilTest::SimulateDropFiles(). +// Used in DraggedFileUtilTest::SimulateDropFiles(). // Random root paths in which we create each file/directory of the // RegularTestCases (so that we can simulate a drop with files/directories // from multiple directories). @@ -87,11 +87,9 @@ FileSystemURL GetOtherURL(FileSystemContext* file_system_context, } // namespace -// TODO(kinuko): we should have separate tests for DraggedFileUtil and -// IsolatedFileUtil. -class IsolatedFileUtilTest : public testing::Test { +class DraggedFileUtilTest : public testing::Test { public: - IsolatedFileUtilTest() {} + DraggedFileUtilTest() {} virtual void SetUp() { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); @@ -184,8 +182,8 @@ class IsolatedFileUtilTest : public testing::Test { EXPECT_NE(platform_path1, platform_path2); std::string content1, content2; - EXPECT_TRUE(file_util::ReadFileToString(platform_path1, &content1)); - EXPECT_TRUE(file_util::ReadFileToString(platform_path2, &content2)); + EXPECT_TRUE(base::ReadFileToString(platform_path1, &content1)); + EXPECT_TRUE(base::ReadFileToString(platform_path2, &content2)); EXPECT_EQ(content1, content2); } @@ -281,11 +279,11 @@ class IsolatedFileUtilTest : public testing::Test { std::string filesystem_id_; scoped_refptr<FileSystemContext> file_system_context_; std::map<base::FilePath, base::FilePath> toplevel_root_map_; - scoped_ptr<IsolatedFileUtil> file_util_; - DISALLOW_COPY_AND_ASSIGN(IsolatedFileUtilTest); + scoped_ptr<DraggedFileUtil> file_util_; + DISALLOW_COPY_AND_ASSIGN(DraggedFileUtilTest); }; -TEST_F(IsolatedFileUtilTest, BasicTest) { +TEST_F(DraggedFileUtilTest, BasicTest) { for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) { SCOPED_TRACE(testing::Message() << "Testing RegularTestCases " << i); const test::TestCaseRecord& test_case = test::kRegularTestCases[i]; @@ -310,7 +308,7 @@ TEST_F(IsolatedFileUtilTest, BasicTest) { } } -TEST_F(IsolatedFileUtilTest, UnregisteredPathsTest) { +TEST_F(DraggedFileUtilTest, UnregisteredPathsTest) { static const fileapi::test::TestCaseRecord kUnregisteredCases[] = { {true, FILE_PATH_LITERAL("nonexistent"), 0}, {true, FILE_PATH_LITERAL("nonexistent/dir foo"), 0}, @@ -345,7 +343,7 @@ TEST_F(IsolatedFileUtilTest, UnregisteredPathsTest) { } } -TEST_F(IsolatedFileUtilTest, ReadDirectoryTest) { +TEST_F(DraggedFileUtilTest, ReadDirectoryTest) { for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) { const test::TestCaseRecord& test_case = test::kRegularTestCases[i]; if (!test_case.is_directory) @@ -404,7 +402,7 @@ TEST_F(IsolatedFileUtilTest, ReadDirectoryTest) { } } -TEST_F(IsolatedFileUtilTest, GetLocalFilePathTest) { +TEST_F(DraggedFileUtilTest, GetLocalFilePathTest) { for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) { const test::TestCaseRecord& test_case = test::kRegularTestCases[i]; FileSystemURL url = GetFileSystemURL(base::FilePath(test_case.path)); @@ -419,7 +417,7 @@ TEST_F(IsolatedFileUtilTest, GetLocalFilePathTest) { } } -TEST_F(IsolatedFileUtilTest, CopyOutFileTest) { +TEST_F(DraggedFileUtilTest, CopyOutFileTest) { FileSystemURL src_root = GetFileSystemURL(base::FilePath()); FileSystemURL dest_root = GetOtherFileSystemURL(base::FilePath()); @@ -460,7 +458,7 @@ TEST_F(IsolatedFileUtilTest, CopyOutFileTest) { } } -TEST_F(IsolatedFileUtilTest, CopyOutDirectoryTest) { +TEST_F(DraggedFileUtilTest, CopyOutDirectoryTest) { FileSystemURL src_root = GetFileSystemURL(base::FilePath()); FileSystemURL dest_root = GetOtherFileSystemURL(base::FilePath()); @@ -488,7 +486,7 @@ TEST_F(IsolatedFileUtilTest, CopyOutDirectoryTest) { } } -TEST_F(IsolatedFileUtilTest, TouchTest) { +TEST_F(DraggedFileUtilTest, TouchTest) { for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) { const test::TestCaseRecord& test_case = test::kRegularTestCases[i]; if (test_case.is_directory) @@ -515,7 +513,7 @@ TEST_F(IsolatedFileUtilTest, TouchTest) { } } -TEST_F(IsolatedFileUtilTest, TruncateTest) { +TEST_F(DraggedFileUtilTest, TruncateTest) { for (size_t i = 0; i < test::kRegularTestCaseSize; ++i) { const test::TestCaseRecord& test_case = test::kRegularTestCases[i]; if (test_case.is_directory) diff --git a/chromium/webkit/browser/fileapi/file_stream_writer.h b/chromium/webkit/browser/fileapi/file_stream_writer.h index 7262cdf6ccd..1ebdfb9191a 100644 --- a/chromium/webkit/browser/fileapi/file_stream_writer.h +++ b/chromium/webkit/browser/fileapi/file_stream_writer.h @@ -9,6 +9,11 @@ #include "net/base/completion_callback.h" #include "webkit/browser/webkit_storage_browser_export.h" +namespace base { +class FilePath; +class TaskRunner; +} + namespace net { class IOBuffer; } @@ -16,8 +21,15 @@ class IOBuffer; namespace fileapi { // A generic interface for writing to a file-like object. -class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE FileStreamWriter { +class FileStreamWriter { public: + // Creates a writer for the existing file in the path |file_path| starting + // from |initial_offset|. Uses |task_runner| for async file operations. + WEBKIT_STORAGE_BROWSER_EXPORT static FileStreamWriter* CreateForLocalFile( + base::TaskRunner* task_runner, + const base::FilePath& file_path, + int64 initial_offset); + // Closes the file. If there's an in-flight operation, it is canceled (i.e., // the callback function associated with the operation is not called). virtual ~FileStreamWriter() {} diff --git a/chromium/webkit/browser/fileapi/file_system_backend.h b/chromium/webkit/browser/fileapi/file_system_backend.h index b368db6c928..2c8be930b3e 100644 --- a/chromium/webkit/browser/fileapi/file_system_backend.h +++ b/chromium/webkit/browser/fileapi/file_system_backend.h @@ -69,11 +69,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemBackend { OpenFileSystemMode mode, const OpenFileSystemCallback& callback) = 0; - // Returns the specialized FileSystemFileUtil for this backend. - // It is ok to return NULL if the filesystem doesn't support synchronous - // version of FileUtil. - virtual FileSystemFileUtil* GetFileUtil(FileSystemType type) = 0; - // Returns the specialized AsyncFileUtil for this backend. virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) = 0; diff --git a/chromium/webkit/browser/fileapi/file_system_context.cc b/chromium/webkit/browser/fileapi/file_system_context.cc index d43ba8a846e..9098649f245 100644 --- a/chromium/webkit/browser/fileapi/file_system_context.cc +++ b/chromium/webkit/browser/fileapi/file_system_context.cc @@ -27,6 +27,7 @@ #include "webkit/browser/fileapi/test_file_system_backend.h" #include "webkit/browser/quota/quota_manager.h" #include "webkit/browser/quota/special_storage_policy.h" +#include "webkit/common/fileapi/file_system_info.h" #include "webkit/common/fileapi/file_system_util.h" using quota::QuotaClient; @@ -49,6 +50,19 @@ void DidOpenFileSystem( callback.Run(error, filesystem_name, filesystem_root); } +void DidGetMetadataForResolveURL( + const base::FilePath& path, + const FileSystemContext::ResolveURLCallback& callback, + const FileSystemInfo& info, + base::PlatformFileError error, + const base::PlatformFileInfo& file_info) { + if (error != base::PLATFORM_FILE_OK) { + callback.Run(error, FileSystemInfo(), base::FilePath(), false); + return; + } + callback.Run(error, info, path, file_info.is_directory); +} + } // namespace // static @@ -108,24 +122,20 @@ FileSystemContext::FileSystemContext( : io_task_runner_(io_task_runner), default_file_task_runner_(file_task_runner), quota_manager_proxy_(quota_manager_proxy), - sandbox_context_(new SandboxContext( + sandbox_delegate_(new SandboxFileSystemBackendDelegate( quota_manager_proxy, file_task_runner, partition_path, special_storage_policy, options)), sandbox_backend_(new SandboxFileSystemBackend( - sandbox_context_.get())), + sandbox_delegate_.get())), isolated_backend_(new IsolatedFileSystemBackend()), additional_backends_(additional_backends.Pass()), external_mount_points_(external_mount_points), partition_path_(partition_path), + is_incognito_(options.is_incognito()), operation_runner_(new FileSystemOperationRunner(this)) { - if (quota_manager_proxy) { - quota_manager_proxy->RegisterClient(CreateQuotaClient( - this, options.is_incognito())); - } - RegisterBackend(sandbox_backend_.get()); RegisterBackend(isolated_backend_.get()); @@ -135,6 +145,12 @@ FileSystemContext::FileSystemContext( RegisterBackend(*iter); } + if (quota_manager_proxy) { + // Quota client assumes all backends have registered. + quota_manager_proxy->RegisterClient(CreateQuotaClient( + this, options.is_incognito())); + } + sandbox_backend_->Initialize(this); isolated_backend_->Initialize(this); for (ScopedVector<FileSystemBackend>::const_iterator iter = @@ -200,14 +216,6 @@ AsyncFileUtil* FileSystemContext::GetAsyncFileUtil( return backend->GetAsyncFileUtil(type); } -FileSystemFileUtil* FileSystemContext::GetFileUtil( - FileSystemType type) const { - FileSystemBackend* backend = GetFileSystemBackend(type); - if (!backend) - return NULL; - return backend->GetFileUtil(type); -} - CopyOrMoveFileValidatorFactory* FileSystemContext::GetCopyOrMoveFileValidatorFactory( FileSystemType type, base::PlatformFileError* error_code) const { @@ -230,7 +238,8 @@ FileSystemBackend* FileSystemContext::GetFileSystemBackend( } bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const { - return GetQuotaUtil(type) != NULL; + FileSystemBackendMap::const_iterator found = backend_map_.find(type); + return found != backend_map_.end() && found->second->GetQuotaUtil(); } const UpdateObserverList* FileSystemContext::GetUpdateObservers( @@ -280,6 +289,26 @@ void FileSystemContext::OpenFileSystem( base::Bind(&DidOpenFileSystem, callback)); } +void FileSystemContext::ResolveURL( + const FileSystemURL& url, + const ResolveURLCallback& callback) { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!callback.is_null()); + + FileSystemBackend* backend = GetFileSystemBackend(url.type()); + if (!backend) { + callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, + FileSystemInfo(), base::FilePath(), false); + return; + } + + backend->OpenFileSystem( + url.origin(), url.type(), + OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, + base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL, + this, url, callback)); +} + void FileSystemContext::DeleteFileSystem( const GURL& origin_url, FileSystemType type, @@ -355,6 +384,16 @@ void FileSystemContext::EnableTemporaryFileSystemInIncognito() { } #endif +bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const { +#if defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD) + if (url.type() == kFileSystemTypeTemporary && + sandbox_backend_->enable_temporary_file_system_in_incognito()) { + return true; + } +#endif + return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type()); +} + FileSystemContext::~FileSystemContext() { } @@ -417,8 +456,7 @@ FileSystemURL FileSystemContext::CrackFileSystemURL( return current; } -void FileSystemContext::RegisterBackend( - FileSystemBackend* backend) { +void FileSystemContext::RegisterBackend(FileSystemBackend* backend) { const FileSystemType mount_types[] = { kFileSystemTypeTemporary, kFileSystemTypePersistent, @@ -445,4 +483,35 @@ void FileSystemContext::RegisterBackend( } } +void FileSystemContext::DidOpenFileSystemForResolveURL( + const FileSystemURL& url, + const FileSystemContext::ResolveURLCallback& callback, + const GURL& filesystem_root, + const std::string& filesystem_name, + base::PlatformFileError error) { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + + if (error != base::PLATFORM_FILE_OK) { + callback.Run(error, FileSystemInfo(), base::FilePath(), false); + return; + } + + fileapi::FileSystemInfo info( + filesystem_name, filesystem_root, url.mount_type()); + + // Extract the virtual path not containing a filesystem type part from |url|. + base::FilePath parent = + base::FilePath::FromUTF8Unsafe(filesystem_root.path()); + base::FilePath child = base::FilePath::FromUTF8Unsafe(url.ToGURL().path()); + base::FilePath path; + + if (parent != child) { + bool result = parent.AppendRelativePath(child, &path); + DCHECK(result); + } + + operation_runner()->GetMetadata( + url, base::Bind(&DidGetMetadataForResolveURL, path, callback, info)); +} + } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/file_system_context.h b/chromium/webkit/browser/fileapi/file_system_context.h index d6934ec7c68..21a31b89eb8 100644 --- a/chromium/webkit/browser/fileapi/file_system_context.h +++ b/chromium/webkit/browser/fileapi/file_system_context.h @@ -17,7 +17,7 @@ #include "base/sequenced_task_runner_helpers.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/fileapi/open_file_system_mode.h" -#include "webkit/browser/fileapi/sandbox_context.h" +#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h" #include "webkit/browser/fileapi/task_runner_bound_observer_list.h" #include "webkit/browser/webkit_storage_browser_export.h" #include "webkit/common/fileapi/file_system_types.h" @@ -49,8 +49,8 @@ class CopyOrMoveFileValidatorFactory; class ExternalFileSystemBackend; class ExternalMountPoints; class FileStreamWriter; -class FileSystemFileUtil; class FileSystemBackend; +class FileSystemFileUtil; class FileSystemOperation; class FileSystemOperationRunner; class FileSystemOptions; @@ -61,6 +61,7 @@ class MountPoints; class SandboxFileSystemBackend; struct DefaultContextDeleter; +struct FileSystemInfo; // This class keeps and provides a file system context for FileSystem API. // An instance of this class is created and owned by profile. @@ -119,11 +120,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemContext // Returns the appropriate AsyncFileUtil instance for the given |type|. AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) const; - // Returns the appropriate FileUtil instance for the given |type|. - // This may return NULL if it is given an invalid type or the filesystem - // does not support synchronous file operations. - FileSystemFileUtil* GetFileUtil(FileSystemType type) const; - // Returns the appropriate CopyOrMoveFileValidatorFactory for the given // |type|. If |error_code| is PLATFORM_FILE_OK and the result is NULL, // then no validator is required. @@ -159,6 +155,12 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemContext const std::string& name, const GURL& root)> OpenFileSystemCallback; + // Used for ResolveURL. + typedef base::Callback<void(base::PlatformFileError result, + const FileSystemInfo& info, + const base::FilePath& file_path, + bool is_directory)> ResolveURLCallback; + // Used for DeleteFileSystem. typedef base::Callback<void(base::PlatformFileError result)> DeleteFileSystemCallback; @@ -174,8 +176,15 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemContext OpenFileSystemMode mode, const OpenFileSystemCallback& callback); + // Opens the filesystem for the given |url| as read-only, and then checks the + // existence of the file entry referred by the URL. This should be called on + // the IO thread. + void ResolveURL( + const FileSystemURL& url, + const ResolveURLCallback& callback); + // Deletes the filesystem for the given |origin_url| and |type|. This should - // be called on the IO Thread. + // be called on the IO thread. void DeleteFileSystem( const GURL& origin_url, FileSystemType type, @@ -228,7 +237,13 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemContext void EnableTemporaryFileSystemInIncognito(); #endif - SandboxContext* sandbox_context() { return sandbox_context_.get(); } + SandboxFileSystemBackendDelegate* sandbox_delegate() { + return sandbox_delegate_.get(); + } + + // Returns true if the requested url is ok to be served. + // (E.g. this returns false if the context is created for incognito mode) + bool CanServeURLRequest(const FileSystemURL& url) const; private: typedef std::map<FileSystemType, FileSystemBackend*> @@ -273,6 +288,13 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemContext // the constructor. void RegisterBackend(FileSystemBackend* backend); + void DidOpenFileSystemForResolveURL( + const FileSystemURL& url, + const ResolveURLCallback& callback, + const GURL& filesystem_root, + const std::string& filesystem_name, + base::PlatformFileError error); + // Returns a FileSystemBackend, used only by test code. SandboxFileSystemBackend* sandbox_backend() const { return sandbox_backend_.get(); @@ -283,7 +305,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemContext scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_; - scoped_ptr<SandboxContext> sandbox_context_; + scoped_ptr<SandboxFileSystemBackendDelegate> sandbox_delegate_; // Regular file system backends. scoped_ptr<SandboxFileSystemBackend> sandbox_backend_; @@ -311,6 +333,8 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemContext // The base path of the storage partition for this context. const base::FilePath partition_path_; + bool is_incognito_; + scoped_ptr<FileSystemOperationRunner> operation_runner_; DISALLOW_IMPLICIT_CONSTRUCTORS(FileSystemContext); diff --git a/chromium/webkit/browser/fileapi/file_system_dir_url_request_job.cc b/chromium/webkit/browser/fileapi/file_system_dir_url_request_job.cc index b91c7d00d9d..721a228b94e 100644 --- a/chromium/webkit/browser/fileapi/file_system_dir_url_request_job.cc +++ b/chromium/webkit/browser/fileapi/file_system_dir_url_request_job.cc @@ -23,6 +23,7 @@ #include "webkit/browser/fileapi/file_system_operation_runner.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/common/fileapi/directory_entry.h" +#include "webkit/common/fileapi/file_system_util.h" using net::NetworkDelegate; using net::URLRequest; @@ -80,6 +81,19 @@ void FileSystemDirURLRequestJob::StartAsync() { if (!request_) return; url_ = file_system_context_->CrackURL(request_->url()); + if (!file_system_context_->CanServeURLRequest(url_)) { + // In incognito mode the API is not usable and there should be no data. + if (url_.is_valid() && VirtualPath::IsRootPath(url_.virtual_path())) { + // Return an empty directory if the filesystem root is queried. + DidReadDirectory(base::PLATFORM_FILE_OK, + std::vector<DirectoryEntry>(), + false); + return; + } + NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, + net::ERR_FILE_NOT_FOUND)); + return; + } file_system_context_->operation_runner()->ReadDirectory( url_, base::Bind(&FileSystemDirURLRequestJob::DidReadDirectory, this)); diff --git a/chromium/webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc b/chromium/webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc index 1c197cd294d..e43ee4dfa3b 100644 --- a/chromium/webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc +++ b/chromium/webkit/browser/fileapi/file_system_dir_url_request_job_unittest.cc @@ -12,6 +12,7 @@ #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/platform_file.h" +#include "base/run_loop.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" #include "net/base/net_errors.h" @@ -57,7 +58,7 @@ class FileSystemDirURLRequestJobTest : public testing::Test { OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, base::Bind(&FileSystemDirURLRequestJobTest::OnOpenFileSystem, weak_factory_.GetWeakPtr())); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); net::URLRequest::Deprecated::RegisterProtocolFactory( "filesystem", &FileSystemDirURLRequestJobFactory); @@ -78,12 +79,13 @@ class FileSystemDirURLRequestJobTest : public testing::Test { ASSERT_EQ(base::PLATFORM_FILE_OK, result); } - void TestRequestHelper(const GURL& url, bool run_to_completion) { + void TestRequestHelper(const GURL& url, bool run_to_completion, + FileSystemContext* file_system_context) { delegate_.reset(new net::TestDelegate()); delegate_->set_quit_on_redirect(true); request_.reset(empty_context_.CreateRequest(url, delegate_.get())); job_ = new FileSystemDirURLRequestJob( - request_.get(), NULL, file_system_context_.get()); + request_.get(), NULL, file_system_context); request_->Start(); ASSERT_TRUE(request_->is_pending()); // verify that we're starting async @@ -92,11 +94,16 @@ class FileSystemDirURLRequestJobTest : public testing::Test { } void TestRequest(const GURL& url) { - TestRequestHelper(url, true); + TestRequestHelper(url, true, file_system_context_.get()); + } + + void TestRequestWithContext(const GURL& url, + FileSystemContext* file_system_context) { + TestRequestHelper(url, true, file_system_context); } void TestRequestNoRun(const GURL& url) { - TestRequestHelper(url, false); + TestRequestHelper(url, false, file_system_context_.get()); } FileSystemURL CreateURL(const base::FilePath& file_path) { @@ -199,7 +206,7 @@ class FileSystemDirURLRequestJobTest : public testing::Test { } FileSystemFileUtil* file_util() { - return file_system_context_->GetFileUtil(kFileSystemTypeTemporary); + return file_system_context_->sandbox_delegate()->sync_file_util(); } // Put the message loop at the top, so that it's the last thing deleted. @@ -282,9 +289,32 @@ TEST_F(FileSystemDirURLRequestJobTest, Cancel) { TestRequestNoRun(CreateFileSystemURL("foo/")); // Run StartAsync() and only StartAsync(). base::MessageLoop::current()->DeleteSoon(FROM_HERE, request_.release()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); // If we get here, success! we didn't crash! } +TEST_F(FileSystemDirURLRequestJobTest, Incognito) { + CreateDirectory("foo"); + + scoped_refptr<FileSystemContext> file_system_context = + CreateIncognitoFileSystemContextForTesting(NULL, temp_dir_.path()); + + TestRequestWithContext(CreateFileSystemURL("/"), + file_system_context.get()); + ASSERT_FALSE(request_->is_pending()); + ASSERT_TRUE(request_->status().is_success()); + + std::istringstream in(delegate_->data_received()); + std::string line; + EXPECT_TRUE(std::getline(in, line)); + EXPECT_FALSE(std::getline(in, line)); + + TestRequestWithContext(CreateFileSystemURL("foo"), + file_system_context.get()); + ASSERT_FALSE(request_->is_pending()); + ASSERT_FALSE(request_->status().is_success()); + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error()); +} + } // namespace (anonymous) } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/file_system_file_stream_reader.cc b/chromium/webkit/browser/fileapi/file_system_file_stream_reader.cc index 71b38278186..d3697c201e5 100644 --- a/chromium/webkit/browser/fileapi/file_system_file_stream_reader.cc +++ b/chromium/webkit/browser/fileapi/file_system_file_stream_reader.cc @@ -10,11 +10,29 @@ #include "net/base/file_stream.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" -#include "webkit/browser/blob/local_file_stream_reader.h" +#include "webkit/browser/blob/file_stream_reader.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_operation_runner.h" -using webkit_blob::LocalFileStreamReader; +using webkit_blob::FileStreamReader; + +// TODO(kinuko): Remove this temporary namespace hack after we move both +// blob and fileapi into content namespace. +namespace webkit_blob { + +FileStreamReader* FileStreamReader::CreateForFileSystemFile( + fileapi::FileSystemContext* file_system_context, + const fileapi::FileSystemURL& url, + int64 initial_offset, + const base::Time& expected_modification_time) { + return new fileapi::FileSystemFileStreamReader( + file_system_context, + url, + initial_offset, + expected_modification_time); +} + +} // webkit_blob namespace fileapi { @@ -46,19 +64,6 @@ void Int64CallbackAdapter(const net::Int64CompletionCallback& callback, } // namespace -FileSystemFileStreamReader::FileSystemFileStreamReader( - FileSystemContext* file_system_context, - const FileSystemURL& url, - int64 initial_offset, - const base::Time& expected_modification_time) - : file_system_context_(file_system_context), - url_(url), - initial_offset_(initial_offset), - expected_modification_time_(expected_modification_time), - has_pending_create_snapshot_(false), - weak_factory_(this) { -} - FileSystemFileStreamReader::~FileSystemFileStreamReader() { } @@ -82,6 +87,19 @@ int64 FileSystemFileStreamReader::GetLength( base::Bind(&Int64CallbackAdapter, callback)); } +FileSystemFileStreamReader::FileSystemFileStreamReader( + FileSystemContext* file_system_context, + const FileSystemURL& url, + int64 initial_offset, + const base::Time& expected_modification_time) + : file_system_context_(file_system_context), + url_(url), + initial_offset_(initial_offset), + expected_modification_time_(expected_modification_time), + has_pending_create_snapshot_(false), + weak_factory_(this) { +} + int FileSystemFileStreamReader::CreateSnapshot( const base::Closure& callback, const net::CompletionCallback& error_callback) { @@ -116,7 +134,7 @@ void FileSystemFileStreamReader::DidCreateSnapshot( snapshot_ref_ = file_ref; local_file_reader_.reset( - new LocalFileStreamReader( + FileStreamReader::CreateForLocalFile( file_system_context_->default_file_task_runner(), platform_path, initial_offset_, expected_modification_time_)); diff --git a/chromium/webkit/browser/fileapi/file_system_file_stream_reader.h b/chromium/webkit/browser/fileapi/file_system_file_stream_reader.h index 634f5684c42..3a90663ed95 100644 --- a/chromium/webkit/browser/fileapi/file_system_file_stream_reader.h +++ b/chromium/webkit/browser/fileapi/file_system_file_stream_reader.h @@ -19,30 +19,18 @@ class FilePath; class SequencedTaskRunner; } -namespace webkit_blob { -class LocalFileStreamReader; -} - namespace fileapi { class FileSystemContext; -// TODO(kinaba,satorux): This generic implementation would work for any -// filesystems but remote filesystem should implement its own reader -// rather than relying on FileSystemOperation::GetSnapshotFile() which -// may force downloading the entire contents for remote files. +// Generic FileStreamReader implementation for FileSystem files. +// Note: This generic implementation would work for any filesystems but +// remote filesystem should implement its own reader rather than relying +// on FileSystemOperation::GetSnapshotFile() which may force downloading +// the entire contents for remote files. class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE FileSystemFileStreamReader - : public webkit_blob::FileStreamReader { + : public NON_EXPORTED_BASE(webkit_blob::FileStreamReader) { public: - // Creates a new FileReader for a filesystem URL |url| form |initial_offset|. - // |expected_modification_time| specifies the expected last modification if - // the value is non-null, the reader will check the underlying file's actual - // modification time to see if the file has been modified, and if it does any - // succeeding read operations should fail with ERR_UPLOAD_FILE_CHANGED error. - FileSystemFileStreamReader(FileSystemContext* file_system_context, - const FileSystemURL& url, - int64 initial_offset, - const base::Time& expected_modification_time); virtual ~FileSystemFileStreamReader(); // FileStreamReader overrides. @@ -52,6 +40,14 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE FileSystemFileStreamReader const net::Int64CompletionCallback& callback) OVERRIDE; private: + friend class webkit_blob::FileStreamReader; + friend class FileSystemFileStreamReaderTest; + + FileSystemFileStreamReader(FileSystemContext* file_system_context, + const FileSystemURL& url, + int64 initial_offset, + const base::Time& expected_modification_time); + int CreateSnapshot(const base::Closure& callback, const net::CompletionCallback& error_callback); void DidCreateSnapshot( @@ -66,7 +62,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE FileSystemFileStreamReader FileSystemURL url_; const int64 initial_offset_; const base::Time expected_modification_time_; - scoped_ptr<webkit_blob::LocalFileStreamReader> local_file_reader_; + scoped_ptr<webkit_blob::FileStreamReader> local_file_reader_; scoped_refptr<webkit_blob::ShareableFileReference> snapshot_ref_; bool has_pending_create_snapshot_; base::WeakPtrFactory<FileSystemFileStreamReader> weak_factory_; diff --git a/chromium/webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc b/chromium/webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc index ca82338a5cc..0ce56585e42 100644 --- a/chromium/webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc +++ b/chromium/webkit/browser/fileapi/file_system_file_stream_reader_unittest.cc @@ -9,16 +9,16 @@ #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/platform_file.h" +#include "base/run_loop.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webkit/browser/fileapi/async_file_test_helper.h" #include "webkit/browser/fileapi/external_mount_points.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_file_util.h" -#include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/mock_file_system_context.h" namespace fileapi { @@ -73,14 +73,14 @@ class FileSystemFileStreamReaderTest : public testing::Test { GURL(kURLOrigin), kFileSystemTypeTemporary, OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, base::Bind(&OnOpenFileSystem)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); WriteFile(kTestFileName, kTestData, kTestDataSize, &test_file_modification_time_); } virtual void TearDown() OVERRIDE { - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } protected: @@ -102,32 +102,16 @@ class FileSystemFileStreamReaderTest : public testing::Test { const char* buf, int buf_size, base::Time* modification_time) { - FileSystemFileUtil* file_util = file_system_context_->GetFileUtil( - kFileSystemTypeTemporary); FileSystemURL url = GetFileSystemURL(file_name); - FileSystemOperationContext context(file_system_context_.get()); - context.set_allowed_bytes_growth(1024); - - base::PlatformFile handle = base::kInvalidPlatformFileValue; - bool created = false; - ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateOrOpen( - &context, - url, - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, - &handle, - &created)); - EXPECT_TRUE(created); - ASSERT_NE(base::kInvalidPlatformFileValue, handle); - ASSERT_EQ(buf_size, - base::WritePlatformFile(handle, 0 /* offset */, buf, buf_size)); - base::ClosePlatformFile(handle); + ASSERT_EQ(base::PLATFORM_FILE_OK, + fileapi::AsyncFileTestHelper::CreateFileWithData( + file_system_context_, url, buf, buf_size)); base::PlatformFileInfo file_info; - base::FilePath platform_path; ASSERT_EQ(base::PLATFORM_FILE_OK, - file_util->GetFileInfo(&context, url, &file_info, - &platform_path)); + AsyncFileTestHelper::GetMetadata( + file_system_context_, url, &file_info)); if (modification_time) *modification_time = file_info.last_modified; } diff --git a/chromium/webkit/browser/fileapi/file_system_operation.h b/chromium/webkit/browser/fileapi/file_system_operation.h index f1adc191a7e..99d3b3d6a97 100644 --- a/chromium/webkit/browser/fileapi/file_system_operation.h +++ b/chromium/webkit/browser/fileapi/file_system_operation.h @@ -11,6 +11,8 @@ #include "base/files/file_path.h" #include "base/platform_file.h" #include "base/process/process.h" +#include "webkit/browser/fileapi/file_system_operation_context.h" +#include "webkit/browser/webkit_storage_browser_export.h" #include "webkit/common/fileapi/directory_entry.h" namespace base { @@ -29,9 +31,9 @@ class GURL; namespace fileapi { +class FileSystemContext; class FileSystemURL; class FileWriterDelegate; -class FileSystemOperationImpl; // The interface class for FileSystemOperation implementations. // @@ -56,6 +58,11 @@ class FileSystemOperationImpl; // it gets called. class FileSystemOperation { public: + WEBKIT_STORAGE_BROWSER_EXPORT static FileSystemOperation* Create( + const FileSystemURL& url, + FileSystemContext* file_system_context, + scoped_ptr<FileSystemOperationContext> operation_context); + virtual ~FileSystemOperation() {} // Used for CreateFile(), etc. |result| is the return code of the operation. @@ -115,6 +122,93 @@ class FileSystemOperation { const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref)> SnapshotFileCallback; + // Used for progress update callback for Copy(). + // + // BEGIN_COPY_ENTRY is fired for each copy creation beginning (for both + // file and directory). + // The |source_url| is the URL of the source entry. |size| should not be + // used. + // + // END_COPY_ENTRY is fired for each copy creation finishing (for both + // file and directory). + // The |source_url| is the URL of the source entry. The |destination_url| is + // the URL of the destination entry. |size| should not be used. + // + // PROGRESS is fired periodically during file copying (not fired for + // directory copy). + // The |source_url| is the URL of the source file. |size| is the number + // of cumulative copied bytes for the currently copied file. + // Both at beginning and ending of file copying, PROGRESS event should be + // called. At beginning, |size| should be 0. At ending, |size| should be + // the size of the file. + // + // Here is an example callback sequence of recursive copy. Suppose + // there are a/b/c.txt (100 bytes) and a/b/d.txt (200 bytes), and trying to + // copy a to x recursively, then the progress update sequence will be: + // + // BEGIN_COPY_ENTRY a (starting create "a" directory in x/). + // END_COPY_ENTRY a x/a (creating "a" directory in x/ is finished). + // + // BEGIN_COPY_ENTRY a/b (starting create "b" directory in x/a). + // END_COPY_ENTRY a/b x/a/b (creating "b" directory in x/a/ is finished). + // + // BEGIN_COPY_ENTRY a/b/c.txt (starting to copy "c.txt" in x/a/b/). + // PROGRESS a/b/c.txt 0 (The first PROGRESS's |size| should be 0). + // PROGRESS a/b/c.txt 10 + // : + // PROGRESS a/b/c.txt 90 + // PROGRESS a/b/c.txt 100 (The last PROGRESS's |size| should be the size of + // the file). + // END_COPY_ENTRY a/b/c.txt x/a/b/c.txt (copying "c.txt" is finished). + // + // BEGIN_COPY_ENTRY a/b/d.txt (starting to copy "d.txt" in x/a/b). + // PROGRESS a/b/d.txt 0 (The first PROGRESS's |size| should be 0). + // PROGRESS a/b/d.txt 10 + // : + // PROGRESS a/b/d.txt 190 + // PROGRESS a/b/d.txt 200 (The last PROGRESS's |size| should be the size of + // the file). + // END_COPY_ENTRY a/b/d.txt x/a/b/d.txt (copy "d.txt" is finished). + // + // Note that event sequence of a/b/c.txt and a/b/d.txt can be interlaced, + // because they can be done in parallel. Also PROGRESS events are optional, + // so they may not be appeared. + // All the progress callback invocation should be done before StatusCallback + // given to the Copy is called. Especially if an error is found before first + // progres callback invocation, the progress callback may NOT invoked for the + // copy. + // + // Note for future extension. Currently this callback is only supported on + // Copy(). We can extend this to Move(), because Move() is sometimes + // implemented as "copy then delete." + // In more precise, Move() usually can be implemented either 1) by updating + // the metadata of resource (e.g. root of moving directory tree), or 2) by + // copying directory tree and them removing the source tree. + // For 1)'s case, we can simply add BEGIN_MOVE_ENTRY and END_MOVE_ENTRY + // for root directory. + // For 2)'s case, we can add BEGIN_DELETE_ENTRY and END_DELETE_ENTRY for each + // entry. + // For both cases, we probably won't need to use PROGRESS event because + // these operations should be done quickly (at least much faster than copying + // usually). + enum CopyProgressType { + BEGIN_COPY_ENTRY, + END_COPY_ENTRY, + PROGRESS, + }; + typedef base::Callback<void(CopyProgressType type, + const FileSystemURL& source_url, + const FileSystemURL& destination_url, + int64 size)> + CopyProgressCallback; + + // Used for CopyFileLocal() to report progress update. + // |size| is the cumulative copied bytes for the copy. + // At the beginning the progress callback should be called with |size| = 0, + // and also at the ending the progress callback should be called with |size| + // set to the copied file size. + typedef base::Callback<void(int64 size)> CopyFileProgressCallback; + // Used for Write(). typedef base::Callback<void(base::PlatformFileError result, int64 bytes, @@ -139,12 +233,34 @@ class FileSystemOperation { // |src_path| is a directory, the contents of |src_path| are copied to // |dest_path| recursively. A new file or directory is created at // |dest_path| as needed. + // |progress_callback| is periodically called to report the progress + // update. See also the comment of CopyProgressCallback. This callback is + // optional. + // + // For recursive case this internally creates new FileSystemOperations and + // calls: + // - ReadDirectory, CopyFileLocal and CreateDirectory + // for same-filesystem case, or + // - ReadDirectory and CreateSnapshotFile on source filesystem and + // CopyInForeignFile and CreateDirectory on dest filesystem + // for cross-filesystem case. + // virtual void Copy(const FileSystemURL& src_path, const FileSystemURL& dest_path, + const CopyProgressCallback& progress_callback, const StatusCallback& callback) = 0; // Moves a file or directory from |src_path| to |dest_path|. A new file // or directory is created at |dest_path| as needed. + // + // For recursive case this internally creates new FileSystemOperations and + // calls: + // - ReadDirectory, MoveFileLocal, CreateDirectory and Remove + // for same-filesystem case, or + // - ReadDirectory, CreateSnapshotFile and Remove on source filesystem and + // CopyInForeignFile and CreateDirectory on dest filesystem + // for cross-filesystem case. + // virtual void Move(const FileSystemURL& src_path, const FileSystemURL& dest_path, const StatusCallback& callback) = 0; @@ -230,11 +346,6 @@ class FileSystemOperation { base::ProcessHandle peer_handle, const OpenFileCallback& callback) = 0; - // For downcasting to FileSystemOperationImpl. - // TODO(kinuko): this hack should go away once appropriate upload-stream - // handling based on element types is supported. - virtual FileSystemOperationImpl* AsFileSystemOperationImpl() = 0; - // Creates a local snapshot file for a given |path| and returns the // metadata and platform path of the snapshot file via |callback|. // In local filesystem cases the implementation may simply return @@ -246,6 +357,86 @@ class FileSystemOperation { virtual void CreateSnapshotFile(const FileSystemURL& path, const SnapshotFileCallback& callback) = 0; + // Copies in a single file from a different filesystem. + // + // This returns: + // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_file_path| + // or the parent directory of |dest_url| does not exist. + // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and + // is not a file. + // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and + // its parent path is a file. + // + virtual void CopyInForeignFile(const base::FilePath& src_local_disk_path, + const FileSystemURL& dest_url, + const StatusCallback& callback) = 0; + + // Removes a single file. + // + // This returns: + // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist. + // - PLATFORM_FILE_ERROR_NOT_A_FILE if |url| is not a file. + // + virtual void RemoveFile(const FileSystemURL& url, + const StatusCallback& callback) = 0; + + // Removes a single empty directory. + // + // This returns: + // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist. + // - PLATFORM_FILE_ERROR_NOT_A_DIRECTORY if |url| is not a directory. + // - PLATFORM_FILE_ERROR_NOT_EMPTY if |url| is not empty. + // + virtual void RemoveDirectory(const FileSystemURL& url, + const StatusCallback& callback) = 0; + + // Copies a file from |src_url| to |dest_url|. + // This must be called for files that belong to the same filesystem + // (i.e. type() and origin() of the |src_url| and |dest_url| must match). + // |progress_callback| is periodically called to report the progress + // update. See also the comment of CopyFileProgressCallback. This callback is + // optional. + // + // This returns: + // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url| + // or the parent directory of |dest_url| does not exist. + // - PLATFORM_FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file. + // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and + // is not a file. + // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and + // its parent path is a file. + // + virtual void CopyFileLocal(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, + const StatusCallback& callback) = 0; + + // Moves a local file from |src_url| to |dest_url|. + // This must be called for files that belong to the same filesystem + // (i.e. type() and origin() of the |src_url| and |dest_url| must match). + // + // This returns: + // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url| + // or the parent directory of |dest_url| does not exist. + // - PLATFORM_FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file. + // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and + // is not a file. + // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and + // its parent path is a file. + // + virtual void MoveFileLocal(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback) = 0; + + // Synchronously gets the platform path for the given |url|. + // This may fail if the given |url|'s filesystem type is neither + // temporary nor persistent. + // In such a case, base::PLATFORM_FILE_ERROR_INVALID_OPERATION will be + // returned. + virtual base::PlatformFileError SyncGetPlatformPath( + const FileSystemURL& url, + base::FilePath* platform_path) = 0; + protected: // Used only for internal assertions. enum OperationType { diff --git a/chromium/webkit/browser/fileapi/file_system_operation_context.h b/chromium/webkit/browser/fileapi/file_system_operation_context.h index 4d175108482..decdecbb5ca 100644 --- a/chromium/webkit/browser/fileapi/file_system_operation_context.h +++ b/chromium/webkit/browser/fileapi/file_system_operation_context.h @@ -52,7 +52,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE FileSystemOperationContext int64 allowed_bytes_growth() const { return allowed_bytes_growth_; } quota::QuotaLimitType quota_limit_type() const { return quota_limit_type_; } base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); } - const base::FilePath& root_path() const { return root_path_; } ChangeObserverList* change_observers() { return &change_observers_; } UpdateObserverList* update_observers() { return &update_observers_; } @@ -72,10 +71,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE FileSystemOperationContext DCHECK(setter_thread_checker_.CalledOnValidThread()); quota_limit_type_ = limit_type; } - void set_root_path(const base::FilePath& root_path) { - DCHECK(setter_thread_checker_.CalledOnValidThread()); - root_path_ = root_path; - } private: scoped_refptr<FileSystemContext> file_system_context_; @@ -91,9 +86,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE FileSystemOperationContext ChangeObserverList change_observers_; UpdateObserverList update_observers_; - // Root path for the operation, used by LocalFileUtil. - base::FilePath root_path_; - // Used to check its setters are not called on arbitrary thread. base::ThreadChecker setter_thread_checker_; diff --git a/chromium/webkit/browser/fileapi/file_system_operation_impl.cc b/chromium/webkit/browser/fileapi/file_system_operation_impl.cc index 60f79901923..c9e75eb9acd 100644 --- a/chromium/webkit/browser/fileapi/file_system_operation_impl.cc +++ b/chromium/webkit/browser/fileapi/file_system_operation_impl.cc @@ -20,7 +20,7 @@ #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/fileapi/file_writer_delegate.h" #include "webkit/browser/fileapi/remove_operation_delegate.h" -#include "webkit/browser/fileapi/sandbox_file_stream_writer.h" +#include "webkit/browser/fileapi/sandbox_file_system_backend.h" #include "webkit/browser/quota/quota_manager.h" #include "webkit/common/blob/shareable_file_reference.h" #include "webkit/common/fileapi/file_system_types.h" @@ -31,19 +31,12 @@ using webkit_blob::ScopedFile; namespace fileapi { -FileSystemOperationImpl::FileSystemOperationImpl( +FileSystemOperation* FileSystemOperation::Create( const FileSystemURL& url, FileSystemContext* file_system_context, - scoped_ptr<FileSystemOperationContext> operation_context) - : file_system_context_(file_system_context), - operation_context_(operation_context.Pass()), - async_file_util_(NULL), - peer_handle_(base::kNullProcessHandle), - pending_operation_(kOperationNone) { - DCHECK(operation_context_.get()); - operation_context_->DetachUserDataThread(); - async_file_util_ = file_system_context_->GetAsyncFileUtil(url.type()); - DCHECK(async_file_util_); + scoped_ptr<FileSystemOperationContext> operation_context) { + return new FileSystemOperationImpl(url, file_system_context, + operation_context.Pass()); } FileSystemOperationImpl::~FileSystemOperationImpl() { @@ -56,7 +49,7 @@ void FileSystemOperationImpl::CreateFile(const FileSystemURL& url, GetUsageAndQuotaThenRunTask( url, base::Bind(&FileSystemOperationImpl::DoCreateFile, - AsWeakPtr(), url, callback, exclusive), + weak_factory_.GetWeakPtr(), url, callback, exclusive), base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); } @@ -68,22 +61,28 @@ void FileSystemOperationImpl::CreateDirectory(const FileSystemURL& url, GetUsageAndQuotaThenRunTask( url, base::Bind(&FileSystemOperationImpl::DoCreateDirectory, - AsWeakPtr(), url, callback, exclusive, recursive), + weak_factory_.GetWeakPtr(), url, callback, + exclusive, recursive), base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); } -void FileSystemOperationImpl::Copy(const FileSystemURL& src_url, - const FileSystemURL& dest_url, - const StatusCallback& callback) { +void FileSystemOperationImpl::Copy( + const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const CopyProgressCallback& progress_callback, + const StatusCallback& callback) { DCHECK(SetPendingOperationType(kOperationCopy)); DCHECK(!recursive_operation_delegate_); + + // TODO(hidehiko): Support |progress_callback|. (crbug.com/278038). recursive_operation_delegate_.reset( new CopyOrMoveOperationDelegate( file_system_context(), src_url, dest_url, CopyOrMoveOperationDelegate::OPERATION_COPY, + progress_callback, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback))); + weak_factory_.GetWeakPtr(), callback))); recursive_operation_delegate_->RunRecursively(); } @@ -97,8 +96,9 @@ void FileSystemOperationImpl::Move(const FileSystemURL& src_url, file_system_context(), src_url, dest_url, CopyOrMoveOperationDelegate::OPERATION_MOVE, + FileSystemOperation::CopyProgressCallback(), base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback))); + weak_factory_.GetWeakPtr(), callback))); recursive_operation_delegate_->RunRecursively(); } @@ -108,7 +108,7 @@ void FileSystemOperationImpl::DirectoryExists(const FileSystemURL& url, async_file_util_->GetFileInfo( operation_context_.Pass(), url, base::Bind(&FileSystemOperationImpl::DidDirectoryExists, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::FileExists(const FileSystemURL& url, @@ -117,7 +117,7 @@ void FileSystemOperationImpl::FileExists(const FileSystemURL& url, async_file_util_->GetFileInfo( operation_context_.Pass(), url, base::Bind(&FileSystemOperationImpl::DidFileExists, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::GetMetadata( @@ -146,7 +146,7 @@ void FileSystemOperationImpl::Remove(const FileSystemURL& url, async_file_util_->DeleteRecursively( operation_context_.Pass(), url, base::Bind(&FileSystemOperationImpl::DidDeleteRecursively, - AsWeakPtr(), url, callback)); + weak_factory_.GetWeakPtr(), url, callback)); return; } @@ -154,7 +154,7 @@ void FileSystemOperationImpl::Remove(const FileSystemURL& url, new RemoveOperationDelegate( file_system_context(), url, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback))); + weak_factory_.GetWeakPtr(), callback))); recursive_operation_delegate_->Run(); } @@ -167,8 +167,8 @@ void FileSystemOperationImpl::Write( file_writer_delegate_ = writer_delegate.Pass(); file_writer_delegate_->Start( blob_request.Pass(), - base::Bind(&FileSystemOperationImpl::DidWrite, AsWeakPtr(), - url, callback)); + base::Bind(&FileSystemOperationImpl::DidWrite, + weak_factory_.GetWeakPtr(), url, callback)); } void FileSystemOperationImpl::Truncate(const FileSystemURL& url, int64 length, @@ -177,7 +177,7 @@ void FileSystemOperationImpl::Truncate(const FileSystemURL& url, int64 length, GetUsageAndQuotaThenRunTask( url, base::Bind(&FileSystemOperationImpl::DoTruncate, - AsWeakPtr(), url, callback, length), + weak_factory_.GetWeakPtr(), url, callback, length), base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); } @@ -190,7 +190,7 @@ void FileSystemOperationImpl::TouchFile(const FileSystemURL& url, operation_context_.Pass(), url, last_access_time, last_modified_time, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::OpenFile(const FileSystemURL& url, @@ -212,7 +212,7 @@ void FileSystemOperationImpl::OpenFile(const FileSystemURL& url, GetUsageAndQuotaThenRunTask( url, base::Bind(&FileSystemOperationImpl::DoOpenFile, - AsWeakPtr(), + weak_factory_.GetWeakPtr(), url, callback, file_flags), base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED, base::kInvalidPlatformFileValue, @@ -230,6 +230,9 @@ void FileSystemOperationImpl::Cancel(const StatusCallback& cancel_callback) { DCHECK_EQ(kOperationWrite, pending_operation_); // This will call DidWrite() with ABORT status code. file_writer_delegate_->Cancel(); + } else if (recursive_operation_delegate_) { + // This will call DidFinishOperation() with ABORT status code. + recursive_operation_delegate_->Cancel(); } else { // For truncate we have no way to cancel the inflight operation (for now). // Let it just run and dispatch cancel callback later. @@ -237,22 +240,6 @@ void FileSystemOperationImpl::Cancel(const StatusCallback& cancel_callback) { } } -FileSystemOperationImpl* FileSystemOperationImpl::AsFileSystemOperationImpl() { - return this; -} - -base::PlatformFileError FileSystemOperationImpl::SyncGetPlatformPath( - const FileSystemURL& url, - base::FilePath* platform_path) { - DCHECK(SetPendingOperationType(kOperationGetLocalPath)); - FileSystemFileUtil* file_util = file_system_context()->GetFileUtil( - url.type()); - if (!file_util) - return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; - file_util->GetLocalFilePath(operation_context_.get(), url, platform_path); - return base::PLATFORM_FILE_OK; -} - void FileSystemOperationImpl::CreateSnapshotFile( const FileSystemURL& url, const SnapshotFileCallback& callback) { @@ -269,7 +256,7 @@ void FileSystemOperationImpl::CopyInForeignFile( GetUsageAndQuotaThenRunTask( dest_url, base::Bind(&FileSystemOperationImpl::DoCopyInForeignFile, - AsWeakPtr(), src_local_disk_file_path, dest_url, + weak_factory_.GetWeakPtr(), src_local_disk_file_path, dest_url, callback), base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); } @@ -281,7 +268,7 @@ void FileSystemOperationImpl::RemoveFile( async_file_util_->DeleteFile( operation_context_.Pass(), url, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::RemoveDirectory( @@ -291,19 +278,22 @@ void FileSystemOperationImpl::RemoveDirectory( async_file_util_->DeleteDirectory( operation_context_.Pass(), url, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::CopyFileLocal( const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, const StatusCallback& callback) { DCHECK(SetPendingOperationType(kOperationCopy)); DCHECK(src_url.IsInSameFileSystem(dest_url)); + GetUsageAndQuotaThenRunTask( dest_url, base::Bind(&FileSystemOperationImpl::DoCopyFileLocal, - AsWeakPtr(), src_url, dest_url, callback), + weak_factory_.GetWeakPtr(), src_url, dest_url, + progress_callback, callback), base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); } @@ -316,10 +306,38 @@ void FileSystemOperationImpl::MoveFileLocal( GetUsageAndQuotaThenRunTask( dest_url, base::Bind(&FileSystemOperationImpl::DoMoveFileLocal, - AsWeakPtr(), src_url, dest_url, callback), + weak_factory_.GetWeakPtr(), src_url, dest_url, callback), base::Bind(callback, base::PLATFORM_FILE_ERROR_FAILED)); } +base::PlatformFileError FileSystemOperationImpl::SyncGetPlatformPath( + const FileSystemURL& url, + base::FilePath* platform_path) { + DCHECK(SetPendingOperationType(kOperationGetLocalPath)); + if (!file_system_context()->IsSandboxFileSystem(url.type())) + return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; + FileSystemFileUtil* file_util = + file_system_context()->sandbox_delegate()->sync_file_util(); + file_util->GetLocalFilePath(operation_context_.get(), url, platform_path); + return base::PLATFORM_FILE_OK; +} + +FileSystemOperationImpl::FileSystemOperationImpl( + const FileSystemURL& url, + FileSystemContext* file_system_context, + scoped_ptr<FileSystemOperationContext> operation_context) + : file_system_context_(file_system_context), + operation_context_(operation_context.Pass()), + async_file_util_(NULL), + peer_handle_(base::kNullProcessHandle), + pending_operation_(kOperationNone), + weak_factory_(this) { + DCHECK(operation_context_.get()); + operation_context_->DetachUserDataThread(); + async_file_util_ = file_system_context_->GetAsyncFileUtil(url.type()); + DCHECK(async_file_util_); +} + void FileSystemOperationImpl::GetUsageAndQuotaThenRunTask( const FileSystemURL& url, const base::Closure& task, @@ -341,7 +359,7 @@ void FileSystemOperationImpl::GetUsageAndQuotaThenRunTask( url.origin(), FileSystemTypeToQuotaStorageType(url.type()), base::Bind(&FileSystemOperationImpl::DidGetUsageAndQuotaAndRunTask, - AsWeakPtr(), task, error_callback)); + weak_factory_.GetWeakPtr(), task, error_callback)); } void FileSystemOperationImpl::DidGetUsageAndQuotaAndRunTask( @@ -369,7 +387,7 @@ void FileSystemOperationImpl::DoCreateFile( exclusive ? &FileSystemOperationImpl::DidEnsureFileExistsExclusive : &FileSystemOperationImpl::DidEnsureFileExistsNonExclusive, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::DoCreateDirectory( @@ -380,17 +398,18 @@ void FileSystemOperationImpl::DoCreateDirectory( operation_context_.Pass(), url, exclusive, recursive, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::DoCopyFileLocal( const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, const StatusCallback& callback) { async_file_util_->CopyFileLocal( - operation_context_.Pass(), src_url, dest_url, + operation_context_.Pass(), src_url, dest_url, progress_callback, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::DoMoveFileLocal( @@ -400,7 +419,7 @@ void FileSystemOperationImpl::DoMoveFileLocal( async_file_util_->MoveFileLocal( operation_context_.Pass(), src_url, dest_url, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::DoCopyInForeignFile( @@ -411,7 +430,7 @@ void FileSystemOperationImpl::DoCopyInForeignFile( operation_context_.Pass(), src_local_disk_file_path, dest_url, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::DoTruncate(const FileSystemURL& url, @@ -420,7 +439,7 @@ void FileSystemOperationImpl::DoTruncate(const FileSystemURL& url, async_file_util_->Truncate( operation_context_.Pass(), url, length, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::DoOpenFile(const FileSystemURL& url, @@ -429,7 +448,7 @@ void FileSystemOperationImpl::DoOpenFile(const FileSystemURL& url, async_file_util_->CreateOrOpen( operation_context_.Pass(), url, file_flags, base::Bind(&FileSystemOperationImpl::DidOpenFile, - AsWeakPtr(), callback)); + weak_factory_.GetWeakPtr(), callback)); } void FileSystemOperationImpl::DidEnsureFileExistsExclusive( @@ -452,11 +471,13 @@ void FileSystemOperationImpl::DidFinishOperation( const StatusCallback& callback, base::PlatformFileError rv) { if (!cancel_callback_.is_null()) { - DCHECK_EQ(kOperationTruncate, pending_operation_); - StatusCallback cancel_callback = cancel_callback_; - callback.Run(base::PLATFORM_FILE_ERROR_ABORT); - cancel_callback.Run(base::PLATFORM_FILE_OK); + callback.Run(rv); + + // Return OK only if we succeeded to stop the operation. + cancel_callback.Run(rv == base::PLATFORM_FILE_ERROR_ABORT ? + base::PLATFORM_FILE_OK : + base::PLATFORM_FILE_ERROR_INVALID_OPERATION); } else { callback.Run(rv); } @@ -491,7 +512,7 @@ void FileSystemOperationImpl::DidDeleteRecursively( new RemoveOperationDelegate( file_system_context(), url, base::Bind(&FileSystemOperationImpl::DidFinishOperation, - AsWeakPtr(), callback))); + weak_factory_.GetWeakPtr(), callback))); recursive_operation_delegate_->RunRecursively(); return; } diff --git a/chromium/webkit/browser/fileapi/file_system_operation_impl.h b/chromium/webkit/browser/fileapi/file_system_operation_impl.h index 293ac5178d8..8433479f881 100644 --- a/chromium/webkit/browser/fileapi/file_system_operation_impl.h +++ b/chromium/webkit/browser/fileapi/file_system_operation_impl.h @@ -26,18 +26,8 @@ class RecursiveOperationDelegate; // The default implementation of FileSystemOperation for file systems. class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationImpl - : public NON_EXPORTED_BASE(FileSystemOperation), - public base::SupportsWeakPtr<FileSystemOperationImpl> { + : public NON_EXPORTED_BASE(FileSystemOperation) { public: - // NOTE: This constructor should not be called outside FileSystemBackends; - // instead please consider using - // file_system_context->CreateFileSystemOperation() to instantiate - // an appropriate FileSystemOperation. - FileSystemOperationImpl( - const FileSystemURL& url, - FileSystemContext* file_system_context, - scoped_ptr<FileSystemOperationContext> operation_context); - virtual ~FileSystemOperationImpl(); // FileSystemOperation overrides. @@ -50,6 +40,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationImpl const StatusCallback& callback) OVERRIDE; virtual void Copy(const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyProgressCallback& progress_callback, const StatusCallback& callback) OVERRIDE; virtual void Move(const FileSystemURL& src_url, const FileSystemURL& dest_url, @@ -79,90 +70,39 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationImpl base::ProcessHandle peer_handle, const OpenFileCallback& callback) OVERRIDE; virtual void Cancel(const StatusCallback& cancel_callback) OVERRIDE; - virtual FileSystemOperationImpl* AsFileSystemOperationImpl() OVERRIDE; virtual void CreateSnapshotFile( const FileSystemURL& path, const SnapshotFileCallback& callback) OVERRIDE; - - // Copies in a single file from a different filesystem. - // - // This returns: - // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_file_path| - // or the parent directory of |dest_url| does not exist. - // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and - // is not a file. - // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and - // its parent path is a file. - // virtual void CopyInForeignFile(const base::FilePath& src_local_disk_path, const FileSystemURL& dest_url, - const StatusCallback& callback); - - // Removes a single file. - // - // This returns: - // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist. - // - PLATFORM_FILE_ERROR_NOT_A_FILE if |url| is not a file. - // - void RemoveFile(const FileSystemURL& url, - const StatusCallback& callback); - - // Removes a single empty directory. - // - // This returns: - // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist. - // - PLATFORM_FILE_ERROR_NOT_A_DIRECTORY if |url| is not a directory. - // - PLATFORM_FILE_ERROR_NOT_EMPTY if |url| is not empty. - // - void RemoveDirectory(const FileSystemURL& url, - const StatusCallback& callback); - - // Copies a file from |src_url| to |dest_url|. - // This must be called for files that belong to the same filesystem - // (i.e. type() and origin() of the |src_url| and |dest_url| must match). - // - // This returns: - // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url| - // or the parent directory of |dest_url| does not exist. - // - PLATFORM_FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file. - // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and - // is not a file. - // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and - // its parent path is a file. - // - void CopyFileLocal(const FileSystemURL& src_url, - const FileSystemURL& dest_url, - const StatusCallback& callback); - - // Moves a local file from |src_url| to |dest_url|. - // This must be called for files that belong to the same filesystem - // (i.e. type() and origin() of the |src_url| and |dest_url| must match). - // - // This returns: - // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url| - // or the parent directory of |dest_url| does not exist. - // - PLATFORM_FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file. - // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and - // is not a file. - // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and - // its parent path is a file. - // - void MoveFileLocal(const FileSystemURL& src_url, - const FileSystemURL& dest_url, - const StatusCallback& callback); - - // Synchronously gets the platform path for the given |url|. - // This may fail if |file_system_context| returns NULL on GetFileUtil(). - // In such a case, base::PLATFORM_FILE_ERROR_INVALID_OPERATION will be - // returned. - base::PlatformFileError SyncGetPlatformPath(const FileSystemURL& url, - base::FilePath* platform_path); + const StatusCallback& callback) OVERRIDE; + virtual void RemoveFile(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE; + virtual void RemoveDirectory(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE; + virtual void CopyFileLocal(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, + const StatusCallback& callback) OVERRIDE; + virtual void MoveFileLocal(const FileSystemURL& src_url, + const FileSystemURL& dest_url, + const StatusCallback& callback) OVERRIDE; + virtual base::PlatformFileError SyncGetPlatformPath( + const FileSystemURL& url, + base::FilePath* platform_path) OVERRIDE; FileSystemContext* file_system_context() const { return file_system_context_.get(); } - protected: + private: + friend class FileSystemOperation; + + FileSystemOperationImpl( + const FileSystemURL& url, + FileSystemContext* file_system_context, + scoped_ptr<FileSystemOperationContext> operation_context); + // Queries the quota and usage and then runs the given |task|. // If an error occurs during the quota query it runs |error_callback| instead. void GetUsageAndQuotaThenRunTask( @@ -191,6 +131,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationImpl bool recursive); void DoCopyFileLocal(const FileSystemURL& src, const FileSystemURL& dest, + const CopyFileProgressCallback& progress_callback, const StatusCallback& callback); void DoMoveFileLocal(const FileSystemURL& src, const FileSystemURL& dest, @@ -255,6 +196,8 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationImpl // A flag to make sure we call operation only once per instance. OperationType pending_operation_; + base::WeakPtrFactory<FileSystemOperationImpl> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(FileSystemOperationImpl); }; diff --git a/chromium/webkit/browser/fileapi/file_system_operation_impl_unittest.cc b/chromium/webkit/browser/fileapi/file_system_operation_impl_unittest.cc index 083fdeb7dbd..7443aa066d1 100644 --- a/chromium/webkit/browser/fileapi/file_system_operation_impl_unittest.cc +++ b/chromium/webkit/browser/fileapi/file_system_operation_impl_unittest.cc @@ -10,7 +10,7 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -226,7 +226,7 @@ class FileSystemOperationImplTest sandbox_file_system_.type(), usage, quota); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); ASSERT_EQ(quota::kQuotaStatusOk, status); } @@ -239,7 +239,7 @@ class FileSystemOperationImplTest operation_runner()->Remove(url, false /* recursive */, base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); change_observer()->ResetCount(); int64 total_usage; @@ -297,7 +297,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcDoesntExist) { change_observer()->ResetCount(); operation_runner()->Move(URLForPath("a"), URLForPath("b"), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -307,7 +307,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveFailureContainsPath) { FileSystemURL dest_dir(CreateDirectory("src/dest")); operation_runner()->Move(src_dir, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -319,7 +319,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcDirExistsDestFile) { FileSystemURL dest_file(CreateFile("dest/file")); operation_runner()->Move(src_dir, dest_file, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -332,7 +332,7 @@ TEST_F(FileSystemOperationImplTest, FileSystemURL dest_file(CreateFile("dest/file")); operation_runner()->Move(src_dir, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -344,7 +344,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcFileExistsDestDir) { FileSystemURL dest_dir(CreateDirectory("dest")); operation_runner()->Move(src_file, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -354,7 +354,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveFailureDestParentDoesntExist) { FileSystemURL src_dir(CreateDirectory("src")); operation_runner()->Move(src_dir, URLForPath("nonexistent/deset"), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -364,7 +364,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndOverwrite) { FileSystemURL dest_file(CreateFile("dest")); operation_runner()->Move(src_file, dest_file, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(FileExists("dest")); @@ -379,7 +379,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndNew) { FileSystemURL src_file(CreateFile("src")); operation_runner()->Move(src_file, URLForPath("new"), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(FileExists("new")); @@ -393,7 +393,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirAndOverwrite) { FileSystemURL dest_dir(CreateDirectory("dest")); operation_runner()->Move(src_dir, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(DirectoryExists("src")); @@ -412,7 +412,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirAndNew) { operation_runner()->Move(src_dir, URLForPath("dest/new"), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(DirectoryExists("src")); EXPECT_TRUE(DirectoryExists("dest/new")); @@ -430,7 +430,7 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirRecursive) { FileSystemURL dest_dir(CreateDirectory("dest")); operation_runner()->Move(src_dir, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(DirectoryExists("dest/dir")); EXPECT_TRUE(FileExists("dest/dir/sub")); @@ -444,8 +444,9 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirRecursive) { TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcDoesntExist) { operation_runner()->Copy(URLForPath("a"), URLForPath("b"), + FileSystemOperationRunner::CopyProgressCallback(), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -454,8 +455,10 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureContainsPath) { FileSystemURL src_dir(CreateDirectory("src")); FileSystemURL dest_dir(CreateDirectory("src/dir")); - operation_runner()->Copy(src_dir, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_dir, dest_dir, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -466,8 +469,10 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcDirExistsDestFile) { FileSystemURL dest_dir(CreateDirectory("dest")); FileSystemURL dest_file(CreateFile("dest/file")); - operation_runner()->Copy(src_dir, dest_file, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_dir, dest_file, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -479,8 +484,10 @@ TEST_F(FileSystemOperationImplTest, FileSystemURL dest_dir(CreateDirectory("dest")); FileSystemURL dest_file(CreateFile("dest/file")); - operation_runner()->Copy(src_dir, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_dir, dest_dir, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -490,8 +497,10 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcFileExistsDestDir) { FileSystemURL src_file(CreateFile("src")); FileSystemURL dest_dir(CreateDirectory("dest")); - operation_runner()->Copy(src_file, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_file, dest_dir, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -501,8 +510,9 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureDestParentDoesntExist) { FileSystemURL src_dir(CreateDirectory("src")); operation_runner()->Copy(src_dir, URLForPath("nonexistent/dest"), + FileSystemOperationRunner::CopyProgressCallback(), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -512,7 +522,7 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureByQuota) { FileSystemURL src_file(CreateFile("src/file")); FileSystemURL dest_dir(CreateDirectory("dest")); operation_runner()->Truncate(src_file, 6, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_EQ(6, GetFileSize("src/file")); @@ -521,8 +531,10 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureByQuota) { GrantQuotaForCurrentUsage(); AddQuota(6 + dest_path_cost - 1); - operation_runner()->Copy(src_file, dest_file, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_file, dest_file, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status()); EXPECT_FALSE(FileExists("dest/file")); } @@ -531,8 +543,10 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcFileAndOverwrite) { FileSystemURL src_file(CreateFile("src")); FileSystemURL dest_file(CreateFile("dest")); - operation_runner()->Copy(src_file, dest_file, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_file, dest_file, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(FileExists("dest")); EXPECT_EQ(2, quota_manager_proxy()->notify_storage_accessed_count()); @@ -545,8 +559,9 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcFileAndNew) { FileSystemURL src_file(CreateFile("src")); operation_runner()->Copy(src_file, URLForPath("new"), + FileSystemOperationRunner::CopyProgressCallback(), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(FileExists("new")); EXPECT_EQ(2, quota_manager_proxy()->notify_storage_accessed_count()); @@ -559,8 +574,10 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirAndOverwrite) { FileSystemURL src_dir(CreateDirectory("src")); FileSystemURL dest_dir(CreateDirectory("dest")); - operation_runner()->Copy(src_dir, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_dir, dest_dir, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); // Make sure we've overwritten but not copied the source under the |dest_dir|. @@ -577,8 +594,10 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirAndNew) { FileSystemURL src_dir(CreateDirectory("src")); FileSystemURL dest_dir_new(URLForPath("dest")); - operation_runner()->Copy(src_dir, dest_dir_new, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_dir, dest_dir_new, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(DirectoryExists("dest")); EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 2); @@ -594,8 +613,10 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirRecursive) { FileSystemURL dest_dir(CreateDirectory("dest")); - operation_runner()->Copy(src_dir, dest_dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + operation_runner()->Copy(src_dir, dest_dir, + FileSystemOperationRunner::CopyProgressCallback(), + RecordStatusCallback()); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(DirectoryExists("dest/dir")); @@ -626,7 +647,7 @@ TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileSuccess) { operation_runner()->CopyInForeignFile(src_local_disk_file_path, URLForPath("dest/file"), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(1, change_observer()->create_file_count()); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); @@ -656,7 +677,7 @@ TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileFailureByQuota) { operation_runner()->CopyInForeignFile(src_local_disk_file_path, URLForPath("dest/file"), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_FALSE(FileExists("dest/file")); EXPECT_EQ(0, change_observer()->create_file_count()); @@ -667,7 +688,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateFileFailure) { // Already existing file and exclusive true. FileSystemURL file(CreateFile("file")); operation_runner()->CreateFile(file, true, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -676,7 +697,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileExists) { // Already existing file and exclusive false. FileSystemURL file(CreateFile("file")); operation_runner()->CreateFile(file, false, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(FileExists("file")); @@ -688,7 +709,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessExclusive) { // File doesn't exist but exclusive is true. operation_runner()->CreateFile(URLForPath("new"), true, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(FileExists("new")); EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); @@ -698,7 +719,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileDoesntExist) { // Non existing file. operation_runner()->CreateFile(URLForPath("nonexistent"), false, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count()); } @@ -709,7 +730,7 @@ TEST_F(FileSystemOperationImplTest, operation_runner()->CreateDirectory( URLForPath("nonexistent/dir"), false, false, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -719,7 +740,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateDirFailureDirExists) { FileSystemURL dir(CreateDirectory("dir")); operation_runner()->CreateDirectory(dir, true, false, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -729,7 +750,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateDirFailureFileExists) { FileSystemURL file(CreateFile("file")); operation_runner()->CreateDirectory(file, true, false, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -739,14 +760,14 @@ TEST_F(FileSystemOperationImplTest, TestCreateDirSuccess) { FileSystemURL dir(CreateDirectory("dir")); operation_runner()->CreateDirectory(dir, false, false, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(change_observer()->HasNoChange()); // Dir doesn't exist. operation_runner()->CreateDirectory(URLForPath("new"), false, false, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(DirectoryExists("new")); EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); @@ -756,7 +777,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateDirSuccessExclusive) { // Dir doesn't exist. operation_runner()->CreateDirectory(URLForPath("new"), true, false, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(DirectoryExists("new")); EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count()); @@ -766,17 +787,17 @@ TEST_F(FileSystemOperationImplTest, TestCreateDirSuccessExclusive) { TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataFailure) { operation_runner()->GetMetadata(URLForPath("nonexistent"), RecordMetadataCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); operation_runner()->FileExists(URLForPath("nonexistent"), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); operation_runner()->DirectoryExists(URLForPath("nonexistent"), RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -787,23 +808,23 @@ TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataSuccess) { int read_access = 0; operation_runner()->DirectoryExists(dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); ++read_access; operation_runner()->GetMetadata(dir, RecordMetadataCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(info().is_directory); ++read_access; operation_runner()->FileExists(file, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); ++read_access; operation_runner()->GetMetadata(file, RecordMetadataCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(info().is_directory); ++read_access; @@ -816,12 +837,12 @@ TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataSuccess) { TEST_F(FileSystemOperationImplTest, TestTypeMismatchErrors) { FileSystemURL dir(CreateDirectory("dir")); operation_runner()->FileExists(dir, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_FILE, status()); FileSystemURL file(CreateFile("file")); operation_runner()->DirectoryExists(file, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, status()); } @@ -829,13 +850,13 @@ TEST_F(FileSystemOperationImplTest, TestReadDirFailure) { // Path doesn't exist operation_runner()->ReadDirectory(URLForPath("nonexistent"), RecordReadDirectoryCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); // File exists. FileSystemURL file(CreateFile("file")); operation_runner()->ReadDirectory(file, RecordReadDirectoryCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -850,7 +871,7 @@ TEST_F(FileSystemOperationImplTest, TestReadDirSuccess) { FileSystemURL child_file(CreateFile("dir/child_file")); operation_runner()->ReadDirectory(parent_dir, RecordReadDirectoryCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_EQ(2u, entries().size()); @@ -868,7 +889,7 @@ TEST_F(FileSystemOperationImplTest, TestRemoveFailure) { // Path doesn't exist. operation_runner()->Remove(URLForPath("nonexistent"), false /* recursive */, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); // It's an error to try to remove a non-empty directory if recursive flag @@ -883,7 +904,7 @@ TEST_F(FileSystemOperationImplTest, TestRemoveFailure) { operation_runner()->Remove(parent_dir, false /* recursive */, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status()); EXPECT_TRUE(change_observer()->HasNoChange()); } @@ -893,7 +914,7 @@ TEST_F(FileSystemOperationImplTest, TestRemoveSuccess) { EXPECT_TRUE(DirectoryExists("empty_dir")); operation_runner()->Remove(empty_dir, false /* recursive */, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(DirectoryExists("empty_dir")); @@ -919,7 +940,7 @@ TEST_F(FileSystemOperationImplTest, TestRemoveSuccessRecursive) { operation_runner()->Remove(parent_dir, true /* recursive */, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(DirectoryExists("parent_dir")); @@ -939,7 +960,7 @@ TEST_F(FileSystemOperationImplTest, TestTruncate) { // Check that its length is the size of the data written. operation_runner()->GetMetadata(file, RecordMetadataCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(info().is_directory); EXPECT_EQ(data_size, info().size); @@ -947,7 +968,7 @@ TEST_F(FileSystemOperationImplTest, TestTruncate) { // Extend the file by truncating it. int length = 17; operation_runner()->Truncate(file, length, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); @@ -968,7 +989,7 @@ TEST_F(FileSystemOperationImplTest, TestTruncate) { // Shorten the file by truncating it. length = 3; operation_runner()->Truncate(file, length, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); @@ -993,7 +1014,7 @@ TEST_F(FileSystemOperationImplTest, TestTruncateFailureByQuota) { AddQuota(10); operation_runner()->Truncate(file, 10, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); EXPECT_TRUE(change_observer()->HasNoChange()); @@ -1001,7 +1022,7 @@ TEST_F(FileSystemOperationImplTest, TestTruncateFailureByQuota) { EXPECT_EQ(10, GetFileSize("dir/file")); operation_runner()->Truncate(file, 11, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status()); EXPECT_TRUE(change_observer()->HasNoChange()); @@ -1027,7 +1048,7 @@ TEST_F(FileSystemOperationImplTest, TestTouchFile) { operation_runner()->TouchFile(file, new_accessed_time, new_modified_time, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(change_observer()->HasNoChange()); @@ -1046,7 +1067,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateSnapshotFile) { operation_runner()->DirectoryExists(dir, RecordStatusCallback()); FileSystemURL file(CreateFile("dir/file")); operation_runner()->FileExists(file, RecordStatusCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); // See if we can get a 'snapshot' file info for the file. @@ -1054,7 +1075,7 @@ TEST_F(FileSystemOperationImplTest, TestCreateSnapshotFile) { // directory it should just returns the same metadata and platform_path // as the file itself. operation_runner()->CreateSnapshotFile(file, RecordSnapshotFileCallback()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(info().is_directory); EXPECT_EQ(PlatformPath("dir/file"), path()); @@ -1092,7 +1113,7 @@ TEST_F(FileSystemOperationImplTest, operation_runner()->Truncate( grandchild_file2, 2, base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); const int64 all_file_size = 5000 + 400 + 30 + 2; EXPECT_EQ(all_file_size, GetDataSizeOnDisk()); @@ -1101,7 +1122,7 @@ TEST_F(FileSystemOperationImplTest, operation_runner()->Move( src, dest, base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_FALSE(DirectoryExists("src/dir")); EXPECT_FALSE(FileExists("src/dir/file2")); @@ -1145,7 +1166,7 @@ TEST_F(FileSystemOperationImplTest, operation_runner()->Truncate( grandchild_file2, 5, base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); const int64 child_file_size = 8000 + 700; const int64 grandchild_file_size = 60 + 5; @@ -1159,8 +1180,9 @@ TEST_F(FileSystemOperationImplTest, // Copy src to dest1. operation_runner()->Copy( src, dest1, + FileSystemOperationRunner::CopyProgressCallback(), base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); expected_usage += all_file_size + child_path_cost + grandchild_path_cost; EXPECT_TRUE(DirectoryExists("src/dir")); @@ -1174,8 +1196,9 @@ TEST_F(FileSystemOperationImplTest, // Copy src/dir to dest2. operation_runner()->Copy( child_dir, dest2, + FileSystemOperationRunner::CopyProgressCallback(), base::Bind(&AssertFileErrorEq, FROM_HERE, base::PLATFORM_FILE_OK)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); expected_usage += grandchild_file_size + grandchild_path_cost; usage = GetUsage(); diff --git a/chromium/webkit/browser/fileapi/file_system_operation_impl_write_unittest.cc b/chromium/webkit/browser/fileapi/file_system_operation_impl_write_unittest.cc index d8ecc280fc8..7fb9aa4ae86 100644 --- a/chromium/webkit/browser/fileapi/file_system_operation_impl_write_unittest.cc +++ b/chromium/webkit/browser/fileapi/file_system_operation_impl_write_unittest.cc @@ -7,15 +7,15 @@ #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/run_loop.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_job.h" #include "net/url_request/url_request_job_factory_impl.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" -#include "webkit/browser/blob/blob_storage_controller.h" +#include "webkit/browser/blob/blob_storage_context.h" #include "webkit/browser/blob/blob_url_request_job.h" #include "webkit/browser/blob/mock_blob_url_request_context.h" #include "webkit/browser/fileapi/file_system_context.h" @@ -88,7 +88,7 @@ class FileSystemOperationImplWriteTest virtual void TearDown() { quota_manager_ = NULL; file_system_context_ = NULL; - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } base::PlatformFileError status() const { return status_; } @@ -174,11 +174,12 @@ class FileSystemOperationImplWriteTest }; TEST_F(FileSystemOperationImplWriteTest, TestWriteSuccess) { - const GURL blob_url("blob:success"); - ScopedTextBlob blob(url_request_context(), blob_url, "Hello, world!\n"); - + ScopedTextBlob blob(url_request_context(), + "blob-id:success", + "Hello, world!\n"); file_system_context_->operation_runner()->Write( - &url_request_context(), URLForPath(virtual_path_), blob_url, + &url_request_context(), URLForPath(virtual_path_), + blob.GetBlobDataHandle(), 0, RecordWriteCallback()); base::MessageLoop::current()->Run(); @@ -190,19 +191,12 @@ TEST_F(FileSystemOperationImplWriteTest, TestWriteSuccess) { } TEST_F(FileSystemOperationImplWriteTest, TestWriteZero) { - GURL blob_url("blob:zero"); - scoped_refptr<webkit_blob::BlobData> blob_data(new webkit_blob::BlobData()); - - url_request_context().blob_storage_controller() - ->AddFinishedBlob(blob_url, blob_data.get()); - + ScopedTextBlob blob(url_request_context(), "blob_id:zero", ""); file_system_context_->operation_runner()->Write( &url_request_context(), URLForPath(virtual_path_), - blob_url, 0, RecordWriteCallback()); + blob.GetBlobDataHandle(), 0, RecordWriteCallback()); base::MessageLoop::current()->Run(); - url_request_context().blob_storage_controller()->RemoveBlob(blob_url); - EXPECT_EQ(0, bytes_written()); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(complete()); @@ -210,10 +204,12 @@ TEST_F(FileSystemOperationImplWriteTest, TestWriteZero) { EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count()); } + TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidBlobUrl) { + scoped_ptr<webkit_blob::BlobDataHandle> null_handle; file_system_context_->operation_runner()->Write( &url_request_context(), URLForPath(virtual_path_), - GURL("blob:invalid"), 0, RecordWriteCallback()); + null_handle.Pass(), 0, RecordWriteCallback()); base::MessageLoop::current()->Run(); EXPECT_EQ(0, bytes_written()); @@ -224,14 +220,12 @@ TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidBlobUrl) { } TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidFile) { - GURL blob_url("blob:writeinvalidfile"); - ScopedTextBlob blob(url_request_context(), blob_url, + ScopedTextBlob blob(url_request_context(), "blob_id:writeinvalidfile", "It\'ll not be written."); - file_system_context_->operation_runner()->Write( &url_request_context(), URLForPath(base::FilePath(FILE_PATH_LITERAL("nonexist"))), - blob_url, 0, RecordWriteCallback()); + blob.GetBlobDataHandle(), 0, RecordWriteCallback()); base::MessageLoop::current()->Run(); EXPECT_EQ(0, bytes_written()); @@ -248,13 +242,11 @@ TEST_F(FileSystemOperationImplWriteTest, TestWriteDir) { true /* exclusive */, false /* recursive */, base::Bind(&AssertStatusEq, base::PLATFORM_FILE_OK)); - GURL blob_url("blob:writedir"); - ScopedTextBlob blob(url_request_context(), blob_url, + ScopedTextBlob blob(url_request_context(), "blob:writedir", "It\'ll not be written, too."); - file_system_context_->operation_runner()->Write( &url_request_context(), URLForPath(virtual_dir_path), - blob_url, 0, RecordWriteCallback()); + blob.GetBlobDataHandle(), 0, RecordWriteCallback()); base::MessageLoop::current()->Run(); EXPECT_EQ(0, bytes_written()); @@ -269,14 +261,13 @@ TEST_F(FileSystemOperationImplWriteTest, TestWriteDir) { } TEST_F(FileSystemOperationImplWriteTest, TestWriteFailureByQuota) { - GURL blob_url("blob:success"); - ScopedTextBlob blob(url_request_context(), blob_url, "Hello, world!\n"); - + ScopedTextBlob blob(url_request_context(), "blob:success", + "Hello, world!\n"); quota_manager_->SetQuota( kOrigin, FileSystemTypeToQuotaStorageType(kFileSystemType), 10); file_system_context_->operation_runner()->Write( - &url_request_context(), URLForPath(virtual_path_), blob_url, - 0, RecordWriteCallback()); + &url_request_context(), URLForPath(virtual_path_), + blob.GetBlobDataHandle(), 0, RecordWriteCallback()); base::MessageLoop::current()->Run(); EXPECT_EQ(10, bytes_written()); @@ -287,18 +278,17 @@ TEST_F(FileSystemOperationImplWriteTest, TestWriteFailureByQuota) { } TEST_F(FileSystemOperationImplWriteTest, TestImmediateCancelSuccessfulWrite) { - GURL blob_url("blob:success"); - ScopedTextBlob blob(url_request_context(), blob_url, "Hello, world!\n"); - + ScopedTextBlob blob(url_request_context(), "blob:success", + "Hello, world!\n"); FileSystemOperationRunner::OperationID id = file_system_context_->operation_runner()->Write( &url_request_context(), URLForPath(virtual_path_), - blob_url, 0, RecordWriteCallback()); + blob.GetBlobDataHandle(), 0, RecordWriteCallback()); file_system_context_->operation_runner()->Cancel(id, RecordCancelCallback()); // We use RunAllPendings() instead of Run() here, because we won't dispatch // callbacks after Cancel() is issued (so no chance to Quit) nor do we need // to run another write cycle. - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); // Issued Cancel() before receiving any response from Write(), // so nothing should have happen. @@ -311,20 +301,18 @@ TEST_F(FileSystemOperationImplWriteTest, TestImmediateCancelSuccessfulWrite) { } TEST_F(FileSystemOperationImplWriteTest, TestImmediateCancelFailingWrite) { - GURL blob_url("blob:writeinvalidfile"); - ScopedTextBlob blob(url_request_context(), blob_url, + ScopedTextBlob blob(url_request_context(), "blob:writeinvalidfile", "It\'ll not be written."); - FileSystemOperationRunner::OperationID id = file_system_context_->operation_runner()->Write( &url_request_context(), URLForPath(base::FilePath(FILE_PATH_LITERAL("nonexist"))), - blob_url, 0, RecordWriteCallback()); + blob.GetBlobDataHandle(), 0, RecordWriteCallback()); file_system_context_->operation_runner()->Cancel(id, RecordCancelCallback()); // We use RunAllPendings() instead of Run() here, because we won't dispatch // callbacks after Cancel() is issued (so no chance to Quit) nor do we need // to run another write cycle. - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); // Issued Cancel() before receiving any response from Write(), // so nothing should have happen. diff --git a/chromium/webkit/browser/fileapi/file_system_operation_runner.cc b/chromium/webkit/browser/fileapi/file_system_operation_runner.cc index 351536b6226..5a31ecc44ec 100644 --- a/chromium/webkit/browser/fileapi/file_system_operation_runner.cc +++ b/chromium/webkit/browser/fileapi/file_system_operation_runner.cc @@ -5,11 +5,14 @@ #include "webkit/browser/fileapi/file_system_operation_runner.h" #include "base/bind.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/stl_util.h" #include "net/url_request/url_request_context.h" +#include "webkit/browser/blob/blob_url_request_job_factory.h" #include "webkit/browser/fileapi/file_observers.h" #include "webkit/browser/fileapi/file_stream_writer.h" #include "webkit/browser/fileapi/file_system_context.h" -#include "webkit/browser/fileapi/file_system_operation_impl.h" +#include "webkit/browser/fileapi/file_system_operation.h" #include "webkit/browser/fileapi/file_writer_delegate.h" #include "webkit/common/blob/shareable_file_reference.h" @@ -17,7 +20,17 @@ namespace fileapi { typedef FileSystemOperationRunner::OperationID OperationID; -const OperationID FileSystemOperationRunner::kErrorOperationID = -1; +class FileSystemOperationRunner::BeginOperationScoper + : public base::SupportsWeakPtr< + FileSystemOperationRunner::BeginOperationScoper> { + public: + BeginOperationScoper() {} + private: + DISALLOW_COPY_AND_ASSIGN(BeginOperationScoper); +}; + +FileSystemOperationRunner::OperationHandle::OperationHandle() {} +FileSystemOperationRunner::OperationHandle::~OperationHandle() {} FileSystemOperationRunner::~FileSystemOperationRunner() { } @@ -33,17 +46,19 @@ OperationID FileSystemOperationRunner::CreateFile( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForWrite(id, url); + PrepareForWrite(handle.id, url); operation->CreateFile( url, exclusive, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::CreateDirectory( @@ -54,38 +69,45 @@ OperationID FileSystemOperationRunner::CreateDirectory( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForWrite(id, url); + PrepareForWrite(handle.id, url); operation->CreateDirectory( url, exclusive, recursive, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::Copy( const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyProgressCallback& progress_callback, const StatusCallback& callback) { base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(dest_url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForWrite(id, dest_url); - PrepareForRead(id, src_url); + PrepareForWrite(handle.id, dest_url); + PrepareForRead(handle.id, src_url); operation->Copy( src_url, dest_url, + progress_callback.is_null() ? + CopyProgressCallback() : + base::Bind(&FileSystemOperationRunner::OnCopyProgress, AsWeakPtr(), + handle, progress_callback), base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::Move( @@ -95,18 +117,19 @@ OperationID FileSystemOperationRunner::Move( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(dest_url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForWrite(id, dest_url); - PrepareForWrite(id, src_url); + PrepareForWrite(handle.id, dest_url); + PrepareForWrite(handle.id, src_url); operation->Move( src_url, dest_url, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::DirectoryExists( @@ -115,17 +138,18 @@ OperationID FileSystemOperationRunner::DirectoryExists( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForRead(id, url); + PrepareForRead(handle.id, url); operation->DirectoryExists( url, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::FileExists( @@ -134,17 +158,18 @@ OperationID FileSystemOperationRunner::FileExists( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForRead(id, url); + PrepareForRead(handle.id, url); operation->FileExists( url, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::GetMetadata( @@ -153,17 +178,18 @@ OperationID FileSystemOperationRunner::GetMetadata( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error, base::PlatformFileInfo()); - return kErrorOperationID; + DidGetMetadata(handle, callback, error, base::PlatformFileInfo()); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForRead(id, url); + PrepareForRead(handle.id, url); operation->GetMetadata( url, base::Bind(&FileSystemOperationRunner::DidGetMetadata, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::ReadDirectory( @@ -172,17 +198,19 @@ OperationID FileSystemOperationRunner::ReadDirectory( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error, std::vector<DirectoryEntry>(), false); - return kErrorOperationID; + DidReadDirectory(handle, callback, error, std::vector<DirectoryEntry>(), + false); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForRead(id, url); + PrepareForRead(handle.id, url); operation->ReadDirectory( url, base::Bind(&FileSystemOperationRunner::DidReadDirectory, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::Remove( @@ -191,54 +219,60 @@ OperationID FileSystemOperationRunner::Remove( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForWrite(id, url); + PrepareForWrite(handle.id, url); operation->Remove( url, recursive, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::Write( const net::URLRequestContext* url_request_context, const FileSystemURL& url, - const GURL& blob_url, + scoped_ptr<webkit_blob::BlobDataHandle> blob, int64 offset, const WriteCallback& callback) { base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error, 0, true); - return kErrorOperationID; + DidWrite(handle, callback, error, 0, true); + return handle.id; } scoped_ptr<FileStreamWriter> writer( file_system_context_->CreateFileStreamWriter(url, offset)); if (!writer) { // Write is not supported. - callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, 0, true); - return kErrorOperationID; + DidWrite(handle, callback, base::PLATFORM_FILE_ERROR_SECURITY, 0, true); + return handle.id; } - DCHECK(blob_url.is_valid()); scoped_ptr<FileWriterDelegate> writer_delegate( new FileWriterDelegate(writer.Pass())); - scoped_ptr<net::URLRequest> blob_request(url_request_context->CreateRequest( - blob_url, writer_delegate.get())); - OperationID id = operations_.Add(operation); - PrepareForWrite(id, url); + scoped_ptr<net::URLRequest> blob_request( + webkit_blob::BlobProtocolHandler::CreateBlobRequest( + blob.Pass(), + url_request_context, + writer_delegate.get())); + + PrepareForWrite(handle.id, url); operation->Write( url, writer_delegate.Pass(), blob_request.Pass(), base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::Truncate( @@ -247,25 +281,31 @@ OperationID FileSystemOperationRunner::Truncate( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForWrite(id, url); + PrepareForWrite(handle.id, url); operation->Truncate( url, length, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } void FileSystemOperationRunner::Cancel( OperationID id, const StatusCallback& callback) { + if (ContainsKey(finished_operations_, id)) { + DCHECK(!ContainsKey(stray_cancel_callbacks_, id)); + stray_cancel_callbacks_[id] = callback; + return; + } FileSystemOperation* operation = operations_.Lookup(id); if (!operation) { - // The operation is already finished; report that we failed to stop it. + // There is no operation with |id|. callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); return; } @@ -280,17 +320,18 @@ OperationID FileSystemOperationRunner::TouchFile( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForWrite(id, url); + PrepareForWrite(handle.id, url); operation->TouchFile( url, last_access_time, last_modified_time, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::OpenFile( @@ -301,27 +342,28 @@ OperationID FileSystemOperationRunner::OpenFile( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error, base::kInvalidPlatformFileValue, - base::Closure(), base::ProcessHandle()); - return kErrorOperationID; + DidOpenFile(handle, callback, error, base::kInvalidPlatformFileValue, + base::Closure(), base::ProcessHandle()); + return handle.id; } - OperationID id = operations_.Add(operation); if (file_flags & (base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_TRUNCATED | base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE | base::PLATFORM_FILE_DELETE_ON_CLOSE | base::PLATFORM_FILE_WRITE_ATTRIBUTES)) { - PrepareForWrite(id, url); + PrepareForWrite(handle.id, url); } else { - PrepareForRead(id, url); + PrepareForRead(handle.id, url); } operation->OpenFile( url, file_flags, peer_handle, base::Bind(&FileSystemOperationRunner::DidOpenFile, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::CreateSnapshotFile( @@ -330,17 +372,19 @@ OperationID FileSystemOperationRunner::CreateSnapshotFile( base::PlatformFileError error = base::PLATFORM_FILE_OK; FileSystemOperation* operation = file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error, base::PlatformFileInfo(), base::FilePath(), NULL); - return kErrorOperationID; + DidCreateSnapshot(handle, callback, error, base::PlatformFileInfo(), + base::FilePath(), NULL); + return handle.id; } - OperationID id = operations_.Add(operation); - PrepareForRead(id, url); + PrepareForRead(handle.id, url); operation->CreateSnapshotFile( url, base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::CopyInForeignFile( @@ -348,71 +392,78 @@ OperationID FileSystemOperationRunner::CopyInForeignFile( const FileSystemURL& dest_url, const StatusCallback& callback) { base::PlatformFileError error = base::PLATFORM_FILE_OK; - FileSystemOperation* operation = CreateFileSystemOperationImpl( - dest_url, &error); + FileSystemOperation* operation = + file_system_context_->CreateFileSystemOperation(dest_url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - operation->AsFileSystemOperationImpl()->CopyInForeignFile( + operation->CopyInForeignFile( src_local_disk_path, dest_url, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::RemoveFile( const FileSystemURL& url, const StatusCallback& callback) { base::PlatformFileError error = base::PLATFORM_FILE_OK; - FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error); + FileSystemOperation* operation = + file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - operation->AsFileSystemOperationImpl()->RemoveFile( + operation->RemoveFile( url, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::RemoveDirectory( const FileSystemURL& url, const StatusCallback& callback) { base::PlatformFileError error = base::PLATFORM_FILE_OK; - FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error); + FileSystemOperation* operation = + file_system_context_->CreateFileSystemOperation(url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - operation->AsFileSystemOperationImpl()->RemoveDirectory( + operation->RemoveDirectory( url, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::CopyFileLocal( const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, const StatusCallback& callback) { base::PlatformFileError error = base::PLATFORM_FILE_OK; - FileSystemOperation* operation = CreateFileSystemOperationImpl( - src_url, &error); + FileSystemOperation* operation = + file_system_context_->CreateFileSystemOperation(src_url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - operation->AsFileSystemOperationImpl()->CopyFileLocal( - src_url, dest_url, + operation->CopyFileLocal( + src_url, dest_url, progress_callback, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } OperationID FileSystemOperationRunner::MoveFileLocal( @@ -420,30 +471,30 @@ OperationID FileSystemOperationRunner::MoveFileLocal( const FileSystemURL& dest_url, const StatusCallback& callback) { base::PlatformFileError error = base::PLATFORM_FILE_OK; - FileSystemOperation* operation = CreateFileSystemOperationImpl( - src_url, &error); + FileSystemOperation* operation = + file_system_context_->CreateFileSystemOperation(src_url, &error); + BeginOperationScoper scope; + OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr()); if (!operation) { - callback.Run(error); - return kErrorOperationID; + DidFinish(handle, callback, error); + return handle.id; } - OperationID id = operations_.Add(operation); - operation->AsFileSystemOperationImpl()->MoveFileLocal( + operation->MoveFileLocal( src_url, dest_url, base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(), - id, callback)); - return id; + handle, callback)); + return handle.id; } base::PlatformFileError FileSystemOperationRunner::SyncGetPlatformPath( const FileSystemURL& url, base::FilePath* platform_path) { base::PlatformFileError error = base::PLATFORM_FILE_OK; - FileSystemOperation* operation = CreateFileSystemOperationImpl(url, &error); + FileSystemOperation* operation = + file_system_context_->CreateFileSystemOperation(url, &error); if (!operation) return error; - - return operation->AsFileSystemOperationImpl()->SyncGetPlatformPath( - url, platform_path); + return operation->SyncGetPlatformPath(url, platform_path); } FileSystemOperationRunner::FileSystemOperationRunner( @@ -451,79 +502,126 @@ FileSystemOperationRunner::FileSystemOperationRunner( : file_system_context_(file_system_context) {} void FileSystemOperationRunner::DidFinish( - OperationID id, + const OperationHandle& handle, const StatusCallback& callback, base::PlatformFileError rv) { + if (handle.scope) { + finished_operations_.insert(handle.id); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(&FileSystemOperationRunner::DidFinish, + AsWeakPtr(), handle, callback, rv)); + return; + } callback.Run(rv); - FinishOperation(id); + FinishOperation(handle.id); } void FileSystemOperationRunner::DidGetMetadata( - OperationID id, + const OperationHandle& handle, const GetMetadataCallback& callback, base::PlatformFileError rv, const base::PlatformFileInfo& file_info) { + if (handle.scope) { + finished_operations_.insert(handle.id); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(&FileSystemOperationRunner::DidGetMetadata, + AsWeakPtr(), handle, callback, rv, file_info)); + return; + } callback.Run(rv, file_info); - FinishOperation(id); + FinishOperation(handle.id); } void FileSystemOperationRunner::DidReadDirectory( - OperationID id, + const OperationHandle& handle, const ReadDirectoryCallback& callback, base::PlatformFileError rv, const std::vector<DirectoryEntry>& entries, bool has_more) { + if (handle.scope) { + finished_operations_.insert(handle.id); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(&FileSystemOperationRunner::DidReadDirectory, + AsWeakPtr(), handle, callback, rv, + entries, has_more)); + return; + } callback.Run(rv, entries, has_more); if (rv != base::PLATFORM_FILE_OK || !has_more) - FinishOperation(id); + FinishOperation(handle.id); } void FileSystemOperationRunner::DidWrite( - OperationID id, + const OperationHandle& handle, const WriteCallback& callback, base::PlatformFileError rv, int64 bytes, bool complete) { + if (handle.scope) { + finished_operations_.insert(handle.id); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(), + handle, callback, rv, bytes, complete)); + return; + } callback.Run(rv, bytes, complete); if (rv != base::PLATFORM_FILE_OK || complete) - FinishOperation(id); + FinishOperation(handle.id); } void FileSystemOperationRunner::DidOpenFile( - OperationID id, + const OperationHandle& handle, const OpenFileCallback& callback, base::PlatformFileError rv, base::PlatformFile file, const base::Closure& on_close_callback, base::ProcessHandle peer_handle) { + if (handle.scope) { + finished_operations_.insert(handle.id); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(&FileSystemOperationRunner::DidOpenFile, + AsWeakPtr(), handle, callback, rv, file, + on_close_callback, peer_handle)); + return; + } callback.Run(rv, file, on_close_callback, peer_handle); - FinishOperation(id); + FinishOperation(handle.id); } void FileSystemOperationRunner::DidCreateSnapshot( - OperationID id, + const OperationHandle& handle, const SnapshotFileCallback& callback, base::PlatformFileError rv, const base::PlatformFileInfo& file_info, const base::FilePath& platform_path, const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { + if (handle.scope) { + finished_operations_.insert(handle.id); + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, + AsWeakPtr(), handle, callback, rv, file_info, + platform_path, file_ref)); + return; + } callback.Run(rv, file_info, platform_path, file_ref); - FinishOperation(id); + FinishOperation(handle.id); } -FileSystemOperation* -FileSystemOperationRunner::CreateFileSystemOperationImpl( - const FileSystemURL& url, base::PlatformFileError* error) { - FileSystemOperation* operation = - file_system_context_->CreateFileSystemOperation(url, error); - if (!operation) - return NULL; - if (!operation->AsFileSystemOperationImpl()) { - *error = base::PLATFORM_FILE_ERROR_INVALID_OPERATION; - delete operation; - return NULL; +void FileSystemOperationRunner::OnCopyProgress( + const OperationHandle& handle, + const CopyProgressCallback& callback, + FileSystemOperation::CopyProgressType type, + const FileSystemURL& source_url, + const FileSystemURL& dest_url, + int64 size) { + if (handle.scope) { + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind( + &FileSystemOperationRunner::OnCopyProgress, + AsWeakPtr(), handle, callback, type, source_url, dest_url, size)); + return; } - return operation; + callback.Run(type, source_url, dest_url, size); } void FileSystemOperationRunner::PrepareForWrite(OperationID id, @@ -543,6 +641,16 @@ void FileSystemOperationRunner::PrepareForRead(OperationID id, } } +FileSystemOperationRunner::OperationHandle +FileSystemOperationRunner::BeginOperation( + FileSystemOperation* operation, + base::WeakPtr<BeginOperationScoper> scope) { + OperationHandle handle; + handle.id = operations_.Add(operation); + handle.scope = scope; + return handle; +} + void FileSystemOperationRunner::FinishOperation(OperationID id) { OperationToURLSet::iterator found = write_target_urls_.find(id); if (found != write_target_urls_.end()) { @@ -556,8 +664,22 @@ void FileSystemOperationRunner::FinishOperation(OperationID id) { } write_target_urls_.erase(found); } - DCHECK(operations_.Lookup(id)); + + // IDMap::Lookup fails if the operation is NULL, so we don't check + // operations_.Lookup(id) here. + operations_.Remove(id); + finished_operations_.erase(id); + + // Dispatch stray cancel callback if exists. + std::map<OperationID, StatusCallback>::iterator found_cancel = + stray_cancel_callbacks_.find(id); + if (found_cancel != stray_cancel_callbacks_.end()) { + // This cancel has been requested after the operation has finished, + // so report that we failed to stop it. + found_cancel->second.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); + stray_cancel_callbacks_.erase(found_cancel); + } } } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/file_system_operation_runner.h b/chromium/webkit/browser/fileapi/file_system_operation_runner.h index 67f30b89b17..ea93f38e1fc 100644 --- a/chromium/webkit/browser/fileapi/file_system_operation_runner.h +++ b/chromium/webkit/browser/fileapi/file_system_operation_runner.h @@ -11,6 +11,7 @@ #include "base/id_map.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "webkit/browser/blob/blob_data_handle.h" #include "webkit/browser/fileapi/file_system_operation.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/webkit_storage_browser_export.h" @@ -31,12 +32,6 @@ class FileSystemContext; // operation fails, in addition to dispatching the callback with an error // code (therefore in most cases the caller does not need to check the // returned operation ID). -// -// Some operations (e.g. CopyInForeignFile, RemoveFile, RemoveDirectory, -// CopyFileLocal, MoveFileLocal and SyncGetPlatformPath) are only supported -// by filesystems which implement FileSystemOperationImpl. -// If they are called on other filesystems -// base::PLATFORM_FILE_ERROR_INVALID_OPERATION is returned via callback. class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner : public base::SupportsWeakPtr<FileSystemOperationRunner> { public: @@ -46,11 +41,12 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner typedef FileSystemOperation::StatusCallback StatusCallback; typedef FileSystemOperation::WriteCallback WriteCallback; typedef FileSystemOperation::OpenFileCallback OpenFileCallback; + typedef FileSystemOperation::CopyProgressCallback CopyProgressCallback; + typedef FileSystemOperation::CopyFileProgressCallback + CopyFileProgressCallback; typedef int OperationID; - static const OperationID kErrorOperationID; - virtual ~FileSystemOperationRunner(); // Cancels all inflight operations. @@ -71,8 +67,10 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner // |src_url| is a directory, the contents of |src_url| are copied to // |dest_url| recursively. A new file or directory is created at // |dest_url| as needed. + // For |progress_callback|, see file_system_operation.h for details. OperationID Copy(const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyProgressCallback& progress_callback, const StatusCallback& callback); // Moves a file or directory from |src_url| to |dest_url|. A new file @@ -103,10 +101,10 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner const StatusCallback& callback); // Writes contents of |blob_url| to |url| at |offset|. - // |url_request_context| is used to read contents in |blob_url|. + // |url_request_context| is used to read contents in |blob|. OperationID Write(const net::URLRequestContext* url_request_context, const FileSystemURL& url, - const GURL& blob_url, + scoped_ptr<webkit_blob::BlobDataHandle> blob, int64 offset, const WriteCallback& callback); @@ -190,6 +188,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner // Copies a file from |src_url| to |dest_url|. // This must be called for files that belong to the same filesystem // (i.e. type() and origin() of the |src_url| and |dest_url| must match). + // For |progress_callback|, see file_system_operation.h for details. // // This returns: // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url| @@ -202,6 +201,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner // OperationID CopyFileLocal(const FileSystemURL& src_url, const FileSystemURL& dest_url, + const CopyFileProgressCallback& progress_callback, const StatusCallback& callback); // Moves a local file from |src_url| to |dest_url|. @@ -228,54 +228,65 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner base::FilePath* platform_path); private: + class BeginOperationScoper; + + struct OperationHandle { + OperationID id; + base::WeakPtr<BeginOperationScoper> scope; + + OperationHandle(); + ~OperationHandle(); + }; + friend class FileSystemContext; explicit FileSystemOperationRunner(FileSystemContext* file_system_context); - void DidFinish(OperationID id, + void DidFinish(const OperationHandle& handle, const StatusCallback& callback, base::PlatformFileError rv); - void DidGetMetadata(OperationID id, + void DidGetMetadata(const OperationHandle& handle, const GetMetadataCallback& callback, base::PlatformFileError rv, const base::PlatformFileInfo& file_info); - void DidReadDirectory(OperationID id, + void DidReadDirectory(const OperationHandle& handle, const ReadDirectoryCallback& callback, base::PlatformFileError rv, const std::vector<DirectoryEntry>& entries, bool has_more); - void DidWrite(OperationID id, + void DidWrite(const OperationHandle& handle, const WriteCallback& callback, base::PlatformFileError rv, int64 bytes, bool complete); void DidOpenFile( - OperationID id, + const OperationHandle& handle, const OpenFileCallback& callback, base::PlatformFileError rv, base::PlatformFile file, const base::Closure& on_close_callback, base::ProcessHandle peer_handle); void DidCreateSnapshot( - OperationID id, + const OperationHandle& handle, const SnapshotFileCallback& callback, base::PlatformFileError rv, const base::PlatformFileInfo& file_info, const base::FilePath& platform_path, const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref); - // A helper method for creating FileSystemOperationImpl for operations - // that are supported only in FileSystemOperationImpl. - // Note that this returns FileSystemOperation, so the caller needs to - // call AsFileSystemOperationImpl() (which is guaranteed to be non-null - // if this method returns without error). - FileSystemOperation* CreateFileSystemOperationImpl( - const FileSystemURL& url, - base::PlatformFileError* error); + void OnCopyProgress( + const OperationHandle& handle, + const CopyProgressCallback& callback, + FileSystemOperation::CopyProgressType type, + const FileSystemURL& source_url, + const FileSystemURL& dest_url, + int64 size); void PrepareForWrite(OperationID id, const FileSystemURL& url); void PrepareForRead(OperationID id, const FileSystemURL& url); - // This must be called at the end of any async operations. + // These must be called at the beginning and end of any async operations. + OperationHandle BeginOperation(FileSystemOperation* operation, + base::WeakPtr<BeginOperationScoper> scope); void FinishOperation(OperationID id); // Not owned; file_system_context owns this. @@ -289,6 +300,12 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemOperationRunner typedef std::map<OperationID, FileSystemURLSet> OperationToURLSet; OperationToURLSet write_target_urls_; + // Operations that are finished but not yet fire their callbacks. + std::set<OperationID> finished_operations_; + + // Callbacks for stray cancels whose target operation is already finished. + std::map<OperationID, StatusCallback> stray_cancel_callbacks_; + DISALLOW_COPY_AND_ASSIGN(FileSystemOperationRunner); }; diff --git a/chromium/webkit/browser/fileapi/file_system_operation_runner_unittest.cc b/chromium/webkit/browser/fileapi/file_system_operation_runner_unittest.cc new file mode 100644 index 00000000000..086c9999ad5 --- /dev/null +++ b/chromium/webkit/browser/fileapi/file_system_operation_runner_unittest.cc @@ -0,0 +1,162 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "base/files/file_path.h" +#include "base/files/scoped_temp_dir.h" +#include "base/platform_file.h" +#include "base/run_loop.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/browser/fileapi/file_system_context.h" +#include "webkit/browser/fileapi/file_system_operation_runner.h" +#include "webkit/browser/fileapi/mock_file_system_context.h" + +namespace fileapi { + +void GetStatus(bool* done, + base::PlatformFileError *status_out, + base::PlatformFileError status) { + ASSERT_FALSE(*done); + *done = true; + *status_out = status; +} + +void GetCancelStatus(bool* operation_done, + bool* cancel_done, + base::PlatformFileError *status_out, + base::PlatformFileError status) { + // Cancel callback must be always called after the operation's callback. + ASSERT_TRUE(*operation_done); + ASSERT_FALSE(*cancel_done); + *cancel_done = true; + *status_out = status; +} + +class FileSystemOperationRunnerTest : public testing::Test { + protected: + FileSystemOperationRunnerTest() {} + virtual ~FileSystemOperationRunnerTest() {} + + virtual void SetUp() OVERRIDE { + ASSERT_TRUE(base_.CreateUniqueTempDir()); + base::FilePath base_dir = base_.path(); + file_system_context_ = + CreateFileSystemContextForTesting(NULL, base_dir); + } + + virtual void TearDown() OVERRIDE { + file_system_context_ = NULL; + base::RunLoop().RunUntilIdle(); + } + + FileSystemURL URL(const std::string& path) { + return file_system_context_->CreateCrackedFileSystemURL( + GURL("http://example.com"), kFileSystemTypeTemporary, + base::FilePath::FromUTF8Unsafe(path)); + } + + FileSystemOperationRunner* operation_runner() { + return file_system_context_->operation_runner(); + } + + private: + base::ScopedTempDir base_; + base::MessageLoop message_loop_; + scoped_refptr<FileSystemContext> file_system_context_; + + DISALLOW_COPY_AND_ASSIGN(FileSystemOperationRunnerTest); +}; + +TEST_F(FileSystemOperationRunnerTest, NotFoundError) { + bool done = false; + base::PlatformFileError status = base::PLATFORM_FILE_ERROR_FAILED; + + // Regular NOT_FOUND error, which is called asynchronously. + operation_runner()->Truncate(URL("foo"), 0, + base::Bind(&GetStatus, &done, &status)); + ASSERT_FALSE(done); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(done); + ASSERT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status); +} + +TEST_F(FileSystemOperationRunnerTest, InvalidURLError) { + bool done = false; + base::PlatformFileError status = base::PLATFORM_FILE_ERROR_FAILED; + + // Invalid URL error, which calls DidFinish synchronously. + operation_runner()->Truncate(FileSystemURL(), 0, + base::Bind(&GetStatus, &done, &status)); + // The error call back shouldn't be fired synchronously. + ASSERT_FALSE(done); + + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(done); + ASSERT_EQ(base::PLATFORM_FILE_ERROR_INVALID_URL, status); +} + +TEST_F(FileSystemOperationRunnerTest, NotFoundErrorAndCancel) { + bool done = false; + bool cancel_done = false; + base::PlatformFileError status = base::PLATFORM_FILE_ERROR_FAILED; + base::PlatformFileError cancel_status = base::PLATFORM_FILE_ERROR_FAILED; + + // Call Truncate with non-existent URL, and try to cancel it immediately + // after that (before its callback is fired). + FileSystemOperationRunner::OperationID id = + operation_runner()->Truncate(URL("foo"), 0, + base::Bind(&GetStatus, &done, &status)); + operation_runner()->Cancel(id, base::Bind(&GetCancelStatus, + &done, &cancel_done, + &cancel_status)); + + ASSERT_FALSE(done); + ASSERT_FALSE(cancel_done); + base::RunLoop().RunUntilIdle(); + + ASSERT_TRUE(done); + ASSERT_TRUE(cancel_done); + ASSERT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status); + ASSERT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, cancel_status); +} + +TEST_F(FileSystemOperationRunnerTest, InvalidURLErrorAndCancel) { + bool done = false; + bool cancel_done = false; + base::PlatformFileError status = base::PLATFORM_FILE_ERROR_FAILED; + base::PlatformFileError cancel_status = base::PLATFORM_FILE_ERROR_FAILED; + + // Call Truncate with invalid URL, and try to cancel it immediately + // after that (before its callback is fired). + FileSystemOperationRunner::OperationID id = + operation_runner()->Truncate(FileSystemURL(), 0, + base::Bind(&GetStatus, &done, &status)); + operation_runner()->Cancel(id, base::Bind(&GetCancelStatus, + &done, &cancel_done, + &cancel_status)); + + ASSERT_FALSE(done); + ASSERT_FALSE(cancel_done); + base::RunLoop().RunUntilIdle(); + + ASSERT_TRUE(done); + ASSERT_TRUE(cancel_done); + ASSERT_EQ(base::PLATFORM_FILE_ERROR_INVALID_URL, status); + ASSERT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, cancel_status); +} + +TEST_F(FileSystemOperationRunnerTest, CancelWithInvalidId) { + const FileSystemOperationRunner::OperationID kInvalidId = -1; + bool done = true; // The operation is not running. + bool cancel_done = false; + base::PlatformFileError cancel_status = base::PLATFORM_FILE_ERROR_FAILED; + operation_runner()->Cancel(kInvalidId, base::Bind(&GetCancelStatus, + &done, &cancel_done, + &cancel_status)); + + ASSERT_TRUE(cancel_done); + ASSERT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, cancel_status); +} + +} // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/file_system_quota_client.cc b/chromium/webkit/browser/fileapi/file_system_quota_client.cc index 343a6e6ee5c..76725df31a8 100644 --- a/chromium/webkit/browser/fileapi/file_system_quota_client.cc +++ b/chromium/webkit/browser/fileapi/file_system_quota_client.cc @@ -197,6 +197,12 @@ void FileSystemQuotaClient::DeleteOriginData( callback); } +bool FileSystemQuotaClient::DoesSupport(quota::StorageType storage_type) const { + FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type); + DCHECK(type != kFileSystemTypeUnknown); + return file_system_context_->IsSandboxFileSystem(type); +} + base::SequencedTaskRunner* FileSystemQuotaClient::file_task_runner() const { return file_system_context_->default_file_task_runner(); } diff --git a/chromium/webkit/browser/fileapi/file_system_quota_client.h b/chromium/webkit/browser/fileapi/file_system_quota_client.h index f2168043f1b..f3cf68ddf13 100644 --- a/chromium/webkit/browser/fileapi/file_system_quota_client.h +++ b/chromium/webkit/browser/fileapi/file_system_quota_client.h @@ -56,6 +56,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE FileSystemQuotaClient const GURL& origin, quota::StorageType type, const DeletionCallback& callback) OVERRIDE; + virtual bool DoesSupport(quota::StorageType type) const OVERRIDE; private: base::SequencedTaskRunner* file_task_runner() const; diff --git a/chromium/webkit/browser/fileapi/file_system_quota_client_unittest.cc b/chromium/webkit/browser/fileapi/file_system_quota_client_unittest.cc index 477bb77e95e..1a9121c1a7a 100644 --- a/chromium/webkit/browser/fileapi/file_system_quota_client_unittest.cc +++ b/chromium/webkit/browser/fileapi/file_system_quota_client_unittest.cc @@ -6,13 +6,13 @@ #include "base/bind.h" #include "base/file_util.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" #include "base/platform_file.h" +#include "base/run_loop.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +#include "webkit/browser/fileapi/async_file_test_helper.h" #include "webkit/browser/fileapi/file_system_context.h" -#include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/file_system_quota_client.h" #include "webkit/browser/fileapi/file_system_usage_cache.h" #include "webkit/browser/fileapi/mock_file_system_context.h" @@ -74,7 +74,7 @@ class FileSystemQuotaClientTest : public testing::Test { const std::string& origin_url, quota::StorageType type) { GetOriginUsageAsync(quota_client, origin_url, type); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); return usage_; } @@ -85,7 +85,7 @@ class FileSystemQuotaClientTest : public testing::Test { type, base::Bind(&FileSystemQuotaClientTest::OnGetOrigins, weak_factory_.GetWeakPtr())); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); return origins_; } @@ -97,7 +97,7 @@ class FileSystemQuotaClientTest : public testing::Test { type, host, base::Bind(&FileSystemQuotaClientTest::OnGetOrigins, weak_factory_.GetWeakPtr())); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); return origins_; } @@ -110,32 +110,16 @@ class FileSystemQuotaClientTest : public testing::Test { weak_factory_.GetWeakPtr())); } - FileSystemOperationContext* CreateFileSystemOperationContext( - FileSystemType type) { - FileSystemOperationContext* context = - new FileSystemOperationContext(file_system_context_.get()); - context->set_allowed_bytes_growth(100000000); - context->set_update_observers( - *file_system_context_->GetUpdateObservers(type)); - return context; - } - bool CreateFileSystemDirectory(const base::FilePath& file_path, const std::string& origin_url, quota::StorageType storage_type) { FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type); - FileSystemFileUtil* file_util = file_system_context_->GetFileUtil(type); - FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( GURL(origin_url), type, file_path); - scoped_ptr<FileSystemOperationContext> context( - CreateFileSystemOperationContext(type)); base::PlatformFileError result = - file_util->CreateDirectory(context.get(), url, false, false); - if (result != base::PLATFORM_FILE_OK) - return false; - return true; + AsyncFileTestHelper::CreateDirectory(file_system_context_, url); + return result == base::PLATFORM_FILE_OK; } bool CreateFileSystemFile(const base::FilePath& file_path, @@ -146,22 +130,17 @@ class FileSystemQuotaClientTest : public testing::Test { return false; FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type); - FileSystemFileUtil* file_util = file_system_context_->GetFileUtil(type); - FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( GURL(origin_url), type, file_path); - scoped_ptr<FileSystemOperationContext> context( - CreateFileSystemOperationContext(type)); - bool created = false; - if (base::PLATFORM_FILE_OK != - file_util->EnsureFileExists(context.get(), url, &created)) - return false; - EXPECT_TRUE(created); - if (base::PLATFORM_FILE_OK != - file_util->Truncate(context.get(), url, file_size)) + base::PlatformFileError result = + AsyncFileTestHelper::CreateFile(file_system_context_, url); + if (result != base::PLATFORM_FILE_OK) return false; - return true; + + result = AsyncFileTestHelper::TruncateFile( + file_system_context_, url, file_size); + return result == base::PLATFORM_FILE_OK; } void InitializeOriginFiles(FileSystemQuotaClient* quota_client, @@ -428,7 +407,7 @@ TEST_F(FileSystemQuotaClientTest, GetUsage_MultipleTasks) { GetOriginUsageAsync(quota_client.get(), kDummyURL1, kTemporary); RunAdditionalOriginUsageTask(quota_client.get(), kDummyURL1, kTemporary); RunAdditionalOriginUsageTask(quota_client.get(), kDummyURL1, kTemporary); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(11 + 22 + file_paths_cost, usage()); EXPECT_EQ(2, additional_callback_count()); @@ -437,7 +416,7 @@ TEST_F(FileSystemQuotaClientTest, GetUsage_MultipleTasks) { RunAdditionalOriginUsageTask(quota_client.get(), kDummyURL1, kTemporary); GetOriginUsageAsync(quota_client.get(), kDummyURL1, kTemporary); RunAdditionalOriginUsageTask(quota_client.get(), kDummyURL1, kTemporary); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(11 + 22 + file_paths_cost, usage()); EXPECT_EQ(2, additional_callback_count()); } @@ -539,15 +518,15 @@ TEST_F(FileSystemQuotaClientTest, DeleteOriginTest) { "https://bar.com/", kPersistent); DeleteOriginData(quota_client.get(), "http://foo.com/", kTemporary); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(quota::kQuotaStatusOk, status()); DeleteOriginData(quota_client.get(), "http://bar.com/", kPersistent); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(quota::kQuotaStatusOk, status()); DeleteOriginData(quota_client.get(), "http://buz.com/", kTemporary); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(quota::kQuotaStatusOk, status()); EXPECT_EQ(0, GetOriginUsage( diff --git a/chromium/webkit/browser/fileapi/file_system_quota_util.h b/chromium/webkit/browser/fileapi/file_system_quota_util.h index be98936c2f5..5f3c7dd77ae 100644 --- a/chromium/webkit/browser/fileapi/file_system_quota_util.h +++ b/chromium/webkit/browser/fileapi/file_system_quota_util.h @@ -56,11 +56,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemQuotaUtil { const GURL& origin_url, fileapi::FileSystemType type) = 0; - virtual void InvalidateUsageCache(const GURL& origin_url, - fileapi::FileSystemType type) = 0; - virtual void StickyInvalidateUsageCache(const GURL& origin, - fileapi::FileSystemType type) = 0; - virtual void AddFileUpdateObserver( FileSystemType type, FileUpdateObserver* observer, @@ -73,6 +68,9 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemQuotaUtil { FileSystemType type, FileAccessObserver* observer, base::SequencedTaskRunner* task_runner) = 0; + + // Returns the observer list for |type|, or returns NULL if any observers + // have not been registered on |type|. virtual const UpdateObserverList* GetUpdateObservers( FileSystemType type) const = 0; virtual const ChangeObserverList* GetChangeObservers( diff --git a/chromium/webkit/browser/fileapi/file_system_url.cc b/chromium/webkit/browser/fileapi/file_system_url.cc index 6269296a684..2f8875a701b 100644 --- a/chromium/webkit/browser/fileapi/file_system_url.cc +++ b/chromium/webkit/browser/fileapi/file_system_url.cc @@ -46,9 +46,6 @@ bool FileSystemURL::ParseFileSystemSchemeURL( if (!url.is_valid() || !url.SchemeIsFileSystem()) return false; - DCHECK(url.inner_url()); - - std::string inner_path = url.inner_url()->path(); const struct { FileSystemType type; @@ -61,8 +58,11 @@ bool FileSystemURL::ParseFileSystemSchemeURL( { kFileSystemTypeTest, kTestDir }, }; + // A path of the inner_url contains only mount type part (e.g. "/temporary"). + DCHECK(url.inner_url()); + std::string inner_path = url.inner_url()->path(); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidTypes); ++i) { - if (StartsWithASCII(inner_path, kValidTypes[i].dir, true)) { + if (inner_path == kValidTypes[i].dir) { file_system_type = kValidTypes[i].type; break; } @@ -135,6 +135,20 @@ FileSystemURL::FileSystemURL(const GURL& origin, FileSystemURL::~FileSystemURL() {} +GURL FileSystemURL::ToGURL() const { + if (!is_valid_) + return GURL(); + + std::string url = GetFileSystemRootURI(origin_, mount_type_).spec(); + if (url.empty()) + return GURL(); + + url.append(virtual_path_.AsUTF8Unsafe()); + + // Build nested GURL. + return GURL(url); +} + std::string FileSystemURL::DebugString() const { if (!is_valid_) return "invalid filesystem: URL"; diff --git a/chromium/webkit/browser/fileapi/file_system_url.h b/chromium/webkit/browser/fileapi/file_system_url.h index 6ac875d6310..d6443e69189 100644 --- a/chromium/webkit/browser/fileapi/file_system_url.h +++ b/chromium/webkit/browser/fileapi/file_system_url.h @@ -118,6 +118,9 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemURL { FileSystemType mount_type() const { return mount_type_; } + // Returns the formatted URL of this instance. + GURL ToGURL() const; + std::string DebugString() const; // Returns true if this URL is a strict parent of the |child|. @@ -127,6 +130,10 @@ class WEBKIT_STORAGE_BROWSER_EXPORT FileSystemURL { bool operator==(const FileSystemURL& that) const; + bool operator!=(const FileSystemURL& that) const { + return !(*this == that); + } + struct WEBKIT_STORAGE_BROWSER_EXPORT Comparator { bool operator() (const FileSystemURL& lhs, const FileSystemURL& rhs) const; }; diff --git a/chromium/webkit/browser/fileapi/file_system_url_request_job.cc b/chromium/webkit/browser/fileapi/file_system_url_request_job.cc index d93c14089f2..7d1f8613138 100644 --- a/chromium/webkit/browser/fileapi/file_system_url_request_job.cc +++ b/chromium/webkit/browser/fileapi/file_system_url_request_job.cc @@ -157,6 +157,11 @@ void FileSystemURLRequestJob::StartAsync() { return; DCHECK(!reader_.get()); url_ = file_system_context_->CrackURL(request_->url()); + if (!file_system_context_->CanServeURLRequest(url_)) { + // In incognito mode the API is not usable and there should be no data. + NotifyFailed(net::ERR_FILE_NOT_FOUND); + return; + } file_system_context_->operation_runner()->GetMetadata( url_, base::Bind(&FileSystemURLRequestJob::DidGetMetadata, diff --git a/chromium/webkit/browser/fileapi/file_system_url_request_job_unittest.cc b/chromium/webkit/browser/fileapi/file_system_url_request_job_unittest.cc index a8f6cabbffe..8f54e62b984 100644 --- a/chromium/webkit/browser/fileapi/file_system_url_request_job_unittest.cc +++ b/chromium/webkit/browser/fileapi/file_system_url_request_job_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,6 +16,7 @@ #include "base/message_loop/message_loop_proxy.h" #include "base/platform_file.h" #include "base/rand_util.h" +#include "base/run_loop.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -28,9 +29,10 @@ #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webkit/browser/fileapi/async_file_test_helper.h" +#include "webkit/browser/fileapi/external_mount_points.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_file_util.h" -#include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/mock_file_system_context.h" namespace fileapi { @@ -66,7 +68,7 @@ class FileSystemURLRequestJobTest : public testing::Test { OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, base::Bind(&FileSystemURLRequestJobTest::OnOpenFileSystem, weak_factory_.GetWeakPtr())); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); net::URLRequest::Deprecated::RegisterProtocolFactory( "filesystem", &FileSystemURLRequestJobFactory); @@ -80,7 +82,7 @@ class FileSystemURLRequestJobTest : public testing::Test { pending_job_ = NULL; } // FileReader posts a task to close the file in destructor. - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } void OnOpenFileSystem(base::PlatformFileError result, @@ -91,7 +93,8 @@ class FileSystemURLRequestJobTest : public testing::Test { void TestRequestHelper(const GURL& url, const net::HttpRequestHeaders* headers, - bool run_to_completion) { + bool run_to_completion, + FileSystemContext* file_system_context) { delegate_.reset(new net::TestDelegate()); // Make delegate_ exit the MessageLoop when the request is done. delegate_->set_quit_on_complete(true); @@ -101,7 +104,7 @@ class FileSystemURLRequestJobTest : public testing::Test { request_->SetExtraRequestHeaders(*headers); ASSERT_TRUE(!job_); job_ = new FileSystemURLRequestJob( - request_.get(), NULL, file_system_context_.get()); + request_.get(), NULL, file_system_context); pending_job_ = job_; request_->Start(); @@ -111,61 +114,41 @@ class FileSystemURLRequestJobTest : public testing::Test { } void TestRequest(const GURL& url) { - TestRequestHelper(url, NULL, true); + TestRequestHelper(url, NULL, true, file_system_context_.get()); + } + + void TestRequestWithContext(const GURL& url, + FileSystemContext* file_system_context) { + TestRequestHelper(url, NULL, true, file_system_context); } void TestRequestWithHeaders(const GURL& url, const net::HttpRequestHeaders* headers) { - TestRequestHelper(url, headers, true); + TestRequestHelper(url, headers, true, file_system_context_.get()); } void TestRequestNoRun(const GURL& url) { - TestRequestHelper(url, NULL, false); + TestRequestHelper(url, NULL, false, file_system_context_.get()); } void CreateDirectory(const base::StringPiece& dir_name) { - FileSystemFileUtil* file_util = file_system_context_->GetFileUtil( - kFileSystemTypeTemporary); FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( GURL("http://remote"), kFileSystemTypeTemporary, base::FilePath().AppendASCII(dir_name)); - - FileSystemOperationContext context(file_system_context_.get()); - context.set_allowed_bytes_growth(1024); - - ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateDirectory( - &context, - url, - false /* exclusive */, - false /* recursive */)); + ASSERT_EQ(base::PLATFORM_FILE_OK, AsyncFileTestHelper::CreateDirectory( + file_system_context_, url)); } void WriteFile(const base::StringPiece& file_name, const char* buf, int buf_size) { - FileSystemFileUtil* file_util = file_system_context_->GetFileUtil( - kFileSystemTypeTemporary); FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( GURL("http://remote"), kFileSystemTypeTemporary, base::FilePath().AppendASCII(file_name)); - - FileSystemOperationContext context(file_system_context_.get()); - context.set_allowed_bytes_growth(1024); - - base::PlatformFile handle = base::kInvalidPlatformFileValue; - bool created = false; - ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateOrOpen( - &context, - url, - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, - &handle, - &created)); - EXPECT_TRUE(created); - ASSERT_NE(base::kInvalidPlatformFileValue, handle); - ASSERT_EQ(buf_size, - base::WritePlatformFile(handle, 0 /* offset */, buf, buf_size)); - base::ClosePlatformFile(handle); + ASSERT_EQ(base::PLATFORM_FILE_OK, + AsyncFileTestHelper::CreateFileWithData( + file_system_context_, url, buf, buf_size)); } GURL CreateFileSystemURL(const std::string& path) { @@ -335,7 +318,7 @@ TEST_F(FileSystemURLRequestJobTest, Cancel) { // Run StartAsync() and only StartAsync(). base::MessageLoop::current()->DeleteSoon(FROM_HERE, request_.release()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); // If we get here, success! we didn't crash! } @@ -357,5 +340,26 @@ TEST_F(FileSystemURLRequestJobTest, GetMimeType) { EXPECT_EQ(mime_type_direct, mime_type_from_job); } +TEST_F(FileSystemURLRequestJobTest, Incognito) { + WriteFile("file", kTestFileData, arraysize(kTestFileData) - 1); + + // Creates a new filesystem context for incognito mode. + scoped_refptr<FileSystemContext> file_system_context = + CreateIncognitoFileSystemContextForTesting(NULL, temp_dir_.path()); + + // The request should return NOT_FOUND error if it's in incognito mode. + TestRequestWithContext(CreateFileSystemURL("file"), + file_system_context.get()); + ASSERT_FALSE(request_->is_pending()); + EXPECT_TRUE(delegate_->request_failed()); + EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error()); + + // Make sure it returns success with regular (non-incognito) context. + TestRequest(CreateFileSystemURL("file")); + ASSERT_FALSE(request_->is_pending()); + EXPECT_EQ(kTestFileData, delegate_->data_received()); + EXPECT_EQ(200, request_->GetResponseCode()); +} + } // namespace } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/file_system_url_unittest.cc b/chromium/webkit/browser/fileapi/file_system_url_unittest.cc index ace67007cb3..c5a632c735c 100644 --- a/chromium/webkit/browser/fileapi/file_system_url_unittest.cc +++ b/chromium/webkit/browser/fileapi/file_system_url_unittest.cc @@ -84,6 +84,8 @@ TEST(FileSystemURLTest, UnescapePath) { TEST(FileSystemURLTest, RejectBadType) { EXPECT_FALSE(CreateFileSystemURL( "filesystem:http://c.org/foobar/file").is_valid()); + EXPECT_FALSE(CreateFileSystemURL( + "filesystem:http://c.org/temporaryfoo/file").is_valid()); } TEST(FileSystemURLTest, RejectMalformedURL) { @@ -156,6 +158,23 @@ TEST(FileSystemURLTest, IsParent) { CreateFileSystemURL(root3 + child))); } +TEST(FileSystemURLTest, ToGURL) { + EXPECT_TRUE(FileSystemURL().ToGURL().is_empty()); + const char* kTestURL[] = { + "filesystem:http://chromium.org/persistent/directory/file0", + "filesystem:http://chromium.org/temporary/directory/file1", + "filesystem:http://chromium.org/isolated/directory/file2", + "filesystem:http://chromium.org/external/directory/file2", + "filesystem:http://chromium.org/test/directory/file3", + }; + + for (size_t i = 0; i < arraysize(kTestURL); ++i) { + EXPECT_EQ( + kTestURL[i], + FileSystemURL::CreateForTest(GURL(kTestURL[i])).ToGURL().spec()); + } +} + TEST(FileSystemURLTest, DebugString) { const GURL kOrigin("http://example.com"); const base::FilePath kPath(FPL("dir/file")); diff --git a/chromium/webkit/browser/fileapi/file_writer_delegate_unittest.cc b/chromium/webkit/browser/fileapi/file_writer_delegate_unittest.cc index 340fcb0120e..28c93e8a0db 100644 --- a/chromium/webkit/browser/fileapi/file_writer_delegate_unittest.cc +++ b/chromium/webkit/browser/fileapi/file_writer_delegate_unittest.cc @@ -9,7 +9,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "net/base/io_buffer.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" @@ -17,9 +17,8 @@ #include "net/url_request/url_request_status.h" #include "testing/platform_test.h" #include "url/gurl.h" +#include "webkit/browser/fileapi/async_file_test_helper.h" #include "webkit/browser/fileapi/file_system_context.h" -#include "webkit/browser/fileapi/file_system_file_util.h" -#include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/file_system_quota_util.h" #include "webkit/browser/fileapi/file_writer_delegate.h" #include "webkit/browser/fileapi/mock_file_system_context.h" @@ -80,10 +79,6 @@ class FileWriterDelegateTest : public PlatformTest { virtual void SetUp() OVERRIDE; virtual void TearDown() OVERRIDE; - FileSystemFileUtil* file_util() { - return file_system_context_->GetFileUtil(kFileSystemType); - } - int64 usage() { return file_system_context_->GetQuotaUtil(kFileSystemType) ->GetOriginUsageOnFileThread( @@ -94,14 +89,13 @@ class FileWriterDelegateTest : public PlatformTest { // There might be in-flight flush/write. base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&base::DoNothing)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); FileSystemURL url = GetFileSystemURL(test_file_path); base::PlatformFileInfo file_info; - base::FilePath platform_path; EXPECT_EQ(base::PLATFORM_FILE_OK, - file_util()->GetFileInfo(NewOperationContext().get(), url, - &file_info, &platform_path)); + AsyncFileTestHelper::GetMetadata( + file_system_context_, url, &file_info)); return file_info.size; } @@ -110,15 +104,6 @@ class FileWriterDelegateTest : public PlatformTest { kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name)); } - scoped_ptr<FileSystemOperationContext> NewOperationContext() { - FileSystemOperationContext* context = - new FileSystemOperationContext(file_system_context_.get()); - context->set_update_observers( - *file_system_context_->GetUpdateObservers(kFileSystemType)); - context->set_root_path(dir_.path()); - return make_scoped_ptr(context); - } - FileWriterDelegate* CreateWriterDelegate( const char* test_file_path, int64 offset, @@ -231,23 +216,16 @@ void FileWriterDelegateTest::SetUp() { file_system_context_ = CreateFileSystemContextForTesting( NULL, dir_.path()); - - bool created = false; - scoped_ptr<FileSystemOperationContext> context = NewOperationContext(); - context->set_allowed_bytes_growth(kint64max); - base::PlatformFileError error = file_util()->EnsureFileExists( - context.get(), - GetFileSystemURL("test"), - &created); - ASSERT_EQ(base::PLATFORM_FILE_OK, error); - ASSERT_TRUE(created); + ASSERT_EQ(base::PLATFORM_FILE_OK, + AsyncFileTestHelper::CreateFile( + file_system_context_, GetFileSystemURL("test"))); net::URLRequest::Deprecated::RegisterProtocolFactory("blob", &Factory); } void FileWriterDelegateTest::TearDown() { net::URLRequest::Deprecated::RegisterProtocolFactory("blob", NULL); file_system_context_ = NULL; - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimit) { @@ -336,11 +314,9 @@ TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) { scoped_ptr<FileWriterDelegate> file_writer_delegate2; scoped_ptr<net::URLRequest> request2; - bool created = false; - file_util()->EnsureFileExists(NewOperationContext().get(), - GetFileSystemURL("test2"), - &created); - ASSERT_TRUE(created); + ASSERT_EQ(base::PLATFORM_FILE_OK, + AsyncFileTestHelper::CreateFile( + file_system_context_, GetFileSystemURL("test2"))); const GURL kBlobURL("blob:nolimitconcurrent"); const GURL kBlobURL2("blob:nolimitconcurrent2"); diff --git a/chromium/webkit/browser/fileapi/isolated_file_system_backend.cc b/chromium/webkit/browser/fileapi/isolated_file_system_backend.cc index db59e35c857..f83ae15d8f3 100644 --- a/chromium/webkit/browser/fileapi/isolated_file_system_backend.cc +++ b/chromium/webkit/browser/fileapi/isolated_file_system_backend.cc @@ -13,16 +13,15 @@ #include "base/message_loop/message_loop_proxy.h" #include "base/platform_file.h" #include "base/sequenced_task_runner.h" -#include "webkit/browser/blob/local_file_stream_reader.h" +#include "webkit/browser/blob/file_stream_reader.h" #include "webkit/browser/fileapi/async_file_util_adapter.h" #include "webkit/browser/fileapi/copy_or_move_file_validator.h" +#include "webkit/browser/fileapi/dragged_file_util.h" +#include "webkit/browser/fileapi/file_stream_writer.h" #include "webkit/browser/fileapi/file_system_context.h" -#include "webkit/browser/fileapi/file_system_file_stream_reader.h" +#include "webkit/browser/fileapi/file_system_operation.h" #include "webkit/browser/fileapi/file_system_operation_context.h" -#include "webkit/browser/fileapi/file_system_operation_impl.h" #include "webkit/browser/fileapi/isolated_context.h" -#include "webkit/browser/fileapi/isolated_file_util.h" -#include "webkit/browser/fileapi/local_file_stream_writer.h" #include "webkit/browser/fileapi/native_file_util.h" #include "webkit/browser/fileapi/transient_file_util.h" #include "webkit/common/fileapi/file_system_types.h" @@ -31,7 +30,7 @@ namespace fileapi { IsolatedFileSystemBackend::IsolatedFileSystemBackend() - : isolated_file_util_(new AsyncFileUtilAdapter(new IsolatedFileUtil())), + : isolated_file_util_(new AsyncFileUtilAdapter(new LocalFileUtil())), dragged_file_util_(new AsyncFileUtilAdapter(new DraggedFileUtil())), transient_file_util_(new AsyncFileUtilAdapter(new TransientFileUtil())) { } @@ -72,21 +71,6 @@ void IsolatedFileSystemBackend::OpenFileSystem( base::PLATFORM_FILE_ERROR_SECURITY)); } -FileSystemFileUtil* IsolatedFileSystemBackend::GetFileUtil( - FileSystemType type) { - switch (type) { - case kFileSystemTypeNativeLocal: - return isolated_file_util_->sync_file_util(); - case kFileSystemTypeDragged: - return dragged_file_util_->sync_file_util(); - case kFileSystemTypeForTransientFile: - return transient_file_util_->sync_file_util(); - default: - NOTREACHED(); - } - return NULL; -} - AsyncFileUtil* IsolatedFileSystemBackend::GetAsyncFileUtil( FileSystemType type) { switch (type) { @@ -114,7 +98,7 @@ FileSystemOperation* IsolatedFileSystemBackend::CreateFileSystemOperation( const FileSystemURL& url, FileSystemContext* context, base::PlatformFileError* error_code) const { - return new FileSystemOperationImpl( + return FileSystemOperation::Create( url, context, make_scoped_ptr(new FileSystemOperationContext(context))); } @@ -125,7 +109,7 @@ IsolatedFileSystemBackend::CreateFileStreamReader( const base::Time& expected_modification_time, FileSystemContext* context) const { return scoped_ptr<webkit_blob::FileStreamReader>( - new webkit_blob::LocalFileStreamReader( + webkit_blob::FileStreamReader::CreateForLocalFile( context->default_file_task_runner(), url.path(), offset, expected_modification_time)); } @@ -134,7 +118,7 @@ scoped_ptr<FileStreamWriter> IsolatedFileSystemBackend::CreateFileStreamWriter( const FileSystemURL& url, int64 offset, FileSystemContext* context) const { - return scoped_ptr<FileStreamWriter>(new LocalFileStreamWriter( + return scoped_ptr<FileStreamWriter>(FileStreamWriter::CreateForLocalFile( context->default_file_task_runner(), url.path(), offset)); } diff --git a/chromium/webkit/browser/fileapi/isolated_file_system_backend.h b/chromium/webkit/browser/fileapi/isolated_file_system_backend.h index cdc70969214..aa038442dc6 100644 --- a/chromium/webkit/browser/fileapi/isolated_file_system_backend.h +++ b/chromium/webkit/browser/fileapi/isolated_file_system_backend.h @@ -25,7 +25,6 @@ class IsolatedFileSystemBackend : public FileSystemBackend { FileSystemType type, OpenFileSystemMode mode, const OpenFileSystemCallback& callback) OVERRIDE; - virtual FileSystemFileUtil* GetFileUtil(FileSystemType type) OVERRIDE; virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE; virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory( FileSystemType type, diff --git a/chromium/webkit/browser/fileapi/local_file_stream_writer.cc b/chromium/webkit/browser/fileapi/local_file_stream_writer.cc index 3f779c969ed..75c2cad8bae 100644 --- a/chromium/webkit/browser/fileapi/local_file_stream_writer.cc +++ b/chromium/webkit/browser/fileapi/local_file_stream_writer.cc @@ -20,14 +20,12 @@ const int kOpenFlagsForWrite = base::PLATFORM_FILE_OPEN | } // namespace -LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner* task_runner, - const base::FilePath& file_path, - int64 initial_offset) - : file_path_(file_path), - initial_offset_(initial_offset), - has_pending_operation_(false), - weak_factory_(this), - task_runner_(task_runner) {} +FileStreamWriter* FileStreamWriter::CreateForLocalFile( + base::TaskRunner* task_runner, + const base::FilePath& file_path, + int64 initial_offset) { + return new LocalFileStreamWriter(task_runner, file_path, initial_offset); +} LocalFileStreamWriter::~LocalFileStreamWriter() { // Invalidate weak pointers so that we won't receive any callbacks from @@ -81,6 +79,15 @@ int LocalFileStreamWriter::Flush(const net::CompletionCallback& callback) { return result; } +LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner* task_runner, + const base::FilePath& file_path, + int64 initial_offset) + : file_path_(file_path), + initial_offset_(initial_offset), + has_pending_operation_(false), + weak_factory_(this), + task_runner_(task_runner) {} + int LocalFileStreamWriter::InitiateOpen( const net::CompletionCallback& error_callback, const base::Closure& main_operation) { diff --git a/chromium/webkit/browser/fileapi/local_file_stream_writer.h b/chromium/webkit/browser/fileapi/local_file_stream_writer.h index 08e12e80e41..dce428a56bd 100644 --- a/chromium/webkit/browser/fileapi/local_file_stream_writer.h +++ b/chromium/webkit/browser/fileapi/local_file_stream_writer.h @@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" +#include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/platform_file.h" @@ -24,13 +25,9 @@ class FileStream; namespace fileapi { // This class is a thin wrapper around net::FileStream for writing local files. -class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE LocalFileStreamWriter - : public FileStreamWriter { +class WEBKIT_STORAGE_BROWSER_EXPORT LocalFileStreamWriter + : public NON_EXPORTED_BASE(FileStreamWriter) { public: - // Creates a writer for the existing file in the path |file_path| starting - // from |initial_offset|. Uses |task_runner| for async file operations. - LocalFileStreamWriter(base::TaskRunner* task_runner, - const base::FilePath& file_path, int64 initial_offset); virtual ~LocalFileStreamWriter(); // FileStreamWriter overrides. @@ -40,6 +37,12 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE LocalFileStreamWriter virtual int Flush(const net::CompletionCallback& callback) OVERRIDE; private: + friend class FileStreamWriter; + friend class LocalFileStreamWriterTest; + LocalFileStreamWriter(base::TaskRunner* task_runner, + const base::FilePath& file_path, + int64 initial_offset); + // Opens |file_path_| and if it succeeds, proceeds to InitiateSeek(). // If failed, the error code is returned by calling |error_callback|. int InitiateOpen(const net::CompletionCallback& error_callback, diff --git a/chromium/webkit/browser/fileapi/local_file_stream_writer_unittest.cc b/chromium/webkit/browser/fileapi/local_file_stream_writer_unittest.cc index bed037d7b09..cf3c06a18cd 100644 --- a/chromium/webkit/browser/fileapi/local_file_stream_writer_unittest.cc +++ b/chromium/webkit/browser/fileapi/local_file_stream_writer_unittest.cc @@ -12,14 +12,13 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "base/threading/thread.h" #include "net/base/io_buffer.h" #include "net/base/test_completion_callback.h" #include "testing/gtest/include/gtest/gtest.h" -namespace { - -using fileapi::LocalFileStreamWriter; +namespace fileapi { class LocalFileStreamWriterTest : public testing::Test { public: @@ -34,9 +33,9 @@ class LocalFileStreamWriterTest : public testing::Test { virtual void TearDown() OVERRIDE { // Give another chance for deleted streams to perform Close. - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); file_thread_.Stop(); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } protected: @@ -65,7 +64,7 @@ class LocalFileStreamWriterTest : public testing::Test { std::string GetFileContent(const base::FilePath& path) { std::string content; - file_util::ReadFileToString(path, &content); + base::ReadFileToString(path, &content); return content; } @@ -80,6 +79,11 @@ class LocalFileStreamWriterTest : public testing::Test { return file_thread_.message_loop_proxy().get(); } + LocalFileStreamWriter* CreateWriter(const base::FilePath& path, + int64 offset) { + return new LocalFileStreamWriter(file_task_runner(), path, offset); + } + private: base::MessageLoop message_loop_; base::Thread file_thread_; @@ -90,38 +94,33 @@ void NeverCalled(int unused) { ADD_FAILURE(); } -} // namespace - TEST_F(LocalFileStreamWriterTest, Write) { base::FilePath path = CreateFileWithContent("file_a", std::string()); - scoped_ptr<LocalFileStreamWriter> writer( - new LocalFileStreamWriter(file_task_runner(), path, 0)); + scoped_ptr<LocalFileStreamWriter> writer(CreateWriter(path, 0)); EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "foo")); EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "bar")); writer.reset(); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_TRUE(base::PathExists(path)); EXPECT_EQ("foobar", GetFileContent(path)); } TEST_F(LocalFileStreamWriterTest, WriteMiddle) { base::FilePath path = CreateFileWithContent("file_a", "foobar"); - scoped_ptr<LocalFileStreamWriter> writer( - new LocalFileStreamWriter(file_task_runner(), path, 2)); + scoped_ptr<LocalFileStreamWriter> writer(CreateWriter(path, 2)); EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx")); writer.reset(); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_TRUE(base::PathExists(path)); EXPECT_EQ("foxxxr", GetFileContent(path)); } TEST_F(LocalFileStreamWriterTest, WriteEnd) { base::FilePath path = CreateFileWithContent("file_a", "foobar"); - scoped_ptr<LocalFileStreamWriter> writer( - new LocalFileStreamWriter(file_task_runner(), path, 6)); + scoped_ptr<LocalFileStreamWriter> writer(CreateWriter(path, 6)); EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "xxx")); writer.reset(); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_TRUE(base::PathExists(path)); EXPECT_EQ("foobarxxx", GetFileContent(path)); } @@ -129,18 +128,16 @@ TEST_F(LocalFileStreamWriterTest, WriteEnd) { TEST_F(LocalFileStreamWriterTest, WriteFailForNonexistingFile) { base::FilePath path = Path("file_a"); ASSERT_FALSE(base::PathExists(path)); - scoped_ptr<LocalFileStreamWriter> writer( - new LocalFileStreamWriter(file_task_runner(), path, 0)); + scoped_ptr<LocalFileStreamWriter> writer(CreateWriter(path, 0)); EXPECT_EQ(net::ERR_FILE_NOT_FOUND, WriteStringToWriter(writer.get(), "foo")); writer.reset(); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_FALSE(base::PathExists(path)); } TEST_F(LocalFileStreamWriterTest, CancelBeforeOperation) { base::FilePath path = Path("file_a"); - scoped_ptr<LocalFileStreamWriter> writer( - new LocalFileStreamWriter(file_task_runner(), path, 0)); + scoped_ptr<LocalFileStreamWriter> writer(CreateWriter(path, 0)); // Cancel immediately fails when there's no in-flight operation. int cancel_result = writer->Cancel(base::Bind(&NeverCalled)); EXPECT_EQ(net::ERR_UNEXPECTED, cancel_result); @@ -148,8 +145,7 @@ TEST_F(LocalFileStreamWriterTest, CancelBeforeOperation) { TEST_F(LocalFileStreamWriterTest, CancelAfterFinishedOperation) { base::FilePath path = CreateFileWithContent("file_a", std::string()); - scoped_ptr<LocalFileStreamWriter> writer( - new LocalFileStreamWriter(file_task_runner(), path, 0)); + scoped_ptr<LocalFileStreamWriter> writer(CreateWriter(path, 0)); EXPECT_EQ(net::OK, WriteStringToWriter(writer.get(), "foo")); // Cancel immediately fails when there's no in-flight operation. @@ -157,7 +153,7 @@ TEST_F(LocalFileStreamWriterTest, CancelAfterFinishedOperation) { EXPECT_EQ(net::ERR_UNEXPECTED, cancel_result); writer.reset(); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); // Write operation is already completed. EXPECT_TRUE(base::PathExists(path)); EXPECT_EQ("foo", GetFileContent(path)); @@ -165,8 +161,7 @@ TEST_F(LocalFileStreamWriterTest, CancelAfterFinishedOperation) { TEST_F(LocalFileStreamWriterTest, CancelWrite) { base::FilePath path = CreateFileWithContent("file_a", "foobar"); - scoped_ptr<LocalFileStreamWriter> writer( - new LocalFileStreamWriter(file_task_runner(), path, 0)); + scoped_ptr<LocalFileStreamWriter> writer(CreateWriter(path, 0)); scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer("xxx")); int result = @@ -178,3 +173,5 @@ TEST_F(LocalFileStreamWriterTest, CancelWrite) { int cancel_result = callback.WaitForResult(); EXPECT_EQ(net::OK, cancel_result); } + +} // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/local_file_util.cc b/chromium/webkit/browser/fileapi/local_file_util.cc index f13af8d207f..d2d653ac78c 100644 --- a/chromium/webkit/browser/fileapi/local_file_util.cc +++ b/chromium/webkit/browser/fileapi/local_file_util.cc @@ -8,6 +8,7 @@ #include "base/files/file_enumerator.h" #include "base/files/file_util_proxy.h" #include "url/gurl.h" +#include "webkit/browser/fileapi/async_file_util_adapter.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/file_system_url.h" @@ -17,6 +18,10 @@ namespace fileapi { +AsyncFileUtil* AsyncFileUtil::CreateForLocalFileSystem() { + return new AsyncFileUtilAdapter(new LocalFileUtil()); +} + using base::PlatformFileError; class LocalFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { @@ -69,11 +74,9 @@ bool LocalFileEnumerator::IsDirectory() { return file_util_info_.IsDirectory(); } -LocalFileUtil::LocalFileUtil() { -} +LocalFileUtil::LocalFileUtil() {} -LocalFileUtil::~LocalFileUtil() { -} +LocalFileUtil::~LocalFileUtil() {} PlatformFileError LocalFileUtil::CreateOrOpen( FileSystemOperationContext* context, @@ -157,10 +160,13 @@ PlatformFileError LocalFileUtil::GetLocalFilePath( FileSystemOperationContext* context, const FileSystemURL& url, base::FilePath* local_file_path) { - base::FilePath root = context->root_path(); - if (root.empty()) - return base::PLATFORM_FILE_ERROR_NOT_FOUND; - *local_file_path = root.Append(url.path()); + DCHECK(local_file_path); + DCHECK(url.is_valid()); + if (url.path().empty()) { + // Root direcory case, which should not be accessed. + return base::PLATFORM_FILE_ERROR_ACCESS_DENIED; + } + *local_file_path = url.path(); return base::PLATFORM_FILE_OK; } diff --git a/chromium/webkit/browser/fileapi/local_file_util.h b/chromium/webkit/browser/fileapi/local_file_util.h index abd6b54e1c3..38f285a6b04 100644 --- a/chromium/webkit/browser/fileapi/local_file_util.h +++ b/chromium/webkit/browser/fileapi/local_file_util.h @@ -6,13 +6,13 @@ #define WEBKIT_BROWSER_FILEAPI_LOCAL_FILE_UTIL_H_ #include "base/compiler_specific.h" +#include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/platform_file.h" #include "webkit/browser/fileapi/file_system_file_util.h" #include "webkit/browser/webkit_storage_browser_export.h" namespace base { -class FilePath; class Time; } @@ -24,7 +24,7 @@ class FileSystemOperationContext; class FileSystemURL; // An instance of this class is created and owned by *FileSystemBackend. -class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE LocalFileUtil +class WEBKIT_STORAGE_BROWSER_EXPORT LocalFileUtil : public FileSystemFileUtil { public: LocalFileUtil(); diff --git a/chromium/webkit/browser/fileapi/local_file_util_unittest.cc b/chromium/webkit/browser/fileapi/local_file_util_unittest.cc index b0b52e718db..bdd2d879925 100644 --- a/chromium/webkit/browser/fileapi/local_file_util_unittest.cc +++ b/chromium/webkit/browser/fileapi/local_file_util_unittest.cc @@ -7,13 +7,14 @@ #include "base/file_util.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" #include "base/platform_file.h" +#include "base/run_loop.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/browser/fileapi/async_file_test_helper.h" +#include "webkit/browser/fileapi/async_file_util_adapter.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_file_util.h" #include "webkit/browser/fileapi/file_system_operation_context.h" @@ -43,7 +44,7 @@ class LocalFileUtilTest : public testing::Test { virtual void TearDown() { file_system_context_ = NULL; - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } protected: @@ -52,13 +53,13 @@ class LocalFileUtilTest : public testing::Test { new FileSystemOperationContext(file_system_context_.get()); context->set_update_observers( *file_system_context_->GetUpdateObservers(kFileSystemType)); - context->set_root_path(data_dir_.path()); return context; } LocalFileUtil* file_util() { - return static_cast<LocalFileUtil*>( - file_system_context_->GetFileUtil(kFileSystemType)); + AsyncFileUtilAdapter* adapter = static_cast<AsyncFileUtilAdapter*>( + file_system_context_->GetAsyncFileUtil(kFileSystemType)); + return static_cast<LocalFileUtil*>(adapter->sync_file_util()); } FileSystemURL CreateURL(const std::string& file_name) { diff --git a/chromium/webkit/browser/fileapi/mock_file_system_context.cc b/chromium/webkit/browser/fileapi/mock_file_system_context.cc index e2556d5da13..ed1715c2bbe 100644 --- a/chromium/webkit/browser/fileapi/mock_file_system_context.cc +++ b/chromium/webkit/browser/fileapi/mock_file_system_context.cc @@ -39,4 +39,19 @@ FileSystemContext* CreateFileSystemContextWithAdditionalProvidersForTesting( CreateAllowFileAccessOptions()); } +FileSystemContext* CreateIncognitoFileSystemContextForTesting( + quota::QuotaManagerProxy* quota_manager_proxy, + const base::FilePath& base_path) { + ScopedVector<FileSystemBackend> additional_providers; + return new FileSystemContext( + base::MessageLoopProxy::current().get(), + base::MessageLoopProxy::current().get(), + ExternalMountPoints::CreateRefCounted().get(), + make_scoped_refptr(new quota::MockSpecialStoragePolicy()).get(), + quota_manager_proxy, + additional_providers.Pass(), + base_path, + CreateIncognitoFileSystemOptions()); +} + } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/mock_file_system_context.h b/chromium/webkit/browser/fileapi/mock_file_system_context.h index bf01ba1594d..83b904d6fde 100644 --- a/chromium/webkit/browser/fileapi/mock_file_system_context.h +++ b/chromium/webkit/browser/fileapi/mock_file_system_context.h @@ -29,6 +29,10 @@ FileSystemContext* CreateFileSystemContextWithAdditionalProvidersForTesting( ScopedVector<FileSystemBackend> additional_providers, const base::FilePath& base_path); +FileSystemContext* CreateIncognitoFileSystemContextForTesting( + quota::QuotaManagerProxy* quota_manager_proxy, + const base::FilePath& base_path); + } // namespace fileapi #endif // WEBKIT_BROWSER_FILEAPI_MOCK_FILE_SYSTEM_CONTEXT_H_ diff --git a/chromium/webkit/browser/fileapi/obfuscated_file_util.cc b/chromium/webkit/browser/fileapi/obfuscated_file_util.cc index 77e2d86a7e7..341f7d0a8bb 100644 --- a/chromium/webkit/browser/fileapi/obfuscated_file_util.cc +++ b/chromium/webkit/browser/fileapi/obfuscated_file_util.cc @@ -12,6 +12,7 @@ #include "base/format_macros.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" +#include "base/metrics/histogram.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" @@ -99,6 +100,12 @@ const base::FilePath::CharType kTemporaryDirectoryName[] = FILE_PATH_LITERAL("t" const base::FilePath::CharType kPersistentDirectoryName[] = FILE_PATH_LITERAL("p"); const base::FilePath::CharType kSyncableDirectoryName[] = FILE_PATH_LITERAL("s"); +enum IsolatedOriginStatus { + kIsolatedOriginMatch, + kIsolatedOriginDontMatch, + kIsolatedOriginStatusMax, +}; + } // namespace using base::PlatformFile; @@ -276,7 +283,7 @@ PlatformFileError ObfuscatedFileUtil::CreateOrOpen( file_flags & base::PLATFORM_FILE_WRITE && context->quota_limit_type() == quota::kQuotaLimitTypeUnlimited) { DCHECK_EQ(base::PLATFORM_FILE_OK, error); - context->file_system_context()->GetQuotaUtil(url.type())-> + context->file_system_context()->sandbox_delegate()-> StickyInvalidateUsageCache(url.origin(), url.type()); } return error; @@ -380,10 +387,9 @@ PlatformFileError ObfuscatedFileUtil::CreateDirectory( int64 growth = UsageForPath(file_info.name.size()); if (!AllocateQuota(context, growth)) return base::PLATFORM_FILE_ERROR_NO_SPACE; - if (!db->AddFileInfo(file_info, &parent_id)) { - NOTREACHED(); - return base::PLATFORM_FILE_ERROR_FAILED; - } + base::PlatformFileError error = db->AddFileInfo(file_info, &parent_id); + if (error != base::PLATFORM_FILE_OK) + return error; UpdateUsage(context, url, growth); context->change_observers()->Notify( &FileChangeObserver::OnCreateDirectory, MakeTuple(url)); @@ -1123,6 +1129,7 @@ PlatformFileError ObfuscatedFileUtil::CreateFile( DCHECK_NE(base::kInvalidPlatformFileValue, *handle); base::ClosePlatformFile(*handle); base::DeleteFile(dest_local_path, false /* recursive */); + *handle = base::kInvalidPlatformFileValue; } return base::PLATFORM_FILE_ERROR_FAILED; } @@ -1133,13 +1140,15 @@ PlatformFileError ObfuscatedFileUtil::CreateFile( dest_local_path.value().substr(root.value().length() + 1)); FileId file_id; - if (!db->AddFileInfo(*dest_file_info, &file_id)) { + error = db->AddFileInfo(*dest_file_info, &file_id); + if (error != base::PLATFORM_FILE_OK) { if (handle) { DCHECK_NE(base::kInvalidPlatformFileValue, *handle); base::ClosePlatformFile(*handle); + *handle = base::kInvalidPlatformFileValue; } base::DeleteFile(dest_local_path, false /* recursive */); - return base::PLATFORM_FILE_ERROR_FAILED; + return error; } TouchDirectory(db, dest_file_info->parent_id); @@ -1261,7 +1270,7 @@ void ObfuscatedFileUtil::InvalidateUsageCache( FileSystemOperationContext* context, const GURL& origin, FileSystemType type) { - context->file_system_context()->GetQuotaUtil(type)-> + context->file_system_context()->sandbox_delegate()-> InvalidateUsageCache(origin, type); } @@ -1436,6 +1445,15 @@ bool ObfuscatedFileUtil::HasIsolatedStorage(const GURL& origin) { isolated_origin_ = origin; // Record isolated_origin_, but always disable for now. // crbug.com/264429 + if (isolated_origin_ != origin) { + UMA_HISTOGRAM_ENUMERATION("FileSystem.IsolatedOriginStatus", + kIsolatedOriginDontMatch, + kIsolatedOriginStatusMax); + } else { + UMA_HISTOGRAM_ENUMERATION("FileSystem.IsolatedOriginStatus", + kIsolatedOriginMatch, + kIsolatedOriginStatusMax); + } return false; } return false; diff --git a/chromium/webkit/browser/fileapi/obfuscated_file_util_unittest.cc b/chromium/webkit/browser/fileapi/obfuscated_file_util_unittest.cc index c4f409f76ed..c37b17caa23 100644 --- a/chromium/webkit/browser/fileapi/obfuscated_file_util_unittest.cc +++ b/chromium/webkit/browser/fileapi/obfuscated_file_util_unittest.cc @@ -11,8 +11,8 @@ #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/platform_file.h" +#include "base/run_loop.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/browser/fileapi/async_file_test_helper.h" #include "webkit/browser/fileapi/external_mount_points.h" @@ -248,7 +248,7 @@ class ObfuscatedFileUtilTest : public testing::Test { } int64 SizeInUsageFile() { - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); int64 usage = 0; return usage_cache()->GetUsage( sandbox_file_system_.GetUsageCachePath(), &usage) ? usage : -1; @@ -375,7 +375,7 @@ class ObfuscatedFileUtilTest : public testing::Test { expected_usage_(expected_usage) {} ~UsageVerifyHelper() { - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); Check(); } @@ -2269,7 +2269,7 @@ TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAliveCase) { // Callback to Drop DB is called while ObfuscatedFileUtilTest is still alive. file_util.db_flush_delay_seconds_ = 0; file_util.MarkUsed(); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); ASSERT_TRUE(file_util.origin_database_ == NULL); } @@ -2287,7 +2287,7 @@ TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAlreadyDeletedCase) { } // At this point the callback is still in the message queue but OFU is gone. - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } TEST_F(ObfuscatedFileUtilTest, DestroyDirectoryDatabase_Isolated) { @@ -2367,9 +2367,37 @@ TEST_F(ObfuscatedFileUtilTest, MigrationBackFromIsolated) { // Check we see the same contents in the new origin directory. std::string origin_db_data; EXPECT_TRUE(base::PathExists(origin_directory.AppendASCII("dummy"))); - EXPECT_TRUE(file_util::ReadFileToString( + EXPECT_TRUE(base::ReadFileToString( origin_directory.AppendASCII("dummy"), &origin_db_data)); EXPECT_EQ(kFakeDirectoryData, origin_db_data); } +TEST_F(ObfuscatedFileUtilTest, OpenPathInNonDirectory) { + FileSystemURL file(CreateURLFromUTF8("file")); + FileSystemURL path_in_file(CreateURLFromUTF8("file/file")); + bool created; + + ASSERT_EQ(base::PLATFORM_FILE_OK, + ofu()->EnsureFileExists(UnlimitedContext().get(), file, &created)); + ASSERT_TRUE(created); + + created = false; + base::PlatformFile file_handle = base::kInvalidPlatformFileValue; + int file_flags = base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE; + ASSERT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, + ofu()->CreateOrOpen(UnlimitedContext().get(), + path_in_file, + file_flags, + &file_handle, + &created)); + ASSERT_FALSE(created); + ASSERT_EQ(base::kInvalidPlatformFileValue, file_handle); + + ASSERT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, + ofu()->CreateDirectory(UnlimitedContext().get(), + path_in_file, + false /* exclusive */, + false /* recursive */)); +} + } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/recursive_operation_delegate.cc b/chromium/webkit/browser/fileapi/recursive_operation_delegate.cc index c91c74cf148..81f26ff1c71 100644 --- a/chromium/webkit/browser/fileapi/recursive_operation_delegate.cc +++ b/chromium/webkit/browser/fileapi/recursive_operation_delegate.cc @@ -18,79 +18,88 @@ const int kMaxInflightOperations = 5; RecursiveOperationDelegate::RecursiveOperationDelegate( FileSystemContext* file_system_context) : file_system_context_(file_system_context), - inflight_operations_(0) { + inflight_operations_(0), + canceled_(false) { } RecursiveOperationDelegate::~RecursiveOperationDelegate() { } +void RecursiveOperationDelegate::Cancel() { + canceled_ = true; +} + void RecursiveOperationDelegate::StartRecursiveOperation( const FileSystemURL& root, const StatusCallback& callback) { + DCHECK(pending_directory_stack_.empty()); + DCHECK(pending_files_.empty()); + DCHECK_EQ(0, inflight_operations_); + callback_ = callback; - pending_directories_.push(root); - ProcessNextDirectory(); + ++inflight_operations_; + ProcessFile( + root, + base::Bind(&RecursiveOperationDelegate::DidTryProcessFile, + AsWeakPtr(), root)); } FileSystemOperationRunner* RecursiveOperationDelegate::operation_runner() { return file_system_context_->operation_runner(); } -void RecursiveOperationDelegate::ProcessNextDirectory() { +void RecursiveOperationDelegate::DidTryProcessFile( + const FileSystemURL& root, + base::PlatformFileError error) { + DCHECK(pending_directory_stack_.empty()); DCHECK(pending_files_.empty()); - if (inflight_operations_ > 0) - return; - if (pending_directories_.empty()) { - callback_.Run(base::PLATFORM_FILE_OK); - return; - } - FileSystemURL url = pending_directories_.front(); - pending_directories_.pop(); - inflight_operations_++; - ProcessDirectory( - url, base::Bind(&RecursiveOperationDelegate::DidProcessDirectory, - AsWeakPtr(), url)); -} + DCHECK_EQ(1, inflight_operations_); -void RecursiveOperationDelegate::ProcessPendingFiles() { - if (pending_files_.empty()) { - ProcessNextDirectory(); + --inflight_operations_; + if (canceled_ || error != base::PLATFORM_FILE_ERROR_NOT_A_FILE) { + Done(error); return; } - while (!pending_files_.empty() && - inflight_operations_ < kMaxInflightOperations) { - FileSystemURL url = pending_files_.front(); - pending_files_.pop(); - inflight_operations_++; - base::MessageLoopProxy::current()->PostTask( - FROM_HERE, - base::Bind(&RecursiveOperationDelegate::ProcessFile, - AsWeakPtr(), url, - base::Bind(&RecursiveOperationDelegate::DidProcessFile, - AsWeakPtr()))); - } + + pending_directory_stack_.push(std::queue<FileSystemURL>()); + pending_directory_stack_.top().push(root); + ProcessNextDirectory(); } -void RecursiveOperationDelegate::DidProcessFile(base::PlatformFileError error) { - inflight_operations_--; - DCHECK_GE(inflight_operations_, 0); - if (error != base::PLATFORM_FILE_OK) { - callback_.Run(error); - return; - } - ProcessPendingFiles(); +void RecursiveOperationDelegate::ProcessNextDirectory() { + DCHECK(pending_files_.empty()); + DCHECK(!pending_directory_stack_.empty()); + DCHECK(!pending_directory_stack_.top().empty()); + DCHECK_EQ(0, inflight_operations_); + + const FileSystemURL& url = pending_directory_stack_.top().front(); + + ++inflight_operations_; + ProcessDirectory( + url, + base::Bind( + &RecursiveOperationDelegate::DidProcessDirectory, AsWeakPtr())); } void RecursiveOperationDelegate::DidProcessDirectory( - const FileSystemURL& url, base::PlatformFileError error) { - if (error != base::PLATFORM_FILE_OK) { - callback_.Run(error); + DCHECK(pending_files_.empty()); + DCHECK(!pending_directory_stack_.empty()); + DCHECK(!pending_directory_stack_.top().empty()); + DCHECK_EQ(1, inflight_operations_); + + --inflight_operations_; + if (canceled_ || error != base::PLATFORM_FILE_OK) { + Done(error); return; } + + const FileSystemURL& parent = pending_directory_stack_.top().front(); + pending_directory_stack_.push(std::queue<FileSystemURL>()); operation_runner()->ReadDirectory( - url, base::Bind(&RecursiveOperationDelegate::DidReadDirectory, - AsWeakPtr(), url)); + parent, + base::Bind(&RecursiveOperationDelegate::DidReadDirectory, + AsWeakPtr(), parent)); } void RecursiveOperationDelegate::DidReadDirectory( @@ -98,44 +107,130 @@ void RecursiveOperationDelegate::DidReadDirectory( base::PlatformFileError error, const FileEntryList& entries, bool has_more) { - if (error != base::PLATFORM_FILE_OK) { - if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) { - // The given path may have been a file, so try RemoveFile now. - ProcessFile(parent, - base::Bind(&RecursiveOperationDelegate::DidTryProcessFile, - AsWeakPtr(), error)); - return; - } - callback_.Run(error); + DCHECK(pending_files_.empty()); + DCHECK(!pending_directory_stack_.empty()); + DCHECK_EQ(0, inflight_operations_); + + if (canceled_ || error != base::PLATFORM_FILE_OK) { + Done(error); return; } + for (size_t i = 0; i < entries.size(); i++) { FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( parent.origin(), parent.mount_type(), parent.virtual_path().Append(entries[i].name)); if (entries[i].is_directory) - pending_directories_.push(url); + pending_directory_stack_.top().push(url); else pending_files_.push(url); } + + // Wait for next entries. if (has_more) return; - inflight_operations_--; - DCHECK_GE(inflight_operations_, 0); ProcessPendingFiles(); } -void RecursiveOperationDelegate::DidTryProcessFile( - base::PlatformFileError previous_error, +void RecursiveOperationDelegate::ProcessPendingFiles() { + DCHECK(!pending_directory_stack_.empty()); + + if ((pending_files_.empty() || canceled_) && inflight_operations_ == 0) { + ProcessSubDirectory(); + return; + } + + // Do not post any new tasks. + if (canceled_) + return; + + // Run ProcessFile in parallel (upto kMaxInflightOperations). + scoped_refptr<base::MessageLoopProxy> current_message_loop = + base::MessageLoopProxy::current(); + while (!pending_files_.empty() && + inflight_operations_ < kMaxInflightOperations) { + ++inflight_operations_; + current_message_loop->PostTask( + FROM_HERE, + base::Bind(&RecursiveOperationDelegate::ProcessFile, + AsWeakPtr(), pending_files_.front(), + base::Bind(&RecursiveOperationDelegate::DidProcessFile, + AsWeakPtr()))); + pending_files_.pop(); + } +} + +void RecursiveOperationDelegate::DidProcessFile( + base::PlatformFileError error) { + --inflight_operations_; + if (error != base::PLATFORM_FILE_OK) { + // If an error occurs, invoke Done immediately (even if there remain + // running operations). It is because in the callback, this instance is + // deleted. + Done(error); + return; + } + + ProcessPendingFiles(); +} + +void RecursiveOperationDelegate::ProcessSubDirectory() { + DCHECK(pending_files_.empty()); + DCHECK(!pending_directory_stack_.empty()); + DCHECK_EQ(0, inflight_operations_); + + if (canceled_) { + Done(base::PLATFORM_FILE_ERROR_ABORT); + return; + } + + if (!pending_directory_stack_.top().empty()) { + // There remain some sub directories. Process them first. + ProcessNextDirectory(); + return; + } + + // All subdirectories are processed. + pending_directory_stack_.pop(); + if (pending_directory_stack_.empty()) { + // All files/directories are processed. + Done(base::PLATFORM_FILE_OK); + return; + } + + DCHECK(!pending_directory_stack_.top().empty()); + ++inflight_operations_; + PostProcessDirectory( + pending_directory_stack_.top().front(), + base::Bind(&RecursiveOperationDelegate::DidPostProcessDirectory, + AsWeakPtr())); +} + +void RecursiveOperationDelegate::DidPostProcessDirectory( base::PlatformFileError error) { - if (error == base::PLATFORM_FILE_ERROR_NOT_A_FILE) { - // It wasn't a file either; returns with the previous error. - callback_.Run(previous_error); + DCHECK(pending_files_.empty()); + DCHECK(!pending_directory_stack_.empty()); + DCHECK(!pending_directory_stack_.top().empty()); + DCHECK_EQ(1, inflight_operations_); + + --inflight_operations_; + pending_directory_stack_.top().pop(); + if (canceled_ || error != base::PLATFORM_FILE_OK) { + Done(error); return; } - DidProcessFile(error); + + ProcessSubDirectory(); +} + +void RecursiveOperationDelegate::Done(base::PlatformFileError error) { + if (canceled_ && error == base::PLATFORM_FILE_OK) { + callback_.Run(base::PLATFORM_FILE_ERROR_ABORT); + } else { + callback_.Run(error); + } } } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/recursive_operation_delegate.h b/chromium/webkit/browser/fileapi/recursive_operation_delegate.h index 551d875d125..a5266777341 100644 --- a/chromium/webkit/browser/fileapi/recursive_operation_delegate.h +++ b/chromium/webkit/browser/fileapi/recursive_operation_delegate.h @@ -6,6 +6,7 @@ #define WEBKIT_BROWSER_FILEAPI_RECURSIVE_OPERATION_DELEGATE_H_ #include <queue> +#include <stack> #include "base/basictypes.h" #include "base/callback.h" @@ -19,23 +20,16 @@ class FileSystemContext; class FileSystemOperationRunner; // A base class for recursive operation delegates. -// This also provides some convenient default implementations for subclasses -// like StartRecursiveOperation() and NewNestedOperation(). // // In short, each subclass should override ProcessFile and ProcessDirectory // to process a directory or a file. To start the recursive operation it // should also call StartRecursiveOperation. -// -// Each subclass can call NewNestedOperation to create a new file system -// operation to perform a sub-operations, e.g. can call RemoveFile for -// recursive Remove. -class RecursiveOperationDelegate +class WEBKIT_STORAGE_BROWSER_EXPORT RecursiveOperationDelegate : public base::SupportsWeakPtr<RecursiveOperationDelegate> { public: typedef FileSystemOperation::StatusCallback StatusCallback; typedef FileSystemOperation::FileEntryList FileEntryList; - RecursiveOperationDelegate(FileSystemContext* file_system_context); virtual ~RecursiveOperationDelegate(); // This is called when the consumer of this instance starts a non-recursive @@ -56,10 +50,58 @@ class RecursiveOperationDelegate virtual void ProcessDirectory(const FileSystemURL& url, const StatusCallback& callback) = 0; + + // This is called each time after files and subdirectories for a + // directory is processed while recursively performing an operation. + virtual void PostProcessDirectory(const FileSystemURL& url, + const StatusCallback& callback) = 0; + + // Cancels the currently running operation. + void Cancel(); + protected: + explicit RecursiveOperationDelegate(FileSystemContext* file_system_context); + // Starts to process files/directories recursively from the given |root|. - // This will call ProcessFile and ProcessDirectory on each directory or file. - // If the given |root| is a file this simply calls ProcessFile and exits. + // This will call ProcessFile and ProcessDirectory on each file or directory. + // + // First, this tries to call ProcessFile with |root| regardless whether it is + // actually a file or a directory. If it is a directory, ProcessFile should + // return PLATFORM_FILE_NOT_A_FILE. + // + // For each directory, the recursive operation works as follows: + // ProcessDirectory is called first for the directory. + // Then the directory contents are read (to obtain its sub directories and + // files in it). + // ProcessFile is called for found files. This may run in parallel. + // The same step is recursively applied to each subdirectory. + // After all files and subdirectories in a directory are processed, + // PostProcessDirectory is called for the directory. + // Here is an example; + // a_dir/ -+- b1_dir/ -+- c1_dir/ -+- d1_file + // | | | + // | +- c2_file +- d2_file + // | + // +- b2_dir/ --- e_dir/ + // | + // +- b3_file + // | + // +- b4_file + // Then traverse order is: + // ProcessFile(a_dir) (This should return PLATFORM_FILE_NOT_A_FILE). + // ProcessDirectory(a_dir). + // ProcessFile(b3_file), ProcessFile(b4_file). (in parallel). + // ProcessDirectory(b1_dir). + // ProcessFile(c2_file) + // ProcessDirectory(c1_dir). + // ProcessFile(d1_file), ProcessFile(d2_file). (in parallel). + // PostProcessDirectory(c1_dir) + // PostProcessDirectory(b1_dir). + // ProcessDirectory(b2_dir) + // ProcessDirectory(e_dir) + // PostProcessDirectory(e_dir) + // PostProcessDirectory(b2_dir) + // PostProcessDirectory(a_dir) // // |callback| is fired with base::PLATFORM_FILE_OK when every file/directory // under |root| is processed, or fired earlier when any suboperation fails. @@ -74,24 +116,29 @@ class RecursiveOperationDelegate FileSystemOperationRunner* operation_runner(); private: + void DidTryProcessFile(const FileSystemURL& root, + base::PlatformFileError error); void ProcessNextDirectory(); + void DidProcessDirectory(base::PlatformFileError error); + void DidReadDirectory(const FileSystemURL& parent, + base::PlatformFileError error, + const FileEntryList& entries, + bool has_more); void ProcessPendingFiles(); void DidProcessFile(base::PlatformFileError error); - void DidProcessDirectory(const FileSystemURL& url, - base::PlatformFileError error); - void DidReadDirectory( - const FileSystemURL& parent, - base::PlatformFileError error, - const FileEntryList& entries, - bool has_more); - void DidTryProcessFile(base::PlatformFileError previous_error, - base::PlatformFileError error); + void ProcessSubDirectory(); + void DidPostProcessDirectory(base::PlatformFileError error); + + // Called when all recursive operation is done (or an error occurs). + void Done(base::PlatformFileError error); FileSystemContext* file_system_context_; StatusCallback callback_; - std::queue<FileSystemURL> pending_directories_; + std::stack<FileSystemURL> pending_directories_; + std::stack<std::queue<FileSystemURL> > pending_directory_stack_; std::queue<FileSystemURL> pending_files_; int inflight_operations_; + bool canceled_; DISALLOW_COPY_AND_ASSIGN(RecursiveOperationDelegate); }; diff --git a/chromium/webkit/browser/fileapi/recursive_operation_delegate_unittest.cc b/chromium/webkit/browser/fileapi/recursive_operation_delegate_unittest.cc new file mode 100644 index 00000000000..b3842279420 --- /dev/null +++ b/chromium/webkit/browser/fileapi/recursive_operation_delegate_unittest.cc @@ -0,0 +1,280 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/browser/fileapi/recursive_operation_delegate.h" + +#include <vector> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/scoped_temp_dir.h" +#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/run_loop.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/browser/fileapi/file_system_file_util.h" +#include "webkit/browser/fileapi/file_system_operation.h" +#include "webkit/browser/fileapi/file_system_operation_runner.h" +#include "webkit/browser/fileapi/sandbox_file_system_test_helper.h" + +namespace fileapi { +namespace { + +class LoggingRecursiveOperation : public RecursiveOperationDelegate { + public: + struct LogEntry { + enum Type { + PROCESS_FILE, + PROCESS_DIRECTORY, + POST_PROCESS_DIRECTORY + }; + Type type; + FileSystemURL url; + }; + + LoggingRecursiveOperation(FileSystemContext* file_system_context, + const FileSystemURL& root, + const StatusCallback& callback) + : RecursiveOperationDelegate(file_system_context), + root_(root), + callback_(callback), + weak_factory_(this) { + } + virtual ~LoggingRecursiveOperation() {} + + const std::vector<LogEntry>& log_entries() const { return log_entries_; } + + // RecursiveOperationDelegate overrides. + virtual void Run() OVERRIDE { + NOTREACHED(); + } + + virtual void RunRecursively() OVERRIDE { + StartRecursiveOperation(root_, callback_); + } + + virtual void ProcessFile(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE { + RecordLogEntry(LogEntry::PROCESS_FILE, url); + operation_runner()->GetMetadata( + url, + base::Bind(&LoggingRecursiveOperation::DidGetMetadata, + weak_factory_.GetWeakPtr(), callback)); + } + + virtual void ProcessDirectory(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE { + RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url); + callback.Run(base::PLATFORM_FILE_OK); + } + + virtual void PostProcessDirectory(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE { + RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY, url); + callback.Run(base::PLATFORM_FILE_OK); + } + + private: + void RecordLogEntry(LogEntry::Type type, const FileSystemURL& url) { + LogEntry entry; + entry.type = type; + entry.url = url; + log_entries_.push_back(entry); + } + + void DidGetMetadata(const StatusCallback& callback, + base::PlatformFileError result, + const base::PlatformFileInfo& file_info) { + if (result != base::PLATFORM_FILE_OK) { + callback.Run(result); + return; + } + + callback.Run(file_info.is_directory ? + base::PLATFORM_FILE_ERROR_NOT_A_FILE : + base::PLATFORM_FILE_OK); + } + + FileSystemURL root_; + StatusCallback callback_; + std::vector<LogEntry> log_entries_; + + base::WeakPtrFactory<LoggingRecursiveOperation> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation); +}; + +void ReportStatus(base::PlatformFileError* out_error, + base::PlatformFileError error) { + DCHECK(out_error); + *out_error = error; +} + +// To test the Cancel() during operation, calls Cancel() of |operation| +// after |counter| times message posting. +void CallCancelLater(RecursiveOperationDelegate* operation, int counter) { + if (counter > 0) { + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, + base::Bind(&CallCancelLater, base::Unretained(operation), counter - 1)); + return; + } + + operation->Cancel(); +} + +} // namespace + +class RecursiveOperationDelegateTest : public testing::Test { + protected: + virtual void SetUp() OVERRIDE { + EXPECT_TRUE(base_.CreateUniqueTempDir()); + sandbox_file_system_.SetUp(base_.path().AppendASCII("filesystem")); + } + + virtual void TearDown() OVERRIDE { + sandbox_file_system_.TearDown(); + } + + scoped_ptr<FileSystemOperationContext> NewContext() { + FileSystemOperationContext* context = + sandbox_file_system_.NewOperationContext(); + // Grant enough quota for all test cases. + context->set_allowed_bytes_growth(1000000); + return make_scoped_ptr(context); + } + + FileSystemFileUtil* file_util() { + return sandbox_file_system_.file_util(); + } + + FileSystemURL URLForPath(const std::string& path) const { + return sandbox_file_system_.CreateURLFromUTF8(path); + } + + FileSystemURL CreateFile(const std::string& path) { + FileSystemURL url = URLForPath(path); + bool created = false; + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_util()->EnsureFileExists(NewContext().get(), + url, &created)); + EXPECT_TRUE(created); + return url; + } + + FileSystemURL CreateDirectory(const std::string& path) { + FileSystemURL url = URLForPath(path); + EXPECT_EQ(base::PLATFORM_FILE_OK, + file_util()->CreateDirectory(NewContext().get(), url, + false /* exclusive */, true)); + return url; + } + + private: + base::MessageLoop message_loop_; + + // Common temp base for nondestructive uses. + base::ScopedTempDir base_; + SandboxFileSystemTestHelper sandbox_file_system_; +}; + +TEST_F(RecursiveOperationDelegateTest, RootIsFile) { + FileSystemURL src_file(CreateFile("src")); + + base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; + scoped_ptr<FileSystemOperationContext> context = NewContext(); + scoped_ptr<LoggingRecursiveOperation> operation( + new LoggingRecursiveOperation( + context->file_system_context(), src_file, + base::Bind(&ReportStatus, &error))); + operation->RunRecursively(); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(base::PLATFORM_FILE_OK, error); + + const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries = + operation->log_entries(); + ASSERT_EQ(1U, log_entries.size()); + const LoggingRecursiveOperation::LogEntry& entry = log_entries[0]; + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, entry.type); + EXPECT_EQ(src_file, entry.url); +} + +TEST_F(RecursiveOperationDelegateTest, RootIsDirectory) { + FileSystemURL src_root(CreateDirectory("src")); + FileSystemURL src_dir1(CreateDirectory("src/dir1")); + FileSystemURL src_file1(CreateFile("src/file1")); + FileSystemURL src_file2(CreateFile("src/dir1/file2")); + FileSystemURL src_file3(CreateFile("src/dir1/file3")); + + base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; + scoped_ptr<FileSystemOperationContext> context = NewContext(); + scoped_ptr<LoggingRecursiveOperation> operation( + new LoggingRecursiveOperation( + context->file_system_context(), src_root, + base::Bind(&ReportStatus, &error))); + operation->RunRecursively(); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(base::PLATFORM_FILE_OK, error); + + const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries = + operation->log_entries(); + ASSERT_EQ(8U, log_entries.size()); + + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, + log_entries[0].type); + EXPECT_EQ(src_root, log_entries[0].url); + + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY, + log_entries[1].type); + EXPECT_EQ(src_root, log_entries[1].url); + + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, + log_entries[2].type); + EXPECT_EQ(src_file1, log_entries[2].url); + + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY, + log_entries[3].type); + EXPECT_EQ(src_dir1, log_entries[3].url); + + // The order of src/dir1/file2 and src/dir1/file3 depends on the file system + // implementation (can be swapped). + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, + log_entries[4].type); + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, + log_entries[5].type); + EXPECT_TRUE((src_file2 == log_entries[4].url && + src_file3 == log_entries[5].url) || + (src_file3 == log_entries[4].url && + src_file2 == log_entries[5].url)); + + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY, + log_entries[6].type); + EXPECT_EQ(src_dir1, log_entries[6].url); + + EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY, + log_entries[7].type); + EXPECT_EQ(src_root, log_entries[7].url); +} + +TEST_F(RecursiveOperationDelegateTest, Cancel) { + FileSystemURL src_root(CreateDirectory("src")); + FileSystemURL src_dir1(CreateDirectory("src/dir1")); + FileSystemURL src_file1(CreateFile("src/file1")); + FileSystemURL src_file2(CreateFile("src/dir1/file2")); + + base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; + scoped_ptr<FileSystemOperationContext> context = NewContext(); + scoped_ptr<LoggingRecursiveOperation> operation( + new LoggingRecursiveOperation( + context->file_system_context(), src_root, + base::Bind(&ReportStatus, &error))); + operation->RunRecursively(); + + // Invoke Cancel(), after 5 times message posting. + CallCancelLater(operation.get(), 5); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(base::PLATFORM_FILE_ERROR_ABORT, error); +} + +} // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/remove_operation_delegate.cc b/chromium/webkit/browser/fileapi/remove_operation_delegate.cc index fcd9ba9cee2..4819f0164e5 100644 --- a/chromium/webkit/browser/fileapi/remove_operation_delegate.cc +++ b/chromium/webkit/browser/fileapi/remove_operation_delegate.cc @@ -28,38 +28,47 @@ void RemoveOperationDelegate::Run() { } void RemoveOperationDelegate::RunRecursively() { - StartRecursiveOperation( - url_, - base::Bind(&RemoveOperationDelegate::RemoveNextDirectory, - weak_factory_.GetWeakPtr())); + StartRecursiveOperation(url_, callback_); } void RemoveOperationDelegate::ProcessFile(const FileSystemURL& url, const StatusCallback& callback) { - if (to_remove_directories_.size() == 1u && - to_remove_directories_.top() == url) { - // We seem to have been re-directed from ProcessDirectory. - to_remove_directories_.pop(); - } - operation_runner()->RemoveFile(url, base::Bind( - &RemoveOperationDelegate::DidRemoveFile, - weak_factory_.GetWeakPtr(), callback)); + operation_runner()->RemoveFile( + url, + base::Bind(&RemoveOperationDelegate::DidRemoveFile, + weak_factory_.GetWeakPtr(), callback)); } void RemoveOperationDelegate::ProcessDirectory(const FileSystemURL& url, const StatusCallback& callback) { - to_remove_directories_.push(url); callback.Run(base::PLATFORM_FILE_OK); } +void RemoveOperationDelegate::PostProcessDirectory( + const FileSystemURL& url, const StatusCallback& callback) { + operation_runner()->RemoveDirectory(url, callback); +} + void RemoveOperationDelegate::DidTryRemoveFile( base::PlatformFileError error) { - if (error == base::PLATFORM_FILE_OK || - error != base::PLATFORM_FILE_ERROR_NOT_A_FILE) { + if (error != base::PLATFORM_FILE_ERROR_NOT_A_FILE && + error != base::PLATFORM_FILE_ERROR_SECURITY) { callback_.Run(error); return; } - operation_runner()->RemoveDirectory(url_, callback_); + operation_runner()->RemoveDirectory( + url_, + base::Bind(&RemoveOperationDelegate::DidTryRemoveDirectory, + weak_factory_.GetWeakPtr(), error)); +} + +void RemoveOperationDelegate::DidTryRemoveDirectory( + base::PlatformFileError remove_file_error, + base::PlatformFileError remove_directory_error) { + callback_.Run( + remove_directory_error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY ? + remove_file_error : + remove_directory_error); } void RemoveOperationDelegate::DidRemoveFile(const StatusCallback& callback, @@ -71,18 +80,4 @@ void RemoveOperationDelegate::DidRemoveFile(const StatusCallback& callback, callback.Run(error); } -void RemoveOperationDelegate::RemoveNextDirectory( - base::PlatformFileError error) { - if (error != base::PLATFORM_FILE_OK || - to_remove_directories_.empty()) { - callback_.Run(error); - return; - } - FileSystemURL url = to_remove_directories_.top(); - to_remove_directories_.pop(); - operation_runner()->RemoveDirectory(url, base::Bind( - &RemoveOperationDelegate::RemoveNextDirectory, - weak_factory_.GetWeakPtr())); -} - } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/remove_operation_delegate.h b/chromium/webkit/browser/fileapi/remove_operation_delegate.h index ef9e1a09409..22d25cb9833 100644 --- a/chromium/webkit/browser/fileapi/remove_operation_delegate.h +++ b/chromium/webkit/browser/fileapi/remove_operation_delegate.h @@ -11,8 +11,7 @@ namespace fileapi { -class RemoveOperationDelegate - : public RecursiveOperationDelegate { +class RemoveOperationDelegate : public RecursiveOperationDelegate { public: RemoveOperationDelegate(FileSystemContext* file_system_context, const FileSystemURL& url, @@ -26,20 +25,19 @@ class RemoveOperationDelegate const StatusCallback& callback) OVERRIDE; virtual void ProcessDirectory(const FileSystemURL& url, const StatusCallback& callback) OVERRIDE; + virtual void PostProcessDirectory(const FileSystemURL& url, + const StatusCallback& callback) OVERRIDE; private: void DidTryRemoveFile(base::PlatformFileError error); + void DidTryRemoveDirectory(base::PlatformFileError remove_file_error, + base::PlatformFileError remove_directory_error); void DidRemoveFile(const StatusCallback& callback, base::PlatformFileError error); - void RemoveNextDirectory(base::PlatformFileError error); FileSystemURL url_; StatusCallback callback_; - - std::stack<FileSystemURL> to_remove_directories_; - base::WeakPtrFactory<RemoveOperationDelegate> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(RemoveOperationDelegate); }; diff --git a/chromium/webkit/browser/fileapi/sandbox_directory_database.cc b/chromium/webkit/browser/fileapi/sandbox_directory_database.cc index 8a90bd33479..06ab1e50acf 100644 --- a/chromium/webkit/browser/fileapi/sandbox_directory_database.cc +++ b/chromium/webkit/browser/fileapi/sandbox_directory_database.cc @@ -518,10 +518,10 @@ bool SandboxDirectoryDatabase::GetFileInfo(FileId file_id, FileInfo* info) { return false; } -bool SandboxDirectoryDatabase::AddFileInfo( +base::PlatformFileError SandboxDirectoryDatabase::AddFileInfo( const FileInfo& info, FileId* file_id) { if (!Init(REPAIR_ON_CORRUPTION)) - return false; + return base::PLATFORM_FILE_ERROR_FAILED; DCHECK(file_id); std::string child_key = GetChildLookupKey(info.parent_id, info.name); std::string child_id_string; @@ -529,36 +529,36 @@ bool SandboxDirectoryDatabase::AddFileInfo( db_->Get(leveldb::ReadOptions(), child_key, &child_id_string); if (status.ok()) { LOG(ERROR) << "File exists already!"; - return false; + return base::PLATFORM_FILE_ERROR_EXISTS; } if (!status.IsNotFound()) { HandleError(FROM_HERE, status); - return false; + return base::PLATFORM_FILE_ERROR_NOT_FOUND; } if (!VerifyIsDirectory(info.parent_id)) - return false; + return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; // This would be a fine place to limit the number of files in a directory, if // we decide to add that restriction. FileId temp_id; if (!GetLastFileId(&temp_id)) - return false; + return base::PLATFORM_FILE_ERROR_FAILED; ++temp_id; leveldb::WriteBatch batch; if (!AddFileInfoHelper(info, temp_id, &batch)) - return false; + return base::PLATFORM_FILE_ERROR_FAILED; batch.Put(LastFileIdKey(), base::Int64ToString(temp_id)); status = db_->Write(leveldb::WriteOptions(), &batch); if (!status.ok()) { HandleError(FROM_HERE, status); - return false; + return base::PLATFORM_FILE_ERROR_FAILED; } *file_id = temp_id; - return true; + return base::PLATFORM_FILE_OK; } bool SandboxDirectoryDatabase::RemoveFileInfo(FileId file_id) { @@ -715,7 +715,7 @@ bool SandboxDirectoryDatabase::Init(RecoveryOption recovery_option) { FilePathToString(filesystem_data_directory_.Append( kDirectoryDatabaseName)); leveldb::Options options; - options.max_open_files = 64; // Use minimum. + options.max_open_files = 0; // Use minimum. options.create_if_missing = true; leveldb::DB* db; leveldb::Status status = leveldb::DB::Open(options, path, &db); @@ -763,7 +763,7 @@ bool SandboxDirectoryDatabase::Init(RecoveryOption recovery_option) { bool SandboxDirectoryDatabase::RepairDatabase(const std::string& db_path) { DCHECK(!db_.get()); leveldb::Options options; - options.max_open_files = 64; // Use minimum. + options.max_open_files = 0; // Use minimum. if (!leveldb::RepairDB(db_path, options).ok()) return false; if (!Init(FAIL_ON_CORRUPTION)) diff --git a/chromium/webkit/browser/fileapi/sandbox_directory_database.h b/chromium/webkit/browser/fileapi/sandbox_directory_database.h index 4cbd43b6cbd..0ad948d630f 100644 --- a/chromium/webkit/browser/fileapi/sandbox_directory_database.h +++ b/chromium/webkit/browser/fileapi/sandbox_directory_database.h @@ -10,6 +10,7 @@ #include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" +#include "base/platform_file.h" #include "base/time/time.h" #include "webkit/browser/webkit_storage_browser_export.h" @@ -68,7 +69,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE SandboxDirectoryDatabase { // exist. bool ListChildren(FileId parent_id, std::vector<FileId>* children); bool GetFileInfo(FileId file_id, FileInfo* info); - bool AddFileInfo(const FileInfo& info, FileId* file_id); + base::PlatformFileError AddFileInfo(const FileInfo& info, FileId* file_id); bool RemoveFileInfo(FileId file_id); // This does a full update of the FileInfo, and is what you'd use for moves // and renames. If you just want to update the modification_time, use diff --git a/chromium/webkit/browser/fileapi/sandbox_directory_database_unittest.cc b/chromium/webkit/browser/fileapi/sandbox_directory_database_unittest.cc index 593ead96efb..9281446e2fd 100644 --- a/chromium/webkit/browser/fileapi/sandbox_directory_database_unittest.cc +++ b/chromium/webkit/browser/fileapi/sandbox_directory_database_unittest.cc @@ -51,7 +51,8 @@ class SandboxDirectoryDatabaseTest : public testing::Test { db_.reset(); } - bool AddFileInfo(FileId parent_id, const base::FilePath::StringType& name) { + base::PlatformFileError AddFileInfo( + FileId parent_id, const base::FilePath::StringType& name) { FileId file_id; FileInfo info; info.parent_id = parent_id; @@ -65,7 +66,7 @@ class SandboxDirectoryDatabaseTest : public testing::Test { FileInfo info; info.parent_id = parent_id; info.name = name; - ASSERT_TRUE(db_->AddFileInfo(info, file_id_out)); + ASSERT_EQ(base::PLATFORM_FILE_OK, db_->AddFileInfo(info, file_id_out)); } void CreateFile(FileId parent_id, @@ -78,7 +79,7 @@ class SandboxDirectoryDatabaseTest : public testing::Test { info.parent_id = parent_id; info.name = name; info.data_path = base::FilePath(data_path).NormalizePathSeparators(); - ASSERT_TRUE(db_->AddFileInfo(info, &file_id)); + ASSERT_EQ(base::PLATFORM_FILE_OK, db_->AddFileInfo(info, &file_id)); base::FilePath local_path = path().Append(data_path); if (!base::DirectoryExists(local_path.DirName())) @@ -160,7 +161,8 @@ TEST_F(SandboxDirectoryDatabaseTest, TestGetRootFileInfoBeforeCreate) { TEST_F(SandboxDirectoryDatabaseTest, TestMissingParentAddFileInfo) { FileId parent_id = 7; - EXPECT_FALSE(AddFileInfo(parent_id, FILE_PATH_LITERAL("foo"))); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, + AddFileInfo(parent_id, FILE_PATH_LITERAL("foo"))); } TEST_F(SandboxDirectoryDatabaseTest, TestAddNameClash) { @@ -168,21 +170,21 @@ TEST_F(SandboxDirectoryDatabaseTest, TestAddNameClash) { FileId file_id; info.parent_id = 0; info.name = FILE_PATH_LITERAL("dir 0"); - EXPECT_TRUE(db()->AddFileInfo(info, &file_id)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id)); // Check for name clash in the root directory. base::FilePath::StringType name = info.name; - EXPECT_FALSE(AddFileInfo(0, name)); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, AddFileInfo(0, name)); name = FILE_PATH_LITERAL("dir 1"); - EXPECT_TRUE(AddFileInfo(0, name)); + EXPECT_EQ(base::PLATFORM_FILE_OK, AddFileInfo(0, name)); name = FILE_PATH_LITERAL("subdir 0"); - EXPECT_TRUE(AddFileInfo(file_id, name)); + EXPECT_EQ(base::PLATFORM_FILE_OK, AddFileInfo(file_id, name)); // Check for name clash in a subdirectory. - EXPECT_FALSE(AddFileInfo(file_id, name)); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, AddFileInfo(file_id, name)); name = FILE_PATH_LITERAL("subdir 1"); - EXPECT_TRUE(AddFileInfo(file_id, name)); + EXPECT_EQ(base::PLATFORM_FILE_OK, AddFileInfo(file_id, name)); } TEST_F(SandboxDirectoryDatabaseTest, TestRenameNoMoveNameClash) { @@ -193,8 +195,8 @@ TEST_F(SandboxDirectoryDatabaseTest, TestRenameNoMoveNameClash) { base::FilePath::StringType name2 = FILE_PATH_LITERAL("bas"); info.parent_id = 0; info.name = name0; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); - EXPECT_TRUE(AddFileInfo(0, name1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id0)); + EXPECT_EQ(base::PLATFORM_FILE_OK, AddFileInfo(0, name1)); info.name = name1; EXPECT_FALSE(db()->UpdateFileInfo(file_id0, info)); info.name = name2; @@ -209,9 +211,9 @@ TEST_F(SandboxDirectoryDatabaseTest, TestMoveSameNameNameClash) { base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); info.parent_id = 0; info.name = name0; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id1)); info.parent_id = 0; EXPECT_FALSE(db()->UpdateFileInfo(file_id1, info)); info.name = name1; @@ -227,10 +229,10 @@ TEST_F(SandboxDirectoryDatabaseTest, TestMoveRenameNameClash) { base::FilePath::StringType name2 = FILE_PATH_LITERAL("bas"); info.parent_id = 0; info.name = name0; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; info.name = name1; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id1)); info.parent_id = 0; info.name = name0; EXPECT_FALSE(db()->UpdateFileInfo(file_id1, info)); @@ -248,9 +250,9 @@ TEST_F(SandboxDirectoryDatabaseTest, TestRemoveWithChildren) { FileId file_id1; info.parent_id = 0; info.name = FILE_PATH_LITERAL("foo"); - EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id1)); EXPECT_FALSE(db()->RemoveFileInfo(file_id0)); EXPECT_TRUE(db()->RemoveFileInfo(file_id1)); EXPECT_TRUE(db()->RemoveFileInfo(file_id0)); @@ -264,10 +266,10 @@ TEST_F(SandboxDirectoryDatabaseTest, TestGetChildWithName) { base::FilePath::StringType name1 = FILE_PATH_LITERAL("bar"); info.parent_id = 0; info.name = name0; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; info.name = name1; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id1)); EXPECT_NE(file_id0, file_id1); FileId check_file_id; @@ -290,14 +292,14 @@ TEST_F(SandboxDirectoryDatabaseTest, TestGetFileWithPath) { info.parent_id = 0; info.name = name0; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id0)); info.parent_id = file_id0; info.name = name1; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id1)); EXPECT_NE(file_id0, file_id1); info.parent_id = file_id1; info.name = name2; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id2)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id2)); EXPECT_NE(file_id0, file_id2); EXPECT_NE(file_id1, file_id2); @@ -326,7 +328,7 @@ TEST_F(SandboxDirectoryDatabaseTest, TestListChildren) { FileInfo info; info.parent_id = 0; info.name = FILE_PATH_LITERAL("foo"); - EXPECT_TRUE(db()->AddFileInfo(info, &file_id0)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id0)); EXPECT_TRUE(db()->ListChildren(0, &children)); EXPECT_EQ(children.size(), 1UL); EXPECT_EQ(children[0], file_id0); @@ -334,7 +336,7 @@ TEST_F(SandboxDirectoryDatabaseTest, TestListChildren) { // Two children in the root. FileId file_id1; info.name = FILE_PATH_LITERAL("bar"); - EXPECT_TRUE(db()->AddFileInfo(info, &file_id1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id1)); EXPECT_TRUE(db()->ListChildren(0, &children)); EXPECT_EQ(2UL, children.size()); if (children[0] == file_id0) { @@ -353,14 +355,14 @@ TEST_F(SandboxDirectoryDatabaseTest, TestListChildren) { info.name = FILE_PATH_LITERAL("foo"); FileId file_id2; FileId file_id3; - EXPECT_TRUE(db()->AddFileInfo(info, &file_id2)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id2)); EXPECT_TRUE(db()->ListChildren(file_id0, &children)); EXPECT_EQ(1UL, children.size()); EXPECT_EQ(children[0], file_id2); // Two children in a subdirectory. info.name = FILE_PATH_LITERAL("bar"); - EXPECT_TRUE(db()->AddFileInfo(info, &file_id3)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info, &file_id3)); EXPECT_TRUE(db()->ListChildren(file_id0, &children)); EXPECT_EQ(2UL, children.size()); if (children[0] == file_id2) { @@ -378,7 +380,7 @@ TEST_F(SandboxDirectoryDatabaseTest, TestUpdateModificationTime) { info0.name = FILE_PATH_LITERAL("name"); info0.data_path = base::FilePath(FILE_PATH_LITERAL("fake path")); info0.modification_time = base::Time::Now(); - EXPECT_TRUE(db()->AddFileInfo(info0, &file_id)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info0, &file_id)); FileInfo info1; EXPECT_TRUE(db()->GetFileInfo(file_id, &info1)); EXPECT_EQ(info0.name, info1.name); @@ -409,7 +411,7 @@ TEST_F(SandboxDirectoryDatabaseTest, TestSimpleFileOperations) { info0.data_path = base::FilePath(FILE_PATH_LITERAL("foo")); info0.name = FILE_PATH_LITERAL("file name"); info0.modification_time = base::Time::Now(); - EXPECT_TRUE(db()->AddFileInfo(info0, &file_id)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info0, &file_id)); FileInfo info1; EXPECT_TRUE(db()->GetFileInfo(file_id, &info1)); EXPECT_EQ(info0.parent_id, info1.parent_id); @@ -426,7 +428,7 @@ TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileSrcDirectory) { info0.parent_id = 0; info0.name = FILE_PATH_LITERAL("directory"); info0.modification_time = base::Time::Now(); - EXPECT_TRUE(db()->AddFileInfo(info0, &directory_id)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info0, &directory_id)); FileId file_id; FileInfo info1; @@ -434,7 +436,7 @@ TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileSrcDirectory) { info1.data_path = base::FilePath(FILE_PATH_LITERAL("bar")); info1.name = FILE_PATH_LITERAL("file"); info1.modification_time = base::Time::UnixEpoch(); - EXPECT_TRUE(db()->AddFileInfo(info1, &file_id)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info1, &file_id)); EXPECT_FALSE(db()->OverwritingMoveFile(directory_id, file_id)); } @@ -446,14 +448,14 @@ TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileDestDirectory) { info0.name = FILE_PATH_LITERAL("file"); info0.data_path = base::FilePath(FILE_PATH_LITERAL("bar")); info0.modification_time = base::Time::Now(); - EXPECT_TRUE(db()->AddFileInfo(info0, &file_id)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info0, &file_id)); FileId directory_id; FileInfo info1; info1.parent_id = 0; info1.name = FILE_PATH_LITERAL("directory"); info1.modification_time = base::Time::UnixEpoch(); - EXPECT_TRUE(db()->AddFileInfo(info1, &directory_id)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info1, &directory_id)); EXPECT_FALSE(db()->OverwritingMoveFile(file_id, directory_id)); } @@ -465,13 +467,13 @@ TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileSuccess) { info0.data_path = base::FilePath(FILE_PATH_LITERAL("foo")); info0.name = FILE_PATH_LITERAL("file name 0"); info0.modification_time = base::Time::Now(); - EXPECT_TRUE(db()->AddFileInfo(info0, &file_id0)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info0, &file_id0)); FileInfo dir_info; FileId dir_id; dir_info.parent_id = 0; dir_info.name = FILE_PATH_LITERAL("directory name"); - EXPECT_TRUE(db()->AddFileInfo(dir_info, &dir_id)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(dir_info, &dir_id)); FileId file_id1; FileInfo info1; @@ -479,7 +481,7 @@ TEST_F(SandboxDirectoryDatabaseTest, TestOverwritingMoveFileSuccess) { info1.data_path = base::FilePath(FILE_PATH_LITERAL("bar")); info1.name = FILE_PATH_LITERAL("file name 1"); info1.modification_time = base::Time::UnixEpoch(); - EXPECT_TRUE(db()->AddFileInfo(info1, &file_id1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, db()->AddFileInfo(info1, &file_id1)); EXPECT_TRUE(db()->OverwritingMoveFile(file_id0, file_id1)); diff --git a/chromium/webkit/browser/fileapi/sandbox_file_stream_writer.cc b/chromium/webkit/browser/fileapi/sandbox_file_stream_writer.cc index 2e075ce39fe..24fe1c947b1 100644 --- a/chromium/webkit/browser/fileapi/sandbox_file_stream_writer.cc +++ b/chromium/webkit/browser/fileapi/sandbox_file_stream_writer.cc @@ -9,11 +9,11 @@ #include "base/sequenced_task_runner.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" -#include "webkit/browser/blob/local_file_stream_reader.h" +#include "webkit/browser/blob/file_stream_reader.h" #include "webkit/browser/fileapi/file_observers.h" +#include "webkit/browser/fileapi/file_stream_writer.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_operation_runner.h" -#include "webkit/browser/fileapi/local_file_stream_writer.h" #include "webkit/browser/quota/quota_manager.h" #include "webkit/common/fileapi/file_system_util.h" @@ -137,7 +137,7 @@ void SandboxFileStreamWriter::DidCreateSnapshotFile( initial_offset_ = file_size_; } DCHECK(!local_file_writer_.get()); - local_file_writer_.reset(new LocalFileStreamWriter( + local_file_writer_.reset(FileStreamWriter::CreateForLocalFile( file_system_context_->default_file_task_runner(), platform_path, initial_offset_)); diff --git a/chromium/webkit/browser/fileapi/sandbox_file_stream_writer.h b/chromium/webkit/browser/fileapi/sandbox_file_stream_writer.h index 43fb0cd7743..81123376f50 100644 --- a/chromium/webkit/browser/fileapi/sandbox_file_stream_writer.h +++ b/chromium/webkit/browser/fileapi/sandbox_file_stream_writer.h @@ -21,10 +21,10 @@ namespace fileapi { class FileSystemContext; class FileSystemQuotaUtil; -class LocalFileStreamWriter; +class FileStreamWriter; class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE SandboxFileStreamWriter - : public FileStreamWriter { + : public NON_EXPORTED_BASE(FileStreamWriter) { public: SandboxFileStreamWriter(FileSystemContext* file_system_context, const FileSystemURL& url, @@ -72,7 +72,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE SandboxFileStreamWriter scoped_refptr<FileSystemContext> file_system_context_; FileSystemURL url_; int64 initial_offset_; - scoped_ptr<LocalFileStreamWriter> local_file_writer_; + scoped_ptr<FileStreamWriter> local_file_writer_; net::CompletionCallback cancel_callback_; UpdateObserverList observers_; diff --git a/chromium/webkit/browser/fileapi/sandbox_file_system_backend.cc b/chromium/webkit/browser/fileapi/sandbox_file_system_backend.cc index 20f732989d4..a5adc63e85d 100644 --- a/chromium/webkit/browser/fileapi/sandbox_file_system_backend.cc +++ b/chromium/webkit/browser/fileapi/sandbox_file_system_backend.cc @@ -10,17 +10,17 @@ #include "base/metrics/histogram.h" #include "base/task_runner_util.h" #include "url/gurl.h" +#include "webkit/browser/blob/file_stream_reader.h" #include "webkit/browser/fileapi/async_file_util_adapter.h" #include "webkit/browser/fileapi/copy_or_move_file_validator.h" +#include "webkit/browser/fileapi/file_stream_writer.h" #include "webkit/browser/fileapi/file_system_context.h" -#include "webkit/browser/fileapi/file_system_file_stream_reader.h" +#include "webkit/browser/fileapi/file_system_operation.h" #include "webkit/browser/fileapi/file_system_operation_context.h" -#include "webkit/browser/fileapi/file_system_operation_impl.h" #include "webkit/browser/fileapi/file_system_options.h" #include "webkit/browser/fileapi/file_system_usage_cache.h" #include "webkit/browser/fileapi/obfuscated_file_util.h" -#include "webkit/browser/fileapi/sandbox_context.h" -#include "webkit/browser/fileapi/sandbox_file_stream_writer.h" +#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h" #include "webkit/browser/fileapi/sandbox_quota_observer.h" #include "webkit/browser/quota/quota_manager.h" #include "webkit/common/fileapi/file_system_types.h" @@ -31,16 +31,9 @@ using quota::SpecialStoragePolicy; namespace fileapi { -namespace { - -const char kTemporaryOriginsCountLabel[] = "FileSystem.TemporaryOriginsCount"; -const char kPersistentOriginsCountLabel[] = "FileSystem.PersistentOriginsCount"; - -} // anonymous namespace - SandboxFileSystemBackend::SandboxFileSystemBackend( - SandboxContext* sandbox_context) - : sandbox_context_(sandbox_context), + SandboxFileSystemBackendDelegate* delegate) + : delegate_(delegate), enable_temporary_file_system_in_incognito_(false) { } @@ -53,12 +46,24 @@ bool SandboxFileSystemBackend::CanHandleType(FileSystemType type) const { } void SandboxFileSystemBackend::Initialize(FileSystemContext* context) { + DCHECK(delegate_); + // Set quota observers. - update_observers_ = update_observers_.AddObserver( - sandbox_context_->quota_observer(), - sandbox_context_->file_task_runner()); - access_observers_ = access_observers_.AddObserver( - sandbox_context_->quota_observer(), NULL); + delegate_->AddFileUpdateObserver( + fileapi::kFileSystemTypeTemporary, + delegate_->quota_observer(), + delegate_->file_task_runner()); + delegate_->AddFileAccessObserver( + fileapi::kFileSystemTypeTemporary, + delegate_->quota_observer(), NULL); + + delegate_->AddFileUpdateObserver( + fileapi::kFileSystemTypePersistent, + delegate_->quota_observer(), + delegate_->file_task_runner()); + delegate_->AddFileAccessObserver( + fileapi::kFileSystemTypePersistent, + delegate_->quota_observer(), NULL); } void SandboxFileSystemBackend::OpenFileSystem( @@ -67,8 +72,8 @@ void SandboxFileSystemBackend::OpenFileSystem( OpenFileSystemMode mode, const OpenFileSystemCallback& callback) { DCHECK(CanHandleType(type)); - DCHECK(sandbox_context_); - if (sandbox_context_->file_system_options().is_incognito() && + DCHECK(delegate_); + if (delegate_->file_system_options().is_incognito() && !(type == kFileSystemTypeTemporary && enable_temporary_file_system_in_incognito_)) { // TODO(kinuko): return an isolated temporary directory. @@ -76,20 +81,15 @@ void SandboxFileSystemBackend::OpenFileSystem( return; } - sandbox_context_->OpenFileSystem( + delegate_->OpenFileSystem( origin_url, type, mode, callback, GetFileSystemRootURI(origin_url, type)); } -FileSystemFileUtil* SandboxFileSystemBackend::GetFileUtil( - FileSystemType type) { - return sandbox_context_->sync_file_util(); -} - AsyncFileUtil* SandboxFileSystemBackend::GetAsyncFileUtil( FileSystemType type) { - DCHECK(sandbox_context_); - return sandbox_context_->file_util(); + DCHECK(delegate_); + return delegate_->file_util(); } CopyOrMoveFileValidatorFactory* @@ -106,24 +106,21 @@ FileSystemOperation* SandboxFileSystemBackend::CreateFileSystemOperation( FileSystemContext* context, base::PlatformFileError* error_code) const { DCHECK(CanHandleType(url.type())); - DCHECK(sandbox_context_); - if (!sandbox_context_->IsAccessValid(url)) { - *error_code = base::PLATFORM_FILE_ERROR_SECURITY; - return NULL; - } + DCHECK(error_code); - scoped_ptr<FileSystemOperationContext> operation_context( - new FileSystemOperationContext(context)); - operation_context->set_update_observers(update_observers_); - operation_context->set_change_observers(change_observers_); + DCHECK(delegate_); + scoped_ptr<FileSystemOperationContext> operation_context = + delegate_->CreateFileSystemOperationContext(url, context, error_code); + if (!operation_context) + return NULL; - SpecialStoragePolicy* policy = sandbox_context_->special_storage_policy(); + SpecialStoragePolicy* policy = delegate_->special_storage_policy(); if (policy && policy->IsStorageUnlimited(url.origin())) operation_context->set_quota_limit_type(quota::kQuotaLimitTypeUnlimited); else operation_context->set_quota_limit_type(quota::kQuotaLimitTypeLimited); - return new FileSystemOperationImpl(url, context, operation_context.Pass()); + return FileSystemOperation::Create(url, context, operation_context.Pass()); } scoped_ptr<webkit_blob::FileStreamReader> @@ -133,12 +130,9 @@ SandboxFileSystemBackend::CreateFileStreamReader( const base::Time& expected_modification_time, FileSystemContext* context) const { DCHECK(CanHandleType(url.type())); - DCHECK(sandbox_context_); - if (!sandbox_context_->IsAccessValid(url)) - return scoped_ptr<webkit_blob::FileStreamReader>(); - return scoped_ptr<webkit_blob::FileStreamReader>( - new FileSystemFileStreamReader( - context, url, offset, expected_modification_time)); + DCHECK(delegate_); + return delegate_->CreateFileStreamReader( + url, offset, expected_modification_time, context); } scoped_ptr<fileapi::FileStreamWriter> @@ -147,128 +141,18 @@ SandboxFileSystemBackend::CreateFileStreamWriter( int64 offset, FileSystemContext* context) const { DCHECK(CanHandleType(url.type())); - DCHECK(sandbox_context_); - if (!sandbox_context_->IsAccessValid(url)) - return scoped_ptr<fileapi::FileStreamWriter>(); - return scoped_ptr<fileapi::FileStreamWriter>( - new SandboxFileStreamWriter(context, url, offset, update_observers_)); + DCHECK(delegate_); + return delegate_->CreateFileStreamWriter(url, offset, context, url.type()); } FileSystemQuotaUtil* SandboxFileSystemBackend::GetQuotaUtil() { - return this; + return delegate_; } -SandboxContext::OriginEnumerator* +SandboxFileSystemBackendDelegate::OriginEnumerator* SandboxFileSystemBackend::CreateOriginEnumerator() { - DCHECK(sandbox_context_); - return sandbox_context_->CreateOriginEnumerator(); -} - -base::PlatformFileError -SandboxFileSystemBackend::DeleteOriginDataOnFileThread( - FileSystemContext* file_system_context, - QuotaManagerProxy* proxy, - const GURL& origin_url, - fileapi::FileSystemType type) { - DCHECK(CanHandleType(type)); - DCHECK(sandbox_context_); - return sandbox_context_->DeleteOriginDataOnFileThread( - file_system_context, proxy, origin_url, type); -} - -void SandboxFileSystemBackend::GetOriginsForTypeOnFileThread( - fileapi::FileSystemType type, std::set<GURL>* origins) { - DCHECK(CanHandleType(type)); - DCHECK(sandbox_context_); - sandbox_context_->GetOriginsForTypeOnFileThread(type, origins); - switch (type) { - case kFileSystemTypeTemporary: - UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size()); - break; - case kFileSystemTypePersistent: - UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size()); - break; - default: - break; - } -} - -void SandboxFileSystemBackend::GetOriginsForHostOnFileThread( - fileapi::FileSystemType type, const std::string& host, - std::set<GURL>* origins) { - DCHECK(CanHandleType(type)); - DCHECK(sandbox_context_); - sandbox_context_->GetOriginsForHostOnFileThread(type, host, origins); -} - -int64 SandboxFileSystemBackend::GetOriginUsageOnFileThread( - FileSystemContext* file_system_context, - const GURL& origin_url, - fileapi::FileSystemType type) { - DCHECK(CanHandleType(type)); - DCHECK(sandbox_context_); - return sandbox_context_->GetOriginUsageOnFileThread( - file_system_context, origin_url, type); -} - -void SandboxFileSystemBackend::InvalidateUsageCache( - const GURL& origin, - fileapi::FileSystemType type) { - DCHECK(CanHandleType(type)); - DCHECK(sandbox_context_); - sandbox_context_->InvalidateUsageCache(origin, type); -} - -void SandboxFileSystemBackend::StickyInvalidateUsageCache( - const GURL& origin, - fileapi::FileSystemType type) { - DCHECK(CanHandleType(type)); - DCHECK(sandbox_context_); - sandbox_context_->StickyInvalidateUsageCache(origin, type); -} - -void SandboxFileSystemBackend::AddFileUpdateObserver( - FileSystemType type, - FileUpdateObserver* observer, - base::SequencedTaskRunner* task_runner) { - DCHECK(CanHandleType(type)); - UpdateObserverList* list = &update_observers_; - *list = list->AddObserver(observer, task_runner); -} - -void SandboxFileSystemBackend::AddFileChangeObserver( - FileSystemType type, - FileChangeObserver* observer, - base::SequencedTaskRunner* task_runner) { - DCHECK(CanHandleType(type)); - ChangeObserverList* list = &change_observers_; - *list = list->AddObserver(observer, task_runner); -} - -void SandboxFileSystemBackend::AddFileAccessObserver( - FileSystemType type, - FileAccessObserver* observer, - base::SequencedTaskRunner* task_runner) { - DCHECK(CanHandleType(type)); - access_observers_ = access_observers_.AddObserver(observer, task_runner); -} - -const UpdateObserverList* SandboxFileSystemBackend::GetUpdateObservers( - FileSystemType type) const { - DCHECK(CanHandleType(type)); - return &update_observers_; -} - -const ChangeObserverList* SandboxFileSystemBackend::GetChangeObservers( - FileSystemType type) const { - DCHECK(CanHandleType(type)); - return &change_observers_; -} - -const AccessObserverList* SandboxFileSystemBackend::GetAccessObservers( - FileSystemType type) const { - DCHECK(CanHandleType(type)); - return &access_observers_; + DCHECK(delegate_); + return delegate_->CreateOriginEnumerator(); } } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/sandbox_file_system_backend.h b/chromium/webkit/browser/fileapi/sandbox_file_system_backend.h index 3e7ff60b529..8531cf862bf 100644 --- a/chromium/webkit/browser/fileapi/sandbox_file_system_backend.h +++ b/chromium/webkit/browser/fileapi/sandbox_file_system_backend.h @@ -14,7 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "webkit/browser/fileapi/file_system_backend.h" #include "webkit/browser/fileapi/file_system_quota_util.h" -#include "webkit/browser/fileapi/sandbox_context.h" +#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h" #include "webkit/browser/fileapi/task_runner_bound_observer_list.h" #include "webkit/browser/quota/special_storage_policy.h" #include "webkit/browser/webkit_storage_browser_export.h" @@ -27,10 +27,9 @@ namespace fileapi { // This interface also lets one enumerate and remove storage for the origins // that use the filesystem. class WEBKIT_STORAGE_BROWSER_EXPORT SandboxFileSystemBackend - : public FileSystemBackend, - public FileSystemQuotaUtil { + : public FileSystemBackend { public: - explicit SandboxFileSystemBackend(SandboxContext* sandbox_context); + explicit SandboxFileSystemBackend(SandboxFileSystemBackendDelegate* delegate); virtual ~SandboxFileSystemBackend(); // FileSystemBackend overrides. @@ -41,7 +40,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT SandboxFileSystemBackend FileSystemType type, OpenFileSystemMode mode, const OpenFileSystemCallback& callback) OVERRIDE; - virtual FileSystemFileUtil* GetFileUtil(FileSystemType type) OVERRIDE; virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE; virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory( FileSystemType type, @@ -63,64 +61,21 @@ class WEBKIT_STORAGE_BROWSER_EXPORT SandboxFileSystemBackend // Returns an origin enumerator of this backend. // This method can only be called on the file thread. - SandboxContext::OriginEnumerator* CreateOriginEnumerator(); - - // FileSystemQuotaUtil overrides. - virtual base::PlatformFileError DeleteOriginDataOnFileThread( - FileSystemContext* context, - quota::QuotaManagerProxy* proxy, - const GURL& origin_url, - FileSystemType type) OVERRIDE; - virtual void GetOriginsForTypeOnFileThread( - FileSystemType type, - std::set<GURL>* origins) OVERRIDE; - virtual void GetOriginsForHostOnFileThread( - FileSystemType type, - const std::string& host, - std::set<GURL>* origins) OVERRIDE; - virtual int64 GetOriginUsageOnFileThread( - FileSystemContext* context, - const GURL& origin_url, - FileSystemType type) OVERRIDE; - virtual void InvalidateUsageCache( - const GURL& origin_url, - FileSystemType type) OVERRIDE; - virtual void StickyInvalidateUsageCache( - const GURL& origin_url, - FileSystemType type) OVERRIDE; - virtual void AddFileUpdateObserver( - FileSystemType type, - FileUpdateObserver* observer, - base::SequencedTaskRunner* task_runner) OVERRIDE; - virtual void AddFileChangeObserver( - FileSystemType type, - FileChangeObserver* observer, - base::SequencedTaskRunner* task_runner) OVERRIDE; - virtual void AddFileAccessObserver( - FileSystemType type, - FileAccessObserver* observer, - base::SequencedTaskRunner* task_runner) OVERRIDE; - virtual const UpdateObserverList* GetUpdateObservers( - FileSystemType type) const OVERRIDE; - virtual const ChangeObserverList* GetChangeObservers( - FileSystemType type) const OVERRIDE; - virtual const AccessObserverList* GetAccessObservers( - FileSystemType type) const OVERRIDE; + SandboxFileSystemBackendDelegate::OriginEnumerator* CreateOriginEnumerator(); void set_enable_temporary_file_system_in_incognito(bool enable) { enable_temporary_file_system_in_incognito_ = enable; } + bool enable_temporary_file_system_in_incognito() const { + return enable_temporary_file_system_in_incognito_; + } + private: - SandboxContext* sandbox_context_; // Not owned. + SandboxFileSystemBackendDelegate* delegate_; // Not owned. bool enable_temporary_file_system_in_incognito_; - // Observers. - UpdateObserverList update_observers_; - ChangeObserverList change_observers_; - AccessObserverList access_observers_; - DISALLOW_COPY_AND_ASSIGN(SandboxFileSystemBackend); }; diff --git a/chromium/webkit/browser/fileapi/sandbox_context.cc b/chromium/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc index d8b7293b6a4..1cb61bb3d60 100644 --- a/chromium/webkit/browser/fileapi/sandbox_context.cc +++ b/chromium/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "webkit/browser/fileapi/sandbox_context.h" +#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h" #include "base/command_line.h" #include "base/file_util.h" @@ -10,12 +10,14 @@ #include "base/stl_util.h" #include "base/task_runner_util.h" #include "net/base/net_util.h" +#include "webkit/browser/blob/file_stream_reader.h" #include "webkit/browser/fileapi/async_file_util_adapter.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/fileapi/file_system_usage_cache.h" #include "webkit/browser/fileapi/obfuscated_file_util.h" +#include "webkit/browser/fileapi/sandbox_file_stream_writer.h" #include "webkit/browser/fileapi/sandbox_file_system_backend.h" #include "webkit/browser/fileapi/sandbox_quota_observer.h" #include "webkit/browser/quota/quota_manager.h" @@ -25,6 +27,9 @@ namespace fileapi { namespace { +const char kTemporaryOriginsCountLabel[] = "FileSystem.TemporaryOriginsCount"; +const char kPersistentOriginsCountLabel[] = "FileSystem.PersistentOriginsCount"; + const char kOpenFileSystemLabel[] = "FileSystem.OpenFileSystem"; const char kOpenFileSystemDetailLabel[] = "FileSystem.OpenFileSystemDetail"; const char kOpenFileSystemDetailNonThrottledLabel[] = @@ -53,7 +58,7 @@ const base::FilePath::CharType kRestrictedChars[] = { }; class ObfuscatedOriginEnumerator - : public SandboxContext::OriginEnumerator { + : public SandboxFileSystemBackendDelegate::OriginEnumerator { public: explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) { enum_.reset(file_util->CreateOriginEnumerator()); @@ -64,7 +69,7 @@ class ObfuscatedOriginEnumerator return enum_->Next(); } - virtual bool HasFileSystemType(fileapi::FileSystemType type) const OVERRIDE { + virtual bool HasFileSystemType(FileSystemType type) const OVERRIDE { return enum_->HasFileSystemType(type); } @@ -94,20 +99,21 @@ void OpenFileSystemOnFileThread( } void DidOpenFileSystem( - base::WeakPtr<SandboxContext> sandbox_context, + base::WeakPtr<SandboxFileSystemBackendDelegate> delegate, const base::Callback<void(base::PlatformFileError error)>& callback, base::PlatformFileError* error) { - if (sandbox_context.get()) - sandbox_context.get()->CollectOpenFileSystemMetrics(*error); + if (delegate.get()) + delegate.get()->CollectOpenFileSystemMetrics(*error); callback.Run(*error); } } // namespace const base::FilePath::CharType -SandboxContext::kFileSystemDirectory[] = FILE_PATH_LITERAL("File System"); +SandboxFileSystemBackendDelegate::kFileSystemDirectory[] = + FILE_PATH_LITERAL("File System"); -SandboxContext::SandboxContext( +SandboxFileSystemBackendDelegate::SandboxFileSystemBackendDelegate( quota::QuotaManagerProxy* quota_manager_proxy, base::SequencedTaskRunner* file_task_runner, const base::FilePath& profile_path, @@ -123,16 +129,18 @@ SandboxContext::SandboxContext( quota_observer_(new SandboxQuotaObserver( quota_manager_proxy, file_task_runner, - sync_file_util(), + obfuscated_file_util(), usage_cache())), special_storage_policy_(special_storage_policy), file_system_options_(file_system_options), + is_filesystem_opened_(false), weak_factory_(this) { } -SandboxContext::~SandboxContext() { +SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() { + io_thread_checker_.DetachFromThread(); if (!file_task_runner_->RunsTasksOnCurrentThread()) { - AsyncFileUtilAdapter* sandbox_file_util = sandbox_file_util_.release(); + AsyncFileUtil* sandbox_file_util = sandbox_file_util_.release(); SandboxQuotaObserver* quota_observer = quota_observer_.release(); FileSystemUsageCache* file_system_usage_cache = file_system_usage_cache_.release(); @@ -145,7 +153,8 @@ SandboxContext::~SandboxContext() { } } -bool SandboxContext::IsAccessValid(const FileSystemURL& url) const { +bool SandboxFileSystemBackendDelegate::IsAccessValid( + const FileSystemURL& url) const { if (!IsAllowedScheme(url.origin())) return false; @@ -176,10 +185,10 @@ bool SandboxContext::IsAccessValid(const FileSystemURL& url) const { return true; } -bool SandboxContext::IsAllowedScheme(const GURL& url) const { +bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL& url) const { // Basically we only accept http or https. We allow file:// URLs // only if --allow-file-access-from-files flag is given. - if (url.SchemeIs("http") || url.SchemeIs("https")) + if (url.SchemeIsHTTPOrHTTPS()) return true; if (url.SchemeIsFileSystem()) return url.inner_url() && IsAllowedScheme(*url.inner_url()); @@ -194,23 +203,27 @@ bool SandboxContext::IsAllowedScheme(const GURL& url) const { return false; } -SandboxContext::OriginEnumerator* SandboxContext::CreateOriginEnumerator() { - return new ObfuscatedOriginEnumerator(sync_file_util()); +SandboxFileSystemBackendDelegate::OriginEnumerator* +SandboxFileSystemBackendDelegate::CreateOriginEnumerator() { + return new ObfuscatedOriginEnumerator(obfuscated_file_util()); } -base::FilePath SandboxContext::GetBaseDirectoryForOriginAndType( - const GURL& origin_url, fileapi::FileSystemType type, bool create) { +base::FilePath +SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType( + const GURL& origin_url, + FileSystemType type, + bool create) { base::PlatformFileError error = base::PLATFORM_FILE_OK; - base::FilePath path = sync_file_util()->GetDirectoryForOriginAndType( + base::FilePath path = obfuscated_file_util()->GetDirectoryForOriginAndType( origin_url, type, create, &error); if (error != base::PLATFORM_FILE_OK) return base::FilePath(); return path; } -void SandboxContext::OpenFileSystem( +void SandboxFileSystemBackendDelegate::OpenFileSystem( const GURL& origin_url, - fileapi::FileSystemType type, + FileSystemType type, OpenFileSystemMode mode, const OpenFileSystemCallback& callback, const GURL& root_url) { @@ -225,23 +238,77 @@ void SandboxContext::OpenFileSystem( file_task_runner_->PostTaskAndReply( FROM_HERE, base::Bind(&OpenFileSystemOnFileThread, - sync_file_util(), origin_url, type, mode, + obfuscated_file_util(), origin_url, type, mode, base::Unretained(error_ptr)), base::Bind(&DidOpenFileSystem, weak_factory_.GetWeakPtr(), base::Bind(callback, root_url, name), base::Owned(error_ptr))); + + io_thread_checker_.DetachFromThread(); + is_filesystem_opened_ = true; +} + +scoped_ptr<FileSystemOperationContext> +SandboxFileSystemBackendDelegate::CreateFileSystemOperationContext( + const FileSystemURL& url, + FileSystemContext* context, + base::PlatformFileError* error_code) const { + if (!IsAccessValid(url)) { + *error_code = base::PLATFORM_FILE_ERROR_SECURITY; + return scoped_ptr<FileSystemOperationContext>(); + } + + const UpdateObserverList* update_observers = GetUpdateObservers(url.type()); + const ChangeObserverList* change_observers = GetChangeObservers(url.type()); + DCHECK(update_observers); + + scoped_ptr<FileSystemOperationContext> operation_context( + new FileSystemOperationContext(context)); + operation_context->set_update_observers(*update_observers); + operation_context->set_change_observers( + change_observers ? *change_observers : ChangeObserverList()); + + return operation_context.Pass(); } -base::PlatformFileError SandboxContext::DeleteOriginDataOnFileThread( +scoped_ptr<webkit_blob::FileStreamReader> +SandboxFileSystemBackendDelegate::CreateFileStreamReader( + const FileSystemURL& url, + int64 offset, + const base::Time& expected_modification_time, + FileSystemContext* context) const { + if (!IsAccessValid(url)) + return scoped_ptr<webkit_blob::FileStreamReader>(); + return scoped_ptr<webkit_blob::FileStreamReader>( + webkit_blob::FileStreamReader::CreateForFileSystemFile( + context, url, offset, expected_modification_time)); +} + +scoped_ptr<FileStreamWriter> +SandboxFileSystemBackendDelegate::CreateFileStreamWriter( + const FileSystemURL& url, + int64 offset, + FileSystemContext* context, + FileSystemType type) const { + if (!IsAccessValid(url)) + return scoped_ptr<FileStreamWriter>(); + const UpdateObserverList* observers = GetUpdateObservers(type); + DCHECK(observers); + return scoped_ptr<FileStreamWriter>( + new SandboxFileStreamWriter(context, url, offset, *observers)); +} + +base::PlatformFileError +SandboxFileSystemBackendDelegate::DeleteOriginDataOnFileThread( FileSystemContext* file_system_context, quota::QuotaManagerProxy* proxy, const GURL& origin_url, - fileapi::FileSystemType type) { + FileSystemType type) { int64 usage = GetOriginUsageOnFileThread( file_system_context, origin_url, type); usage_cache()->CloseCacheFiles(); - bool result = sync_file_util()->DeleteDirectoryForOriginAndType( + bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType( origin_url, type); if (result && proxy) { proxy->NotifyStorageModified( @@ -256,8 +323,8 @@ base::PlatformFileError SandboxContext::DeleteOriginDataOnFileThread( return base::PLATFORM_FILE_ERROR_FAILED; } -void SandboxContext::GetOriginsForTypeOnFileThread( - fileapi::FileSystemType type, std::set<GURL>* origins) { +void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileThread( + FileSystemType type, std::set<GURL>* origins) { DCHECK(origins); scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); GURL origin; @@ -265,10 +332,20 @@ void SandboxContext::GetOriginsForTypeOnFileThread( if (enumerator->HasFileSystemType(type)) origins->insert(origin); } + switch (type) { + case kFileSystemTypeTemporary: + UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size()); + break; + case kFileSystemTypePersistent: + UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size()); + break; + default: + break; + } } -void SandboxContext::GetOriginsForHostOnFileThread( - fileapi::FileSystemType type, const std::string& host, +void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileThread( + FileSystemType type, const std::string& host, std::set<GURL>* origins) { DCHECK(origins); scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); @@ -280,10 +357,10 @@ void SandboxContext::GetOriginsForHostOnFileThread( } } -int64 SandboxContext::GetOriginUsageOnFileThread( +int64 SandboxFileSystemBackendDelegate::GetOriginUsageOnFileThread( FileSystemContext* file_system_context, const GURL& origin_url, - fileapi::FileSystemType type) { + FileSystemType type) { // Don't use usage cache and return recalculated usage for sticky invalidated // origins. if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type))) @@ -318,41 +395,101 @@ int64 SandboxContext::GetOriginUsageOnFileThread( return usage; } -void SandboxContext::InvalidateUsageCache( +void SandboxFileSystemBackendDelegate::AddFileUpdateObserver( + FileSystemType type, + FileUpdateObserver* observer, + base::SequencedTaskRunner* task_runner) { + DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); + update_observers_[type] = + update_observers_[type].AddObserver(observer, task_runner); +} + +void SandboxFileSystemBackendDelegate::AddFileChangeObserver( + FileSystemType type, + FileChangeObserver* observer, + base::SequencedTaskRunner* task_runner) { + DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); + change_observers_[type] = + change_observers_[type].AddObserver(observer, task_runner); +} + +void SandboxFileSystemBackendDelegate::AddFileAccessObserver( + FileSystemType type, + FileAccessObserver* observer, + base::SequencedTaskRunner* task_runner) { + DCHECK(!is_filesystem_opened_ || io_thread_checker_.CalledOnValidThread()); + access_observers_[type] = + access_observers_[type].AddObserver(observer, task_runner); +} + +const UpdateObserverList* SandboxFileSystemBackendDelegate::GetUpdateObservers( + FileSystemType type) const { + std::map<FileSystemType, UpdateObserverList>::const_iterator iter = + update_observers_.find(type); + if (iter == update_observers_.end()) + return NULL; + return &iter->second; +} + +const ChangeObserverList* SandboxFileSystemBackendDelegate::GetChangeObservers( + FileSystemType type) const { + std::map<FileSystemType, ChangeObserverList>::const_iterator iter = + change_observers_.find(type); + if (iter == change_observers_.end()) + return NULL; + return &iter->second; +} + +const AccessObserverList* SandboxFileSystemBackendDelegate::GetAccessObservers( + FileSystemType type) const { + std::map<FileSystemType, AccessObserverList>::const_iterator iter = + access_observers_.find(type); + if (iter == access_observers_.end()) + return NULL; + return &iter->second; +} + +void SandboxFileSystemBackendDelegate::InvalidateUsageCache( const GURL& origin, - fileapi::FileSystemType type) { + FileSystemType type) { base::PlatformFileError error = base::PLATFORM_FILE_OK; base::FilePath usage_file_path = GetUsageCachePathForOriginAndType( - sync_file_util(), origin, type, &error); + obfuscated_file_util(), origin, type, &error); if (error != base::PLATFORM_FILE_OK) return; usage_cache()->IncrementDirty(usage_file_path); } -void SandboxContext::StickyInvalidateUsageCache( +void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache( const GURL& origin, - fileapi::FileSystemType type) { + FileSystemType type) { sticky_dirty_origins_.insert(std::make_pair(origin, type)); quota_observer()->SetUsageCacheEnabled(origin, type, false); InvalidateUsageCache(origin, type); } -base::FilePath SandboxContext::GetUsageCachePathForOriginAndType( +FileSystemFileUtil* SandboxFileSystemBackendDelegate::sync_file_util() { + return static_cast<AsyncFileUtilAdapter*>(file_util())->sync_file_util(); +} + +base::FilePath +SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( const GURL& origin_url, FileSystemType type) { base::PlatformFileError error; base::FilePath path = GetUsageCachePathForOriginAndType( - sync_file_util(), origin_url, type, &error); + obfuscated_file_util(), origin_url, type, &error); if (error != base::PLATFORM_FILE_OK) return base::FilePath(); return path; } // static -base::FilePath SandboxContext::GetUsageCachePathForOriginAndType( +base::FilePath +SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( ObfuscatedFileUtil* sandbox_file_util, const GURL& origin_url, - fileapi::FileSystemType type, + FileSystemType type, base::PlatformFileError* error_out) { DCHECK(error_out); *error_out = base::PLATFORM_FILE_OK; @@ -363,14 +500,16 @@ base::FilePath SandboxContext::GetUsageCachePathForOriginAndType( return base_path.Append(FileSystemUsageCache::kUsageFileName); } -int64 SandboxContext::RecalculateUsage(FileSystemContext* context, - const GURL& origin, - FileSystemType type) { +int64 SandboxFileSystemBackendDelegate::RecalculateUsage( + FileSystemContext* context, + const GURL& origin, + FileSystemType type) { FileSystemOperationContext operation_context(context); FileSystemURL url = context->CreateCrackedFileSystemURL( origin, type, base::FilePath()); scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( - sync_file_util()->CreateFileEnumerator(&operation_context, url, true)); + obfuscated_file_util()->CreateFileEnumerator( + &operation_context, url, true)); base::FilePath file_path_each; int64 usage = 0; @@ -383,7 +522,7 @@ int64 SandboxContext::RecalculateUsage(FileSystemContext* context, return usage; } -void SandboxContext::CollectOpenFileSystemMetrics( +void SandboxFileSystemBackendDelegate::CollectOpenFileSystemMetrics( base::PlatformFileError error_code) { base::Time now = base::Time::Now(); bool throttled = now < next_release_time_for_open_filesystem_stat_; @@ -420,8 +559,8 @@ void SandboxContext::CollectOpenFileSystemMetrics( #undef REPORT } -ObfuscatedFileUtil* SandboxContext::sync_file_util() { - return static_cast<ObfuscatedFileUtil*>(file_util()->sync_file_util()); +ObfuscatedFileUtil* SandboxFileSystemBackendDelegate::obfuscated_file_util() { + return static_cast<ObfuscatedFileUtil*>(sync_file_util()); } } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/sandbox_context.h b/chromium/webkit/browser/fileapi/sandbox_file_system_backend_delegate.h index c765077b8d3..33d791e5920 100644 --- a/chromium/webkit/browser/fileapi/sandbox_context.h +++ b/chromium/webkit/browser/fileapi/sandbox_file_system_backend_delegate.h @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef WEBKIT_BROWSER_FILEAPI_SANDBOX_CONTEXT_H_ -#define WEBKIT_BROWSER_FILEAPI_SANDBOX_CONTEXT_H_ +#ifndef WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_BACKEND_DELEGATE_H_ +#define WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_BACKEND_DELEGATE_H_ +#include <map> #include <set> #include <string> #include <utility> @@ -13,6 +14,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/threading/thread_checker.h" #include "base/time/time.h" #include "webkit/browser/fileapi/file_system_backend.h" #include "webkit/browser/fileapi/file_system_options.h" @@ -28,9 +30,16 @@ class QuotaManagerProxy; class SpecialStoragePolicy; } +namespace webkit_blob { +class FileStreamReader; +} + namespace fileapi { -class AsyncFileUtilAdapter; +class AsyncFileUtil; +class FileStreamWriter; +class FileSystemFileUtil; +class FileSystemOperationContext; class FileSystemURL; class FileSystemUsageCache; class ObfuscatedFileUtil; @@ -38,9 +47,10 @@ class SandboxFileSystemBackend; class SandboxFileSystemTestHelper; class SandboxQuotaObserver; -// This class keeps and provides a sandbox file system context. +// Delegate implementation of the some methods in Sandbox/SyncFileSystemBackend. // An instance of this class is created and owned by FileSystemContext. -class WEBKIT_STORAGE_BROWSER_EXPORT SandboxContext { +class WEBKIT_STORAGE_BROWSER_EXPORT SandboxFileSystemBackendDelegate + : public FileSystemQuotaUtil { public: typedef FileSystemBackend::OpenFileSystemCallback OpenFileSystemCallback; @@ -60,14 +70,14 @@ class WEBKIT_STORAGE_BROWSER_EXPORT SandboxContext { virtual bool HasFileSystemType(FileSystemType type) const = 0; }; - SandboxContext( + SandboxFileSystemBackendDelegate( quota::QuotaManagerProxy* quota_manager_proxy, base::SequencedTaskRunner* file_task_runner, const base::FilePath& profile_path, quota::SpecialStoragePolicy* special_storage_policy, const FileSystemOptions& file_system_options); - ~SandboxContext(); + virtual ~SandboxFileSystemBackendDelegate(); // Performs API-specific validity checks on the given path |url|. // Returns true if access to |url| is valid in this filesystem. @@ -99,30 +109,61 @@ class WEBKIT_STORAGE_BROWSER_EXPORT SandboxContext { OpenFileSystemMode mode, const OpenFileSystemCallback& callback, const GURL& root_url); + scoped_ptr<FileSystemOperationContext> CreateFileSystemOperationContext( + const FileSystemURL& url, + FileSystemContext* context, + base::PlatformFileError* error_code) const; + scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader( + const FileSystemURL& url, + int64 offset, + const base::Time& expected_modification_time, + FileSystemContext* context) const; + scoped_ptr<FileStreamWriter> CreateFileStreamWriter( + const FileSystemURL& url, + int64 offset, + FileSystemContext* context, + FileSystemType type) const; - // FileSystemQuotaUtil helpers. - base::PlatformFileError DeleteOriginDataOnFileThread( + // FileSystemQuotaUtil overrides. + virtual base::PlatformFileError DeleteOriginDataOnFileThread( FileSystemContext* context, quota::QuotaManagerProxy* proxy, const GURL& origin_url, - FileSystemType type); - void GetOriginsForTypeOnFileThread( + FileSystemType type) OVERRIDE; + virtual void GetOriginsForTypeOnFileThread( FileSystemType type, - std::set<GURL>* origins); - void GetOriginsForHostOnFileThread( + std::set<GURL>* origins) OVERRIDE; + virtual void GetOriginsForHostOnFileThread( FileSystemType type, const std::string& host, - std::set<GURL>* origins); - int64 GetOriginUsageOnFileThread( + std::set<GURL>* origins) OVERRIDE; + virtual int64 GetOriginUsageOnFileThread( FileSystemContext* context, const GURL& origin_url, - FileSystemType type); - void InvalidateUsageCache( - const GURL& origin_url, - FileSystemType type); - void StickyInvalidateUsageCache( - const GURL& origin_url, - FileSystemType type); + FileSystemType type) OVERRIDE; + virtual void AddFileUpdateObserver( + FileSystemType type, + FileUpdateObserver* observer, + base::SequencedTaskRunner* task_runner) OVERRIDE; + virtual void AddFileChangeObserver( + FileSystemType type, + FileChangeObserver* observer, + base::SequencedTaskRunner* task_runner) OVERRIDE; + virtual void AddFileAccessObserver( + FileSystemType type, + FileAccessObserver* observer, + base::SequencedTaskRunner* task_runner) OVERRIDE; + virtual const UpdateObserverList* GetUpdateObservers( + FileSystemType type) const OVERRIDE; + virtual const ChangeObserverList* GetChangeObservers( + FileSystemType type) const OVERRIDE; + virtual const AccessObserverList* GetAccessObservers( + FileSystemType type) const OVERRIDE; + + void InvalidateUsageCache(const GURL& origin_url, + FileSystemType type); + void StickyInvalidateUsageCache(const GURL& origin_url, + FileSystemType type); void CollectOpenFileSystemMetrics(base::PlatformFileError error_code); @@ -130,17 +171,19 @@ class WEBKIT_STORAGE_BROWSER_EXPORT SandboxContext { return file_task_runner_.get(); } - AsyncFileUtilAdapter* file_util() { return sandbox_file_util_.get(); } + AsyncFileUtil* file_util() { return sandbox_file_util_.get(); } FileSystemUsageCache* usage_cache() { return file_system_usage_cache_.get(); } - SandboxQuotaObserver* quota_observer() { return quota_observer_.get(); }; + SandboxQuotaObserver* quota_observer() { return quota_observer_.get(); } quota::SpecialStoragePolicy* special_storage_policy() { return special_storage_policy_.get(); } - FileSystemOptions file_system_options() { return file_system_options_; } + const FileSystemOptions& file_system_options() const { + return file_system_options_; + } - ObfuscatedFileUtil* sync_file_util(); + FileSystemFileUtil* sync_file_util(); private: friend class SandboxQuotaObserver; @@ -162,9 +205,11 @@ class WEBKIT_STORAGE_BROWSER_EXPORT SandboxContext { const GURL& origin, FileSystemType type); + ObfuscatedFileUtil* obfuscated_file_util(); + scoped_refptr<base::SequencedTaskRunner> file_task_runner_; - scoped_ptr<AsyncFileUtilAdapter> sandbox_file_util_; + scoped_ptr<AsyncFileUtil> sandbox_file_util_; scoped_ptr<FileSystemUsageCache> file_system_usage_cache_; scoped_ptr<SandboxQuotaObserver> quota_observer_; @@ -172,18 +217,25 @@ class WEBKIT_STORAGE_BROWSER_EXPORT SandboxContext { FileSystemOptions file_system_options_; - // Acccessed only on the file thread. + bool is_filesystem_opened_; + base::ThreadChecker io_thread_checker_; + + // Accessed only on the file thread. std::set<GURL> visited_origins_; std::set<std::pair<GURL, FileSystemType> > sticky_dirty_origins_; + std::map<FileSystemType, UpdateObserverList> update_observers_; + std::map<FileSystemType, ChangeObserverList> change_observers_; + std::map<FileSystemType, AccessObserverList> access_observers_; + base::Time next_release_time_for_open_filesystem_stat_; - base::WeakPtrFactory<SandboxContext> weak_factory_; + base::WeakPtrFactory<SandboxFileSystemBackendDelegate> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(SandboxContext); + DISALLOW_COPY_AND_ASSIGN(SandboxFileSystemBackendDelegate); }; } // namespace fileapi -#endif // WEBKIT_BROWSER_FILEAPI_SANDBOX_CONTEXT_H_ +#endif // WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_BACKEND_DELEGATE_H_ diff --git a/chromium/webkit/browser/fileapi/sandbox_context_unittest.cc b/chromium/webkit/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc index 841e10b5b83..48c3b8c4e70 100644 --- a/chromium/webkit/browser/fileapi/sandbox_context_unittest.cc +++ b/chromium/webkit/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "webkit/browser/fileapi/sandbox_context.h" +#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h" #include "base/basictypes.h" #include "base/file_util.h" @@ -27,11 +27,11 @@ FileSystemURL CreateFileSystemURL(const char* path) { } // namespace -class SandboxContextTest : public testing::Test { +class SandboxFileSystemBackendDelegateTest : public testing::Test { protected: virtual void SetUp() { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); - context_.reset(new SandboxContext( + delegate_.reset(new SandboxFileSystemBackendDelegate( NULL /* quota_manager_proxy */, base::MessageLoopProxy::current().get(), data_dir_.path(), @@ -41,42 +41,42 @@ class SandboxContextTest : public testing::Test { base::ScopedTempDir data_dir_; base::MessageLoop message_loop_; - scoped_ptr<SandboxContext> context_; + scoped_ptr<SandboxFileSystemBackendDelegate> delegate_; }; -TEST_F(SandboxContextTest, IsAccessValid) { +TEST_F(SandboxFileSystemBackendDelegateTest, IsAccessValid) { // Normal case. - EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL("a"))); + EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL("a"))); // Access to a path with parent references ('..') should be disallowed. - EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL("a/../b"))); + EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL("a/../b"))); // Access from non-allowed scheme should be disallowed. - EXPECT_FALSE(context_->IsAccessValid( + EXPECT_FALSE(delegate_->IsAccessValid( FileSystemURL::CreateForTest( GURL("unknown://bar"), kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe("foo")))); // Access with restricted name should be disallowed. - EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL("."))); - EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL(".."))); + EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL("."))); + EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL(".."))); // This is also disallowed due to Windows XP parent path handling. - EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL("..."))); + EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL("..."))); // These are identified as unsafe cases due to weird path handling // on Windows. - EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL(" .."))); - EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL(".. "))); + EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL(" .."))); + EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL(".. "))); // Similar but safe cases. - EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL(" ."))); - EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL(". "))); - EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL("b."))); - EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL(".b"))); + EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL(" ."))); + EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL(". "))); + EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL("b."))); + EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL(".b"))); // A path that looks like a drive letter. - EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL("c:"))); + EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL("c:"))); } } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc b/chromium/webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc index ec213a36386..ed06d17ad70 100644 --- a/chromium/webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc +++ b/chromium/webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc @@ -10,14 +10,14 @@ #include "base/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/run_loop.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" #include "webkit/browser/fileapi/file_system_backend.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/fileapi/mock_file_system_options.h" -#include "webkit/browser/fileapi/sandbox_context.h" +#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h" #include "webkit/common/fileapi/file_system_util.h" // PS stands for path separator. @@ -85,11 +85,11 @@ class SandboxFileSystemBackendTest : public testing::Test { protected: virtual void SetUp() { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); - SetUpNewSandboxContext(CreateAllowFileAccessOptions()); + SetUpNewDelegate(CreateAllowFileAccessOptions()); } - void SetUpNewSandboxContext(const FileSystemOptions& options) { - context_.reset(new SandboxContext( + void SetUpNewDelegate(const FileSystemOptions& options) { + delegate_.reset(new SandboxFileSystemBackendDelegate( NULL /* quota_manager_proxy */, base::MessageLoopProxy::current().get(), data_dir_.path(), @@ -98,17 +98,18 @@ class SandboxFileSystemBackendTest : public testing::Test { } void SetUpNewBackend(const FileSystemOptions& options) { - SetUpNewSandboxContext(options); - backend_.reset(new SandboxFileSystemBackend(context_.get())); + SetUpNewDelegate(options); + backend_.reset(new SandboxFileSystemBackend(delegate_.get())); } - SandboxContext::OriginEnumerator* CreateOriginEnumerator() const { + SandboxFileSystemBackendDelegate::OriginEnumerator* + CreateOriginEnumerator() const { return backend_->CreateOriginEnumerator(); } void CreateOriginTypeDirectory(const GURL& origin, fileapi::FileSystemType type) { - base::FilePath target = context_-> + base::FilePath target = delegate_-> GetBaseDirectoryForOriginAndType(origin, type, true); ASSERT_TRUE(!target.empty()); ASSERT_TRUE(base::DirectoryExists(target)); @@ -122,11 +123,11 @@ class SandboxFileSystemBackendTest : public testing::Test { backend_->OpenFileSystem( origin_url, type, mode, base::Bind(&DidOpenFileSystem, &error)); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); if (error != base::PLATFORM_FILE_OK) return false; base::FilePath returned_root_path = - context_->GetBaseDirectoryForOriginAndType( + delegate_->GetBaseDirectoryForOriginAndType( origin_url, type, false /* create */); if (root_path) *root_path = returned_root_path; @@ -134,18 +135,19 @@ class SandboxFileSystemBackendTest : public testing::Test { } base::FilePath file_system_path() const { - return data_dir_.path().Append(SandboxContext::kFileSystemDirectory); + return data_dir_.path().Append( + SandboxFileSystemBackendDelegate::kFileSystemDirectory); } base::ScopedTempDir data_dir_; base::MessageLoop message_loop_; - scoped_ptr<SandboxContext> context_; + scoped_ptr<SandboxFileSystemBackendDelegate> delegate_; scoped_ptr<SandboxFileSystemBackend> backend_; }; TEST_F(SandboxFileSystemBackendTest, Empty) { SetUpNewBackend(CreateAllowFileAccessOptions()); - scoped_ptr<SandboxContext::OriginEnumerator> enumerator( + scoped_ptr<SandboxFileSystemBackendDelegate::OriginEnumerator> enumerator( CreateOriginEnumerator()); ASSERT_TRUE(enumerator->Next().is_empty()); } @@ -178,7 +180,7 @@ TEST_F(SandboxFileSystemBackendTest, EnumerateOrigins) { persistent_set.insert(GURL(persistent_origins[i])); } - scoped_ptr<SandboxContext::OriginEnumerator> enumerator( + scoped_ptr<SandboxFileSystemBackendDelegate::OriginEnumerator> enumerator( CreateOriginEnumerator()); size_t temporary_actual_size = 0; size_t persistent_actual_size = 0; diff --git a/chromium/webkit/browser/fileapi/sandbox_file_system_test_helper.cc b/chromium/webkit/browser/fileapi/sandbox_file_system_test_helper.cc index 179bf9b2c1a..df579e488e4 100644 --- a/chromium/webkit/browser/fileapi/sandbox_file_system_test_helper.cc +++ b/chromium/webkit/browser/fileapi/sandbox_file_system_test_helper.cc @@ -5,8 +5,8 @@ #include "webkit/browser/fileapi/sandbox_file_system_test_helper.h" #include "base/file_util.h" -#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/run_loop.h" #include "url/gurl.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_file_util.h" @@ -57,11 +57,11 @@ void SandboxFileSystemTestHelper::SetUp( void SandboxFileSystemTestHelper::TearDown() { file_system_context_ = NULL; - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } base::FilePath SandboxFileSystemTestHelper::GetOriginRootPath() { - return file_system_context_->sandbox_context()-> + return file_system_context_->sandbox_delegate()-> GetBaseDirectoryForOriginAndType(origin_, type_, false); } @@ -80,8 +80,8 @@ base::FilePath SandboxFileSystemTestHelper::GetLocalPathFromASCII( } base::FilePath SandboxFileSystemTestHelper::GetUsageCachePath() const { - return file_system_context_-> - sandbox_context()->GetUsageCachePathForOriginAndType(origin_, type_); + return file_system_context_->sandbox_delegate()-> + GetUsageCachePathForOriginAndType(origin_, type_); } FileSystemURL SandboxFileSystemTestHelper::CreateURL( @@ -124,23 +124,23 @@ SandboxFileSystemTestHelper::NewOperationContext() { void SandboxFileSystemTestHelper::AddFileChangeObserver( FileChangeObserver* observer) { - file_system_context_->sandbox_backend()-> + file_system_context_->sandbox_backend()->GetQuotaUtil()-> AddFileChangeObserver(type_, observer, NULL); } FileSystemUsageCache* SandboxFileSystemTestHelper::usage_cache() { - return file_system_context()->sandbox_context()->usage_cache(); + return file_system_context()->sandbox_delegate()->usage_cache(); } void SandboxFileSystemTestHelper::SetUpFileSystem() { DCHECK(file_system_context_.get()); DCHECK(file_system_context_->sandbox_backend()->CanHandleType(type_)); - file_util_ = file_system_context_->GetFileUtil(type_); + file_util_ = file_system_context_->sandbox_delegate()->sync_file_util(); DCHECK(file_util_); // Prepare the origin's root directory. - file_system_context_->sandbox_context()-> + file_system_context_->sandbox_delegate()-> GetBaseDirectoryForOriginAndType(origin_, type_, true /* create */); // Initialize the usage cache file. diff --git a/chromium/webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc b/chromium/webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc index 7eeab2185b6..aad2c7e6cc3 100644 --- a/chromium/webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc +++ b/chromium/webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc @@ -76,7 +76,7 @@ TEST(SandboxIsolatedOriginDatabaseTest, MigrationTest) { base::FilePath directory_db_path = dir.path().Append(path); EXPECT_TRUE(base::DirectoryExists(directory_db_path)); EXPECT_TRUE(base::PathExists(directory_db_path.AppendASCII("dummy"))); - EXPECT_TRUE(file_util::ReadFileToString( + EXPECT_TRUE(base::ReadFileToString( directory_db_path.AppendASCII("dummy"), &origin_db_data)); EXPECT_EQ(kFakeDirectoryData, origin_db_data); diff --git a/chromium/webkit/browser/fileapi/sandbox_origin_database.cc b/chromium/webkit/browser/fileapi/sandbox_origin_database.cc index 9ca399673fd..4ce83017cc0 100644 --- a/chromium/webkit/browser/fileapi/sandbox_origin_database.cc +++ b/chromium/webkit/browser/fileapi/sandbox_origin_database.cc @@ -76,7 +76,7 @@ bool SandboxOriginDatabase::Init(InitOption init_option, std::string path = FilePathToString(db_path); leveldb::Options options; - options.max_open_files = 64; // Use minimum. + options.max_open_files = 0; // Use minimum. options.create_if_missing = true; leveldb::DB* db; leveldb::Status status = leveldb::DB::Open(options, path, &db); @@ -122,7 +122,7 @@ bool SandboxOriginDatabase::Init(InitOption init_option, bool SandboxOriginDatabase::RepairDatabase(const std::string& db_path) { DCHECK(!db_.get()); leveldb::Options options; - options.max_open_files = 64; // Use minimum. + options.max_open_files = 0; // Use minimum. if (!leveldb::RepairDB(db_path, options).ok() || !Init(FAIL_IF_NONEXISTENT, FAIL_ON_CORRUPTION)) { LOG(WARNING) << "Failed to repair SandboxOriginDatabase."; diff --git a/chromium/webkit/browser/fileapi/sandbox_quota_observer.cc b/chromium/webkit/browser/fileapi/sandbox_quota_observer.cc index 02a47ee255c..fe5ee3796fb 100644 --- a/chromium/webkit/browser/fileapi/sandbox_quota_observer.cc +++ b/chromium/webkit/browser/fileapi/sandbox_quota_observer.cc @@ -7,7 +7,7 @@ #include "base/sequenced_task_runner.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/fileapi/file_system_usage_cache.h" -#include "webkit/browser/fileapi/sandbox_context.h" +#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h" #include "webkit/browser/fileapi/timed_task_helper.h" #include "webkit/browser/quota/quota_client.h" #include "webkit/browser/quota/quota_manager.h" @@ -107,7 +107,7 @@ base::FilePath SandboxQuotaObserver::GetUsageCachePath( DCHECK(sandbox_file_util_); base::PlatformFileError error = base::PLATFORM_FILE_OK; base::FilePath path = - SandboxContext::GetUsageCachePathForOriginAndType( + SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType( sandbox_file_util_, url.origin(), url.type(), &error); if (error != base::PLATFORM_FILE_OK) { LOG(WARNING) << "Could not get usage cache path for: " diff --git a/chromium/webkit/browser/fileapi/test_file_system_backend.cc b/chromium/webkit/browser/fileapi/test_file_system_backend.cc index 584e2e3a10d..44109cf6148 100644 --- a/chromium/webkit/browser/fileapi/test_file_system_backend.cc +++ b/chromium/webkit/browser/fileapi/test_file_system_backend.cc @@ -10,11 +10,11 @@ #include "base/file_util.h" #include "base/sequenced_task_runner.h" +#include "webkit/browser/blob/file_stream_reader.h" #include "webkit/browser/fileapi/copy_or_move_file_validator.h" #include "webkit/browser/fileapi/file_observers.h" -#include "webkit/browser/fileapi/file_system_file_stream_reader.h" +#include "webkit/browser/fileapi/file_system_operation.h" #include "webkit/browser/fileapi/file_system_operation_context.h" -#include "webkit/browser/fileapi/file_system_operation_impl.h" #include "webkit/browser/fileapi/file_system_quota_util.h" #include "webkit/browser/fileapi/local_file_util.h" #include "webkit/browser/fileapi/native_file_util.h" @@ -24,6 +24,29 @@ namespace fileapi { +namespace { + +class TestFileUtil : public LocalFileUtil { + public: + explicit TestFileUtil(const base::FilePath& base_path) + : base_path_(base_path) {} + virtual ~TestFileUtil() {} + + // LocalFileUtil overrides. + virtual base::PlatformFileError GetLocalFilePath( + FileSystemOperationContext* context, + const FileSystemURL& file_system_url, + base::FilePath* local_file_path) OVERRIDE { + *local_file_path = base_path_.Append(file_system_url.path()); + return base::PLATFORM_FILE_OK; + } + + private: + base::FilePath base_path_; +}; + +} // namespace + // This only supports single origin. class TestFileSystemBackend::QuotaUtil : public FileSystemQuotaUtil, @@ -66,17 +89,6 @@ class TestFileSystemBackend::QuotaUtil return usage_; } - virtual void InvalidateUsageCache(const GURL& origin_url, - FileSystemType type) OVERRIDE { - // Do nothing. - } - - virtual void StickyInvalidateUsageCache( - const GURL& origin, - FileSystemType type) OVERRIDE { - // Do nothing. - } - virtual void AddFileUpdateObserver( FileSystemType type, FileUpdateObserver* observer, @@ -136,7 +148,7 @@ TestFileSystemBackend::TestFileSystemBackend( base::SequencedTaskRunner* task_runner, const base::FilePath& base_path) : base_path_(base_path), - local_file_util_(new AsyncFileUtilAdapter(new LocalFileUtil())), + file_util_(new AsyncFileUtilAdapter(new TestFileUtil(base_path))), quota_util_(new QuotaUtil(task_runner)), require_copy_or_move_validator_(false) { } @@ -161,13 +173,8 @@ void TestFileSystemBackend::OpenFileSystem( base::PLATFORM_FILE_OK); } -FileSystemFileUtil* TestFileSystemBackend::GetFileUtil(FileSystemType type) { - DCHECK(local_file_util_.get()); - return local_file_util_->sync_file_util(); -} - AsyncFileUtil* TestFileSystemBackend::GetAsyncFileUtil(FileSystemType type) { - return local_file_util_.get(); + return file_util_.get(); } CopyOrMoveFileValidatorFactory* @@ -198,8 +205,7 @@ FileSystemOperation* TestFileSystemBackend::CreateFileSystemOperation( operation_context->set_update_observers(*GetUpdateObservers(url.type())); operation_context->set_change_observers( *quota_util_->GetChangeObservers(url.type())); - operation_context->set_root_path(base_path_); - return new FileSystemOperationImpl(url, context, operation_context.Pass()); + return FileSystemOperation::Create(url, context, operation_context.Pass()); } scoped_ptr<webkit_blob::FileStreamReader> @@ -209,7 +215,7 @@ TestFileSystemBackend::CreateFileStreamReader( const base::Time& expected_modification_time, FileSystemContext* context) const { return scoped_ptr<webkit_blob::FileStreamReader>( - new FileSystemFileStreamReader( + webkit_blob::FileStreamReader::CreateForFileSystemFile( context, url, offset, expected_modification_time)); } diff --git a/chromium/webkit/browser/fileapi/test_file_system_backend.h b/chromium/webkit/browser/fileapi/test_file_system_backend.h index ef252c13118..dc1cbce2298 100644 --- a/chromium/webkit/browser/fileapi/test_file_system_backend.h +++ b/chromium/webkit/browser/fileapi/test_file_system_backend.h @@ -41,7 +41,6 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE TestFileSystemBackend FileSystemType type, OpenFileSystemMode mode, const OpenFileSystemCallback& callback) OVERRIDE; - virtual FileSystemFileUtil* GetFileUtil(FileSystemType type) OVERRIDE; virtual AsyncFileUtil* GetAsyncFileUtil(FileSystemType type) OVERRIDE; virtual CopyOrMoveFileValidatorFactory* GetCopyOrMoveFileValidatorFactory( FileSystemType type, @@ -81,7 +80,7 @@ class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE TestFileSystemBackend base::FilePath base_path_; scoped_refptr<base::SequencedTaskRunner> task_runner_; - scoped_ptr<AsyncFileUtilAdapter> local_file_util_; + scoped_ptr<AsyncFileUtilAdapter> file_util_; scoped_ptr<QuotaUtil> quota_util_; bool require_copy_or_move_validator_; diff --git a/chromium/webkit/browser/fileapi/timed_task_helper_unittest.cc b/chromium/webkit/browser/fileapi/timed_task_helper_unittest.cc index 6966c614c3d..fa3e84d523d 100644 --- a/chromium/webkit/browser/fileapi/timed_task_helper_unittest.cc +++ b/chromium/webkit/browser/fileapi/timed_task_helper_unittest.cc @@ -6,8 +6,8 @@ #include "base/bind.h" #include "base/location.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/run_loop.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/browser/fileapi/timed_task_helper.h" @@ -51,7 +51,7 @@ TEST(TimedTaskHelper, FireTimerWhenAlive) { embedder.timer()->Reset(); ASSERT_TRUE(embedder.timer()->IsRunning()); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); ASSERT_TRUE(embedder.timer_fired()); } @@ -77,7 +77,7 @@ TEST(TimedTaskHelper, FireTimerWhenAlreadyDeleted) { // At this point the callback is still in the message queue but // embedder is gone. - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } } // namespace fileapi diff --git a/chromium/webkit/browser/fileapi/transient_file_util.h b/chromium/webkit/browser/fileapi/transient_file_util.h index d3d56c1c173..1e67c852027 100644 --- a/chromium/webkit/browser/fileapi/transient_file_util.h +++ b/chromium/webkit/browser/fileapi/transient_file_util.h @@ -6,7 +6,7 @@ #define WEBKIT_BROWSER_FILEAPI_TRANSIENT_FILE_UTIL_H_ #include "base/memory/scoped_ptr.h" -#include "webkit/browser/fileapi/isolated_file_util.h" +#include "webkit/browser/fileapi/local_file_util.h" #include "webkit/browser/webkit_storage_browser_export.h" namespace fileapi { @@ -14,12 +14,12 @@ namespace fileapi { class FileSystemOperationContext; class WEBKIT_STORAGE_BROWSER_EXPORT_PRIVATE TransientFileUtil - : public IsolatedFileUtil { + : public LocalFileUtil { public: TransientFileUtil() {} virtual ~TransientFileUtil() {} - // IsolatedFileUtil overrides. + // LocalFileUtil overrides. virtual webkit_blob::ScopedFile CreateSnapshotFile( FileSystemOperationContext* context, const FileSystemURL& url, diff --git a/chromium/webkit/browser/fileapi/transient_file_util_unittest.cc b/chromium/webkit/browser/fileapi/transient_file_util_unittest.cc index 2a809a30779..3b6e284070d 100644 --- a/chromium/webkit/browser/fileapi/transient_file_util_unittest.cc +++ b/chromium/webkit/browser/fileapi/transient_file_util_unittest.cc @@ -7,8 +7,8 @@ #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/platform_file.h" +#include "base/run_loop.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/browser/fileapi/file_system_context.h" #include "webkit/browser/fileapi/file_system_operation_context.h" @@ -34,7 +34,7 @@ class TransientFileUtilTest : public testing::Test { virtual void TearDown() OVERRIDE { file_system_context_ = NULL; - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } void CreateAndRegisterTemporaryFile( @@ -110,7 +110,7 @@ TEST_F(TransientFileUtilTest, TransientFile) { } // The file's now scoped out. - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); // Now the temporary file and the transient filesystem must be gone too. ASSERT_FALSE(base::PathExists(temp_path)); diff --git a/chromium/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc b/chromium/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc index e6e0d4cd2b4..429edf2fe05 100644 --- a/chromium/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc +++ b/chromium/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc @@ -5,13 +5,13 @@ #include "webkit/browser/fileapi/upload_file_system_file_element_reader.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "net/base/io_buffer.h" #include "net/base/test_completion_callback.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webkit/browser/fileapi/async_file_test_helper.h" #include "webkit/browser/fileapi/file_system_backend.h" #include "webkit/browser/fileapi/file_system_context.h" -#include "webkit/browser/fileapi/file_system_file_util.h" #include "webkit/browser/fileapi/file_system_operation_context.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/fileapi/mock_file_system_context.h" @@ -43,7 +43,7 @@ class UploadFileSystemFileElementReaderTest : public testing::Test { OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, base::Bind(&UploadFileSystemFileElementReaderTest::OnOpenFileSystem, base::Unretained(this))); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); ASSERT_TRUE(file_system_root_url_.is_valid()); // Prepare a file on file system. @@ -71,7 +71,7 @@ class UploadFileSystemFileElementReaderTest : public testing::Test { virtual void TearDown() OVERRIDE { reader_.reset(); - base::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } protected: @@ -89,31 +89,14 @@ class UploadFileSystemFileElementReaderTest : public testing::Test { kFileSystemType, base::FilePath().AppendASCII(filename)); - fileapi::FileSystemFileUtil* file_util = - file_system_context_->GetFileUtil(kFileSystemType); - - fileapi::FileSystemOperationContext context(file_system_context_.get()); - context.set_allowed_bytes_growth(1024); - - base::PlatformFile handle = base::kInvalidPlatformFileValue; - bool created = false; - ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateOrOpen( - &context, - url, - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, - &handle, - &created)); - EXPECT_TRUE(created); - ASSERT_NE(base::kInvalidPlatformFileValue, handle); - ASSERT_EQ(buf_size, - base::WritePlatformFile(handle, 0 /* offset */, buf, buf_size)); - base::ClosePlatformFile(handle); + ASSERT_EQ(base::PLATFORM_FILE_OK, + AsyncFileTestHelper::CreateFileWithData( + file_system_context_, url, buf, buf_size)); base::PlatformFileInfo file_info; - base::FilePath platform_path; ASSERT_EQ(base::PLATFORM_FILE_OK, - file_util->GetFileInfo(&context, url, &file_info, - &platform_path)); + AsyncFileTestHelper::GetMetadata( + file_system_context_, url, &file_info)); *modification_time = file_info.last_modified; } |