Home | History | Annotate | Download | only in drive
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/drive/webkit_file_stream_writer_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback_helpers.h"
      9 #include "chrome/browser/chromeos/drive/file_system_util.h"
     10 #include "chrome/browser/chromeos/drive/fileapi_worker.h"
     11 #include "chrome/browser/google_apis/task_util.h"
     12 #include "content/public/browser/browser_thread.h"
     13 #include "net/base/io_buffer.h"
     14 #include "net/base/net_errors.h"
     15 #include "webkit/browser/fileapi/local_file_stream_writer.h"
     16 
     17 using content::BrowserThread;
     18 
     19 namespace drive {
     20 namespace internal {
     21 namespace {
     22 
     23 // Creates a writable snapshot file of the |drive_path|.
     24 void CreateWritableSnapshotFile(
     25     const WebkitFileStreamWriterImpl::FileSystemGetter& file_system_getter,
     26     const base::FilePath& drive_path,
     27     const fileapi_internal::CreateWritableSnapshotFileCallback& callback) {
     28   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     29 
     30   BrowserThread::PostTask(
     31       BrowserThread::UI,
     32       FROM_HERE,
     33       base::Bind(
     34           &fileapi_internal::RunFileSystemCallback,
     35           file_system_getter,
     36           base::Bind(&fileapi_internal::CreateWritableSnapshotFile,
     37                      drive_path, google_apis::CreateRelayCallback(callback)),
     38           google_apis::CreateRelayCallback(base::Bind(
     39               callback, base::PLATFORM_FILE_ERROR_FAILED, base::FilePath(),
     40               base::Closure()))));
     41 }
     42 
     43 }  // namespace
     44 
     45 WebkitFileStreamWriterImpl::WebkitFileStreamWriterImpl(
     46     const FileSystemGetter& file_system_getter,
     47     base::TaskRunner* file_task_runner,
     48     const base::FilePath& file_path,
     49     int64 offset)
     50     : file_system_getter_(file_system_getter),
     51       file_task_runner_(file_task_runner),
     52       file_path_(file_path),
     53       offset_(offset),
     54       weak_ptr_factory_(this) {
     55 }
     56 
     57 WebkitFileStreamWriterImpl::~WebkitFileStreamWriterImpl() {
     58   if (local_file_writer_) {
     59     // If the file is opened, close it at destructor.
     60     // It is necessary to close the local file in advance.
     61     local_file_writer_.reset();
     62     DCHECK(!close_callback_on_ui_thread_.is_null());
     63     BrowserThread::PostTask(BrowserThread::UI,
     64                             FROM_HERE,
     65                             close_callback_on_ui_thread_);
     66   }
     67 }
     68 
     69 int WebkitFileStreamWriterImpl::Write(net::IOBuffer* buf,
     70                                       int buf_len,
     71                                       const net::CompletionCallback& callback) {
     72   DCHECK(pending_write_callback_.is_null());
     73   DCHECK(pending_cancel_callback_.is_null());
     74   DCHECK(!callback.is_null());
     75 
     76   // If the local file is already available, just delegate to it.
     77   if (local_file_writer_)
     78     return local_file_writer_->Write(buf, buf_len, callback);
     79 
     80   // The local file is not yet ready. Create the writable snapshot.
     81   if (file_path_.empty())
     82     return net::ERR_FILE_NOT_FOUND;
     83 
     84   pending_write_callback_ = callback;
     85   CreateWritableSnapshotFile(
     86       file_system_getter_, file_path_,
     87       base::Bind(
     88           &WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile,
     89           weak_ptr_factory_.GetWeakPtr(), make_scoped_refptr(buf), buf_len));
     90   return net::ERR_IO_PENDING;
     91 }
     92 
     93 int WebkitFileStreamWriterImpl::Cancel(
     94     const net::CompletionCallback& callback) {
     95   DCHECK(pending_cancel_callback_.is_null());
     96   DCHECK(!callback.is_null());
     97 
     98   // If LocalFileWriter is already created, just delegate the cancel to it.
     99   if (local_file_writer_)
    100     return local_file_writer_->Cancel(callback);
    101 
    102   // If file open operation is in-flight, wait for its completion and cancel
    103   // further write operation in WriteAfterCreateWritableSnapshotFile.
    104   if (!pending_write_callback_.is_null()) {
    105     // Dismiss pending write callback immediately.
    106     pending_write_callback_.Reset();
    107     pending_cancel_callback_ = callback;
    108     return net::ERR_IO_PENDING;
    109   }
    110 
    111   // Write() is not called yet.
    112   return net::ERR_UNEXPECTED;
    113 }
    114 
    115 int WebkitFileStreamWriterImpl::Flush(const net::CompletionCallback& callback) {
    116   DCHECK(pending_cancel_callback_.is_null());
    117   DCHECK(!callback.is_null());
    118 
    119   // If LocalFileWriter is already created, just delegate to it.
    120   if (local_file_writer_)
    121     return local_file_writer_->Flush(callback);
    122 
    123   // There shouldn't be in-flight Write operation.
    124   DCHECK(pending_write_callback_.is_null());
    125 
    126   // Here is the case Flush() is called before any Write() invocation.
    127   // Do nothing.
    128   // Synchronization to the remote server is not done until the file is closed.
    129   return net::OK;
    130 }
    131 
    132 void WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile(
    133     net::IOBuffer* buf,
    134     int buf_len,
    135     base::PlatformFileError open_result,
    136     const base::FilePath& local_path,
    137     const base::Closure& close_callback_on_ui_thread) {
    138   DCHECK(!local_file_writer_);
    139 
    140   if (!pending_cancel_callback_.is_null()) {
    141     DCHECK(pending_write_callback_.is_null());
    142     // Cancel() is called during the creation of the snapshot file.
    143     // Don't write to the file.
    144     if (open_result == base::PLATFORM_FILE_OK) {
    145       // Here the file is internally created. To revert the operation, close
    146       // the file.
    147       DCHECK(!close_callback_on_ui_thread.is_null());
    148       BrowserThread::PostTask(BrowserThread::UI,
    149                               FROM_HERE,
    150                               close_callback_on_ui_thread);
    151     }
    152 
    153     base::ResetAndReturn(&pending_cancel_callback_).Run(net::OK);
    154     return;
    155   }
    156 
    157   DCHECK(!pending_write_callback_.is_null());
    158 
    159   const net::CompletionCallback callback =
    160       base::ResetAndReturn(&pending_write_callback_);
    161   if (open_result != base::PLATFORM_FILE_OK) {
    162     DCHECK(close_callback_on_ui_thread.is_null());
    163     callback.Run(net::PlatformFileErrorToNetError(open_result));
    164     return;
    165   }
    166 
    167   // Keep |close_callback| to close the file when the stream is destructed.
    168   DCHECK(!close_callback_on_ui_thread.is_null());
    169   close_callback_on_ui_thread_ = close_callback_on_ui_thread;
    170   local_file_writer_.reset(new fileapi::LocalFileStreamWriter(
    171       file_task_runner_.get(), local_path, offset_));
    172   int result = local_file_writer_->Write(buf, buf_len, callback);
    173   if (result != net::ERR_IO_PENDING)
    174     callback.Run(result);
    175 }
    176 
    177 }  // namespace internal
    178 }  // namespace drive
    179