• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/base/file_stream_context.h"
6 
7 #include <windows.h>
8 
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"
15 
16 namespace net {
17 
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);
22 
23 namespace {
24 
SetOffset(OVERLAPPED * overlapped,const LARGE_INTEGER & offset)25 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
26   overlapped->Offset = offset.LowPart;
27   overlapped->OffsetHigh = offset.HighPart;
28 }
29 
IncrementOffset(OVERLAPPED * overlapped,DWORD count)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);
36 }
37 
38 }  // namespace
39 
Context(const BoundNetLog & bound_net_log,const scoped_refptr<base::TaskRunner> & task_runner)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));
52 }
53 
Context(base::PlatformFile file,const BoundNetLog & bound_net_log,int open_flags,const scoped_refptr<base::TaskRunner> & task_runner)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();
71   }
72 }
73 
~Context()74 FileStream::Context::~Context() {
75 }
76 
GetFileSize() const77 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;
84   }
85 
86   return file_size.QuadPart;
87 }
88 
ReadAsync(IOBuffer * buf,int buf_len,const CompletionCallback & callback)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;
94 
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);
106     }
107     return error.result;
108   }
109 
110   IOCompletionIsPending(callback, buf);
111   return ERR_IO_PENDING;
112 }
113 
ReadSync(char * buf,int buf_len)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);
123     }
124     return error.result;
125   }
126 
127   return bytes_read;
128 }
129 
WriteAsync(IOBuffer * buf,int buf_len,const CompletionCallback & callback)130 int FileStream::Context::WriteAsync(IOBuffer* buf,
131                                     int buf_len,
132                                     const CompletionCallback& callback) {
133   error_source_ = FILE_ERROR_SOURCE_WRITE;
134 
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);
144     }
145     return error.result;
146   }
147 
148   IOCompletionIsPending(callback, buf);
149   return ERR_IO_PENDING;
150 }
151 
WriteSync(const char * buf,int buf_len)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;
159   }
160 
161   return bytes_written;
162 }
163 
Truncate(int64 bytes)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;
170   }
171 
172   return bytes;
173 }
174 
OnAsyncFileOpened()175 void FileStream::Context::OnAsyncFileOpened() {
176   base::MessageLoopForIO::current()->RegisterIOHandler(file_, this);
177 }
178 
SeekFileImpl(Whence whence,int64 offset)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);
187   }
188 
189   return IOResult::FromOSError(GetLastError());
190 }
191 
FlushFileImpl()192 FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
193   if (FlushFileBuffers(file_))
194     return IOResult(OK, 0);
195 
196   return IOResult::FromOSError(GetLastError());
197 }
198 
CloseFileImpl()199 FileStream::Context::IOResult FileStream::Context::CloseFileImpl() {
200   bool success = base::ClosePlatformFile(file_);
201   file_ = base::kInvalidPlatformFileValue;
202   if (success)
203     return IOResult(OK, 0);
204 
205   return IOResult::FromOSError(GetLastError());
206 }
207 
IOCompletionIsPending(const CompletionCallback & callback,IOBuffer * buf)208 void FileStream::Context::IOCompletionIsPending(
209     const CompletionCallback& callback,
210     IOBuffer* buf) {
211   DCHECK(callback_.is_null());
212   callback_ = callback;
213   in_flight_buf_ = buf;  // Hold until the async operation ends.
214   async_in_progress_ = true;
215 }
216 
OnIOCompleted(base::MessageLoopForIO::IOContext * context,DWORD bytes_read,DWORD error)217 void FileStream::Context::OnIOCompleted(
218     base::MessageLoopForIO::IOContext* context,
219     DWORD bytes_read,
220     DWORD error) {
221   DCHECK_EQ(&io_context_, context);
222   DCHECK(!callback_.is_null());
223   DCHECK(async_in_progress_);
224 
225   async_in_progress_ = false;
226   if (orphaned_) {
227     callback_.Reset();
228     in_flight_buf_ = NULL;
229     CloseAndDelete();
230     return;
231   }
232 
233   int result;
234   if (error == ERROR_HANDLE_EOF) {
235     result = 0;
236   } else if (error) {
237     IOResult error_result = IOResult::FromOSError(error);
238     RecordError(error_result, error_source_);
239     result = error_result.result;
240   } else {
241     result = bytes_read;
242     IncrementOffset(&io_context_.overlapped, bytes_read);
243   }
244 
245   CompletionCallback temp_callback = callback_;
246   callback_.Reset();
247   scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
248   in_flight_buf_ = NULL;
249   temp_callback.Run(result);
250 }
251 
252 }  // namespace net
253