Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / file_system_provider / fileapi / file_stream_writer.cc
index 1a53d0f..6441cfb 100644 (file)
@@ -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 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) {
 }
 
@@ -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