15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer.h"
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/debug/trace_event.h"
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/memory/ref_counted.h"
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/base/io_buffer.h"
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/base/net_errors.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)using content::BrowserThread;
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace chromeos {
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace file_system_provider {
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace {
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Dicards the callback from CloseFile().
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void EmptyStatusCallback(base::File::Error /* result */) {
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}  // namespace
2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)class FileStreamWriter::OperationRunner
2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : public base::RefCountedThreadSafe<FileStreamWriter::OperationRunner> {
3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) public:
3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  OperationRunner() : file_handle_(-1) {}
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Opens a file for writing and calls the completion callback. Must be called
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // on UI thread.
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void OpenFileOnUIThread(
3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const storage::FileSystemURL& url,
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const storage::AsyncFileUtil::StatusCallback& callback) {
3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK_CURRENTLY_ON(BrowserThread::UI);
3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    util::FileSystemURLParser parser(url);
4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!parser.Parse()) {
4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      BrowserThread::PostTask(
4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          BrowserThread::IO,
4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          FROM_HERE,
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          base::Bind(callback, base::File::FILE_ERROR_SECURITY));
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    file_system_ = parser.file_system()->GetWeakPtr();
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    abort_callback_ = parser.file_system()->OpenFile(
5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        parser.file_path(),
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE,
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        base::Bind(
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            &OperationRunner::OnOpenFileCompletedOnUIThread, this, callback));
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Closes a file. Ignores result, since outlives the caller. Must be called on
5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // UI thread.
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void CloseFileOnUIThread() {
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK_CURRENTLY_ON(BrowserThread::UI);
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (file_system_.get() && file_handle_ != -1) {
6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Closing a file must not be aborted, since we could end up on files
6303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // which are never closed.
6403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      file_system_->CloseFile(file_handle_, base::Bind(&EmptyStatusCallback));
6503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
6603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Requests writing bytes to the file. In case of either success or a failure
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // |callback| is executed. Must be called on UI thread.
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void WriteFileOnUIThread(
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      scoped_refptr<net::IOBuffer> buffer,
7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      int64 offset,
7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      int length,
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const storage::AsyncFileUtil::StatusCallback& callback) {
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK_CURRENTLY_ON(BrowserThread::UI);
7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If the file system got unmounted, then abort the writing operation.
7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!file_system_.get()) {
7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      BrowserThread::PostTask(
8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          BrowserThread::IO,
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          FROM_HERE,
8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          base::Bind(callback, base::File::FILE_ERROR_ABORT));
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    abort_callback_ = file_system_->WriteFile(
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        file_handle_,
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        buffer.get(),
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        offset,
9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        length,
9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        base::Bind(
9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback));
9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Aborts the most recent operation (if exists), and calls the callback.
9603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void AbortOnUIThread(const storage::AsyncFileUtil::StatusCallback& callback) {
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK_CURRENTLY_ON(BrowserThread::UI);
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
9903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (abort_callback_.is_null()) {
10003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // No operation to be cancelled. At most a callback call, which will be
10103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // discarded.
10203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      BrowserThread::PostTask(BrowserThread::IO,
10303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              FROM_HERE,
10403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                              base::Bind(callback, base::File::FILE_OK));
10503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return;
10603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
10703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const ProvidedFileSystemInterface::AbortCallback abort_callback =
10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        abort_callback_;
11003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    abort_callback_ = ProvidedFileSystemInterface::AbortCallback();
11103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    abort_callback.Run(base::Bind(
11203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        &OperationRunner::OnAbortCompletedOnUIThread, this, callback));
11303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) private:
11603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  friend class base::RefCountedThreadSafe<OperationRunner>;
11703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  virtual ~OperationRunner() {}
11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Remembers a file handle for further operations and forwards the result to
12103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // the IO thread.
12203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void OnOpenFileCompletedOnUIThread(
12303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const storage::AsyncFileUtil::StatusCallback& callback,
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      int file_handle,
12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::File::Error result) {
12603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK_CURRENTLY_ON(BrowserThread::UI);
12703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    file_handle_ = file_handle;
12903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    BrowserThread::PostTask(
13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Forwards a response of writing to a file to the IO thread.
13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void OnWriteFileCompletedOnUIThread(
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const storage::AsyncFileUtil::StatusCallback& callback,
13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::File::Error result) {
13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK_CURRENTLY_ON(BrowserThread::UI);
13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    BrowserThread::PostTask(
13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Forwards a response of aborting an operation to the IO thread.
14303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  void OnAbortCompletedOnUIThread(
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      const storage::AsyncFileUtil::StatusCallback& callback,
14503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::File::Error result) {
14603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK_CURRENTLY_ON(BrowserThread::UI);
14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    BrowserThread::PostTask(
14803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        BrowserThread::IO, FROM_HERE, base::Bind(callback, result));
14903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
15103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ProvidedFileSystemInterface::AbortCallback abort_callback_;
15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  base::WeakPtr<ProvidedFileSystemInterface> file_system_;
15303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  int file_handle_;
15403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OperationRunner);
15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)};
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
15803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)FileStreamWriter::FileStreamWriter(const storage::FileSystemURL& url,
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                   int64 initial_offset)
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : url_(url),
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      current_offset_(initial_offset),
16203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      runner_(new OperationRunner),
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      state_(NOT_INITIALIZED),
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      weak_ptr_factory_(this) {
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)FileStreamWriter::~FileStreamWriter() {
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  BrowserThread::PostTask(
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BrowserThread::UI,
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::Bind(&OperationRunner::CloseFileOnUIThread, runner_));
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FileStreamWriter::Initialize(
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const base::Closure& pending_closure,
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const net::CompletionCallback& error_callback) {
17703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(NOT_INITIALIZED, state_);
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  state_ = INITIALIZING;
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  BrowserThread::PostTask(
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BrowserThread::UI,
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::Bind(&OperationRunner::OpenFileOnUIThread,
18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 runner_,
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 url_,
18703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 base::Bind(&FileStreamWriter::OnOpenFileCompleted,
18803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
18903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            pending_closure,
19003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            error_callback)));
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FileStreamWriter::OnOpenFileCompleted(
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const base::Closure& pending_closure,
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const net::CompletionCallback& error_callback,
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::File::Error result) {
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(INITIALIZING, state_);
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // In case of an error, return immediately using the |error_callback| of the
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Write() pending request.
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (result != base::File::FILE_OK) {
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    state_ = FAILED;
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    error_callback.Run(net::FileErrorToNetError(result));
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(base::File::FILE_OK, result);
2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  state_ = INITIALIZED;
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Run the task waiting for the initialization to be completed.
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  pending_closure.Run();
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int FileStreamWriter::Write(net::IOBuffer* buffer,
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            int buffer_length,
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            const net::CompletionCallback& callback) {
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           "FileStreamWriter::Write",
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           this,
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           "buffer_length",
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           buffer_length);
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  switch (state_) {
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case NOT_INITIALIZED:
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Lazily initialize with the first call to Write().
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      Initialize(base::Bind(&FileStreamWriter::WriteAfterInitialized,
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            make_scoped_refptr(buffer),
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            buffer_length,
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            base::Bind(&FileStreamWriter::OnWriteCompleted,
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       weak_ptr_factory_.GetWeakPtr(),
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       callback)),
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 base::Bind(&FileStreamWriter::OnWriteCompleted,
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            callback));
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case INITIALIZING:
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NOTREACHED();
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case INITIALIZED:
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      WriteAfterInitialized(buffer,
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            buffer_length,
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            base::Bind(&FileStreamWriter::OnWriteCompleted,
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       weak_ptr_factory_.GetWeakPtr(),
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       callback));
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    case FAILED:
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NOTREACHED();
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return net::ERR_IO_PENDING;
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int FileStreamWriter::Cancel(const net::CompletionCallback& callback) {
26103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
26203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
26303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserThread::PostTask(
26403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      BrowserThread::UI,
26503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      FROM_HERE,
26603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::Bind(&OperationRunner::AbortOnUIThread,
26703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 runner_,
26803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 base::Bind(&FileStreamWriter::OnAbortCompleted,
26903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
27003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            callback)));
27103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return net::ERR_IO_PENDING;
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int FileStreamWriter::Flush(const net::CompletionCallback& callback) {
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (state_ != INITIALIZED)
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return net::ERR_FAILED;
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return net::OK;
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FileStreamWriter::OnWriteFileCompleted(
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int buffer_length,
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const net::CompletionCallback& callback,
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::File::Error result) {
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(INITIALIZED, state_);
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (result != base::File::FILE_OK) {
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    state_ = FAILED;
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    callback.Run(net::FileErrorToNetError(result));
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  current_offset_ += buffer_length;
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  callback.Run(buffer_length);
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback,
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                        int result) {
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  callback.Run(result);
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TRACE_EVENT_ASYNC_END0(
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "file_system_provider", "FileStreamWriter::Write", this);
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
30603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback,
30703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                        base::File::Error result) {
30803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
30903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
31003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (result != base::File::FILE_OK)
31103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    state_ = FAILED;
31203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
31303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  callback.Run(net::FileErrorToNetError(result));
31403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
31503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void FileStreamWriter::WriteAfterInitialized(
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<net::IOBuffer> buffer,
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int buffer_length,
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const net::CompletionCallback& callback) {
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(INITIALIZED, state_);
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  BrowserThread::PostTask(
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BrowserThread::UI,
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
32603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::Bind(&OperationRunner::WriteFileOnUIThread,
32703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 runner_,
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 buffer,
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 current_offset_,
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 buffer_length,
33103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 base::Bind(&FileStreamWriter::OnWriteFileCompleted,
33203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            weak_ptr_factory_.GetWeakPtr(),
33303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            buffer_length,
33403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            callback)));
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace file_system_provider
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace chromeos
339