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 storage::FileSystemURL& url,
+ const storage::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) {
+ // Closing a file must not be aborted, since we could end up on files
+ // which are never closed.
+ 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 storage::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.get(),
+ 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 storage::AsyncFileUtil::StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (abort_callback_.is_null()) {
+ // No operation to be cancelled. At most a callback call, which will be
+ // discarded.
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, base::File::FILE_OK));
+ 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 storage::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 storage::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 storage::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,
+FileStreamWriter::FileStreamWriter(const storage::FileSystemURL& url,
int64 initial_offset)
: url_(url),
current_offset_(initial_offset),
+ runner_(new OperationRunner),
state_(NOT_INITIALIZED),
- file_handle_(0),
weak_ptr_factory_(this) {
}
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_);
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;
}
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) {
"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,
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