| Index: chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.cc
|
| diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.cc b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.cc
|
| index 1a53d0fccb6c99aa8121912bcaddcf7cf5170278..81094b19c11b06b85557186a7f2d405e79099bef 100644
|
| --- a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.cc
|
| +++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.cc
|
| @@ -23,89 +23,144 @@ namespace {
|
| void EmptyStatusCallback(base::File::Error /* result */) {
|
| }
|
|
|
| -// Opens a file for writing and calls the completion callback. Must be called
|
| -// on UI thread.
|
| -void OpenFileOnUIThread(
|
| - const fileapi::FileSystemURL& url,
|
| - const FileStreamWriter::OpenFileCompletedCallback& callback) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - util::FileSystemURLParser parser(url);
|
| - if (!parser.Parse()) {
|
| - callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(),
|
| - base::FilePath(),
|
| - 0 /* file_handle */,
|
| - base::File::FILE_ERROR_SECURITY);
|
| - return;
|
| +} // namespace
|
| +
|
| +class FileStreamWriter::OperationRunner
|
| + : public base::RefCountedThreadSafe<FileStreamWriter::OperationRunner> {
|
| + public:
|
| + OperationRunner() : file_handle_(-1) {}
|
| +
|
| + // Opens a file for writing and calls the completion callback. Must be called
|
| + // on UI thread.
|
| + void OpenFileOnUIThread(
|
| + const fileapi::FileSystemURL& url,
|
| + const fileapi::AsyncFileUtil::StatusCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + util::FileSystemURLParser parser(url);
|
| + if (!parser.Parse()) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(callback, base::File::FILE_ERROR_SECURITY));
|
| + return;
|
| + }
|
| +
|
| + file_system_ = parser.file_system()->GetWeakPtr();
|
| + abort_callback_ = parser.file_system()->OpenFile(
|
| + parser.file_path(),
|
| + ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE,
|
| + base::Bind(
|
| + &OperationRunner::OnOpenFileCompletedOnUIThread, this, callback));
|
| }
|
|
|
| - parser.file_system()->OpenFile(
|
| - parser.file_path(),
|
| - ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE,
|
| - base::Bind(
|
| - callback, parser.file_system()->GetWeakPtr(), parser.file_path()));
|
| -}
|
| + // Closes a file. Ignores result, since outlives the caller. Must be called on
|
| + // UI thread.
|
| + void CloseFileOnUIThread() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| + if (file_system_.get() && file_handle_ != -1) {
|
| + abort_callback_ = file_system_->CloseFile(
|
| + file_handle_, base::Bind(&EmptyStatusCallback));
|
| + }
|
| + }
|
|
|
| -// Forwards results of calling OpenFileOnUIThread back to the IO thread.
|
| -void OnOpenFileCompletedOnUIThread(
|
| - const FileStreamWriter::OpenFileCompletedCallback& callback,
|
| - base::WeakPtr<ProvidedFileSystemInterface> file_system,
|
| - const base::FilePath& file_path,
|
| - int file_handle,
|
| - base::File::Error result) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO,
|
| - FROM_HERE,
|
| - base::Bind(callback, file_system, file_path, file_handle, result));
|
| -}
|
| + // Requests writing bytes to the file. In case of either success or a failure
|
| + // |callback| is executed. Must be called on UI thread.
|
| + void WriteFileOnUIThread(
|
| + scoped_refptr<net::IOBuffer> buffer,
|
| + int64 offset,
|
| + int length,
|
| + const fileapi::AsyncFileUtil::StatusCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + // If the file system got unmounted, then abort the writing operation.
|
| + if (!file_system_.get()) {
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(callback, base::File::FILE_ERROR_ABORT));
|
| + return;
|
| + }
|
| +
|
| + abort_callback_ = file_system_->WriteFile(
|
| + file_handle_,
|
| + buffer,
|
| + offset,
|
| + length,
|
| + base::Bind(
|
| + &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback));
|
| + }
|
|
|
| -// Closes a file. Ignores result, since it is called from a constructor.
|
| -// Must be called on UI thread.
|
| -void CloseFileOnUIThread(base::WeakPtr<ProvidedFileSystemInterface> file_system,
|
| - int file_handle) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - if (file_system.get())
|
| - file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback));
|
| -}
|
| + // Aborts the most recent operation (if exists), and calls the callback.
|
| + void AbortOnUIThread(const fileapi::AsyncFileUtil::StatusCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + if (abort_callback_.is_null()) {
|
| + // No operation on the file system being performed. At most a callback
|
| + // call, which will be discarded.
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO,
|
| + FROM_HERE,
|
| + base::Bind(callback, base::File::FILE_ERROR_ABORT));
|
| + return;
|
| + }
|
| +
|
| + const ProvidedFileSystemInterface::AbortCallback abort_callback =
|
| + abort_callback_;
|
| + abort_callback_ = ProvidedFileSystemInterface::AbortCallback();
|
| + abort_callback.Run(base::Bind(
|
| + &OperationRunner::OnAbortCompletedOnUIThread, this, callback));
|
| + }
|
|
|
| -// Requests writing bytes to the file. In case of either success or a failure
|
| -// |callback| is executed. Must be called on UI thread.
|
| -void WriteFileOnUIThread(
|
| - base::WeakPtr<ProvidedFileSystemInterface> file_system,
|
| - int file_handle,
|
| - scoped_refptr<net::IOBuffer> buffer,
|
| - int64 offset,
|
| - int length,
|
| - const fileapi::AsyncFileUtil::StatusCallback& callback) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| - // If the file system got unmounted, then abort the writing operation.
|
| - if (!file_system.get()) {
|
| - callback.Run(base::File::FILE_ERROR_ABORT);
|
| - return;
|
| + private:
|
| + friend class base::RefCountedThreadSafe<OperationRunner>;
|
| +
|
| + virtual ~OperationRunner() {}
|
| +
|
| + // Remembers a file handle for further operations and forwards the result to
|
| + // the IO thread.
|
| + void OnOpenFileCompletedOnUIThread(
|
| + const fileapi::AsyncFileUtil::StatusCallback& callback,
|
| + int file_handle,
|
| + base::File::Error result) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| +
|
| + file_handle_ = file_handle;
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
|
| }
|
|
|
| - file_system->WriteFile(file_handle, buffer, offset, length, callback);
|
| -}
|
| + // Forwards a response of writing to a file to the IO thread.
|
| + void OnWriteFileCompletedOnUIThread(
|
| + const fileapi::AsyncFileUtil::StatusCallback& callback,
|
| + base::File::Error result) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
|
| + }
|
|
|
| -// Forward the completion callback to IO thread.
|
| -void OnWriteFileCompletedOnUIThread(
|
| - const fileapi::AsyncFileUtil::StatusCallback& callback,
|
| - base::File::Error result) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
|
| -}
|
| + // Forwards a response of aborting an operation to the IO thread.
|
| + void OnAbortCompletedOnUIThread(
|
| + const fileapi::AsyncFileUtil::StatusCallback& callback,
|
| + base::File::Error result) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
|
| + }
|
|
|
| -} // namespace
|
| + ProvidedFileSystemInterface::AbortCallback abort_callback_;
|
| + base::WeakPtr<ProvidedFileSystemInterface> file_system_;
|
| + int file_handle_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(OperationRunner);
|
| +};
|
|
|
| FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url,
|
| int64 initial_offset)
|
| : url_(url),
|
| current_offset_(initial_offset),
|
| + runner_(new OperationRunner),
|
| state_(NOT_INITIALIZED),
|
| - file_handle_(0),
|
| weak_ptr_factory_(this) {
|
| }
|
|
|
| @@ -113,33 +168,31 @@ FileStreamWriter::~FileStreamWriter() {
|
| BrowserThread::PostTask(
|
| BrowserThread::UI,
|
| FROM_HERE,
|
| - base::Bind(&CloseFileOnUIThread, file_system_, file_handle_));
|
| + base::Bind(&OperationRunner::CloseFileOnUIThread, runner_));
|
| }
|
|
|
| void FileStreamWriter::Initialize(
|
| const base::Closure& pending_closure,
|
| const net::CompletionCallback& error_callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| DCHECK_EQ(NOT_INITIALIZED, state_);
|
| state_ = INITIALIZING;
|
|
|
| BrowserThread::PostTask(
|
| BrowserThread::UI,
|
| FROM_HERE,
|
| - base::Bind(&OpenFileOnUIThread,
|
| + base::Bind(&OperationRunner::OpenFileOnUIThread,
|
| + runner_,
|
| url_,
|
| - base::Bind(&OnOpenFileCompletedOnUIThread,
|
| - base::Bind(&FileStreamWriter::OnOpenFileCompleted,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - pending_closure,
|
| - error_callback))));
|
| + base::Bind(&FileStreamWriter::OnOpenFileCompleted,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + pending_closure,
|
| + error_callback)));
|
| }
|
|
|
| void FileStreamWriter::OnOpenFileCompleted(
|
| const base::Closure& pending_closure,
|
| const net::CompletionCallback& error_callback,
|
| - base::WeakPtr<ProvidedFileSystemInterface> file_system,
|
| - const base::FilePath& file_path,
|
| - int file_handle,
|
| base::File::Error result) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| DCHECK_EQ(INITIALIZING, state_);
|
| @@ -152,10 +205,6 @@ void FileStreamWriter::OnOpenFileCompleted(
|
| return;
|
| }
|
|
|
| - file_system_ = file_system;
|
| - file_path_ = file_path;
|
| - file_handle_ = file_handle;
|
| - DCHECK_LT(0, file_handle);
|
| DCHECK_EQ(base::File::FILE_OK, result);
|
| state_ = INITIALIZED;
|
|
|
| @@ -209,8 +258,17 @@ int FileStreamWriter::Write(net::IOBuffer* buffer,
|
| }
|
|
|
| int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
|
| - NOTIMPLEMENTED();
|
| - return net::ERR_FAILED;
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + BrowserThread::PostTask(
|
| + BrowserThread::UI,
|
| + FROM_HERE,
|
| + base::Bind(&OperationRunner::AbortOnUIThread,
|
| + runner_,
|
| + base::Bind(&FileStreamWriter::OnAbortCompleted,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + callback)));
|
| + return net::ERR_IO_PENDING;
|
| }
|
|
|
| int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
|
| @@ -245,6 +303,16 @@ void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
|
| "file_system_provider", "FileStreamWriter::Write", this);
|
| }
|
|
|
| +void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback,
|
| + base::File::Error result) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + if (result != base::File::FILE_OK)
|
| + state_ = FAILED;
|
| +
|
| + callback.Run(net::FileErrorToNetError(result));
|
| +}
|
| +
|
| void FileStreamWriter::WriteAfterInitialized(
|
| scoped_refptr<net::IOBuffer> buffer,
|
| int buffer_length,
|
| @@ -255,17 +323,15 @@ void FileStreamWriter::WriteAfterInitialized(
|
| BrowserThread::PostTask(
|
| BrowserThread::UI,
|
| FROM_HERE,
|
| - base::Bind(&WriteFileOnUIThread,
|
| - file_system_,
|
| - file_handle_,
|
| + base::Bind(&OperationRunner::WriteFileOnUIThread,
|
| + runner_,
|
| buffer,
|
| current_offset_,
|
| buffer_length,
|
| - base::Bind(&OnWriteFileCompletedOnUIThread,
|
| - base::Bind(&FileStreamWriter::OnWriteFileCompleted,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - buffer_length,
|
| - callback))));
|
| + base::Bind(&FileStreamWriter::OnWriteFileCompleted,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + buffer_length,
|
| + callback)));
|
| }
|
|
|
| } // namespace file_system_provider
|
|
|