| 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 |