• 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.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15 
16 namespace net {
17 
18 namespace {
19 
SetOffset(OVERLAPPED * overlapped,const LARGE_INTEGER & offset)20 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
21   overlapped->Offset = offset.LowPart;
22   overlapped->OffsetHigh = offset.HighPart;
23 }
24 
IncrementOffset(OVERLAPPED * overlapped,DWORD count)25 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
26   LARGE_INTEGER offset;
27   offset.LowPart = overlapped->Offset;
28   offset.HighPart = overlapped->OffsetHigh;
29   offset.QuadPart += static_cast<LONGLONG>(count);
30   SetOffset(overlapped, offset);
31 }
32 
33 }  // namespace
34 
Context(const scoped_refptr<base::TaskRunner> & task_runner)35 FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner)
36     : io_context_(),
37       async_in_progress_(false),
38       orphaned_(false),
39       task_runner_(task_runner) {
40   io_context_.handler = this;
41   memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
42 }
43 
Context(base::File file,const scoped_refptr<base::TaskRunner> & task_runner)44 FileStream::Context::Context(base::File file,
45                              const scoped_refptr<base::TaskRunner>& task_runner)
46     : io_context_(),
47       file_(file.Pass()),
48       async_in_progress_(false),
49       orphaned_(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.
55     OnFileOpened();
56   }
57 }
58 
~Context()59 FileStream::Context::~Context() {
60 }
61 
Read(IOBuffer * buf,int buf_len,const CompletionCallback & callback)62 int FileStream::Context::Read(IOBuffer* buf,
63                               int buf_len,
64                               const CompletionCallback& callback) {
65   DCHECK(!async_in_progress_);
66 
67   DWORD bytes_read;
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.
75     } else {
76       LOG(WARNING) << "ReadFile failed: " << error.os_error;
77     }
78     return error.result;
79   }
80 
81   IOCompletionIsPending(callback, buf);
82   return ERR_IO_PENDING;
83 }
84 
Write(IOBuffer * buf,int buf_len,const CompletionCallback & callback)85 int FileStream::Context::Write(IOBuffer* buf,
86                                int buf_len,
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);
94     } else {
95       LOG(WARNING) << "WriteFile failed: " << error.os_error;
96     }
97     return error.result;
98   }
99 
100   IOCompletionIsPending(callback, buf);
101   return ERR_IO_PENDING;
102 }
103 
SeekFileImpl(base::File::Whence whence,int64 offset)104 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(
105     base::File::Whence whence,
106     int64 offset) {
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);
112   }
113 
114   return IOResult::FromOSError(GetLastError());
115 }
116 
OnFileOpened()117 void FileStream::Context::OnFileOpened() {
118   base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(),
119                                                        this);
120 }
121 
IOCompletionIsPending(const CompletionCallback & callback,IOBuffer * buf)122 void FileStream::Context::IOCompletionIsPending(
123     const CompletionCallback& callback,
124     IOBuffer* buf) {
125   DCHECK(callback_.is_null());
126   callback_ = callback;
127   in_flight_buf_ = buf;  // Hold until the async operation ends.
128   async_in_progress_ = true;
129 }
130 
OnIOCompleted(base::MessageLoopForIO::IOContext * context,DWORD bytes_read,DWORD error)131 void FileStream::Context::OnIOCompleted(
132     base::MessageLoopForIO::IOContext* context,
133     DWORD bytes_read,
134     DWORD error) {
135   DCHECK_EQ(&io_context_, context);
136   DCHECK(!callback_.is_null());
137   DCHECK(async_in_progress_);
138 
139   async_in_progress_ = false;
140   if (orphaned_) {
141     callback_.Reset();
142     in_flight_buf_ = NULL;
143     CloseAndDelete();
144     return;
145   }
146 
147   int result;
148   if (error == ERROR_HANDLE_EOF) {
149     result = 0;
150   } else if (error) {
151     IOResult error_result = IOResult::FromOSError(error);
152     result = error_result.result;
153   } else {
154     result = bytes_read;
155     IncrementOffset(&io_context_.overlapped, bytes_read);
156   }
157 
158   CompletionCallback temp_callback = callback_;
159   callback_.Reset();
160   scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
161   in_flight_buf_ = NULL;
162   temp_callback.Run(result);
163 }
164 
165 }  // namespace net
166