file_manager: Fix a bug where hosted documents could not be opened without active...
[chromium-blink-merge.git] / net / base / file_stream_context_win.cc
blob5fb30859e7559996f8d65b4ee52473089ed1dedd
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/task_runner_util.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
16 namespace net {
18 // Ensure that we can just use our Whence values directly.
19 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin);
20 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current);
21 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end);
23 namespace {
25 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
26 overlapped->Offset = offset.LowPart;
27 overlapped->OffsetHigh = offset.HighPart;
30 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
31 LARGE_INTEGER offset;
32 offset.LowPart = overlapped->Offset;
33 offset.HighPart = overlapped->OffsetHigh;
34 offset.QuadPart += static_cast<LONGLONG>(count);
35 SetOffset(overlapped, offset);
38 } // namespace
40 FileStream::Context::Context(const BoundNetLog& bound_net_log,
41 const scoped_refptr<base::TaskRunner>& task_runner)
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 task_runner_(task_runner) {
50 io_context_.handler = this;
51 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
54 FileStream::Context::Context(base::PlatformFile file,
55 const BoundNetLog& bound_net_log,
56 int open_flags,
57 const scoped_refptr<base::TaskRunner>& task_runner)
58 : io_context_(),
59 file_(file),
60 record_uma_(false),
61 async_in_progress_(false),
62 orphaned_(false),
63 bound_net_log_(bound_net_log),
64 error_source_(FILE_ERROR_SOURCE_COUNT),
65 task_runner_(task_runner) {
66 io_context_.handler = this;
67 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
68 if (file_ != base::kInvalidPlatformFileValue &&
69 (open_flags & base::PLATFORM_FILE_ASYNC)) {
70 OnAsyncFileOpened();
74 FileStream::Context::~Context() {
77 int64 FileStream::Context::GetFileSize() const {
78 LARGE_INTEGER file_size;
79 if (!GetFileSizeEx(file_, &file_size)) {
80 IOResult error = IOResult::FromOSError(GetLastError());
81 LOG(WARNING) << "GetFileSizeEx failed: " << error.os_error;
82 RecordError(error, FILE_ERROR_SOURCE_GET_SIZE);
83 return error.result;
86 return file_size.QuadPart;
89 int FileStream::Context::ReadAsync(IOBuffer* buf,
90 int buf_len,
91 const CompletionCallback& callback) {
92 DCHECK(!async_in_progress_);
93 error_source_ = FILE_ERROR_SOURCE_READ;
95 DWORD bytes_read;
96 if (!ReadFile(file_, buf->data(), buf_len,
97 &bytes_read, &io_context_.overlapped)) {
98 IOResult error = IOResult::FromOSError(GetLastError());
99 if (error.os_error == ERROR_IO_PENDING) {
100 IOCompletionIsPending(callback, buf);
101 } else if (error.os_error == ERROR_HANDLE_EOF) {
102 return 0; // Report EOF by returning 0 bytes read.
103 } else {
104 LOG(WARNING) << "ReadFile failed: " << error.os_error;
105 RecordError(error, FILE_ERROR_SOURCE_READ);
107 return error.result;
110 IOCompletionIsPending(callback, buf);
111 return ERR_IO_PENDING;
114 int FileStream::Context::ReadSync(char* buf, int buf_len) {
115 DWORD bytes_read;
116 if (!ReadFile(file_, buf, buf_len, &bytes_read, NULL)) {
117 IOResult error = IOResult::FromOSError(GetLastError());
118 if (error.os_error == ERROR_HANDLE_EOF) {
119 return 0; // Report EOF by returning 0 bytes read.
120 } else {
121 LOG(WARNING) << "ReadFile failed: " << error.os_error;
122 RecordError(error, FILE_ERROR_SOURCE_READ);
124 return error.result;
127 return bytes_read;
130 int FileStream::Context::WriteAsync(IOBuffer* buf,
131 int buf_len,
132 const CompletionCallback& callback) {
133 error_source_ = FILE_ERROR_SOURCE_WRITE;
135 DWORD bytes_written = 0;
136 if (!WriteFile(file_, buf->data(), buf_len,
137 &bytes_written, &io_context_.overlapped)) {
138 IOResult error = IOResult::FromOSError(GetLastError());
139 if (error.os_error == ERROR_IO_PENDING) {
140 IOCompletionIsPending(callback, buf);
141 } else {
142 LOG(WARNING) << "WriteFile failed: " << error.os_error;
143 RecordError(error, FILE_ERROR_SOURCE_WRITE);
145 return error.result;
148 IOCompletionIsPending(callback, buf);
149 return ERR_IO_PENDING;
152 int FileStream::Context::WriteSync(const char* buf, int buf_len) {
153 DWORD bytes_written = 0;
154 if (!WriteFile(file_, buf, buf_len, &bytes_written, NULL)) {
155 IOResult error = IOResult::FromOSError(GetLastError());
156 LOG(WARNING) << "WriteFile failed: " << error.os_error;
157 RecordError(error, FILE_ERROR_SOURCE_WRITE);
158 return error.result;
161 return bytes_written;
164 int FileStream::Context::Truncate(int64 bytes) {
165 if (!SetEndOfFile(file_)) {
166 IOResult error = IOResult::FromOSError(GetLastError());
167 LOG(WARNING) << "SetEndOfFile failed: " << error.os_error;
168 RecordError(error, FILE_ERROR_SOURCE_SET_EOF);
169 return error.result;
172 return bytes;
175 void FileStream::Context::OnAsyncFileOpened() {
176 base::MessageLoopForIO::current()->RegisterIOHandler(file_, this);
179 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(Whence whence,
180 int64 offset) {
181 LARGE_INTEGER distance, res;
182 distance.QuadPart = offset;
183 DWORD move_method = static_cast<DWORD>(whence);
184 if (SetFilePointerEx(file_, distance, &res, move_method)) {
185 SetOffset(&io_context_.overlapped, res);
186 return IOResult(res.QuadPart, 0);
189 return IOResult::FromOSError(GetLastError());
192 FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
193 if (FlushFileBuffers(file_))
194 return IOResult(OK, 0);
196 return IOResult::FromOSError(GetLastError());
199 void FileStream::Context::IOCompletionIsPending(
200 const CompletionCallback& callback,
201 IOBuffer* buf) {
202 DCHECK(callback_.is_null());
203 callback_ = callback;
204 in_flight_buf_ = buf; // Hold until the async operation ends.
205 async_in_progress_ = true;
208 void FileStream::Context::OnIOCompleted(
209 base::MessageLoopForIO::IOContext* context,
210 DWORD bytes_read,
211 DWORD error) {
212 DCHECK_EQ(&io_context_, context);
213 DCHECK(!callback_.is_null());
214 DCHECK(async_in_progress_);
216 async_in_progress_ = false;
217 if (orphaned_) {
218 callback_.Reset();
219 in_flight_buf_ = NULL;
220 CloseAndDelete();
221 return;
224 int result;
225 if (error == ERROR_HANDLE_EOF) {
226 result = 0;
227 } else if (error) {
228 IOResult error_result = IOResult::FromOSError(error);
229 RecordError(error_result, error_source_);
230 result = error_result.result;
231 } else {
232 result = bytes_read;
233 IncrementOffset(&io_context_.overlapped, bytes_read);
236 CompletionCallback temp_callback = callback_;
237 callback_.Reset();
238 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
239 in_flight_buf_ = NULL;
240 temp_callback.Run(result);
243 } // namespace net