Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / base / file_stream_context_win.cc
blob907d863b8e4eb7296180a328cd64b2a9dd3c068c
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/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/task_runner.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/threading/worker_pool.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
19 namespace net {
21 namespace {
23 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
24 overlapped->Offset = offset.LowPart;
25 overlapped->OffsetHigh = offset.HighPart;
28 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
29 LARGE_INTEGER offset;
30 offset.LowPart = overlapped->Offset;
31 offset.HighPart = overlapped->OffsetHigh;
32 offset.QuadPart += static_cast<LONGLONG>(count);
33 SetOffset(overlapped, offset);
36 } // namespace
38 FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner)
39 : async_in_progress_(false),
40 orphaned_(false),
41 task_runner_(task_runner),
42 io_context_(),
43 async_read_initiated_(false),
44 async_read_completed_(false),
45 io_complete_for_read_received_(false),
46 result_(0) {
47 io_context_.handler = this;
48 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
51 FileStream::Context::Context(base::File file,
52 const scoped_refptr<base::TaskRunner>& task_runner)
53 : file_(file.Pass()),
54 async_in_progress_(false),
55 orphaned_(false),
56 task_runner_(task_runner),
57 io_context_(),
58 async_read_initiated_(false),
59 async_read_completed_(false),
60 io_complete_for_read_received_(false),
61 result_(0) {
62 io_context_.handler = this;
63 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
64 if (file_.IsValid()) {
65 DCHECK(file_.async());
66 OnFileOpened();
70 FileStream::Context::~Context() {
73 int FileStream::Context::Read(IOBuffer* buf,
74 int buf_len,
75 const CompletionCallback& callback) {
76 CHECK(!async_in_progress_);
77 DCHECK(!async_read_initiated_);
78 DCHECK(!async_read_completed_);
79 DCHECK(!io_complete_for_read_received_);
81 IOCompletionIsPending(callback, buf);
83 async_read_initiated_ = true;
84 result_ = 0;
86 task_runner_->PostTask(
87 FROM_HERE,
88 base::Bind(&FileStream::Context::ReadAsync, base::Unretained(this),
89 file_.GetPlatformFile(), make_scoped_refptr(buf), buf_len,
90 &io_context_.overlapped, base::ThreadTaskRunnerHandle::Get()));
91 return ERR_IO_PENDING;
94 int FileStream::Context::Write(IOBuffer* buf,
95 int buf_len,
96 const CompletionCallback& callback) {
97 CHECK(!async_in_progress_);
99 result_ = 0;
101 DWORD bytes_written = 0;
102 if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len,
103 &bytes_written, &io_context_.overlapped)) {
104 IOResult error = IOResult::FromOSError(GetLastError());
105 if (error.os_error == ERROR_IO_PENDING)
106 IOCompletionIsPending(callback, buf);
107 else
108 LOG(WARNING) << "WriteFile failed: " << error.os_error;
109 return static_cast<int>(error.result);
112 IOCompletionIsPending(callback, buf);
113 return ERR_IO_PENDING;
116 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(
117 int64_t offset) {
118 LARGE_INTEGER result;
119 result.QuadPart = offset;
120 SetOffset(&io_context_.overlapped, result);
121 return IOResult(result.QuadPart, 0);
124 void FileStream::Context::OnFileOpened() {
125 base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(),
126 this);
129 void FileStream::Context::IOCompletionIsPending(
130 const CompletionCallback& callback,
131 IOBuffer* buf) {
132 DCHECK(callback_.is_null());
133 callback_ = callback;
134 in_flight_buf_ = buf; // Hold until the async operation ends.
135 async_in_progress_ = true;
138 void FileStream::Context::OnIOCompleted(
139 base::MessageLoopForIO::IOContext* context,
140 DWORD bytes_read,
141 DWORD error) {
142 DCHECK_EQ(&io_context_, context);
143 DCHECK(!callback_.is_null());
144 DCHECK(async_in_progress_);
146 if (!async_read_initiated_)
147 async_in_progress_ = false;
149 if (orphaned_) {
150 io_complete_for_read_received_ = true;
151 // If we are called due to a pending read and the asynchronous read task
152 // has not completed we have to keep the context around until it completes.
153 if (async_read_initiated_ && !async_read_completed_)
154 return;
155 DeleteOrphanedContext();
156 return;
159 if (error == ERROR_HANDLE_EOF) {
160 result_ = 0;
161 } else if (error) {
162 IOResult error_result = IOResult::FromOSError(error);
163 result_ = static_cast<int>(error_result.result);
164 } else {
165 if (result_)
166 DCHECK_EQ(result_, static_cast<int>(bytes_read));
167 result_ = bytes_read;
168 IncrementOffset(&io_context_.overlapped, bytes_read);
171 if (async_read_initiated_)
172 io_complete_for_read_received_ = true;
174 InvokeUserCallback();
177 void FileStream::Context::InvokeUserCallback() {
178 // For an asynchonous Read operation don't invoke the user callback until
179 // we receive the IO completion notification and the asynchronous Read
180 // completion notification.
181 if (async_read_initiated_) {
182 if (!io_complete_for_read_received_ || !async_read_completed_)
183 return;
184 async_read_initiated_ = false;
185 io_complete_for_read_received_ = false;
186 async_read_completed_ = false;
187 async_in_progress_ = false;
189 CompletionCallback temp_callback = callback_;
190 callback_.Reset();
191 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
192 in_flight_buf_ = NULL;
193 temp_callback.Run(result_);
196 void FileStream::Context::DeleteOrphanedContext() {
197 async_in_progress_ = false;
198 callback_.Reset();
199 in_flight_buf_ = NULL;
200 CloseAndDelete();
203 // static
204 void FileStream::Context::ReadAsync(
205 FileStream::Context* context,
206 HANDLE file,
207 scoped_refptr<IOBuffer> buf,
208 int buf_len,
209 OVERLAPPED* overlapped,
210 scoped_refptr<base::SingleThreadTaskRunner> origin_thread_task_runner) {
211 DWORD bytes_read = 0;
212 BOOL ret = ::ReadFile(file, buf->data(), buf_len, &bytes_read, overlapped);
213 origin_thread_task_runner->PostTask(
214 FROM_HERE,
215 base::Bind(&FileStream::Context::ReadAsyncResult,
216 base::Unretained(context), ret, bytes_read, ::GetLastError()));
219 void FileStream::Context::ReadAsyncResult(BOOL read_file_ret,
220 DWORD bytes_read,
221 DWORD os_error) {
222 // If the context is orphaned and we already received the io completion
223 // notification then we should delete the context and get out.
224 if (orphaned_ && io_complete_for_read_received_) {
225 DeleteOrphanedContext();
226 return;
229 async_read_completed_ = true;
230 if (read_file_ret) {
231 result_ = bytes_read;
232 InvokeUserCallback();
233 return;
236 IOResult error = IOResult::FromOSError(os_error);
237 if (error.os_error == ERROR_IO_PENDING) {
238 InvokeUserCallback();
239 } else {
240 OnIOCompleted(&io_context_, 0, error.os_error);
244 } // namespace net