Convert ARRAYSIZE_UNSAFE -> arraysize in net/.
[chromium-blink-merge.git] / net / base / file_stream_context_win.cc
blob3b942d35edc532659f8ccdf2035c4aa990cafe70
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.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
16 namespace net {
18 namespace {
20 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
21 overlapped->Offset = offset.LowPart;
22 overlapped->OffsetHigh = offset.HighPart;
25 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
26 LARGE_INTEGER offset;
27 offset.LowPart = overlapped->Offset;
28 offset.HighPart = overlapped->OffsetHigh;
29 offset.QuadPart += static_cast<LONGLONG>(count);
30 SetOffset(overlapped, offset);
33 } // namespace
35 FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner)
36 : io_context_(),
37 async_in_progress_(false),
38 orphaned_(false),
39 task_runner_(task_runner) {
40 io_context_.handler = this;
41 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
44 FileStream::Context::Context(base::File file,
45 const scoped_refptr<base::TaskRunner>& task_runner)
46 : io_context_(),
47 file_(file.Pass()),
48 async_in_progress_(false),
49 orphaned_(false),
50 task_runner_(task_runner) {
51 io_context_.handler = this;
52 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
53 if (file_.IsValid()) {
54 // TODO(hashimoto): Check that file_ is async.
55 OnFileOpened();
59 FileStream::Context::~Context() {
62 int FileStream::Context::Read(IOBuffer* buf,
63 int buf_len,
64 const CompletionCallback& callback) {
65 DCHECK(!async_in_progress_);
67 DWORD bytes_read;
68 if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len,
69 &bytes_read, &io_context_.overlapped)) {
70 IOResult error = IOResult::FromOSError(GetLastError());
71 if (error.os_error == ERROR_IO_PENDING) {
72 IOCompletionIsPending(callback, buf);
73 } else if (error.os_error == ERROR_HANDLE_EOF) {
74 return 0; // Report EOF by returning 0 bytes read.
75 } else {
76 LOG(WARNING) << "ReadFile failed: " << error.os_error;
78 return error.result;
81 IOCompletionIsPending(callback, buf);
82 return ERR_IO_PENDING;
85 int FileStream::Context::Write(IOBuffer* buf,
86 int buf_len,
87 const CompletionCallback& callback) {
88 DWORD bytes_written = 0;
89 if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len,
90 &bytes_written, &io_context_.overlapped)) {
91 IOResult error = IOResult::FromOSError(GetLastError());
92 if (error.os_error == ERROR_IO_PENDING) {
93 IOCompletionIsPending(callback, buf);
94 } else {
95 LOG(WARNING) << "WriteFile failed: " << error.os_error;
97 return error.result;
100 IOCompletionIsPending(callback, buf);
101 return ERR_IO_PENDING;
104 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(
105 base::File::Whence whence,
106 int64 offset) {
107 LARGE_INTEGER result;
108 result.QuadPart = file_.Seek(whence, offset);
109 if (result.QuadPart >= 0) {
110 SetOffset(&io_context_.overlapped, result);
111 return IOResult(result.QuadPart, 0);
114 return IOResult::FromOSError(GetLastError());
117 void FileStream::Context::OnFileOpened() {
118 base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(),
119 this);
122 void FileStream::Context::IOCompletionIsPending(
123 const CompletionCallback& callback,
124 IOBuffer* buf) {
125 DCHECK(callback_.is_null());
126 callback_ = callback;
127 in_flight_buf_ = buf; // Hold until the async operation ends.
128 async_in_progress_ = true;
131 void FileStream::Context::OnIOCompleted(
132 base::MessageLoopForIO::IOContext* context,
133 DWORD bytes_read,
134 DWORD error) {
135 DCHECK_EQ(&io_context_, context);
136 DCHECK(!callback_.is_null());
137 DCHECK(async_in_progress_);
139 async_in_progress_ = false;
140 if (orphaned_) {
141 callback_.Reset();
142 in_flight_buf_ = NULL;
143 CloseAndDelete();
144 return;
147 int result;
148 if (error == ERROR_HANDLE_EOF) {
149 result = 0;
150 } else if (error) {
151 IOResult error_result = IOResult::FromOSError(error);
152 result = error_result.result;
153 } else {
154 result = bytes_read;
155 IncrementOffset(&io_context_.overlapped, bytes_read);
158 CompletionCallback temp_callback = callback_;
159 callback_.Reset();
160 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
161 in_flight_buf_ = NULL;
162 temp_callback.Run(result);
165 } // namespace net