blob: 3b942d35edc532659f8ccdf2035c4aa990cafe70 [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"
[email protected]866534a92014-05-07 03:39:1512#include "base/task_runner.h"
[email protected]aab1b9e2012-11-06 00:29:5113#include "net/base/io_buffer.h"
14#include "net/base/net_errors.h"
15
16namespace net {
17
[email protected]aab1b9e2012-11-06 00:29:5118namespace {
19
20void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
21 overlapped->Offset = offset.LowPart;
22 overlapped->OffsetHigh = offset.HighPart;
23}
24
25void 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);
31}
32
33} // namespace
34
[email protected]619a0398c2014-04-23 08:28:4535FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner)
[email protected]aab1b9e2012-11-06 00:29:5136 : io_context_(),
[email protected]aab1b9e2012-11-06 00:29:5137 async_in_progress_(false),
38 orphaned_(false),
[email protected]53aafaed2013-06-17 19:16:3239 task_runner_(task_runner) {
[email protected]aab1b9e2012-11-06 00:29:5140 io_context_.handler = this;
[email protected]bfb88ec2013-02-27 20:21:3541 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
[email protected]aab1b9e2012-11-06 00:29:5142}
43
[email protected]a08305912014-03-21 00:41:1544FileStream::Context::Context(base::File file,
[email protected]53aafaed2013-06-17 19:16:3245 const scoped_refptr<base::TaskRunner>& task_runner)
[email protected]aab1b9e2012-11-06 00:29:5146 : io_context_(),
[email protected]a08305912014-03-21 00:41:1547 file_(file.Pass()),
[email protected]aab1b9e2012-11-06 00:29:5148 async_in_progress_(false),
49 orphaned_(false),
[email protected]53aafaed2013-06-17 19:16:3250 task_runner_(task_runner) {
[email protected]aab1b9e2012-11-06 00:29:5151 io_context_.handler = this;
[email protected]bfb88ec2013-02-27 20:21:3552 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
[email protected]50f91af2014-04-09 17:28:5653 if (file_.IsValid()) {
54 // TODO(hashimoto): Check that file_ is async.
[email protected]633ff3b12014-06-20 23:30:1855 OnFileOpened();
[email protected]50f91af2014-04-09 17:28:5656 }
[email protected]aab1b9e2012-11-06 00:29:5157}
58
59FileStream::Context::~Context() {
60}
61
[email protected]633ff3b12014-06-20 23:30:1862int FileStream::Context::Read(IOBuffer* buf,
63 int buf_len,
64 const CompletionCallback& callback) {
[email protected]aab1b9e2012-11-06 00:29:5165 DCHECK(!async_in_progress_);
[email protected]aab1b9e2012-11-06 00:29:5166
[email protected]aab1b9e2012-11-06 00:29:5167 DWORD bytes_read;
[email protected]a08305912014-03-21 00:41:1568 if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len,
[email protected]aab1b9e2012-11-06 00:29:5169 &bytes_read, &io_context_.overlapped)) {
[email protected]bfb88ec2013-02-27 20:21:3570 IOResult error = IOResult::FromOSError(GetLastError());
71 if (error.os_error == ERROR_IO_PENDING) {
[email protected]aab1b9e2012-11-06 00:29:5172 IOCompletionIsPending(callback, buf);
[email protected]bfb88ec2013-02-27 20:21:3573 } else if (error.os_error == ERROR_HANDLE_EOF) {
74 return 0; // Report EOF by returning 0 bytes read.
[email protected]aab1b9e2012-11-06 00:29:5175 } else {
[email protected]bfb88ec2013-02-27 20:21:3576 LOG(WARNING) << "ReadFile failed: " << error.os_error;
[email protected]aab1b9e2012-11-06 00:29:5177 }
[email protected]bfb88ec2013-02-27 20:21:3578 return error.result;
[email protected]aab1b9e2012-11-06 00:29:5179 }
[email protected]bfb88ec2013-02-27 20:21:3580
81 IOCompletionIsPending(callback, buf);
82 return ERR_IO_PENDING;
[email protected]aab1b9e2012-11-06 00:29:5183}
84
[email protected]633ff3b12014-06-20 23:30:1885int FileStream::Context::Write(IOBuffer* buf,
86 int buf_len,
87 const CompletionCallback& callback) {
[email protected]aab1b9e2012-11-06 00:29:5188 DWORD bytes_written = 0;
[email protected]a08305912014-03-21 00:41:1589 if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len,
[email protected]aab1b9e2012-11-06 00:29:5190 &bytes_written, &io_context_.overlapped)) {
[email protected]bfb88ec2013-02-27 20:21:3591 IOResult error = IOResult::FromOSError(GetLastError());
92 if (error.os_error == ERROR_IO_PENDING) {
[email protected]aab1b9e2012-11-06 00:29:5193 IOCompletionIsPending(callback, buf);
[email protected]aab1b9e2012-11-06 00:29:5194 } else {
[email protected]bfb88ec2013-02-27 20:21:3595 LOG(WARNING) << "WriteFile failed: " << error.os_error;
[email protected]aab1b9e2012-11-06 00:29:5196 }
[email protected]bfb88ec2013-02-27 20:21:3597 return error.result;
[email protected]aab1b9e2012-11-06 00:29:5198 }
[email protected]bfb88ec2013-02-27 20:21:3599
100 IOCompletionIsPending(callback, buf);
101 return ERR_IO_PENDING;
[email protected]aab1b9e2012-11-06 00:29:51102}
103
[email protected]633ff3b12014-06-20 23:30:18104FileStream::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);
[email protected]aab1b9e2012-11-06 00:29:51112 }
113
[email protected]bfb88ec2013-02-27 20:21:35114 return IOResult::FromOSError(GetLastError());
[email protected]aab1b9e2012-11-06 00:29:51115}
116
[email protected]633ff3b12014-06-20 23:30:18117void FileStream::Context::OnFileOpened() {
118 base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(),
119 this);
[email protected]c1d9cf742013-09-12 06:37:19120}
121
[email protected]aab1b9e2012-11-06 00:29:51122void 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;
129}
130
[email protected]2da659e2013-05-23 20:51:34131void FileStream::Context::OnIOCompleted(
132 base::MessageLoopForIO::IOContext* context,
133 DWORD bytes_read,
134 DWORD error) {
[email protected]aab1b9e2012-11-06 00:29:51135 DCHECK_EQ(&io_context_, context);
136 DCHECK(!callback_.is_null());
137 DCHECK(async_in_progress_);
138
139 async_in_progress_ = false;
140 if (orphaned_) {
141 callback_.Reset();
142 in_flight_buf_ = NULL;
143 CloseAndDelete();
144 return;
145 }
146
[email protected]bfb88ec2013-02-27 20:21:35147 int result;
148 if (error == ERROR_HANDLE_EOF) {
149 result = 0;
150 } else if (error) {
151 IOResult error_result = IOResult::FromOSError(error);
[email protected]bfb88ec2013-02-27 20:21:35152 result = error_result.result;
153 } else {
154 result = bytes_read;
[email protected]aab1b9e2012-11-06 00:29:51155 IncrementOffset(&io_context_.overlapped, bytes_read);
[email protected]bfb88ec2013-02-27 20:21:35156 }
[email protected]aab1b9e2012-11-06 00:29:51157
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);
163}
164
165} // namespace net