Home | History | Annotate | Download | only in fileapi
      1 // Copyright (c) 2012 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 "webkit/browser/fileapi/local_file_stream_writer.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "net/base/file_stream.h"
     10 #include "net/base/io_buffer.h"
     11 #include "net/base/net_errors.h"
     12 
     13 namespace fileapi {
     14 
     15 namespace {
     16 
     17 const int kOpenFlagsForWrite = base::PLATFORM_FILE_OPEN |
     18                                base::PLATFORM_FILE_WRITE |
     19                                base::PLATFORM_FILE_ASYNC;
     20 
     21 }  // namespace
     22 
     23 FileStreamWriter* FileStreamWriter::CreateForLocalFile(
     24     base::TaskRunner* task_runner,
     25     const base::FilePath& file_path,
     26     int64 initial_offset) {
     27   return new LocalFileStreamWriter(task_runner, file_path, initial_offset);
     28 }
     29 
     30 LocalFileStreamWriter::~LocalFileStreamWriter() {
     31   // Invalidate weak pointers so that we won't receive any callbacks from
     32   // in-flight stream operations, which might be triggered during the file close
     33   // in the FileStream destructor.
     34   weak_factory_.InvalidateWeakPtrs();
     35 
     36   // FileStream's destructor closes the file safely, since we opened the file
     37   // by its Open() method.
     38 }
     39 
     40 int LocalFileStreamWriter::Write(net::IOBuffer* buf, int buf_len,
     41                                  const net::CompletionCallback& callback) {
     42   DCHECK(!has_pending_operation_);
     43   DCHECK(cancel_callback_.is_null());
     44 
     45   has_pending_operation_ = true;
     46   if (stream_impl_) {
     47     int result = InitiateWrite(buf, buf_len, callback);
     48     if (result != net::ERR_IO_PENDING)
     49       has_pending_operation_ = false;
     50     return result;
     51   }
     52   return InitiateOpen(callback,
     53                       base::Bind(&LocalFileStreamWriter::ReadyToWrite,
     54                                  weak_factory_.GetWeakPtr(),
     55                                  make_scoped_refptr(buf), buf_len, callback));
     56 }
     57 
     58 int LocalFileStreamWriter::Cancel(const net::CompletionCallback& callback) {
     59   if (!has_pending_operation_)
     60     return net::ERR_UNEXPECTED;
     61 
     62   DCHECK(!callback.is_null());
     63   cancel_callback_ = callback;
     64   return net::ERR_IO_PENDING;
     65 }
     66 
     67 int LocalFileStreamWriter::Flush(const net::CompletionCallback& callback) {
     68   DCHECK(!has_pending_operation_);
     69   DCHECK(cancel_callback_.is_null());
     70 
     71   // Write() is not called yet, so there's nothing to flush.
     72   if (!stream_impl_)
     73     return net::OK;
     74 
     75   has_pending_operation_ = true;
     76   int result = InitiateFlush(callback);
     77   if (result != net::ERR_IO_PENDING)
     78     has_pending_operation_ = false;
     79   return result;
     80 }
     81 
     82 LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner* task_runner,
     83                                              const base::FilePath& file_path,
     84                                              int64 initial_offset)
     85     : file_path_(file_path),
     86       initial_offset_(initial_offset),
     87       task_runner_(task_runner),
     88       has_pending_operation_(false),
     89       weak_factory_(this) {}
     90 
     91 int LocalFileStreamWriter::InitiateOpen(
     92     const net::CompletionCallback& error_callback,
     93     const base::Closure& main_operation) {
     94   DCHECK(has_pending_operation_);
     95   DCHECK(!stream_impl_.get());
     96 
     97   stream_impl_.reset(new net::FileStream(NULL, task_runner_));
     98 
     99   return stream_impl_->Open(file_path_,
    100                             kOpenFlagsForWrite,
    101                             base::Bind(&LocalFileStreamWriter::DidOpen,
    102                                        weak_factory_.GetWeakPtr(),
    103                                        error_callback,
    104                                        main_operation));
    105 }
    106 
    107 void LocalFileStreamWriter::DidOpen(
    108     const net::CompletionCallback& error_callback,
    109     const base::Closure& main_operation,
    110     int result) {
    111   DCHECK(has_pending_operation_);
    112   DCHECK(stream_impl_.get());
    113 
    114   if (CancelIfRequested())
    115     return;
    116 
    117   if (result != net::OK) {
    118     has_pending_operation_ = false;
    119     stream_impl_.reset(NULL);
    120     error_callback.Run(result);
    121     return;
    122   }
    123 
    124   InitiateSeek(error_callback, main_operation);
    125 }
    126 
    127 void LocalFileStreamWriter::InitiateSeek(
    128     const net::CompletionCallback& error_callback,
    129     const base::Closure& main_operation) {
    130   DCHECK(has_pending_operation_);
    131   DCHECK(stream_impl_.get());
    132 
    133   if (initial_offset_ == 0) {
    134     // No need to seek.
    135     main_operation.Run();
    136     return;
    137   }
    138 
    139   int result = stream_impl_->Seek(net::FROM_BEGIN, initial_offset_,
    140                                   base::Bind(&LocalFileStreamWriter::DidSeek,
    141                                              weak_factory_.GetWeakPtr(),
    142                                              error_callback,
    143                                              main_operation));
    144   if (result != net::ERR_IO_PENDING) {
    145     has_pending_operation_ = false;
    146     error_callback.Run(result);
    147   }
    148 }
    149 
    150 void LocalFileStreamWriter::DidSeek(
    151     const net::CompletionCallback& error_callback,
    152     const base::Closure& main_operation,
    153     int64 result) {
    154   DCHECK(has_pending_operation_);
    155 
    156   if (CancelIfRequested())
    157     return;
    158 
    159   if (result != initial_offset_) {
    160     // TODO(kinaba) add a more specific error code.
    161     result = net::ERR_FAILED;
    162   }
    163 
    164   if (result < 0) {
    165     has_pending_operation_ = false;
    166     error_callback.Run(static_cast<int>(result));
    167     return;
    168   }
    169 
    170   main_operation.Run();
    171 }
    172 
    173 void LocalFileStreamWriter::ReadyToWrite(
    174     net::IOBuffer* buf, int buf_len,
    175     const net::CompletionCallback& callback) {
    176   DCHECK(has_pending_operation_);
    177 
    178   int result = InitiateWrite(buf, buf_len, callback);
    179   if (result != net::ERR_IO_PENDING) {
    180     has_pending_operation_ = false;
    181     callback.Run(result);
    182   }
    183 }
    184 
    185 int LocalFileStreamWriter::InitiateWrite(
    186     net::IOBuffer* buf, int buf_len,
    187     const net::CompletionCallback& callback) {
    188   DCHECK(has_pending_operation_);
    189   DCHECK(stream_impl_.get());
    190 
    191   return stream_impl_->Write(buf, buf_len,
    192                              base::Bind(&LocalFileStreamWriter::DidWrite,
    193                                         weak_factory_.GetWeakPtr(),
    194                                         callback));
    195 }
    196 
    197 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback& callback,
    198                                      int result) {
    199   DCHECK(has_pending_operation_);
    200 
    201   if (CancelIfRequested())
    202     return;
    203   has_pending_operation_ = false;
    204   callback.Run(result);
    205 }
    206 
    207 int LocalFileStreamWriter::InitiateFlush(
    208     const net::CompletionCallback& callback) {
    209   DCHECK(has_pending_operation_);
    210   DCHECK(stream_impl_.get());
    211 
    212   return stream_impl_->Flush(base::Bind(&LocalFileStreamWriter::DidFlush,
    213                                         weak_factory_.GetWeakPtr(),
    214                                         callback));
    215 }
    216 
    217 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback& callback,
    218                                      int result) {
    219   DCHECK(has_pending_operation_);
    220 
    221   if (CancelIfRequested())
    222     return;
    223   has_pending_operation_ = false;
    224   callback.Run(result);
    225 }
    226 
    227 bool LocalFileStreamWriter::CancelIfRequested() {
    228   DCHECK(has_pending_operation_);
    229 
    230   if (cancel_callback_.is_null())
    231     return false;
    232 
    233   net::CompletionCallback pending_cancel = cancel_callback_;
    234   has_pending_operation_ = false;
    235   cancel_callback_.Reset();
    236   pending_cancel.Run(net::OK);
    237   return true;
    238 }
    239 
    240 }  // namespace fileapi
    241