| 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
|
|
|