This source file includes following definitions.
- CopyOrMoveImpl
- CopyOrMoveImpl
- file_progress_callback_
- Run
- Cancel
- weak_factory_
- Run
- Cancel
- RunAfterCreateSnapshot
- RunAfterPreWriteValidation
- RunAfterCopyInForeignFile
- RunAfterTouchFile
- RunAfterPostWriteValidation
- RunAfterRemoveSourceForMove
- DidRemoveDestForError
- PreWriteValidation
- PostWriteValidation
- PostWriteValidationAfterCreateSnapshotFile
- DidPostWriteValidation
- weak_factory_
- Run
- Cancel
- RunAfterGetMetadataForSource
- RunAfterCreateFileForDestination
- RunAfterStreamCopy
- RunAfterTouchFile
- RunAfterRemoveForMove
- weak_factory_
- Run
- Cancel
- Read
- DidRead
- Write
- DidWrite
- Flush
- DidFlush
- weak_factory_
- Run
- RunRecursively
- ProcessFile
- ProcessDirectory
- PostProcessDirectory
- OnCancel
- DidCopyOrMoveFile
- DidTryRemoveDestRoot
- ProcessDirectoryInternal
- DidCreateDirectory
- PostProcessDirectoryAfterGetMetadata
- PostProcessDirectoryAfterTouchFile
- DidRemoveSourceForMove
- OnCopyFileProgress
- CreateDestURL
#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_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 fileapi {
const int64 kFlushIntervalInBytes = 10 << 20;
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 {
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 {
}
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);
};
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<webkit_blob::ShareableFileReference>& file_ref) {
if (cancel_requested_)
error = base::File::FILE_ERROR_ABORT;
if (error != base::File::FILE_OK) {
callback.Run(error);
return;
}
DCHECK(!platform_path.empty());
if (!validator_factory_) {
RunAfterPreWriteValidation(platform_path, file_info, file_ref, callback,
base::File::FILE_OK);
return;
}
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<webkit_blob::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;
}
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<webkit_blob::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() ,
file_info.last_modified,
base::Bind(&SnapshotCopyOrMoveImpl::RunAfterTouchFile,
weak_factory_.GetWeakPtr(), callback));
}
void RunAfterTouchFile(
const CopyOrMoveOperationDelegate::StatusCallback& callback,
base::File::Error error) {
if (cancel_requested_) {
callback.Run(base::File::FILE_ERROR_ABORT);
return;
}
if (!validator_) {
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) {
operation_runner_->Remove(
dest_url_, true ,
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_);
operation_runner_->Remove(
src_url_, true ,
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);
}
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);
}
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<webkit_blob::ShareableFileReference>& file_ref) {
if (cancel_requested_)
error = base::File::FILE_ERROR_ABORT;
if (error != base::File::FILE_OK) {
callback.Run(error);
return;
}
DCHECK(validator_);
validator_->StartPostWriteValidation(
platform_path,
base::Bind(&SnapshotCopyOrMoveImpl::DidPostWriteValidation,
weak_factory_.GetWeakPtr(), file_ref, callback));
}
void DidPostWriteValidation(
const scoped_refptr<webkit_blob::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);
};
const int kReadBufferSize = 32768;
const int kMinProgressCallbackInvocationSpanInMilliseconds = 50;
class StreamCopyOrMoveImpl
: public CopyOrMoveOperationDelegate::CopyOrMoveImpl {
public:
StreamCopyOrMoveImpl(
FileSystemOperationRunner* operation_runner,
CopyOrMoveOperationDelegate::OperationType operation_type,
const FileSystemURL& src_url,
const FileSystemURL& dest_url,
CopyOrMoveOperationDelegate::CopyOrMoveOption option,
scoped_ptr<webkit_blob::FileStreamReader> reader,
scoped_ptr<FileStreamWriter> writer,
const FileSystemOperation::CopyFileProgressCallback&
file_progress_callback)
: operation_runner_(operation_runner),
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 {
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 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) {
callback.Run(base::File::FILE_ERROR_NOT_A_FILE);
return;
}
operation_runner_->CreateFile(
dest_url_, false ,
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;
if (error != base::File::FILE_OK) {
callback.Run(error);
return;
}
const bool need_flush = dest_url_.mount_option().copy_sync_option() ==
fileapi::COPY_SYNC_OPTION_SYNC;
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) {
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_modified,
base::Bind(&StreamCopyOrMoveImpl::RunAfterTouchFile,
weak_factory_.GetWeakPtr(), callback));
}
void RunAfterTouchFile(
const CopyOrMoveOperationDelegate::StatusCallback& callback,
base::File::Error error) {
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_);
operation_runner_->Remove(
src_url_, false ,
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_;
CopyOrMoveOperationDelegate::OperationType operation_type_;
FileSystemURL src_url_;
FileSystemURL dest_url_;
CopyOrMoveOperationDelegate::CopyOrMoveOption option_;
scoped_ptr<webkit_blob::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);
};
}
CopyOrMoveOperationDelegate::StreamCopyHelper::StreamCopyHelper(
scoped_ptr<webkit_blob::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) {
if (need_flush_)
Flush(callback, true );
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;
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 );
} 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() {
NOTREACHED();
}
void CopyOrMoveOperationDelegate::RunRecursively() {
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()) {
callback_.Run(base::File::FILE_OK);
return;
}
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_) {
impl = new CopyOrMoveOnSameFileSystemImpl(
operation_runner(), operation_type_, src_url, dest_url, option_,
base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress,
weak_factory_.GetWeakPtr(), src_url));
} else {
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<webkit_blob::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(), 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));
}
}
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_) {
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() {
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) {
operation_runner()->CreateDirectory(
dest_url, false , false ,
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) {
PostProcessDirectoryAfterTouchFile(
src_url, callback, base::File::FILE_OK);
return;
}
operation_runner()->TouchFile(
CreateDestURL(src_url), base::Time::Now() ,
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) {
if (operation_type_ == OPERATION_COPY) {
callback.Run(base::File::FILE_OK);
return;
}
DCHECK_EQ(OPERATION_MOVE, operation_type_);
operation_runner()->Remove(
src_url, false ,
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);
}
}