OLD | NEW |
| (Empty) |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this | |
2 // source code is governed by a BSD-style license that can be found in the | |
3 // LICENSE file. | |
4 | |
5 #include "net/base/file_input_stream.h" | |
6 | |
7 #include <windows.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/message_loop.h" | |
11 #include "net/base/net_errors.h" | |
12 | |
13 namespace net { | |
14 | |
15 // Ensure that we can just use our Whence values directly. | |
16 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin); | |
17 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current); | |
18 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end); | |
19 | |
20 static void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { | |
21 overlapped->Offset = offset.LowPart; | |
22 overlapped->OffsetHigh = offset.HighPart; | |
23 } | |
24 | |
25 static 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 static int MapErrorCode(DWORD err) { | |
34 switch (err) { | |
35 case ERROR_FILE_NOT_FOUND: | |
36 case ERROR_PATH_NOT_FOUND: | |
37 return ERR_FILE_NOT_FOUND; | |
38 case ERROR_ACCESS_DENIED: | |
39 return ERR_ACCESS_DENIED; | |
40 case ERROR_SUCCESS: | |
41 return OK; | |
42 default: | |
43 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | |
44 return ERR_FAILED; | |
45 } | |
46 } | |
47 | |
48 // FileInputStream::AsyncContext ---------------------------------------------- | |
49 | |
50 class FileInputStream::AsyncContext : public MessageLoopForIO::IOHandler { | |
51 public: | |
52 AsyncContext(FileInputStream* owner) | |
53 : owner_(owner), overlapped_(), callback_(NULL) { | |
54 overlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | |
55 } | |
56 | |
57 ~AsyncContext() { | |
58 if (callback_) | |
59 MessageLoopForIO::current()->RegisterIOContext(&overlapped_, NULL); | |
60 CloseHandle(overlapped_.hEvent); | |
61 } | |
62 | |
63 void IOCompletionIsPending(CompletionCallback* callback); | |
64 | |
65 OVERLAPPED* overlapped() { return &overlapped_; } | |
66 CompletionCallback* callback() const { return callback_; } | |
67 | |
68 private: | |
69 // MessageLoopForIO::IOHandler implementation: | |
70 virtual void OnIOCompleted(OVERLAPPED* context, DWORD bytes_read, | |
71 DWORD error); | |
72 | |
73 FileInputStream* owner_; | |
74 OVERLAPPED overlapped_; | |
75 CompletionCallback* callback_; | |
76 }; | |
77 | |
78 void FileInputStream::AsyncContext::IOCompletionIsPending( | |
79 CompletionCallback* callback) { | |
80 DCHECK(!callback_); | |
81 callback_ = callback; | |
82 | |
83 MessageLoopForIO::current()->RegisterIOContext(&overlapped_, this); | |
84 } | |
85 | |
86 void FileInputStream::AsyncContext::OnIOCompleted(OVERLAPPED* context, | |
87 DWORD bytes_read, | |
88 DWORD error) { | |
89 DCHECK(&overlapped_ == context); | |
90 DCHECK(callback_); | |
91 | |
92 MessageLoopForIO::current()->RegisterIOContext(&overlapped_, NULL); | |
93 | |
94 HANDLE handle = owner_->handle_; | |
95 | |
96 int result = static_cast<int>(bytes_read); | |
97 if (error && error != ERROR_HANDLE_EOF) | |
98 result = MapErrorCode(error); | |
99 | |
100 if (bytes_read) | |
101 IncrementOffset(&overlapped_, bytes_read); | |
102 | |
103 CompletionCallback* temp = NULL; | |
104 std::swap(temp, callback_); | |
105 temp->Run(result); | |
106 } | |
107 | |
108 // FileInputStream ------------------------------------------------------------ | |
109 | |
110 FileInputStream::FileInputStream() : handle_(INVALID_HANDLE_VALUE) { | |
111 } | |
112 | |
113 FileInputStream::~FileInputStream() { | |
114 Close(); | |
115 } | |
116 | |
117 void FileInputStream::Close() { | |
118 if (handle_ != INVALID_HANDLE_VALUE) { | |
119 CloseHandle(handle_); | |
120 handle_ = INVALID_HANDLE_VALUE; | |
121 } | |
122 async_context_.reset(); | |
123 } | |
124 | |
125 int FileInputStream::Open(const std::wstring& path, bool asynchronous_mode) { | |
126 if (IsOpen()) { | |
127 DLOG(FATAL) << "File is already open!"; | |
128 return ERR_UNEXPECTED; | |
129 } | |
130 | |
131 // Optimize for streaming, not seeking. If someone does a lot of random | |
132 // access operations, then we should consider revising this. | |
133 DWORD create_file_flags = FILE_FLAG_SEQUENTIAL_SCAN; | |
134 | |
135 if (asynchronous_mode) | |
136 create_file_flags |= FILE_FLAG_OVERLAPPED; | |
137 | |
138 handle_ = | |
139 CreateFile(path.c_str(), GENERIC_READ | SYNCHRONIZE, | |
140 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
141 NULL, OPEN_EXISTING, create_file_flags, NULL); | |
142 if (handle_ == INVALID_HANDLE_VALUE) { | |
143 DWORD error = GetLastError(); | |
144 LOG(WARNING) << "Failed to open file: " << error; | |
145 return MapErrorCode(error); | |
146 } | |
147 | |
148 if (asynchronous_mode) { | |
149 async_context_.reset(new AsyncContext(this)); | |
150 MessageLoopForIO::current()->RegisterIOHandler(handle_, | |
151 async_context_.get()); | |
152 } | |
153 | |
154 return OK; | |
155 } | |
156 | |
157 bool FileInputStream::IsOpen() const { | |
158 return handle_ != INVALID_HANDLE_VALUE; | |
159 } | |
160 | |
161 int64 FileInputStream::Seek(Whence whence, int64 offset) { | |
162 if (!IsOpen()) | |
163 return ERR_UNEXPECTED; | |
164 DCHECK(!async_context_.get() || !async_context_->callback()); | |
165 | |
166 LARGE_INTEGER distance, result; | |
167 distance.QuadPart = offset; | |
168 DWORD move_method = static_cast<DWORD>(whence); | |
169 if (!SetFilePointerEx(handle_, distance, &result, move_method)) { | |
170 DWORD error = GetLastError(); | |
171 LOG(WARNING) << "SetFilePointerEx failed: " << error; | |
172 return MapErrorCode(error); | |
173 } | |
174 if (async_context_.get()) | |
175 SetOffset(async_context_->overlapped(), result); | |
176 return result.QuadPart; | |
177 } | |
178 | |
179 int64 FileInputStream::Available() { | |
180 if (!IsOpen()) | |
181 return ERR_UNEXPECTED; | |
182 | |
183 int64 cur_pos = Seek(FROM_CURRENT, 0); | |
184 if (cur_pos < 0) | |
185 return cur_pos; | |
186 | |
187 LARGE_INTEGER file_size; | |
188 if (!GetFileSizeEx(handle_, &file_size)) { | |
189 DWORD error = GetLastError(); | |
190 LOG(WARNING) << "GetFileSizeEx failed: " << error; | |
191 return MapErrorCode(error); | |
192 } | |
193 | |
194 return file_size.QuadPart - cur_pos; | |
195 } | |
196 | |
197 int FileInputStream::Read( | |
198 char* buf, int buf_len, CompletionCallback* callback) { | |
199 if (!IsOpen()) | |
200 return ERR_UNEXPECTED; | |
201 | |
202 OVERLAPPED* overlapped = NULL; | |
203 if (async_context_.get()) { | |
204 DCHECK(!async_context_->callback()); | |
205 overlapped = async_context_->overlapped(); | |
206 } | |
207 | |
208 int rv; | |
209 | |
210 DWORD bytes_read; | |
211 if (!ReadFile(handle_, buf, buf_len, &bytes_read, overlapped)) { | |
212 DWORD error = GetLastError(); | |
213 if (async_context_.get() && error == ERROR_IO_PENDING) { | |
214 async_context_->IOCompletionIsPending(callback); | |
215 rv = ERR_IO_PENDING; | |
216 } else if (error == ERROR_HANDLE_EOF) { | |
217 rv = 0; // Report EOF by returning 0 bytes read. | |
218 } else { | |
219 LOG(WARNING) << "ReadFile failed: " << error; | |
220 rv = MapErrorCode(error); | |
221 } | |
222 } else { | |
223 if (overlapped) | |
224 IncrementOffset(overlapped, bytes_read); | |
225 rv = static_cast<int>(bytes_read); | |
226 } | |
227 return rv; | |
228 } | |
229 | |
230 } // namespace net | |
OLD | NEW |