blob: 7072f1df526dec04d60fcbeea5c8d5313c4493ee [file] [log] [blame]
[email protected]aab1b9e2012-11-06 00:29:511// 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_context.h"
6
7#include <windows.h>
8
[email protected]57999812013-02-24 05:40:529#include "base/files/file_path.h"
[email protected]aab1b9e2012-11-06 00:29:5110#include "base/logging.h"
11#include "base/metrics/histogram.h"
12#include "base/task_runner_util.h"
13#include "base/threading/worker_pool.h"
14#include "net/base/io_buffer.h"
15#include "net/base/net_errors.h"
16
17namespace net {
18
19// Ensure that we can just use our Whence values directly.
20COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin);
21COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current);
22COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end);
23
24namespace {
25
26void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
27 overlapped->Offset = offset.LowPart;
28 overlapped->OffsetHigh = offset.HighPart;
29}
30
31void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
32 LARGE_INTEGER offset;
33 offset.LowPart = overlapped->Offset;
34 offset.HighPart = overlapped->OffsetHigh;
35 offset.QuadPart += static_cast<LONGLONG>(count);
36 SetOffset(overlapped, offset);
37}
38
39} // namespace
40
41FileStream::Context::Context(const BoundNetLog& bound_net_log)
42 : io_context_(),
43 file_(base::kInvalidPlatformFileValue),
44 record_uma_(false),
45 async_in_progress_(false),
46 orphaned_(false),
47 bound_net_log_(bound_net_log),
48 error_source_(FILE_ERROR_SOURCE_COUNT) {
49 io_context_.handler = this;
[email protected]bfb88ec2013-02-27 20:21:3550 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
[email protected]aab1b9e2012-11-06 00:29:5151}
52
53FileStream::Context::Context(base::PlatformFile file,
54 const BoundNetLog& bound_net_log,
55 int open_flags)
56 : io_context_(),
57 file_(file),
58 record_uma_(false),
59 async_in_progress_(false),
60 orphaned_(false),
61 bound_net_log_(bound_net_log),
62 error_source_(FILE_ERROR_SOURCE_COUNT) {
63 io_context_.handler = this;
[email protected]bfb88ec2013-02-27 20:21:3564 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
[email protected]aab1b9e2012-11-06 00:29:5165 if (file_ != base::kInvalidPlatformFileValue &&
66 (open_flags & base::PLATFORM_FILE_ASYNC)) {
67 OnAsyncFileOpened();
68 }
69}
70
71FileStream::Context::~Context() {
72}
73
74int64 FileStream::Context::GetFileSize() const {
75 LARGE_INTEGER file_size;
76 if (!GetFileSizeEx(file_, &file_size)) {
[email protected]bfb88ec2013-02-27 20:21:3577 IOResult error = IOResult::FromOSError(GetLastError());
78 LOG(WARNING) << "GetFileSizeEx failed: " << error.os_error;
79 RecordError(error, FILE_ERROR_SOURCE_GET_SIZE);
80 return error.result;
[email protected]aab1b9e2012-11-06 00:29:5181 }
82
83 return file_size.QuadPart;
84}
85
86int FileStream::Context::ReadAsync(IOBuffer* buf,
87 int buf_len,
88 const CompletionCallback& callback) {
89 DCHECK(!async_in_progress_);
90 error_source_ = FILE_ERROR_SOURCE_READ;
91
[email protected]aab1b9e2012-11-06 00:29:5192 DWORD bytes_read;
93 if (!ReadFile(file_, buf->data(), buf_len,
94 &bytes_read, &io_context_.overlapped)) {
[email protected]bfb88ec2013-02-27 20:21:3595 IOResult error = IOResult::FromOSError(GetLastError());
96 if (error.os_error == ERROR_IO_PENDING) {
[email protected]aab1b9e2012-11-06 00:29:5197 IOCompletionIsPending(callback, buf);
[email protected]bfb88ec2013-02-27 20:21:3598 } else if (error.os_error == ERROR_HANDLE_EOF) {
99 return 0; // Report EOF by returning 0 bytes read.
[email protected]aab1b9e2012-11-06 00:29:51100 } else {
[email protected]bfb88ec2013-02-27 20:21:35101 LOG(WARNING) << "ReadFile failed: " << error.os_error;
102 RecordError(error, FILE_ERROR_SOURCE_READ);
[email protected]aab1b9e2012-11-06 00:29:51103 }
[email protected]bfb88ec2013-02-27 20:21:35104 return error.result;
[email protected]aab1b9e2012-11-06 00:29:51105 }
[email protected]bfb88ec2013-02-27 20:21:35106
107 IOCompletionIsPending(callback, buf);
108 return ERR_IO_PENDING;
[email protected]aab1b9e2012-11-06 00:29:51109}
110
111int FileStream::Context::ReadSync(char* buf, int buf_len) {
[email protected]aab1b9e2012-11-06 00:29:51112 DWORD bytes_read;
113 if (!ReadFile(file_, buf, buf_len, &bytes_read, NULL)) {
[email protected]bfb88ec2013-02-27 20:21:35114 IOResult error = IOResult::FromOSError(GetLastError());
115 if (error.os_error == ERROR_HANDLE_EOF) {
116 return 0; // Report EOF by returning 0 bytes read.
[email protected]aab1b9e2012-11-06 00:29:51117 } else {
[email protected]bfb88ec2013-02-27 20:21:35118 LOG(WARNING) << "ReadFile failed: " << error.os_error;
119 RecordError(error, FILE_ERROR_SOURCE_READ);
[email protected]aab1b9e2012-11-06 00:29:51120 }
[email protected]bfb88ec2013-02-27 20:21:35121 return error.result;
[email protected]aab1b9e2012-11-06 00:29:51122 }
[email protected]bfb88ec2013-02-27 20:21:35123
124 return bytes_read;
[email protected]aab1b9e2012-11-06 00:29:51125}
126
127int FileStream::Context::WriteAsync(IOBuffer* buf,
128 int buf_len,
129 const CompletionCallback& callback) {
130 error_source_ = FILE_ERROR_SOURCE_WRITE;
131
[email protected]aab1b9e2012-11-06 00:29:51132 DWORD bytes_written = 0;
133 if (!WriteFile(file_, buf->data(), buf_len,
134 &bytes_written, &io_context_.overlapped)) {
[email protected]bfb88ec2013-02-27 20:21:35135 IOResult error = IOResult::FromOSError(GetLastError());
136 if (error.os_error == ERROR_IO_PENDING) {
[email protected]aab1b9e2012-11-06 00:29:51137 IOCompletionIsPending(callback, buf);
[email protected]aab1b9e2012-11-06 00:29:51138 } else {
[email protected]bfb88ec2013-02-27 20:21:35139 LOG(WARNING) << "WriteFile failed: " << error.os_error;
140 RecordError(error, FILE_ERROR_SOURCE_WRITE);
[email protected]aab1b9e2012-11-06 00:29:51141 }
[email protected]bfb88ec2013-02-27 20:21:35142 return error.result;
[email protected]aab1b9e2012-11-06 00:29:51143 }
[email protected]bfb88ec2013-02-27 20:21:35144
145 IOCompletionIsPending(callback, buf);
146 return ERR_IO_PENDING;
[email protected]aab1b9e2012-11-06 00:29:51147}
148
149int FileStream::Context::WriteSync(const char* buf, int buf_len) {
[email protected]aab1b9e2012-11-06 00:29:51150 DWORD bytes_written = 0;
151 if (!WriteFile(file_, buf, buf_len, &bytes_written, NULL)) {
[email protected]bfb88ec2013-02-27 20:21:35152 IOResult error = IOResult::FromOSError(GetLastError());
153 LOG(WARNING) << "WriteFile failed: " << error.os_error;
154 RecordError(error, FILE_ERROR_SOURCE_WRITE);
155 return error.result;
[email protected]aab1b9e2012-11-06 00:29:51156 }
[email protected]bfb88ec2013-02-27 20:21:35157
158 return bytes_written;
[email protected]aab1b9e2012-11-06 00:29:51159}
160
161int FileStream::Context::Truncate(int64 bytes) {
[email protected]bfb88ec2013-02-27 20:21:35162 if (!SetEndOfFile(file_)) {
163 IOResult error = IOResult::FromOSError(GetLastError());
164 LOG(WARNING) << "SetEndOfFile failed: " << error.os_error;
165 RecordError(error, FILE_ERROR_SOURCE_SET_EOF);
166 return error.result;
167 }
[email protected]aab1b9e2012-11-06 00:29:51168
[email protected]bfb88ec2013-02-27 20:21:35169 return bytes;
[email protected]aab1b9e2012-11-06 00:29:51170}
171
172void FileStream::Context::OnAsyncFileOpened() {
173 MessageLoopForIO::current()->RegisterIOHandler(file_, this);
174}
175
[email protected]bfb88ec2013-02-27 20:21:35176FileStream::Context::IOResult FileStream::Context::SeekFileImpl(Whence whence,
177 int64 offset) {
[email protected]aab1b9e2012-11-06 00:29:51178 LARGE_INTEGER distance, res;
179 distance.QuadPart = offset;
180 DWORD move_method = static_cast<DWORD>(whence);
181 if (SetFilePointerEx(file_, distance, &res, move_method)) {
182 SetOffset(&io_context_.overlapped, res);
[email protected]bfb88ec2013-02-27 20:21:35183 return IOResult(res.QuadPart, 0);
[email protected]aab1b9e2012-11-06 00:29:51184 }
185
[email protected]bfb88ec2013-02-27 20:21:35186 return IOResult::FromOSError(GetLastError());
[email protected]aab1b9e2012-11-06 00:29:51187}
188
[email protected]bfb88ec2013-02-27 20:21:35189FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
[email protected]aab1b9e2012-11-06 00:29:51190 if (FlushFileBuffers(file_))
[email protected]bfb88ec2013-02-27 20:21:35191 return IOResult(OK, 0);
[email protected]aab1b9e2012-11-06 00:29:51192
[email protected]bfb88ec2013-02-27 20:21:35193 return IOResult::FromOSError(GetLastError());
[email protected]aab1b9e2012-11-06 00:29:51194}
195
196void FileStream::Context::IOCompletionIsPending(
197 const CompletionCallback& callback,
198 IOBuffer* buf) {
199 DCHECK(callback_.is_null());
200 callback_ = callback;
201 in_flight_buf_ = buf; // Hold until the async operation ends.
202 async_in_progress_ = true;
203}
204
205void FileStream::Context::OnIOCompleted(MessageLoopForIO::IOContext* context,
206 DWORD bytes_read,
207 DWORD error) {
208 DCHECK_EQ(&io_context_, context);
209 DCHECK(!callback_.is_null());
210 DCHECK(async_in_progress_);
211
212 async_in_progress_ = false;
213 if (orphaned_) {
214 callback_.Reset();
215 in_flight_buf_ = NULL;
216 CloseAndDelete();
217 return;
218 }
219
[email protected]bfb88ec2013-02-27 20:21:35220 int result;
221 if (error == ERROR_HANDLE_EOF) {
222 result = 0;
223 } else if (error) {
224 IOResult error_result = IOResult::FromOSError(error);
225 RecordError(error_result, error_source_);
226 result = error_result.result;
227 } else {
228 result = bytes_read;
[email protected]aab1b9e2012-11-06 00:29:51229 IncrementOffset(&io_context_.overlapped, bytes_read);
[email protected]bfb88ec2013-02-27 20:21:35230 }
[email protected]aab1b9e2012-11-06 00:29:51231
232 CompletionCallback temp_callback = callback_;
233 callback_.Reset();
234 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
235 in_flight_buf_ = NULL;
236 temp_callback.Run(result);
237}
238
239} // namespace net