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 int FileStream::Close(const CompletionCallback& callback) {
     97   DCHECK(is_async());
     98   context_->CloseAsync(callback);
     99   return ERR_IO_PENDING;
    100 }
    101 
    102 int FileStream::CloseSync() {
    103   DCHECK(!is_async());
    104   base::ThreadRestrictions::AssertIOAllowed();
    105   context_->CloseSync();
    106   return OK;
    107 }
    108 
    109 bool FileStream::IsOpen() const {
    110   return context_->file() != base::kInvalidPlatformFileValue;
    111 }
    112 
    113 int FileStream::Seek(Whence whence,
    114                      int64 offset,
    115                      const Int64CompletionCallback& callback) {
    116   if (!IsOpen())
    117     return ERR_UNEXPECTED;
    118 
    119   // Make sure we're async.
    120   DCHECK(is_async());
    121   context_->SeekAsync(whence, offset, callback);
    122   return ERR_IO_PENDING;
    123 }
    124 
    125 int64 FileStream::SeekSync(Whence whence, int64 offset) {
    126   base::ThreadRestrictions::AssertIOAllowed();
    127 
    128   if (!IsOpen())
    129     return ERR_UNEXPECTED;
    130 
    131   // If we're in async, make sure we don't have a request in flight.
    132   DCHECK(!is_async() || !context_->async_in_progress());
    133   return context_->SeekSync(whence, offset);
    134 }
    135 
    136 int64 FileStream::Available() {
    137   base::ThreadRestrictions::AssertIOAllowed();
    138 
    139   if (!IsOpen())
    140     return ERR_UNEXPECTED;
    141 
    142   int64 cur_pos = SeekSync(FROM_CURRENT, 0);
    143   if (cur_pos < 0)
    144     return cur_pos;
    145 
    146   int64 size = context_->GetFileSize();
    147   if (size < 0)
    148     return size;
    149 
    150   DCHECK_GE(size, cur_pos);
    151   return size - cur_pos;
    152 }
    153 
    154 int FileStream::Read(IOBuffer* buf,
    155                      int buf_len,
    156                      const CompletionCallback& callback) {
    157   if (!IsOpen())
    158     return ERR_UNEXPECTED;
    159 
    160   // read(..., 0) will return 0, which indicates end-of-file.
    161   DCHECK_GT(buf_len, 0);
    162   DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
    163   DCHECK(is_async());
    164 
    165   return context_->ReadAsync(buf, buf_len, callback);
    166 }
    167 
    168 int FileStream::ReadSync(char* buf, int buf_len) {
    169   base::ThreadRestrictions::AssertIOAllowed();
    170 
    171   if (!IsOpen())
    172     return ERR_UNEXPECTED;
    173 
    174   DCHECK(!is_async());
    175   // read(..., 0) will return 0, which indicates end-of-file.
    176   DCHECK_GT(buf_len, 0);
    177   DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
    178 
    179   return context_->ReadSync(buf, buf_len);
    180 }
    181 
    182 int FileStream::ReadUntilComplete(char *buf, int buf_len) {
    183   base::ThreadRestrictions::AssertIOAllowed();
    184 
    185   int to_read = buf_len;
    186   int bytes_total = 0;
    187 
    188   do {
    189     int bytes_read = ReadSync(buf, to_read);
    190     if (bytes_read <= 0) {
    191       if (bytes_total == 0)
    192         return bytes_read;
    193 
    194       return bytes_total;
    195     }
    196 
    197     bytes_total += bytes_read;
    198     buf += bytes_read;
    199     to_read -= bytes_read;
    200   } while (bytes_total < buf_len);
    201 
    202   return bytes_total;
    203 }
    204 
    205 int FileStream::Write(IOBuffer* buf,
    206                       int buf_len,
    207                       const CompletionCallback& callback) {
    208   if (!IsOpen())
    209     return ERR_UNEXPECTED;
    210 
    211   DCHECK(is_async());
    212   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    213   // write(..., 0) will return 0, which indicates end-of-file.
    214   DCHECK_GT(buf_len, 0);
    215 
    216   return context_->WriteAsync(buf, buf_len, callback);
    217 }
    218 
    219 int FileStream::WriteSync(const char* buf, int buf_len) {
    220   base::ThreadRestrictions::AssertIOAllowed();
    221 
    222   if (!IsOpen())
    223     return ERR_UNEXPECTED;
    224 
    225   DCHECK(!is_async());
    226   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    227   // write(..., 0) will return 0, which indicates end-of-file.
    228   DCHECK_GT(buf_len, 0);
    229 
    230   return context_->WriteSync(buf, buf_len);
    231 }
    232 
    233 int64 FileStream::Truncate(int64 bytes) {
    234   base::ThreadRestrictions::AssertIOAllowed();
    235 
    236   if (!IsOpen())
    237     return ERR_UNEXPECTED;
    238 
    239   // We'd better be open for writing.
    240   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    241 
    242   // Seek to the position to truncate from.
    243   int64 seek_position = SeekSync(FROM_BEGIN, bytes);
    244   if (seek_position != bytes)
    245     return ERR_UNEXPECTED;
    246 
    247   // And truncate the file.
    248   return context_->Truncate(bytes);
    249 }
    250 
    251 int FileStream::Flush(const CompletionCallback& callback) {
    252   if (!IsOpen())
    253     return ERR_UNEXPECTED;
    254 
    255   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    256   // Make sure we're async.
    257   DCHECK(is_async());
    258 
    259   context_->FlushAsync(callback);
    260   return ERR_IO_PENDING;
    261 }
    262 
    263 int FileStream::FlushSync() {
    264   base::ThreadRestrictions::AssertIOAllowed();
    265 
    266   if (!IsOpen())
    267     return ERR_UNEXPECTED;
    268 
    269   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
    270   return context_->FlushSync();
    271 }
    272 
    273 void FileStream::EnableErrorStatistics() {
    274   context_->set_record_uma(true);
    275 }
    276 
    277 void FileStream::SetBoundNetLogSource(const BoundNetLog& owner_bound_net_log) {
    278   if ((owner_bound_net_log.source().id == NetLog::Source::kInvalidId) &&
    279       (bound_net_log_.source().id == NetLog::Source::kInvalidId)) {
    280     // Both |BoundNetLog|s are invalid.
    281     return;
    282   }
    283 
    284   // Should never connect to itself.
    285   DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id);
    286 
    287   bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER,
    288       owner_bound_net_log.source().ToEventParametersCallback());
    289 
    290   owner_bound_net_log.AddEvent(NetLog::TYPE_FILE_STREAM_SOURCE,
    291       bound_net_log_.source().ToEventParametersCallback());
    292 }
    293 
    294 base::PlatformFile FileStream::GetPlatformFileForTesting() {
    295   return context_->file();
    296 }
    297 
    298 }  // namespace net
    299