Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / net / base / file_stream_context_win.cc
blob2477535f57fc80115934380ccc663904723f7674
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.
5 #include "net/base/file_stream_context.h"
7 #include <windows.h>
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/task_runner_util.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
16 namespace net {
18 // Ensure that we can just use our Whence values directly.
19 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin);
20 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current);
21 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end);
23 namespace {
25 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
26 overlapped->Offset = offset.LowPart;
27 overlapped->OffsetHigh = offset.HighPart;
30 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
31 LARGE_INTEGER offset;
32 offset.LowPart = overlapped->Offset;
33 offset.HighPart = overlapped->OffsetHigh;
34 offset.QuadPart += static_cast<LONGLONG>(count);
35 SetOffset(overlapped, offset);
38 } // namespace
40 FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner)
41 : io_context_(),
42 async_in_progress_(false),
43 orphaned_(false),
44 task_runner_(task_runner) {
45 io_context_.handler = this;
46 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
49 FileStream::Context::Context(base::File file,
50 const scoped_refptr<base::TaskRunner>& task_runner)
51 : io_context_(),
52 file_(file.Pass()),
53 async_in_progress_(false),
54 orphaned_(false),
55 task_runner_(task_runner) {
56 io_context_.handler = this;
57 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
58 if (file_.IsValid()) {
59 // TODO(hashimoto): Check that file_ is async.
60 OnAsyncFileOpened();
64 FileStream::Context::~Context() {
67 int FileStream::Context::ReadAsync(IOBuffer* buf,
68 int buf_len,
69 const CompletionCallback& callback) {
70 DCHECK(!async_in_progress_);
72 DWORD bytes_read;
73 if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len,
74 &bytes_read, &io_context_.overlapped)) {
75 IOResult error = IOResult::FromOSError(GetLastError());
76 if (error.os_error == ERROR_IO_PENDING) {
77 IOCompletionIsPending(callback, buf);
78 } else if (error.os_error == ERROR_HANDLE_EOF) {
79 return 0; // Report EOF by returning 0 bytes read.
80 } else {
81 LOG(WARNING) << "ReadFile failed: " << error.os_error;
83 return error.result;
86 IOCompletionIsPending(callback, buf);
87 return ERR_IO_PENDING;
90 int FileStream::Context::WriteAsync(IOBuffer* buf,
91 int buf_len,
92 const CompletionCallback& callback) {
93 DWORD bytes_written = 0;
94 if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len,
95 &bytes_written, &io_context_.overlapped)) {
96 IOResult error = IOResult::FromOSError(GetLastError());
97 if (error.os_error == ERROR_IO_PENDING) {
98 IOCompletionIsPending(callback, buf);
99 } else {
100 LOG(WARNING) << "WriteFile failed: " << error.os_error;
102 return error.result;
105 IOCompletionIsPending(callback, buf);
106 return ERR_IO_PENDING;
109 void FileStream::Context::OnAsyncFileOpened() {
110 base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(),
111 this);
114 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(Whence whence,
115 int64 offset) {
116 LARGE_INTEGER distance, res;
117 distance.QuadPart = offset;
118 DWORD move_method = static_cast<DWORD>(whence);
119 if (SetFilePointerEx(file_.GetPlatformFile(), distance, &res, move_method)) {
120 SetOffset(&io_context_.overlapped, res);
121 return IOResult(res.QuadPart, 0);
124 return IOResult::FromOSError(GetLastError());
127 FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
128 if (FlushFileBuffers(file_.GetPlatformFile()))
129 return IOResult(OK, 0);
131 return IOResult::FromOSError(GetLastError());
134 void FileStream::Context::IOCompletionIsPending(
135 const CompletionCallback& callback,
136 IOBuffer* buf) {
137 DCHECK(callback_.is_null());
138 callback_ = callback;
139 in_flight_buf_ = buf; // Hold until the async operation ends.
140 async_in_progress_ = true;
143 void FileStream::Context::OnIOCompleted(
144 base::MessageLoopForIO::IOContext* context,
145 DWORD bytes_read,
146 DWORD error) {
147 DCHECK_EQ(&io_context_, context);
148 DCHECK(!callback_.is_null());
149 DCHECK(async_in_progress_);
151 async_in_progress_ = false;
152 if (orphaned_) {
153 callback_.Reset();
154 in_flight_buf_ = NULL;
155 CloseAndDelete();
156 return;
159 int result;
160 if (error == ERROR_HANDLE_EOF) {
161 result = 0;
162 } else if (error) {
163 IOResult error_result = IOResult::FromOSError(error);
164 result = error_result.result;
165 } else {
166 result = bytes_read;
167 IncrementOffset(&io_context_.overlapped, bytes_read);
170 CompletionCallback temp_callback = callback_;
171 callback_.Reset();
172 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
173 in_flight_buf_ = NULL;
174 temp_callback.Run(result);
177 } // namespace net