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