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/profiler/scoped_tracker.h"
13 #include "base/task_runner.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
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
) {
28 offset
.LowPart
= overlapped
->Offset
;
29 offset
.HighPart
= overlapped
->OffsetHigh
;
30 offset
.QuadPart
+= static_cast<LONGLONG
>(count
);
31 SetOffset(overlapped
, offset
);
36 FileStream::Context::Context(const scoped_refptr
<base::TaskRunner
>& task_runner
)
38 async_in_progress_(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
)
49 async_in_progress_(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.
60 FileStream::Context::~Context() {
63 int FileStream::Context::Read(IOBuffer
* buf
,
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_
);
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
);
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
,
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
);
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
,
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(),
125 void FileStream::Context::IOCompletionIsPending(
126 const CompletionCallback
& callback
,
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
,
138 DCHECK_EQ(&io_context_
, context
);
139 DCHECK(!callback_
.is_null());
140 DCHECK(async_in_progress_
);
142 async_in_progress_
= false;
145 in_flight_buf_
= NULL
;
151 if (error
== ERROR_HANDLE_EOF
) {
154 IOResult error_result
= IOResult::FromOSError(error
);
155 result
= static_cast<int>(error_result
.result
);
158 IncrementOffset(&io_context_
.overlapped
, bytes_read
);
161 CompletionCallback temp_callback
= callback_
;
163 scoped_refptr
<IOBuffer
> temp_buf
= in_flight_buf_
;
164 in_flight_buf_
= NULL
;
165 temp_callback
.Run(result
);