1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/file_stream.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <windows.h>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/file_path.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/message_loop.h"
12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/threading/thread_restrictions.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Ensure that we can just use our Whence values directly.
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCOMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin);
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCOMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current);
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCOMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end);
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  overlapped->Offset = offset.LowPart;
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  overlapped->OffsetHigh = offset.HighPart;
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LARGE_INTEGER offset;
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  offset.LowPart = overlapped->Offset;
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  offset.HighPart = overlapped->OffsetHigh;
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  offset.QuadPart += static_cast<LONGLONG>(count);
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetOffset(overlapped, offset);
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int MapErrorCode(DWORD err) {
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (err) {
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case ERROR_FILE_NOT_FOUND:
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case ERROR_PATH_NOT_FOUND:
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_FILE_NOT_FOUND;
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case ERROR_ACCESS_DENIED:
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_ACCESS_DENIED;
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case ERROR_SUCCESS:
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return OK;
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_FAILED;
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// FileStream::AsyncContext ----------------------------------------------
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass FileStream::AsyncContext : public MessageLoopForIO::IOHandler {
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AsyncContext(FileStream* owner)
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : owner_(owner), context_(), callback_(NULL), is_closing_(false) {
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    context_.handler = this;
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~AsyncContext();
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void IOCompletionIsPending(CompletionCallback* callback);
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  OVERLAPPED* overlapped() { return &context_.overlapped; }
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* callback() const { return callback_; }
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             DWORD bytes_read, DWORD error);
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  FileStream* owner_;
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoopForIO::IOContext context_;
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* callback_;
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool is_closing_;
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottFileStream::AsyncContext::~AsyncContext() {
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  is_closing_ = true;
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool waited = false;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::TimeTicks start = base::TimeTicks::Now();
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (callback_) {
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    waited = true;
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (waited) {
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // We want to see if we block the message loop for too long.
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        base::TimeTicks::Now() - start);
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid FileStream::AsyncContext::IOCompletionIsPending(
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CompletionCallback* callback) {
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!callback_);
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  callback_ = callback;
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid FileStream::AsyncContext::OnIOCompleted(
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error) {
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(&context_ == context);
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(callback_);
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (is_closing_) {
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    callback_ = NULL;
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int result = static_cast<int>(bytes_read);
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (error && error != ERROR_HANDLE_EOF)
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = MapErrorCode(error);
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (bytes_read)
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    IncrementOffset(&context->overlapped, bytes_read);
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CompletionCallback* temp = NULL;
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::swap(temp, callback_);
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  temp->Run(result);
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// FileStream ------------------------------------------------------------
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottFileStream::FileStream()
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : file_(INVALID_HANDLE_VALUE),
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      open_flags_(0),
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      auto_closed_(true) {
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottFileStream::FileStream(base::PlatformFile file, int flags)
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : file_(file),
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      open_flags_(flags),
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      auto_closed_(false) {
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // make sure we will perform asynchronous File IO to it.
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (flags & base::PLATFORM_FILE_ASYNC) {
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    async_context_.reset(new AsyncContext(this));
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    MessageLoopForIO::current()->RegisterIOHandler(file_,
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                   async_context_.get());
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottFileStream::~FileStream() {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (auto_closed_)
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Close();
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid FileStream::Close() {
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (file_ != INVALID_HANDLE_VALUE)
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CancelIo(file_);
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  async_context_.reset();
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (file_ != INVALID_HANDLE_VALUE) {
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CloseHandle(file_);
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    file_ = INVALID_HANDLE_VALUE;
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint FileStream::Open(const FilePath& path, int open_flags) {
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (IsOpen()) {
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DLOG(FATAL) << "File is already open!";
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  open_flags_ = open_flags;
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (file_ == INVALID_HANDLE_VALUE) {
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DWORD error = GetLastError();
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(WARNING) << "Failed to open file: " << error;
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return MapErrorCode(error);
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    async_context_.reset(new AsyncContext(this));
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    MessageLoopForIO::current()->RegisterIOHandler(file_,
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                   async_context_.get());
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool FileStream::IsOpen() const {
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return file_ != INVALID_HANDLE_VALUE;
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint64 FileStream::Seek(Whence whence, int64 offset) {
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!IsOpen())
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!async_context_.get() || !async_context_->callback());
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LARGE_INTEGER distance, result;
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  distance.QuadPart = offset;
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD move_method = static_cast<DWORD>(whence);
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!SetFilePointerEx(file_, distance, &result, move_method)) {
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DWORD error = GetLastError();
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(WARNING) << "SetFilePointerEx failed: " << error;
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return MapErrorCode(error);
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (async_context_.get())
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SetOffset(async_context_->overlapped(), result);
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result.QuadPart;
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint64 FileStream::Available() {
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::ThreadRestrictions::AssertIOAllowed();
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!IsOpen())
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int64 cur_pos = Seek(FROM_CURRENT, 0);
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (cur_pos < 0)
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return cur_pos;
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LARGE_INTEGER file_size;
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!GetFileSizeEx(file_, &file_size)) {
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DWORD error = GetLastError();
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(WARNING) << "GetFileSizeEx failed: " << error;
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return MapErrorCode(error);
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return file_size.QuadPart - cur_pos;
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint FileStream::Read(
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    char* buf, int buf_len, CompletionCallback* callback) {
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!IsOpen())
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  OVERLAPPED* overlapped = NULL;
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (async_context_.get()) {
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(callback);
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(!async_context_->callback());
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    overlapped = async_context_->overlapped();
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(!callback);
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::ThreadRestrictions::AssertIOAllowed();
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int rv;
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD bytes_read;
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) {
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DWORD error = GetLastError();
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (async_context_.get() && error == ERROR_IO_PENDING) {
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      async_context_->IOCompletionIsPending(callback);
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      rv = ERR_IO_PENDING;
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else if (error == ERROR_HANDLE_EOF) {
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      rv = 0;  // Report EOF by returning 0 bytes read.
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(WARNING) << "ReadFile failed: " << error;
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      rv = MapErrorCode(error);
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (overlapped) {
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    async_context_->IOCompletionIsPending(callback);
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = ERR_IO_PENDING;
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = static_cast<int>(bytes_read);
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return rv;
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint FileStream::ReadUntilComplete(char *buf, int buf_len) {
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int to_read = buf_len;
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int bytes_total = 0;
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  do {
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int bytes_read = Read(buf, to_read, NULL);
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (bytes_read <= 0) {
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (bytes_total == 0)
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return bytes_read;
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return bytes_total;
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bytes_total += bytes_read;
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    buf += bytes_read;
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    to_read -= bytes_read;
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } while (bytes_total < buf_len);
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return bytes_total;
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint FileStream::Write(
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const char* buf, int buf_len, CompletionCallback* callback) {
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!IsOpen())
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  OVERLAPPED* overlapped = NULL;
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (async_context_.get()) {
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(callback);
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(!async_context_->callback());
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    overlapped = async_context_->overlapped();
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(!callback);
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::ThreadRestrictions::AssertIOAllowed();
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int rv;
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD bytes_written;
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) {
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DWORD error = GetLastError();
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (async_context_.get() && error == ERROR_IO_PENDING) {
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      async_context_->IOCompletionIsPending(callback);
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      rv = ERR_IO_PENDING;
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(WARNING) << "WriteFile failed: " << error;
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      rv = MapErrorCode(error);
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (overlapped) {
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    async_context_->IOCompletionIsPending(callback);
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = ERR_IO_PENDING;
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    rv = static_cast<int>(bytes_written);
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return rv;
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint FileStream::Flush() {
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::ThreadRestrictions::AssertIOAllowed();
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IsOpen())
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_UNEXPECTED;
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (FlushFileBuffers(file_)) {
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv;
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DWORD error = GetLastError();
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  rv = MapErrorCode(error);
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint64 FileStream::Truncate(int64 bytes) {
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::ThreadRestrictions::AssertIOAllowed();
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!IsOpen())
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We better be open for reading.
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Seek to the position to truncate from.
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int64 seek_position = Seek(FROM_BEGIN, bytes);
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (seek_position != bytes)
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_UNEXPECTED;
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // And truncate the file.
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BOOL result = SetEndOfFile(file_);
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!result) {
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DWORD error = GetLastError();
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(WARNING) << "SetEndOfFile failed: " << error;
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return MapErrorCode(error);
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Success.
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return seek_position;
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
361