[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 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. |
| 4 | |
| 5 | #include "net/base/file_stream_context.h" |
| 6 | |
| 7 | #include <windows.h> |
| 8 | |
[email protected] | 5799981 | 2013-02-24 05:40:52 | [diff] [blame] | 9 | #include "base/files/file_path.h" |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 10 | #include "base/logging.h" |
| 11 | #include "base/metrics/histogram.h" |
[email protected] | 866534a9 | 2014-05-07 03:39:15 | [diff] [blame] | 12 | #include "base/task_runner.h" |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 13 | #include "net/base/io_buffer.h" |
| 14 | #include "net/base/net_errors.h" |
| 15 | |
| 16 | namespace net { |
| 17 | |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 18 | namespace { |
| 19 | |
| 20 | void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { |
| 21 | overlapped->Offset = offset.LowPart; |
| 22 | overlapped->OffsetHigh = offset.HighPart; |
| 23 | } |
| 24 | |
| 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); |
| 31 | } |
| 32 | |
| 33 | } // namespace |
| 34 | |
[email protected] | 619a0398c | 2014-04-23 08:28:45 | [diff] [blame] | 35 | FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner) |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 36 | : io_context_(), |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 37 | async_in_progress_(false), |
| 38 | orphaned_(false), |
[email protected] | 53aafaed | 2013-06-17 19:16:32 | [diff] [blame] | 39 | task_runner_(task_runner) { |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 40 | io_context_.handler = this; |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 41 | memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped)); |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 42 | } |
| 43 | |
[email protected] | a0830591 | 2014-03-21 00:41:15 | [diff] [blame] | 44 | FileStream::Context::Context(base::File file, |
[email protected] | 53aafaed | 2013-06-17 19:16:32 | [diff] [blame] | 45 | const scoped_refptr<base::TaskRunner>& task_runner) |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 46 | : io_context_(), |
[email protected] | a0830591 | 2014-03-21 00:41:15 | [diff] [blame] | 47 | file_(file.Pass()), |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 48 | async_in_progress_(false), |
| 49 | orphaned_(false), |
[email protected] | 53aafaed | 2013-06-17 19:16:32 | [diff] [blame] | 50 | task_runner_(task_runner) { |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 51 | io_context_.handler = this; |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 52 | memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped)); |
[email protected] | 50f91af | 2014-04-09 17:28:56 | [diff] [blame] | 53 | if (file_.IsValid()) { |
| 54 | // TODO(hashimoto): Check that file_ is async. |
[email protected] | 633ff3b1 | 2014-06-20 23:30:18 | [diff] [blame] | 55 | OnFileOpened(); |
[email protected] | 50f91af | 2014-04-09 17:28:56 | [diff] [blame] | 56 | } |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 57 | } |
| 58 | |
| 59 | FileStream::Context::~Context() { |
| 60 | } |
| 61 | |
[email protected] | 633ff3b1 | 2014-06-20 23:30:18 | [diff] [blame] | 62 | int FileStream::Context::Read(IOBuffer* buf, |
| 63 | int buf_len, |
| 64 | const CompletionCallback& callback) { |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 65 | DCHECK(!async_in_progress_); |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 66 | |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 67 | DWORD bytes_read; |
[email protected] | a0830591 | 2014-03-21 00:41:15 | [diff] [blame] | 68 | if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len, |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 69 | &bytes_read, &io_context_.overlapped)) { |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 70 | IOResult error = IOResult::FromOSError(GetLastError()); |
| 71 | if (error.os_error == ERROR_IO_PENDING) { |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 72 | IOCompletionIsPending(callback, buf); |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 73 | } else if (error.os_error == ERROR_HANDLE_EOF) { |
| 74 | return 0; // Report EOF by returning 0 bytes read. |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 75 | } else { |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 76 | LOG(WARNING) << "ReadFile failed: " << error.os_error; |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 77 | } |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 78 | return error.result; |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 79 | } |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 80 | |
| 81 | IOCompletionIsPending(callback, buf); |
| 82 | return ERR_IO_PENDING; |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 83 | } |
| 84 | |
[email protected] | 633ff3b1 | 2014-06-20 23:30:18 | [diff] [blame] | 85 | int FileStream::Context::Write(IOBuffer* buf, |
| 86 | int buf_len, |
| 87 | const CompletionCallback& callback) { |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 88 | DWORD bytes_written = 0; |
[email protected] | a0830591 | 2014-03-21 00:41:15 | [diff] [blame] | 89 | if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len, |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 90 | &bytes_written, &io_context_.overlapped)) { |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 91 | IOResult error = IOResult::FromOSError(GetLastError()); |
| 92 | if (error.os_error == ERROR_IO_PENDING) { |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 93 | IOCompletionIsPending(callback, buf); |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 94 | } else { |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 95 | LOG(WARNING) << "WriteFile failed: " << error.os_error; |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 96 | } |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 97 | return error.result; |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 98 | } |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 99 | |
| 100 | IOCompletionIsPending(callback, buf); |
| 101 | return ERR_IO_PENDING; |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 102 | } |
| 103 | |
[email protected] | 633ff3b1 | 2014-06-20 23:30:18 | [diff] [blame] | 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); |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 112 | } |
| 113 | |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 114 | return IOResult::FromOSError(GetLastError()); |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 115 | } |
| 116 | |
[email protected] | 633ff3b1 | 2014-06-20 23:30:18 | [diff] [blame] | 117 | void FileStream::Context::OnFileOpened() { |
| 118 | base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(), |
| 119 | this); |
[email protected] | c1d9cf74 | 2013-09-12 06:37:19 | [diff] [blame] | 120 | } |
| 121 | |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 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; |
| 129 | } |
| 130 | |
[email protected] | 2da659e | 2013-05-23 20:51:34 | [diff] [blame] | 131 | void FileStream::Context::OnIOCompleted( |
| 132 | base::MessageLoopForIO::IOContext* context, |
| 133 | DWORD bytes_read, |
| 134 | DWORD error) { |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 135 | 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] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 147 | int result; |
| 148 | if (error == ERROR_HANDLE_EOF) { |
| 149 | result = 0; |
| 150 | } else if (error) { |
| 151 | IOResult error_result = IOResult::FromOSError(error); |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 152 | result = error_result.result; |
| 153 | } else { |
| 154 | result = bytes_read; |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 155 | IncrementOffset(&io_context_.overlapped, bytes_read); |
[email protected] | bfb88ec | 2013-02-27 20:21:35 | [diff] [blame] | 156 | } |
[email protected] | aab1b9e | 2012-11-06 00:29:51 | [diff] [blame] | 157 | |
| 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 |