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"
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"
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
);
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
) {
32 offset
.LowPart
= overlapped
->Offset
;
33 offset
.HighPart
= overlapped
->OffsetHigh
;
34 offset
.QuadPart
+= static_cast<LONGLONG
>(count
);
35 SetOffset(overlapped
, offset
);
40 FileStream::Context::Context(const scoped_refptr
<base::TaskRunner
>& task_runner
)
42 async_in_progress_(false),
44 task_runner_(task_runner
) {
45 io_context_
.handler
= this;
46 memset(&io_context_
.overlapped
, 0, sizeof(io_context_
.overlapped
));
49 FileStream::Context::Context(base::File file
,
50 const scoped_refptr
<base::TaskRunner
>& task_runner
)
53 async_in_progress_(false),
55 task_runner_(task_runner
) {
56 io_context_
.handler
= this;
57 memset(&io_context_
.overlapped
, 0, sizeof(io_context_
.overlapped
));
58 if (file_
.IsValid()) {
59 // TODO(hashimoto): Check that file_ is async.
64 FileStream::Context::~Context() {
67 int FileStream::Context::ReadAsync(IOBuffer
* buf
,
69 const CompletionCallback
& callback
) {
70 DCHECK(!async_in_progress_
);
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_IO_PENDING
) {
77 IOCompletionIsPending(callback
, buf
);
78 } else if (error
.os_error
== ERROR_HANDLE_EOF
) {
79 return 0; // Report EOF by returning 0 bytes read.
81 LOG(WARNING
) << "ReadFile failed: " << error
.os_error
;
86 IOCompletionIsPending(callback
, buf
);
87 return ERR_IO_PENDING
;
90 int FileStream::Context::WriteAsync(IOBuffer
* buf
,
92 const CompletionCallback
& callback
) {
93 DWORD bytes_written
= 0;
94 if (!WriteFile(file_
.GetPlatformFile(), buf
->data(), buf_len
,
95 &bytes_written
, &io_context_
.overlapped
)) {
96 IOResult error
= IOResult::FromOSError(GetLastError());
97 if (error
.os_error
== ERROR_IO_PENDING
) {
98 IOCompletionIsPending(callback
, buf
);
100 LOG(WARNING
) << "WriteFile failed: " << error
.os_error
;
105 IOCompletionIsPending(callback
, buf
);
106 return ERR_IO_PENDING
;
109 void FileStream::Context::OnAsyncFileOpened() {
110 base::MessageLoopForIO::current()->RegisterIOHandler(file_
.GetPlatformFile(),
114 FileStream::Context::IOResult
FileStream::Context::SeekFileImpl(Whence whence
,
116 LARGE_INTEGER distance
, res
;
117 distance
.QuadPart
= offset
;
118 DWORD move_method
= static_cast<DWORD
>(whence
);
119 if (SetFilePointerEx(file_
.GetPlatformFile(), distance
, &res
, move_method
)) {
120 SetOffset(&io_context_
.overlapped
, res
);
121 return IOResult(res
.QuadPart
, 0);
124 return IOResult::FromOSError(GetLastError());
127 FileStream::Context::IOResult
FileStream::Context::FlushFileImpl() {
128 if (FlushFileBuffers(file_
.GetPlatformFile()))
129 return IOResult(OK
, 0);
131 return IOResult::FromOSError(GetLastError());
134 void FileStream::Context::IOCompletionIsPending(
135 const CompletionCallback
& callback
,
137 DCHECK(callback_
.is_null());
138 callback_
= callback
;
139 in_flight_buf_
= buf
; // Hold until the async operation ends.
140 async_in_progress_
= true;
143 void FileStream::Context::OnIOCompleted(
144 base::MessageLoopForIO::IOContext
* context
,
147 DCHECK_EQ(&io_context_
, context
);
148 DCHECK(!callback_
.is_null());
149 DCHECK(async_in_progress_
);
151 async_in_progress_
= false;
154 in_flight_buf_
= NULL
;
160 if (error
== ERROR_HANDLE_EOF
) {
163 IOResult error_result
= IOResult::FromOSError(error
);
164 result
= error_result
.result
;
167 IncrementOffset(&io_context_
.overlapped
, bytes_read
);
170 CompletionCallback temp_callback
= callback_
;
172 scoped_refptr
<IOBuffer
> temp_buf
= in_flight_buf_
;
173 in_flight_buf_
= NULL
;
174 temp_callback
.Run(result
);