root/net/base/file_stream.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. context_
  2. context_
  3. context_
  4. context_
  5. context_
  6. context_
  7. Open
  8. OpenSync
  9. Close
  10. CloseSync
  11. IsOpen
  12. Seek
  13. SeekSync
  14. Available
  15. Read
  16. ReadSync
  17. ReadUntilComplete
  18. Write
  19. WriteSync
  20. Truncate
  21. Flush
  22. FlushSync
  23. EnableErrorStatistics
  24. SetBoundNetLogSource
  25. GetFileForTesting

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/file_stream.h"

#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
#include "net/base/file_stream_context.h"
#include "net/base/file_stream_net_log_parameters.h"
#include "net/base/net_errors.h"

namespace net {

FileStream::FileStream(NetLog* net_log,
                       const scoped_refptr<base::TaskRunner>& task_runner)
      /* To allow never opened stream to be destroyed on any thread we set flags
         as if stream was opened asynchronously. */
    : bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(bound_net_log_, task_runner)) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::FileStream(NetLog* net_log)
      /* To allow never opened stream to be destroyed on any thread we set flags
         as if stream was opened asynchronously. */
    : bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(bound_net_log_,
                           base::WorkerPool::GetTaskRunner(true /* slow */))) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::FileStream(base::PlatformFile file,
                       int flags,
                       NetLog* net_log,
                       const scoped_refptr<base::TaskRunner>& task_runner)
    : bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(base::File(file), flags, bound_net_log_,
                           task_runner)) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::FileStream(base::PlatformFile file, int flags, NetLog* net_log)
    : bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(base::File(file), flags, bound_net_log_,
                           base::WorkerPool::GetTaskRunner(true /* slow */))) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::FileStream(base::File file,
                       net::NetLog* net_log,
                       const scoped_refptr<base::TaskRunner>& task_runner)
    : bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(file.Pass(), bound_net_log_, task_runner)) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::FileStream(base::File file, net::NetLog* net_log)
    : bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
      context_(new Context(file.Pass(), bound_net_log_,
                           base::WorkerPool::GetTaskRunner(true /* slow */))) {
  bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

FileStream::~FileStream() {
  if (context_->async()) {
    context_.release()->Orphan();
  } else {
    context_->CloseSync();
    context_.reset();
  }

  bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
}

int FileStream::Open(const base::FilePath& path, int open_flags,
                     const CompletionCallback& callback) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  DCHECK(open_flags & base::File::FLAG_ASYNC);
  context_->OpenAsync(path, open_flags, callback);
  return ERR_IO_PENDING;
}

int FileStream::OpenSync(const base::FilePath& path, int open_flags) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  DCHECK(!context_->async());
  return context_->OpenSync(path, open_flags);
}

int FileStream::Close(const CompletionCallback& callback) {
  DCHECK(context_->async());
  context_->CloseAsync(callback);
  return ERR_IO_PENDING;
}

int FileStream::CloseSync() {
  DCHECK(!context_->async());
  base::ThreadRestrictions::AssertIOAllowed();
  context_->CloseSync();
  return OK;
}

bool FileStream::IsOpen() const {
  return context_->file().IsValid();
}

int FileStream::Seek(Whence whence,
                     int64 offset,
                     const Int64CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // Make sure we're async.
  DCHECK(context_->async());
  context_->SeekAsync(whence, offset, callback);
  return ERR_IO_PENDING;
}

int64 FileStream::SeekSync(Whence whence, int64 offset) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!context_->async() || !context_->async_in_progress());
  return context_->SeekSync(whence, offset);
}

int64 FileStream::Available() {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = SeekSync(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  int64 size = context_->GetFileSize();
  if (size < 0)
    return size;

  DCHECK_GE(size, cur_pos);
  return size - cur_pos;
}

int FileStream::Read(IOBuffer* buf,
                     int buf_len,
                     const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);
  DCHECK(context_->async());

  return context_->ReadAsync(buf, buf_len, callback);
}

int FileStream::ReadSync(char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(!context_->async());
  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  return context_->ReadSync(buf, buf_len);
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = ReadSync(buf, to_read);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(IOBuffer* buf,
                      int buf_len,
                      const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(context_->async());
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  return context_->WriteAsync(buf, buf_len, callback);
}

int FileStream::WriteSync(const char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  DCHECK(!context_->async());
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  return context_->WriteSync(buf, buf_len);
}

int64 FileStream::Truncate(int64 bytes) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // Seek to the position to truncate from.
  int64 seek_position = SeekSync(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  return context_->Truncate(bytes);
}

int FileStream::Flush(const CompletionCallback& callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // Make sure we're async.
  DCHECK(context_->async());

  context_->FlushAsync(callback);
  return ERR_IO_PENDING;
}

int FileStream::FlushSync() {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  return context_->FlushSync();
}

void FileStream::EnableErrorStatistics() {
  context_->set_record_uma(true);
}

void FileStream::SetBoundNetLogSource(const BoundNetLog& owner_bound_net_log) {
  if ((owner_bound_net_log.source().id == NetLog::Source::kInvalidId) &&
      (bound_net_log_.source().id == NetLog::Source::kInvalidId)) {
    // Both |BoundNetLog|s are invalid.
    return;
  }

  // Should never connect to itself.
  DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id);

  bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER,
      owner_bound_net_log.source().ToEventParametersCallback());

  owner_bound_net_log.AddEvent(NetLog::TYPE_FILE_STREAM_SOURCE,
      bound_net_log_.source().ToEventParametersCallback());
}

const base::File& FileStream::GetFileForTesting() const {
  return context_->file();
}

}  // namespace net

/* [<][>][^][v][top][bottom][index][help] */