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 BoundNetLog
& bound_net_log
,
41 const scoped_refptr
<base::TaskRunner
>& task_runner
)
43 file_(base::kInvalidPlatformFileValue
),
45 async_in_progress_(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
,
57 const scoped_refptr
<base::TaskRunner
>& task_runner
)
61 async_in_progress_(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
)) {
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
);
86 return file_size
.QuadPart
;
89 int FileStream::Context::ReadAsync(IOBuffer
* buf
,
91 const CompletionCallback
& callback
) {
92 DCHECK(!async_in_progress_
);
93 error_source_
= FILE_ERROR_SOURCE_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.
104 LOG(WARNING
) << "ReadFile failed: " << error
.os_error
;
105 RecordError(error
, FILE_ERROR_SOURCE_READ
);
110 IOCompletionIsPending(callback
, buf
);
111 return ERR_IO_PENDING
;
114 int FileStream::Context::ReadSync(char* buf
, int buf_len
) {
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.
121 LOG(WARNING
) << "ReadFile failed: " << error
.os_error
;
122 RecordError(error
, FILE_ERROR_SOURCE_READ
);
130 int FileStream::Context::WriteAsync(IOBuffer
* buf
,
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
);
142 LOG(WARNING
) << "WriteFile failed: " << error
.os_error
;
143 RecordError(error
, FILE_ERROR_SOURCE_WRITE
);
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
);
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
);
175 void FileStream::Context::OnAsyncFileOpened() {
176 base::MessageLoopForIO::current()->RegisterIOHandler(file_
, this);
179 FileStream::Context::IOResult
FileStream::Context::SeekFileImpl(Whence whence
,
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
,
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
,
212 DCHECK_EQ(&io_context_
, context
);
213 DCHECK(!callback_
.is_null());
214 DCHECK(async_in_progress_
);
216 async_in_progress_
= false;
219 in_flight_buf_
= NULL
;
225 if (error
== ERROR_HANDLE_EOF
) {
228 IOResult error_result
= IOResult::FromOSError(error
);
229 RecordError(error_result
, error_source_
);
230 result
= error_result
.result
;
233 IncrementOffset(&io_context_
.overlapped
, bytes_read
);
236 CompletionCallback temp_callback
= callback_
;
238 scoped_refptr
<IOBuffer
> temp_buf
= in_flight_buf_
;
239 in_flight_buf_
= NULL
;
240 temp_callback
.Run(result
);