Roll src/third_party/WebKit 8121bc6:918aba1 (svn 188871:188878)
[chromium-blink-merge.git] / net / base / file_stream_context_win.cc
blob85a596872b110292534629278e237e8130829979
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/profiler/scoped_tracker.h"
13 #include "base/task_runner.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
17 namespace net {
19 namespace {
21 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
22 overlapped->Offset = offset.LowPart;
23 overlapped->OffsetHigh = offset.HighPart;
26 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
27 LARGE_INTEGER offset;
28 offset.LowPart = overlapped->Offset;
29 offset.HighPart = overlapped->OffsetHigh;
30 offset.QuadPart += static_cast<LONGLONG>(count);
31 SetOffset(overlapped, offset);
34 } // namespace
36 FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner)
37 : io_context_(),
38 async_in_progress_(false),
39 orphaned_(false),
40 task_runner_(task_runner) {
41 io_context_.handler = this;
42 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
45 FileStream::Context::Context(base::File file,
46 const scoped_refptr<base::TaskRunner>& task_runner)
47 : io_context_(),
48 file_(file.Pass()),
49 async_in_progress_(false),
50 orphaned_(false),
51 task_runner_(task_runner) {
52 io_context_.handler = this;
53 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
54 if (file_.IsValid()) {
55 // TODO(hashimoto): Check that file_ is async.
56 OnFileOpened();
60 FileStream::Context::~Context() {
63 int FileStream::Context::Read(IOBuffer* buf,
64 int buf_len,
65 const CompletionCallback& callback) {
66 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
67 tracked_objects::ScopedTracker tracking_profile(
68 FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 FileStream::Context::Read"));
70 DCHECK(!async_in_progress_);
72 DWORD bytes_read;
73 if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len,
74 &bytes_read, &io_context_.overlapped)) {
75 IOResult error = IOResult::FromOSError(GetLastError());
76 if (error.os_error == ERROR_HANDLE_EOF)
77 return 0; // Report EOF by returning 0 bytes read.
78 if (error.os_error == ERROR_IO_PENDING)
79 IOCompletionIsPending(callback, buf);
80 else
81 LOG(WARNING) << "ReadFile failed: " << error.os_error;
82 return static_cast<int>(error.result);
85 IOCompletionIsPending(callback, buf);
86 return ERR_IO_PENDING;
89 int FileStream::Context::Write(IOBuffer* buf,
90 int buf_len,
91 const CompletionCallback& callback) {
92 DWORD bytes_written = 0;
93 if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len,
94 &bytes_written, &io_context_.overlapped)) {
95 IOResult error = IOResult::FromOSError(GetLastError());
96 if (error.os_error == ERROR_IO_PENDING)
97 IOCompletionIsPending(callback, buf);
98 else
99 LOG(WARNING) << "WriteFile failed: " << error.os_error;
100 return static_cast<int>(error.result);
103 IOCompletionIsPending(callback, buf);
104 return ERR_IO_PENDING;
107 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(
108 base::File::Whence whence,
109 int64 offset) {
110 LARGE_INTEGER result;
111 result.QuadPart = file_.Seek(whence, offset);
112 if (result.QuadPart >= 0) {
113 SetOffset(&io_context_.overlapped, result);
114 return IOResult(result.QuadPart, 0);
117 return IOResult::FromOSError(GetLastError());
120 void FileStream::Context::OnFileOpened() {
121 base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(),
122 this);
125 void FileStream::Context::IOCompletionIsPending(
126 const CompletionCallback& callback,
127 IOBuffer* buf) {
128 DCHECK(callback_.is_null());
129 callback_ = callback;
130 in_flight_buf_ = buf; // Hold until the async operation ends.
131 async_in_progress_ = true;
134 void FileStream::Context::OnIOCompleted(
135 base::MessageLoopForIO::IOContext* context,
136 DWORD bytes_read,
137 DWORD error) {
138 DCHECK_EQ(&io_context_, context);
139 DCHECK(!callback_.is_null());
140 DCHECK(async_in_progress_);
142 async_in_progress_ = false;
143 if (orphaned_) {
144 callback_.Reset();
145 in_flight_buf_ = NULL;
146 CloseAndDelete();
147 return;
150 int result;
151 if (error == ERROR_HANDLE_EOF) {
152 result = 0;
153 } else if (error) {
154 IOResult error_result = IOResult::FromOSError(error);
155 result = static_cast<int>(error_result.result);
156 } else {
157 result = bytes_read;
158 IncrementOffset(&io_context_.overlapped, bytes_read);
161 CompletionCallback temp_callback = callback_;
162 callback_.Reset();
163 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
164 in_flight_buf_ = NULL;
165 temp_callback.Run(result);
168 } // namespace net