Chromium Code Reviews| Index: webkit/browser/fileapi/copy_or_move_operation_delegate.cc |
| diff --git a/webkit/browser/fileapi/copy_or_move_operation_delegate.cc b/webkit/browser/fileapi/copy_or_move_operation_delegate.cc |
| index 844234ffa5388b7571c0c48d4ef2c655a6430e0c..149904ca3911c8c413e2e185a92d2ae45866b667 100644 |
| --- a/webkit/browser/fileapi/copy_or_move_operation_delegate.cc |
| +++ b/webkit/browser/fileapi/copy_or_move_operation_delegate.cc |
| @@ -16,6 +16,264 @@ |
| namespace fileapi { |
| +// Needs to define the interface in before the each implementation define below. |
|
kinuko
2013/09/09 16:12:38
nit: ditto, this comment's probably not necessary
hidehiko
2013/09/09 16:55:35
Removed.
|
| +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) |
| + : operation_runner_(operation_runner), |
| + operation_type_(operation_type), |
| + src_url_(src_url), |
| + dest_url_(dest_url) { |
| + } |
| + |
| + virtual void Run( |
| + const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE { |
| + if (operation_type_ == CopyOrMoveOperationDelegate::OPERATION_MOVE) { |
| + operation_runner_->MoveFileLocal(src_url_, dest_url_, callback); |
| + } else { |
| + // TODO(hidehiko): Support progress callback. |
| + operation_runner_->CopyFileLocal( |
| + src_url_, dest_url_, |
| + FileSystemOperationRunner::CopyFileProgressCallback(), callback); |
| + } |
| + } |
| + |
| + private: |
| + FileSystemOperationRunner* operation_runner_; |
| + CopyOrMoveOperationDelegate::OperationType operation_type_; |
| + FileSystemURL src_url_; |
| + FileSystemURL dest_url_; |
| + DISALLOW_COPY_AND_ASSIGN(CopyOrMoveOnSameFileSystemImpl); |
| +}; |
| + |
| +// Espacially for cross file system copy/move operation, this class creates |
|
kinuko
2013/09/09 16:12:38
nit: Especially -> Specifically ? (Since it's spe
hidehiko
2013/09/09 16:55:35
Done.
|
| +// a snapshot file, validate it if necessary, run copying process, |
| +// validate the created file, and remove source file for move (noop for copy). |
|
kinuko
2013/09/09 16:12:38
nit: validate -> validates, run -> runs, remove ->
hidehiko
2013/09/09 16:55:35
Done.
|
| +class SnapshotCopyOrMoveImpl |
| + : public CopyOrMoveOperationDelegate::CopyOrMoveImpl { |
| + public: |
| + SnapshotCopyOrMoveImpl( |
| + FileSystemOperationRunner* operation_runner, |
| + CopyOrMoveOperationDelegate::OperationType operation_type, |
| + const FileSystemURL& src_url, |
| + const FileSystemURL& dest_url, |
|
kinuko
2013/09/09 16:12:38
nit: extra space
hidehiko
2013/09/09 16:55:35
Oops done.
|
| + CopyOrMoveFileValidatorFactory* validator_factory) |
| + : operation_runner_(operation_runner), |
| + operation_type_(operation_type), |
| + src_url_(src_url), |
| + dest_url_(dest_url), |
| + validator_factory_(validator_factory), |
| + weak_factory_(this) { |
| + } |
| + |
| + virtual void Run( |
| + const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE { |
| + 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. |
| + // TODO(kinuko): Otherwise create a FileStreamReader to perform a copy/move. |
|
kinuko
2013/09/09 16:12:38
nit: maybe we can remove this comment now?
hidehiko
2013/09/09 16:55:35
Done.
|
| + DCHECK(!platform_path.empty()); |
| + |
| + if (!validator_factory_) { |
| + // No validation is needed. |
| + RunAfterPreWriteValidation( |
| + platform_path, file_ref, callback, base::PLATFORM_FILE_OK); |
| + return; |
| + } |
| + |
| + // Runs pre write validation. |
|
kinuko
2013/09/09 16:12:38
nit: Runs -> Run
hidehiko
2013/09/09 16:55:35
Done.
|
| + PreWriteValidation( |
| + platform_path, |
| + base::Bind(&SnapshotCopyOrMoveImpl::RunAfterPreWriteValidation, |
| + weak_factory_.GetWeakPtr(), |
| + platform_path, file_ref, callback)); |
| + } |
| + |
| + void RunAfterPreWriteValidation( |
| + const base::FilePath& platform_path, |
| + 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_ref, callback)); |
| + } |
| + |
| + void RunAfterCopyInForeignFile( |
| + 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; |
| + } |
| + |
| + // |validator_| is NULL in when the destination filesystem does not do |
|
kinuko
2013/09/09 16:12:38
nit: 'in when' -> when
hidehiko
2013/09/09 16:55:35
Done.
|
| + // 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, |
|
kinuko
2013/09/09 16:12:38
nit: can you add /* recursive */ after true while
hidehiko
2013/09/09 16:55:35
Done.
|
| + 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_; |
| + |
| + base::WeakPtrFactory<SnapshotCopyOrMoveImpl> weak_factory_; |
| + DISALLOW_COPY_AND_ASSIGN(SnapshotCopyOrMoveImpl); |
| +}; |
| + |
| +} // namespace |
| + |
| + |
| CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( |
| FileSystemContext* file_system_context, |
| const FileSystemURL& src_root, |
| @@ -32,6 +290,7 @@ CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( |
| } |
| CopyOrMoveOperationDelegate::~CopyOrMoveOperationDelegate() { |
| + STLDeleteElements(&running_copy_set_); |
| } |
| void CopyOrMoveOperationDelegate::Run() { |
| @@ -55,14 +314,14 @@ void CopyOrMoveOperationDelegate::RunRecursively() { |
| } |
| // First try to copy/move it as a file. |
| - CopyOrMoveFile(URLPair(src_root_, dest_root_), |
| + CopyOrMoveFile(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); |
| + CopyOrMoveFile(src_url, CreateDestURL(src_url), callback); |
| } |
| void CopyOrMoveOperationDelegate::ProcessDirectory(const FileSystemURL& src_url, |
| @@ -116,85 +375,6 @@ void CopyOrMoveOperationDelegate::DidTryRemoveDestRoot( |
| weak_factory_.GetWeakPtr(), src_root_, callback_)); |
| } |
| -void CopyOrMoveOperationDelegate::CopyOrMoveFile( |
| - const URLPair& url_pair, |
| - 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 { |
| - // TODO(hidehiko): Support progress callback. |
| - operation_runner()->CopyFileLocal( |
| - url_pair.src, url_pair.dest, |
| - FileSystemOperationRunner::CopyFileProgressCallback(), callback); |
| - } |
| - return; |
| - } |
| - |
| - // 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)); |
| -} |
| - |
| -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; |
| - } |
| - 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()); |
| - |
| - 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); |
| - 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; |
| - } |
| - |
| - operation_runner()->CopyInForeignFile(platform_path, dest, callback); |
| -} |
| - |
| void CopyOrMoveOperationDelegate::DidFinishRecursiveCopyDir( |
| const FileSystemURL& src, |
| const StatusCallback& callback, |
| @@ -214,89 +394,51 @@ void CopyOrMoveOperationDelegate::DidFinishRecursiveCopyDir( |
| weak_factory_.GetWeakPtr(), callback)); |
| } |
| -void CopyOrMoveOperationDelegate::DidFinishCopy( |
| - const URLPair& url_pair, |
| +void CopyOrMoveOperationDelegate::DidRemoveSourceForMove( |
| const StatusCallback& callback, |
| base::PlatformFileError error) { |
| - if (error != base::PLATFORM_FILE_OK) { |
| - callback.Run(error); |
| - return; |
| - } |
| - |
| - // |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; |
| - } |
| - |
| - DCHECK(!same_file_system_); |
| - operation_runner()->CreateSnapshotFile( |
| - url_pair.dest, |
| - base::Bind(&CopyOrMoveOperationDelegate::DoPostWriteValidation, |
| - weak_factory_.GetWeakPtr(), url_pair, callback)); |
| + if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) |
| + error = base::PLATFORM_FILE_OK; |
| + callback.Run(error); |
| } |
| -void CopyOrMoveOperationDelegate::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) { |
| - if (error != base::PLATFORM_FILE_OK) { |
| - operation_runner()->Remove( |
| - url_pair.dest, true, |
| - base::Bind(&CopyOrMoveOperationDelegate::DidRemoveDestForError, |
| - weak_factory_.GetWeakPtr(), error, callback)); |
| - 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)); |
| -} |
| +void CopyOrMoveOperationDelegate::CopyOrMoveFile( |
| + const FileSystemURL& src_url, |
| + const FileSystemURL& dest_url, |
| + const StatusCallback& callback) { |
| + CopyOrMoveImpl* impl = NULL; |
| + if (same_file_system_) { |
| + impl = new CopyOrMoveOnSameFileSystemImpl( |
| + operation_runner(), operation_type_, src_url, dest_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; |
| + } |
| -// |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, |
| - 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; |
| + impl = new SnapshotCopyOrMoveImpl( |
| + operation_runner(), operation_type_, src_url, dest_url, |
| + validator_factory); |
| } |
| - 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)); |
| + // Register the running task. |
| + running_copy_set_.insert(impl); |
| + impl->Run(base::Bind(&CopyOrMoveOperationDelegate::DidCopyOrMoveFile, |
| + weak_factory_.GetWeakPtr(), impl, callback)); |
| } |
| -void CopyOrMoveOperationDelegate::DidRemoveSourceForMove( |
| +void CopyOrMoveOperationDelegate::DidCopyOrMoveFile( |
| + CopyOrMoveImpl* impl, |
| const StatusCallback& callback, |
| base::PlatformFileError error) { |
| - if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) |
| - error = base::PLATFORM_FILE_OK; |
| + running_copy_set_.erase(impl); |
| + delete impl; |
| callback.Run(error); |
| } |
| @@ -314,15 +456,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 |