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 |
deleted file mode 100644 |
index 84a6472720e2990da9b88b01c15e7555c456f6cd..0000000000000000000000000000000000000000 |
--- a/webkit/browser/fileapi/copy_or_move_operation_delegate.cc |
+++ /dev/null |
@@ -1,1034 +0,0 @@ |
-// 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. |
- |
-#include "webkit/browser/fileapi/copy_or_move_operation_delegate.h" |
- |
-#include "base/bind.h" |
-#include "base/files/file_path.h" |
-#include "net/base/io_buffer.h" |
-#include "net/base/net_errors.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_stream_writer.h" |
-#include "webkit/browser/fileapi/file_system_context.h" |
-#include "webkit/browser/fileapi/file_system_operation_runner.h" |
-#include "webkit/browser/fileapi/file_system_url.h" |
-#include "webkit/browser/fileapi/recursive_operation_delegate.h" |
-#include "webkit/common/blob/shareable_file_reference.h" |
-#include "webkit/common/fileapi/file_system_util.h" |
- |
-namespace storage { |
- |
-const int64 kFlushIntervalInBytes = 10 << 20; // 10MB. |
- |
-class CopyOrMoveOperationDelegate::CopyOrMoveImpl { |
- public: |
- virtual ~CopyOrMoveImpl() {} |
- virtual void Run( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback) = 0; |
- virtual void Cancel() = 0; |
- |
- protected: |
- CopyOrMoveImpl() {} |
- |
- private: |
- 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, |
- CopyOrMoveOperationDelegate::CopyOrMoveOption option, |
- const FileSystemOperation::CopyFileProgressCallback& |
- file_progress_callback) |
- : operation_runner_(operation_runner), |
- operation_type_(operation_type), |
- src_url_(src_url), |
- dest_url_(dest_url), |
- option_(option), |
- 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_, option_, callback); |
- } else { |
- operation_runner_->CopyFileLocal( |
- src_url_, dest_url_, option_, file_progress_callback_, callback); |
- } |
- } |
- |
- virtual void Cancel() OVERRIDE { |
- // We can do nothing for the copy/move operation on a local file system. |
- // Assuming the operation is quickly done, it should be ok to just wait |
- // for the completion. |
- } |
- |
- private: |
- FileSystemOperationRunner* operation_runner_; |
- CopyOrMoveOperationDelegate::OperationType operation_type_; |
- FileSystemURL src_url_; |
- FileSystemURL dest_url_; |
- CopyOrMoveOperationDelegate::CopyOrMoveOption option_; |
- 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, |
- CopyOrMoveOperationDelegate::CopyOrMoveOption option, |
- 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), |
- option_(option), |
- validator_factory_(validator_factory), |
- file_progress_callback_(file_progress_callback), |
- cancel_requested_(false), |
- 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)); |
- } |
- |
- virtual void Cancel() OVERRIDE { |
- cancel_requested_ = true; |
- } |
- |
- private: |
- void RunAfterCreateSnapshot( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error, |
- const base::File::Info& file_info, |
- const base::FilePath& platform_path, |
- const scoped_refptr<storage::ShareableFileReference>& file_ref) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- |
- if (error != base::File::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::File::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::File::Info& file_info, |
- const scoped_refptr<storage::ShareableFileReference>& file_ref, |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- |
- if (error != base::File::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::File::Info& file_info, |
- const scoped_refptr<storage::ShareableFileReference>& file_ref, |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- |
- if (error != base::File::FILE_OK) { |
- callback.Run(error); |
- return; |
- } |
- |
- file_progress_callback_.Run(file_info.size); |
- |
- if (option_ == FileSystemOperation::OPTION_NONE) { |
- RunAfterTouchFile(callback, base::File::FILE_OK); |
- return; |
- } |
- |
- operation_runner_->TouchFile( |
- dest_url_, base::Time::Now() /* last_access */, |
- file_info.last_modified, |
- base::Bind(&SnapshotCopyOrMoveImpl::RunAfterTouchFile, |
- weak_factory_.GetWeakPtr(), callback)); |
- } |
- |
- void RunAfterTouchFile( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error) { |
- // Even if TouchFile is failed, just ignore it. |
- |
- if (cancel_requested_) { |
- callback.Run(base::File::FILE_ERROR_ABORT); |
- return; |
- } |
- |
- // |validator_| is NULL when the destination filesystem does not do |
- // validation. |
- if (!validator_) { |
- // No validation is needed. |
- RunAfterPostWriteValidation(callback, base::File::FILE_OK); |
- return; |
- } |
- |
- PostWriteValidation( |
- base::Bind(&SnapshotCopyOrMoveImpl::RunAfterPostWriteValidation, |
- weak_factory_.GetWeakPtr(), callback)); |
- } |
- |
- void RunAfterPostWriteValidation( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error) { |
- if (cancel_requested_) { |
- callback.Run(base::File::FILE_ERROR_ABORT); |
- return; |
- } |
- |
- if (error != base::File::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::File::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::File::Error error) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- |
- if (error == base::File::FILE_ERROR_NOT_FOUND) |
- error = base::File::FILE_OK; |
- callback.Run(error); |
- } |
- |
- void DidRemoveDestForError( |
- base::File::Error prior_error, |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error) { |
- if (error != base::File::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::File::Error error, |
- const base::File::Info& file_info, |
- const base::FilePath& platform_path, |
- const scoped_refptr<storage::ShareableFileReference>& file_ref) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- |
- if (error != base::File::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<storage::ShareableFileReference>& file_ref, |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error) { |
- callback.Run(error); |
- } |
- |
- FileSystemOperationRunner* operation_runner_; |
- CopyOrMoveOperationDelegate::OperationType operation_type_; |
- FileSystemURL src_url_; |
- FileSystemURL dest_url_; |
- |
- CopyOrMoveOperationDelegate::CopyOrMoveOption option_; |
- CopyOrMoveFileValidatorFactory* validator_factory_; |
- scoped_ptr<CopyOrMoveFileValidator> validator_; |
- FileSystemOperation::CopyFileProgressCallback file_progress_callback_; |
- bool cancel_requested_; |
- base::WeakPtrFactory<SnapshotCopyOrMoveImpl> weak_factory_; |
- DISALLOW_COPY_AND_ASSIGN(SnapshotCopyOrMoveImpl); |
-}; |
- |
-// The size of buffer for StreamCopyHelper. |
-const int kReadBufferSize = 32768; |
- |
-// To avoid too many progress callbacks, it should be called less |
-// frequently than 50ms. |
-const int kMinProgressCallbackInvocationSpanInMilliseconds = 50; |
- |
-// Specifically for cross file system copy/move operation, this class uses |
-// stream reader and writer for copying. Validator is not supported, so if |
-// necessary SnapshotCopyOrMoveImpl should be used. |
-class StreamCopyOrMoveImpl |
- : public CopyOrMoveOperationDelegate::CopyOrMoveImpl { |
- public: |
- StreamCopyOrMoveImpl( |
- FileSystemOperationRunner* operation_runner, |
- FileSystemContext* file_system_context, |
- CopyOrMoveOperationDelegate::OperationType operation_type, |
- const FileSystemURL& src_url, |
- const FileSystemURL& dest_url, |
- CopyOrMoveOperationDelegate::CopyOrMoveOption option, |
- scoped_ptr<storage::FileStreamReader> reader, |
- scoped_ptr<FileStreamWriter> writer, |
- const FileSystemOperation::CopyFileProgressCallback& |
- file_progress_callback) |
- : operation_runner_(operation_runner), |
- file_system_context_(file_system_context), |
- operation_type_(operation_type), |
- src_url_(src_url), |
- dest_url_(dest_url), |
- option_(option), |
- reader_(reader.Pass()), |
- writer_(writer.Pass()), |
- file_progress_callback_(file_progress_callback), |
- cancel_requested_(false), |
- weak_factory_(this) {} |
- |
- virtual void Run( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE { |
- // Reader can be created even if the entry does not exist or the entry is |
- // a directory. To check errors before destination file creation, |
- // check metadata first. |
- operation_runner_->GetMetadata( |
- src_url_, |
- base::Bind(&StreamCopyOrMoveImpl::RunAfterGetMetadataForSource, |
- weak_factory_.GetWeakPtr(), callback)); |
- } |
- |
- virtual void Cancel() OVERRIDE { |
- cancel_requested_ = true; |
- if (copy_helper_) |
- copy_helper_->Cancel(); |
- } |
- |
- private: |
- void NotifyOnStartUpdate(const FileSystemURL& url) { |
- if (file_system_context_->GetUpdateObservers(url.type())) { |
- file_system_context_->GetUpdateObservers(url.type()) |
- ->Notify(&FileUpdateObserver::OnStartUpdate, MakeTuple(url)); |
- } |
- } |
- |
- void NotifyOnModifyFile(const FileSystemURL& url) { |
- if (file_system_context_->GetChangeObservers(url.type())) { |
- file_system_context_->GetChangeObservers(url.type()) |
- ->Notify(&FileChangeObserver::OnModifyFile, MakeTuple(url)); |
- } |
- } |
- |
- void NotifyOnEndUpdate(const FileSystemURL& url) { |
- if (file_system_context_->GetUpdateObservers(url.type())) { |
- file_system_context_->GetUpdateObservers(url.type()) |
- ->Notify(&FileUpdateObserver::OnEndUpdate, MakeTuple(url)); |
- } |
- } |
- |
- void RunAfterGetMetadataForSource( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error, |
- const base::File::Info& file_info) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- |
- if (error != base::File::FILE_OK) { |
- callback.Run(error); |
- return; |
- } |
- |
- if (file_info.is_directory) { |
- // If not a directory, failed with appropriate error code. |
- callback.Run(base::File::FILE_ERROR_NOT_A_FILE); |
- return; |
- } |
- |
- // To use FileStreamWriter, we need to ensure the destination file exists. |
- operation_runner_->CreateFile( |
- dest_url_, |
- true /* exclusive */, |
- base::Bind(&StreamCopyOrMoveImpl::RunAfterCreateFileForDestination, |
- weak_factory_.GetWeakPtr(), |
- callback, |
- file_info.last_modified)); |
- } |
- |
- void RunAfterCreateFileForDestination( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- const base::Time& last_modified, |
- base::File::Error error) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- // This conversion is to return the consistent status code with |
- // FileSystemFileUtil::Copy. |
- if (error == base::File::FILE_ERROR_NOT_A_FILE) |
- error = base::File::FILE_ERROR_INVALID_OPERATION; |
- |
- if (error != base::File::FILE_OK && |
- error != base::File::FILE_ERROR_EXISTS) { |
- callback.Run(error); |
- return; |
- } |
- |
- if (error == base::File::FILE_ERROR_EXISTS) { |
- operation_runner_->Truncate( |
- dest_url_, |
- 0 /* length */, |
- base::Bind(&StreamCopyOrMoveImpl::RunAfterTruncateForDestination, |
- weak_factory_.GetWeakPtr(), |
- callback, |
- last_modified)); |
- return; |
- } |
- RunAfterTruncateForDestination( |
- callback, last_modified, base::File::FILE_OK); |
- } |
- |
- void RunAfterTruncateForDestination( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- const base::Time& last_modified, |
- base::File::Error error) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- |
- if (error != base::File::FILE_OK) { |
- callback.Run(error); |
- return; |
- } |
- |
- const bool need_flush = dest_url_.mount_option().copy_sync_option() == |
- storage::COPY_SYNC_OPTION_SYNC; |
- |
- NotifyOnStartUpdate(dest_url_); |
- DCHECK(!copy_helper_); |
- copy_helper_.reset( |
- new CopyOrMoveOperationDelegate::StreamCopyHelper( |
- reader_.Pass(), writer_.Pass(), |
- need_flush, |
- kReadBufferSize, |
- file_progress_callback_, |
- base::TimeDelta::FromMilliseconds( |
- kMinProgressCallbackInvocationSpanInMilliseconds))); |
- copy_helper_->Run( |
- base::Bind(&StreamCopyOrMoveImpl::RunAfterStreamCopy, |
- weak_factory_.GetWeakPtr(), callback, last_modified)); |
- } |
- |
- void RunAfterStreamCopy( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- const base::Time& last_modified, |
- base::File::Error error) { |
- NotifyOnModifyFile(dest_url_); |
- NotifyOnEndUpdate(dest_url_); |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- |
- if (error != base::File::FILE_OK) { |
- callback.Run(error); |
- return; |
- } |
- |
- if (option_ == FileSystemOperation::OPTION_NONE) { |
- RunAfterTouchFile(callback, base::File::FILE_OK); |
- return; |
- } |
- |
- operation_runner_->TouchFile( |
- dest_url_, base::Time::Now() /* last_access */, last_modified, |
- base::Bind(&StreamCopyOrMoveImpl::RunAfterTouchFile, |
- weak_factory_.GetWeakPtr(), callback)); |
- } |
- |
- void RunAfterTouchFile( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error) { |
- // Even if TouchFile is failed, just ignore it. |
- if (cancel_requested_) { |
- callback.Run(base::File::FILE_ERROR_ABORT); |
- return; |
- } |
- |
- if (operation_type_ == CopyOrMoveOperationDelegate::OPERATION_COPY) { |
- callback.Run(base::File::FILE_OK); |
- return; |
- } |
- |
- DCHECK_EQ(CopyOrMoveOperationDelegate::OPERATION_MOVE, operation_type_); |
- |
- // Remove the source for finalizing move operation. |
- operation_runner_->Remove( |
- src_url_, false /* recursive */, |
- base::Bind(&StreamCopyOrMoveImpl::RunAfterRemoveForMove, |
- weak_factory_.GetWeakPtr(), callback)); |
- } |
- |
- void RunAfterRemoveForMove( |
- const CopyOrMoveOperationDelegate::StatusCallback& callback, |
- base::File::Error error) { |
- if (cancel_requested_) |
- error = base::File::FILE_ERROR_ABORT; |
- if (error == base::File::FILE_ERROR_NOT_FOUND) |
- error = base::File::FILE_OK; |
- callback.Run(error); |
- } |
- |
- FileSystemOperationRunner* operation_runner_; |
- scoped_refptr<FileSystemContext> file_system_context_; |
- CopyOrMoveOperationDelegate::OperationType operation_type_; |
- FileSystemURL src_url_; |
- FileSystemURL dest_url_; |
- CopyOrMoveOperationDelegate::CopyOrMoveOption option_; |
- scoped_ptr<storage::FileStreamReader> reader_; |
- scoped_ptr<FileStreamWriter> writer_; |
- FileSystemOperation::CopyFileProgressCallback file_progress_callback_; |
- scoped_ptr<CopyOrMoveOperationDelegate::StreamCopyHelper> copy_helper_; |
- bool cancel_requested_; |
- base::WeakPtrFactory<StreamCopyOrMoveImpl> weak_factory_; |
- DISALLOW_COPY_AND_ASSIGN(StreamCopyOrMoveImpl); |
-}; |
- |
-} // namespace |
- |
-CopyOrMoveOperationDelegate::StreamCopyHelper::StreamCopyHelper( |
- scoped_ptr<storage::FileStreamReader> reader, |
- scoped_ptr<FileStreamWriter> writer, |
- bool need_flush, |
- int buffer_size, |
- const FileSystemOperation::CopyFileProgressCallback& file_progress_callback, |
- const base::TimeDelta& min_progress_callback_invocation_span) |
- : reader_(reader.Pass()), |
- writer_(writer.Pass()), |
- need_flush_(need_flush), |
- file_progress_callback_(file_progress_callback), |
- io_buffer_(new net::IOBufferWithSize(buffer_size)), |
- num_copied_bytes_(0), |
- previous_flush_offset_(0), |
- min_progress_callback_invocation_span_( |
- min_progress_callback_invocation_span), |
- cancel_requested_(false), |
- weak_factory_(this) { |
-} |
- |
-CopyOrMoveOperationDelegate::StreamCopyHelper::~StreamCopyHelper() { |
-} |
- |
-void CopyOrMoveOperationDelegate::StreamCopyHelper::Run( |
- const StatusCallback& callback) { |
- file_progress_callback_.Run(0); |
- last_progress_callback_invocation_time_ = base::Time::Now(); |
- Read(callback); |
-} |
- |
-void CopyOrMoveOperationDelegate::StreamCopyHelper::Cancel() { |
- cancel_requested_ = true; |
-} |
- |
-void CopyOrMoveOperationDelegate::StreamCopyHelper::Read( |
- const StatusCallback& callback) { |
- int result = reader_->Read( |
- io_buffer_.get(), io_buffer_->size(), |
- base::Bind(&StreamCopyHelper::DidRead, |
- weak_factory_.GetWeakPtr(), callback)); |
- if (result != net::ERR_IO_PENDING) |
- DidRead(callback, result); |
-} |
- |
-void CopyOrMoveOperationDelegate::StreamCopyHelper::DidRead( |
- const StatusCallback& callback, int result) { |
- if (cancel_requested_) { |
- callback.Run(base::File::FILE_ERROR_ABORT); |
- return; |
- } |
- |
- if (result < 0) { |
- callback.Run(NetErrorToFileError(result)); |
- return; |
- } |
- |
- if (result == 0) { |
- // Here is the EOF. |
- if (need_flush_) |
- Flush(callback, true /* is_eof */); |
- else |
- callback.Run(base::File::FILE_OK); |
- return; |
- } |
- |
- Write(callback, new net::DrainableIOBuffer(io_buffer_.get(), result)); |
-} |
- |
-void CopyOrMoveOperationDelegate::StreamCopyHelper::Write( |
- const StatusCallback& callback, |
- scoped_refptr<net::DrainableIOBuffer> buffer) { |
- DCHECK_GT(buffer->BytesRemaining(), 0); |
- |
- int result = writer_->Write( |
- buffer.get(), buffer->BytesRemaining(), |
- base::Bind(&StreamCopyHelper::DidWrite, |
- weak_factory_.GetWeakPtr(), callback, buffer)); |
- if (result != net::ERR_IO_PENDING) |
- DidWrite(callback, buffer, result); |
-} |
- |
-void CopyOrMoveOperationDelegate::StreamCopyHelper::DidWrite( |
- const StatusCallback& callback, |
- scoped_refptr<net::DrainableIOBuffer> buffer, |
- int result) { |
- if (cancel_requested_) { |
- callback.Run(base::File::FILE_ERROR_ABORT); |
- return; |
- } |
- |
- if (result < 0) { |
- callback.Run(NetErrorToFileError(result)); |
- return; |
- } |
- |
- buffer->DidConsume(result); |
- num_copied_bytes_ += result; |
- |
- // Check the elapsed time since last |file_progress_callback_| invocation. |
- base::Time now = base::Time::Now(); |
- if (now - last_progress_callback_invocation_time_ >= |
- min_progress_callback_invocation_span_) { |
- file_progress_callback_.Run(num_copied_bytes_); |
- last_progress_callback_invocation_time_ = now; |
- } |
- |
- if (buffer->BytesRemaining() > 0) { |
- Write(callback, buffer); |
- return; |
- } |
- |
- if (need_flush_ && |
- (num_copied_bytes_ - previous_flush_offset_) > kFlushIntervalInBytes) { |
- Flush(callback, false /* not is_eof */); |
- } else { |
- Read(callback); |
- } |
-} |
- |
-void CopyOrMoveOperationDelegate::StreamCopyHelper::Flush( |
- const StatusCallback& callback, bool is_eof) { |
- int result = writer_->Flush( |
- base::Bind(&StreamCopyHelper::DidFlush, |
- weak_factory_.GetWeakPtr(), callback, is_eof)); |
- if (result != net::ERR_IO_PENDING) |
- DidFlush(callback, is_eof, result); |
-} |
- |
-void CopyOrMoveOperationDelegate::StreamCopyHelper::DidFlush( |
- const StatusCallback& callback, bool is_eof, int result) { |
- if (cancel_requested_) { |
- callback.Run(base::File::FILE_ERROR_ABORT); |
- return; |
- } |
- |
- previous_flush_offset_ = num_copied_bytes_; |
- if (is_eof) |
- callback.Run(NetErrorToFileError(result)); |
- else |
- Read(callback); |
-} |
- |
-CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( |
- FileSystemContext* file_system_context, |
- const FileSystemURL& src_root, |
- const FileSystemURL& dest_root, |
- OperationType operation_type, |
- CopyOrMoveOption option, |
- const CopyProgressCallback& progress_callback, |
- const StatusCallback& callback) |
- : RecursiveOperationDelegate(file_system_context), |
- src_root_(src_root), |
- dest_root_(dest_root), |
- operation_type_(operation_type), |
- option_(option), |
- 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() { |
- // Not supported; this should never be called. |
- NOTREACHED(); |
-} |
- |
-void CopyOrMoveOperationDelegate::RunRecursively() { |
- // Perform light-weight checks first. |
- |
- // It is an error to try to copy/move an entry into its child. |
- if (same_file_system_ && src_root_.path().IsParent(dest_root_.path())) { |
- callback_.Run(base::File::FILE_ERROR_INVALID_OPERATION); |
- return; |
- } |
- |
- if (same_file_system_ && src_root_.path() == dest_root_.path()) { |
- // In JS API this should return error, but we return success because Pepper |
- // wants to return success and we have a code path that returns error in |
- // Blink for JS (http://crbug.com/329517). |
- callback_.Run(base::File::FILE_OK); |
- 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_, callback_); |
-} |
- |
-void CopyOrMoveOperationDelegate::ProcessFile( |
- const FileSystemURL& src_url, |
- const StatusCallback& callback) { |
- if (!progress_callback_.is_null()) { |
- progress_callback_.Run( |
- FileSystemOperation::BEGIN_COPY_ENTRY, src_url, FileSystemURL(), 0); |
- } |
- |
- FileSystemURL dest_url = CreateDestURL(src_url); |
- CopyOrMoveImpl* impl = NULL; |
- if (same_file_system_ && |
- (file_system_context() |
- ->GetFileSystemBackend(src_url.type()) |
- ->HasInplaceCopyImplementation(src_url.type()) || |
- operation_type_ == OperationType::OPERATION_MOVE)) { |
- impl = new CopyOrMoveOnSameFileSystemImpl( |
- operation_runner(), operation_type_, src_url, dest_url, option_, |
- base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, |
- weak_factory_.GetWeakPtr(), src_url)); |
- } else { |
- // Cross filesystem case. |
- base::File::Error error = base::File::FILE_ERROR_FAILED; |
- CopyOrMoveFileValidatorFactory* validator_factory = |
- file_system_context()->GetCopyOrMoveFileValidatorFactory( |
- dest_root_.type(), &error); |
- if (error != base::File::FILE_OK) { |
- callback.Run(error); |
- return; |
- } |
- |
- if (!validator_factory) { |
- scoped_ptr<storage::FileStreamReader> reader = |
- file_system_context()->CreateFileStreamReader( |
- src_url, 0, base::Time()); |
- scoped_ptr<FileStreamWriter> writer = |
- file_system_context()->CreateFileStreamWriter(dest_url, 0); |
- if (reader && writer) { |
- impl = new StreamCopyOrMoveImpl( |
- operation_runner(), |
- file_system_context(), |
- operation_type_, |
- src_url, |
- dest_url, |
- option_, |
- reader.Pass(), |
- writer.Pass(), |
- base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, |
- weak_factory_.GetWeakPtr(), |
- src_url)); |
- } |
- } |
- |
- if (!impl) { |
- impl = new SnapshotCopyOrMoveImpl( |
- operation_runner(), operation_type_, src_url, dest_url, option_, |
- validator_factory, |
- base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, |
- weak_factory_.GetWeakPtr(), src_url)); |
- } |
- } |
- |
- // Register the running task. |
- running_copy_set_.insert(impl); |
- impl->Run(base::Bind( |
- &CopyOrMoveOperationDelegate::DidCopyOrMoveFile, |
- weak_factory_.GetWeakPtr(), src_url, dest_url, callback, impl)); |
-} |
- |
-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; |
- } |
- |
- if (!progress_callback_.is_null()) { |
- progress_callback_.Run( |
- FileSystemOperation::BEGIN_COPY_ENTRY, src_url, FileSystemURL(), 0); |
- } |
- |
- ProcessDirectoryInternal(src_url, CreateDestURL(src_url), callback); |
-} |
- |
-void CopyOrMoveOperationDelegate::PostProcessDirectory( |
- const FileSystemURL& src_url, |
- const StatusCallback& callback) { |
- if (option_ == FileSystemOperation::OPTION_NONE) { |
- PostProcessDirectoryAfterTouchFile( |
- src_url, callback, base::File::FILE_OK); |
- return; |
- } |
- |
- operation_runner()->GetMetadata( |
- src_url, |
- base::Bind( |
- &CopyOrMoveOperationDelegate::PostProcessDirectoryAfterGetMetadata, |
- weak_factory_.GetWeakPtr(), src_url, callback)); |
-} |
- |
-void CopyOrMoveOperationDelegate::OnCancel() { |
- // Request to cancel all running Copy/Move file. |
- for (std::set<CopyOrMoveImpl*>::iterator iter = running_copy_set_.begin(); |
- iter != running_copy_set_.end(); ++iter) |
- (*iter)->Cancel(); |
-} |
- |
-void CopyOrMoveOperationDelegate::DidCopyOrMoveFile( |
- const FileSystemURL& src_url, |
- const FileSystemURL& dest_url, |
- const StatusCallback& callback, |
- CopyOrMoveImpl* impl, |
- base::File::Error error) { |
- running_copy_set_.erase(impl); |
- delete impl; |
- |
- if (!progress_callback_.is_null() && error == base::File::FILE_OK) { |
- progress_callback_.Run( |
- FileSystemOperation::END_COPY_ENTRY, src_url, dest_url, 0); |
- } |
- |
- callback.Run(error); |
-} |
- |
-void CopyOrMoveOperationDelegate::DidTryRemoveDestRoot( |
- const StatusCallback& callback, |
- base::File::Error error) { |
- if (error == base::File::FILE_ERROR_NOT_A_DIRECTORY) { |
- callback_.Run(base::File::FILE_ERROR_INVALID_OPERATION); |
- return; |
- } |
- if (error != base::File::FILE_OK && |
- error != base::File::FILE_ERROR_NOT_FOUND) { |
- callback_.Run(error); |
- return; |
- } |
- |
- 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)); |
-} |
- |
-void CopyOrMoveOperationDelegate::DidCreateDirectory( |
- const FileSystemURL& src_url, |
- const FileSystemURL& dest_url, |
- const StatusCallback& callback, |
- base::File::Error error) { |
- if (!progress_callback_.is_null() && error == base::File::FILE_OK) { |
- progress_callback_.Run( |
- FileSystemOperation::END_COPY_ENTRY, src_url, dest_url, 0); |
- } |
- |
- callback.Run(error); |
-} |
- |
-void CopyOrMoveOperationDelegate::PostProcessDirectoryAfterGetMetadata( |
- const FileSystemURL& src_url, |
- const StatusCallback& callback, |
- base::File::Error error, |
- const base::File::Info& file_info) { |
- if (error != base::File::FILE_OK) { |
- // Ignore the error, and run post process which should run after TouchFile. |
- PostProcessDirectoryAfterTouchFile( |
- src_url, callback, base::File::FILE_OK); |
- return; |
- } |
- |
- operation_runner()->TouchFile( |
- CreateDestURL(src_url), base::Time::Now() /* last access */, |
- file_info.last_modified, |
- base::Bind( |
- &CopyOrMoveOperationDelegate::PostProcessDirectoryAfterTouchFile, |
- weak_factory_.GetWeakPtr(), src_url, callback)); |
-} |
- |
-void CopyOrMoveOperationDelegate::PostProcessDirectoryAfterTouchFile( |
- const FileSystemURL& src_url, |
- const StatusCallback& callback, |
- base::File::Error error) { |
- // Even if the TouchFile is failed, just ignore it. |
- |
- if (operation_type_ == OPERATION_COPY) { |
- callback.Run(base::File::FILE_OK); |
- return; |
- } |
- |
- DCHECK_EQ(OPERATION_MOVE, operation_type_); |
- |
- // All files and subdirectories in the directory should be moved here, |
- // so remove the source directory for finalizing move operation. |
- operation_runner()->Remove( |
- src_url, false /* recursive */, |
- base::Bind(&CopyOrMoveOperationDelegate::DidRemoveSourceForMove, |
- weak_factory_.GetWeakPtr(), callback)); |
-} |
- |
-void CopyOrMoveOperationDelegate::DidRemoveSourceForMove( |
- const StatusCallback& callback, |
- base::File::Error error) { |
- if (error == base::File::FILE_ERROR_NOT_FOUND) |
- error = base::File::FILE_OK; |
- 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()); |
- DCHECK_EQ(src_root_.origin(), src_url.origin()); |
- |
- base::FilePath relative = dest_root_.virtual_path(); |
- src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), |
- &relative); |
- return file_system_context()->CreateCrackedFileSystemURL( |
- dest_root_.origin(), |
- dest_root_.mount_type(), |
- relative); |
-} |
- |
-} // namespace storage |