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.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
20 void SetOffset(OVERLAPPED
* overlapped
, const LARGE_INTEGER
& offset
) {
21 overlapped
->Offset
= offset
.LowPart
;
22 overlapped
->OffsetHigh
= offset
.HighPart
;
25 void IncrementOffset(OVERLAPPED
* overlapped
, DWORD count
) {
27 offset
.LowPart
= overlapped
->Offset
;
28 offset
.HighPart
= overlapped
->OffsetHigh
;
29 offset
.QuadPart
+= static_cast<LONGLONG
>(count
);
30 SetOffset(overlapped
, offset
);
35 FileStream::Context::Context(const scoped_refptr
<base::TaskRunner
>& task_runner
)
37 async_in_progress_(false),
39 task_runner_(task_runner
) {
40 io_context_
.handler
= this;
41 memset(&io_context_
.overlapped
, 0, sizeof(io_context_
.overlapped
));
44 FileStream::Context::Context(base::File file
,
45 const scoped_refptr
<base::TaskRunner
>& task_runner
)
48 async_in_progress_(false),
50 task_runner_(task_runner
) {
51 io_context_
.handler
= this;
52 memset(&io_context_
.overlapped
, 0, sizeof(io_context_
.overlapped
));
53 if (file_
.IsValid()) {
54 // TODO(hashimoto): Check that file_ is async.
59 FileStream::Context::~Context() {
62 int FileStream::Context::Read(IOBuffer
* buf
,
64 const CompletionCallback
& callback
) {
65 DCHECK(!async_in_progress_
);
68 if (!ReadFile(file_
.GetPlatformFile(), buf
->data(), buf_len
,
69 &bytes_read
, &io_context_
.overlapped
)) {
70 IOResult error
= IOResult::FromOSError(GetLastError());
71 if (error
.os_error
== ERROR_IO_PENDING
) {
72 IOCompletionIsPending(callback
, buf
);
73 } else if (error
.os_error
== ERROR_HANDLE_EOF
) {
74 return 0; // Report EOF by returning 0 bytes read.
76 LOG(WARNING
) << "ReadFile failed: " << error
.os_error
;
81 IOCompletionIsPending(callback
, buf
);
82 return ERR_IO_PENDING
;
85 int FileStream::Context::Write(IOBuffer
* buf
,
87 const CompletionCallback
& callback
) {
88 DWORD bytes_written
= 0;
89 if (!WriteFile(file_
.GetPlatformFile(), buf
->data(), buf_len
,
90 &bytes_written
, &io_context_
.overlapped
)) {
91 IOResult error
= IOResult::FromOSError(GetLastError());
92 if (error
.os_error
== ERROR_IO_PENDING
) {
93 IOCompletionIsPending(callback
, buf
);
95 LOG(WARNING
) << "WriteFile failed: " << error
.os_error
;
100 IOCompletionIsPending(callback
, buf
);
101 return ERR_IO_PENDING
;
104 FileStream::Context::IOResult
FileStream::Context::SeekFileImpl(
105 base::File::Whence whence
,
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);
114 return IOResult::FromOSError(GetLastError());
117 void FileStream::Context::OnFileOpened() {
118 base::MessageLoopForIO::current()->RegisterIOHandler(file_
.GetPlatformFile(),
122 void FileStream::Context::IOCompletionIsPending(
123 const CompletionCallback
& callback
,
125 DCHECK(callback_
.is_null());
126 callback_
= callback
;
127 in_flight_buf_
= buf
; // Hold until the async operation ends.
128 async_in_progress_
= true;
131 void FileStream::Context::OnIOCompleted(
132 base::MessageLoopForIO::IOContext
* context
,
135 DCHECK_EQ(&io_context_
, context
);
136 DCHECK(!callback_
.is_null());
137 DCHECK(async_in_progress_
);
139 async_in_progress_
= false;
142 in_flight_buf_
= NULL
;
148 if (error
== ERROR_HANDLE_EOF
) {
151 IOResult error_result
= IOResult::FromOSError(error
);
152 result
= error_result
.result
;
155 IncrementOffset(&io_context_
.overlapped
, bytes_read
);
158 CompletionCallback temp_callback
= callback_
;
160 scoped_refptr
<IOBuffer
> temp_buf
= in_flight_buf_
;
161 in_flight_buf_
= NULL
;
162 temp_callback
.Run(result
);