Home | History | Annotate | Download | only in base
      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 "net/base/file_stream.h"
      6 
      7 #include "base/location.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "base/task_runner_util.h"
     10 #include "base/threading/thread_restrictions.h"
     11 #include "base/threading/worker_pool.h"
     12 #include "net/base/file_stream_context.h"
     13 #include "net/base/file_stream_net_log_parameters.h"
     14 #include "net/base/net_errors.h"
     15 
     16 namespace net {
     17 
     18 FileStream::FileStream(NetLog* net_log,
     19                        const scoped_refptr<base::TaskRunner>& task_runner)
     20       /* To allow never opened stream to be destroyed on any thread we set flags
     21          as if stream was opened asynchronously. */
     22     : open_flags_(base::PLATFORM_FILE_ASYNC),
     23       bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
     24       context_(new Context(bound_net_log_, task_runner)) {
     25   bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
     26 }
     27 
     28 FileStream::FileStream(NetLog* net_log)
     29       /* To allow never opened stream to be destroyed on any thread we set flags
     30          as if stream was opened asynchronously. */
     31     : open_flags_(base::PLATFORM_FILE_ASYNC),
     32       bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
     33       context_(new Context(bound_net_log_,
     34                            base::WorkerPool::GetTaskRunner(true /* slow */))) {
     35   bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
     36 }
     37 
     38 FileStream::FileStream(base::PlatformFile file,
     39                        int flags,
     40                        NetLog* net_log,
     41                        const scoped_refptr<base::TaskRunner>& task_runner)
     42     : open_flags_(flags),
     43       bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
     44       context_(new Context(file, bound_net_log_, open_flags_, task_runner)) {
     45   bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
     46 }
     47 
     48 FileStream::FileStream(base::PlatformFile file, int flags, NetLog* net_log)
     49     : open_flags_(flags),
     50       bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
     51       context_(new Context(file,
     52                            bound_net_log_,
     53                            open_flags_,
     54                            base::WorkerPool::GetTaskRunner(true /* slow */))) {
     55   bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
     56 }
     57 
     58 FileStream::~FileStream() {
     59   if (!is_async()) {
     60     base::ThreadRestrictions::AssertIOAllowed();
     61     context_->CloseSync();
     62     context_.reset();
     63   } else {
     64     context_.release()->Orphan();
     65   }
     66 
     67   bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
     68 }
     69 
     70 int FileStream::Open(const base::FilePath& path, int open_flags,
     71                      const CompletionCallback& callback) {
     72   if (IsOpen()) {
     73     DLOG(FATAL) << "File is already open!";
     74     return ERR_UNEXPECTED;
     75   }
     76 
     77   open_flags_ = open_flags;
     78   DCHECK(is_async());
     79   context_->OpenAsync(path, open_flags, callback);
     80   return ERR_IO_PENDING;
     81 }
     82 
     83 int FileStream::OpenSync(const base::FilePath& path, int open_flags) {
     84   base::ThreadRestrictions::AssertIOAllowed();
     85 
     86   if (IsOpen()) {
     87     DLOG(FATAL) << "File is already open!";
     88     return ERR_UNEXPECTED;
     89   }
     90 
     91   open_flags_ = open_flags;
     92   DCHECK(!is_async());
     93   return context_->OpenSync(path, open_flags_);
     94 }
     95 
     96 bool FileStream::IsOpen() const {
     97   return context_->file() != base::kInvalidPlatformFileValue;
     98 }
     99 
    100 int FileStream::Seek(Whence whence,
    101                      int64 offset,
    102                      const Int64CompletionCallback& callback) {
    103   if (!IsOpen())
    104     return ERR_UNEXPECTED;
    105 
    106   // Make sure we're async.
    107   DCHECK(is_async());
    108   context_->SeekAsync(whence, offset, callback);
    109   return ERR_IO_PENDING;
    110 }
    111 
    112 int64 FileStream::SeekSync(Whence whence, int64 offset) {
    113   base::ThreadRestrictions::AssertIOAllowed();
    114 
    115   if (!IsOpen())
    116     return ERR_UNEXPECTED;
    117 
    118   // If we're in async, make sure we don't have a request in flight.
    119   DCHECK(!is_async() || !context_->async_in_progress());
    120   return context_->SeekSync(whence, offset);
    121 }
    122 
    123 int64 FileStream::Available() {
    124   base::ThreadRestrictions::AssertIOAllowed();
    125 
    126   if (!IsOpen())
    127     return ERR_UNEXPECTED;
    128 
    129   int64 cur_pos = SeekSync(FROM_CURRENT, 0);
    130   if (cur_pos < 0)
    131     return cur_pos;
    132 
    133   int64 size = context_->GetFileSize();
    134   if (size < 0)
    135     return size;
    136 
    137   DCHECK_GE(size, cur_pos);
    138   return size - cur_pos;
    139 }
    140 
    141 int FileStream::Read(IOBuffer* buf,
    142                      int buf_len,
    143                      const CompletionCallback& callback) {
    144   if (!IsOpen())
    145     return ERR_UNEXPECTED;
    146 
    147   // read(..., 0) will return 0, which indicates end-of-file.
    148   DCHECK_GT(buf_len, 0);
    149   DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
    150   DCHECK(is_async());
    151 
    152   return context_->ReadAsync(buf, buf_len, callback);
    153 }
    154 
    155 int FileStream::ReadSync(char* buf, int buf_len) {
    156   base::ThreadRestrictions::AssertIOAllowed();
    157 
    158   if (!IsOpen())
    159     return ERR_UNEXPECTED;
    160 
    161   DCHECK(!is_async());
    162   // read(..., 0) will return 0, which indicates end-of-file.
    163   DCHECK_GT(buf_len, 0);
    164   DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
    165 
    166   return context_->ReadSync(buf, buf_len);
    167 }
    168 
    169 int FileStream::ReadUntilComplete(char *buf, int buf_len) {
    170   base::ThreadRestrictions::AssertIOAllowed();
    171 
    172   int to_read = buf_len;
    173   int bytes_total = 0;
    174 
    175   do {
    176     int bytes_read = ReadSync(buf, to_read);
    177     if (bytes_read <= 0) {
    178       if (bytes_total == 0)
    179         return bytes_read;
    180 
    181       return bytes_total;
    182     }
    183 
    184     bytes_total += bytes_read;
    185     buf += bytes_read;
    186     to_read -= bytes_read;
    187   } while (bytes_total < buf_len);
    188 
    189   return bytes_total;
    190 }
    191 
    192 int FileStream::Write(IOBuffer* buf,
    193                       int buf_len,
    194                       const CompletionCallback& callback) {
    195   if (!IsOpen())
    196     return ERR_UNEXPECTED;
    197 
    198   DCHECK(is_async());
    199   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    200   // write(..., 0) will return 0, which indicates end-of-file.
    201   DCHECK_GT(buf_len, 0);
    202 
    203   return context_->WriteAsync(buf, buf_len, callback);
    204 }
    205 
    206 int FileStream::WriteSync(const char* buf, int buf_len) {
    207   base::ThreadRestrictions::AssertIOAllowed();
    208 
    209   if (!IsOpen())
    210     return ERR_UNEXPECTED;
    211 
    212   DCHECK(!is_async());
    213   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    214   // write(..., 0) will return 0, which indicates end-of-file.
    215   DCHECK_GT(buf_len, 0);
    216 
    217   return context_->WriteSync(buf, buf_len);
    218 }
    219 
    220 int64 FileStream::Truncate(int64 bytes) {
    221   base::ThreadRestrictions::AssertIOAllowed();
    222 
    223   if (!IsOpen())
    224     return ERR_UNEXPECTED;
    225 
    226   // We'd better be open for writing.
    227   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    228 
    229   // Seek to the position to truncate from.
    230   int64 seek_position = SeekSync(FROM_BEGIN, bytes);
    231   if (seek_position != bytes)
    232     return ERR_UNEXPECTED;
    233 
    234   // And truncate the file.
    235   return context_->Truncate(bytes);
    236 }
    237 
    238 int FileStream::Flush(const CompletionCallback& callback) {
    239   if (!IsOpen())
    240     return ERR_UNEXPECTED;
    241 
    242   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    243   // Make sure we're async.
    244   DCHECK(is_async());
    245 
    246   context_->FlushAsync(callback);
    247   return ERR_IO_PENDING;
    248 }
    249 
    250 int FileStream::FlushSync() {
    251   base::ThreadRestrictions::AssertIOAllowed();
    252 
    253   if (!IsOpen())
    254     return ERR_UNEXPECTED;
    255 
    256   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    257   return context_->FlushSync();
    258 }
    259 
    260 void FileStream::EnableErrorStatistics() {
    261   context_->set_record_uma(true);
    262 }
    263 
    264 void FileStream::SetBoundNetLogSource(const BoundNetLog& owner_bound_net_log) {
    265   if ((owner_bound_net_log.source().id == NetLog::Source::kInvalidId) &&
    266       (bound_net_log_.source().id == NetLog::Source::kInvalidId)) {
    267     // Both |BoundNetLog|s are invalid.
    268     return;
    269   }
    270 
    271   // Should never connect to itself.
    272   DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id);
    273 
    274   bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER,
    275       owner_bound_net_log.source().ToEventParametersCallback());
    276 
    277   owner_bound_net_log.AddEvent(NetLog::TYPE_FILE_STREAM_SOURCE,
    278       bound_net_log_.source().ToEventParametersCallback());
    279 }
    280 
    281 base::PlatformFile FileStream::GetPlatformFileForTesting() {
    282   return context_->file();
    283 }
    284 
    285 }  // namespace net
    286