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