OLD | NEW |
(Empty) | |
| 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/file_path.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/metrics/histogram.h" |
| 12 #include "base/task_runner_util.h" |
| 13 #include "base/threading/worker_pool.h" |
| 14 #include "net/base/io_buffer.h" |
| 15 #include "net/base/net_errors.h" |
| 16 |
| 17 namespace net { |
| 18 |
| 19 // Ensure that we can just use our Whence values directly. |
| 20 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin); |
| 21 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current); |
| 22 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end); |
| 23 |
| 24 namespace { |
| 25 |
| 26 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { |
| 27 overlapped->Offset = offset.LowPart; |
| 28 overlapped->OffsetHigh = offset.HighPart; |
| 29 } |
| 30 |
| 31 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) { |
| 32 LARGE_INTEGER offset; |
| 33 offset.LowPart = overlapped->Offset; |
| 34 offset.HighPart = overlapped->OffsetHigh; |
| 35 offset.QuadPart += static_cast<LONGLONG>(count); |
| 36 SetOffset(overlapped, offset); |
| 37 } |
| 38 |
| 39 } // namespace |
| 40 |
| 41 FileStream::Context::Context(const BoundNetLog& bound_net_log) |
| 42 : io_context_(), |
| 43 file_(base::kInvalidPlatformFileValue), |
| 44 record_uma_(false), |
| 45 async_in_progress_(false), |
| 46 orphaned_(false), |
| 47 bound_net_log_(bound_net_log), |
| 48 error_source_(FILE_ERROR_SOURCE_COUNT) { |
| 49 io_context_.handler = this; |
| 50 } |
| 51 |
| 52 FileStream::Context::Context(base::PlatformFile file, |
| 53 const BoundNetLog& bound_net_log, |
| 54 int open_flags) |
| 55 : io_context_(), |
| 56 file_(file), |
| 57 record_uma_(false), |
| 58 async_in_progress_(false), |
| 59 orphaned_(false), |
| 60 bound_net_log_(bound_net_log), |
| 61 error_source_(FILE_ERROR_SOURCE_COUNT) { |
| 62 io_context_.handler = this; |
| 63 if (file_ != base::kInvalidPlatformFileValue && |
| 64 (open_flags & base::PLATFORM_FILE_ASYNC)) { |
| 65 OnAsyncFileOpened(); |
| 66 } |
| 67 } |
| 68 |
| 69 FileStream::Context::~Context() { |
| 70 } |
| 71 |
| 72 int64 FileStream::Context::GetFileSize() const { |
| 73 LARGE_INTEGER file_size; |
| 74 if (!GetFileSizeEx(file_, &file_size)) { |
| 75 DWORD error = GetLastError(); |
| 76 LOG(WARNING) << "GetFileSizeEx failed: " << error; |
| 77 return RecordAndMapError(error, FILE_ERROR_SOURCE_GET_SIZE); |
| 78 } |
| 79 |
| 80 return file_size.QuadPart; |
| 81 } |
| 82 |
| 83 int FileStream::Context::ReadAsync(IOBuffer* buf, |
| 84 int buf_len, |
| 85 const CompletionCallback& callback) { |
| 86 DCHECK(!async_in_progress_); |
| 87 error_source_ = FILE_ERROR_SOURCE_READ; |
| 88 |
| 89 int rv = 0; |
| 90 |
| 91 DWORD bytes_read; |
| 92 if (!ReadFile(file_, buf->data(), buf_len, |
| 93 &bytes_read, &io_context_.overlapped)) { |
| 94 DWORD error = GetLastError(); |
| 95 if (error == ERROR_IO_PENDING) { |
| 96 IOCompletionIsPending(callback, buf); |
| 97 rv = ERR_IO_PENDING; |
| 98 } else if (error == ERROR_HANDLE_EOF) { |
| 99 rv = 0; // Report EOF by returning 0 bytes read. |
| 100 } else { |
| 101 LOG(WARNING) << "ReadFile failed: " << error; |
| 102 rv = RecordAndMapError(error, FILE_ERROR_SOURCE_READ); |
| 103 } |
| 104 } else { |
| 105 IOCompletionIsPending(callback, buf); |
| 106 rv = ERR_IO_PENDING; |
| 107 } |
| 108 return rv; |
| 109 } |
| 110 |
| 111 int FileStream::Context::ReadSync(char* buf, int buf_len) { |
| 112 int rv = 0; |
| 113 |
| 114 DWORD bytes_read; |
| 115 if (!ReadFile(file_, buf, buf_len, &bytes_read, NULL)) { |
| 116 DWORD error = GetLastError(); |
| 117 if (error == ERROR_HANDLE_EOF) { |
| 118 rv = 0; // Report EOF by returning 0 bytes read. |
| 119 } else { |
| 120 LOG(WARNING) << "ReadFile failed: " << error; |
| 121 rv = RecordAndMapError(error, FILE_ERROR_SOURCE_READ); |
| 122 } |
| 123 } else { |
| 124 rv = static_cast<int>(bytes_read); |
| 125 } |
| 126 return rv; |
| 127 } |
| 128 |
| 129 int FileStream::Context::WriteAsync(IOBuffer* buf, |
| 130 int buf_len, |
| 131 const CompletionCallback& callback) { |
| 132 error_source_ = FILE_ERROR_SOURCE_WRITE; |
| 133 |
| 134 int rv = 0; |
| 135 DWORD bytes_written = 0; |
| 136 if (!WriteFile(file_, buf->data(), buf_len, |
| 137 &bytes_written, &io_context_.overlapped)) { |
| 138 DWORD error = GetLastError(); |
| 139 if (error == ERROR_IO_PENDING) { |
| 140 IOCompletionIsPending(callback, buf); |
| 141 rv = ERR_IO_PENDING; |
| 142 } else { |
| 143 LOG(WARNING) << "WriteFile failed: " << error; |
| 144 rv = RecordAndMapError(error, FILE_ERROR_SOURCE_WRITE); |
| 145 } |
| 146 } else { |
| 147 IOCompletionIsPending(callback, buf); |
| 148 rv = ERR_IO_PENDING; |
| 149 } |
| 150 return rv; |
| 151 } |
| 152 |
| 153 int FileStream::Context::WriteSync(const char* buf, int buf_len) { |
| 154 int rv = 0; |
| 155 DWORD bytes_written = 0; |
| 156 if (!WriteFile(file_, buf, buf_len, &bytes_written, NULL)) { |
| 157 DWORD error = GetLastError(); |
| 158 LOG(WARNING) << "WriteFile failed: " << error; |
| 159 rv = RecordAndMapError(error, FILE_ERROR_SOURCE_WRITE); |
| 160 } else { |
| 161 rv = static_cast<int>(bytes_written); |
| 162 } |
| 163 return rv; |
| 164 } |
| 165 |
| 166 int FileStream::Context::Truncate(int64 bytes) { |
| 167 BOOL result = SetEndOfFile(file_); |
| 168 if (result) |
| 169 return bytes; |
| 170 |
| 171 DWORD error = GetLastError(); |
| 172 LOG(WARNING) << "SetEndOfFile failed: " << error; |
| 173 return RecordAndMapError(error, FILE_ERROR_SOURCE_SET_EOF); |
| 174 } |
| 175 |
| 176 void FileStream::Context::OnAsyncFileOpened() { |
| 177 MessageLoopForIO::current()->RegisterIOHandler(file_, this); |
| 178 } |
| 179 |
| 180 int64 FileStream::Context::SeekFileImpl(Whence whence, int64 offset) { |
| 181 LARGE_INTEGER distance, res; |
| 182 distance.QuadPart = offset; |
| 183 DWORD move_method = static_cast<DWORD>(whence); |
| 184 if (SetFilePointerEx(file_, distance, &res, move_method)) { |
| 185 SetOffset(&io_context_.overlapped, res); |
| 186 return res.QuadPart; |
| 187 } |
| 188 |
| 189 return -static_cast<int>(GetLastError()); |
| 190 } |
| 191 |
| 192 int64 FileStream::Context::FlushFileImpl() { |
| 193 if (FlushFileBuffers(file_)) |
| 194 return OK; |
| 195 |
| 196 return -static_cast<int>(GetLastError()); |
| 197 } |
| 198 |
| 199 void FileStream::Context::IOCompletionIsPending( |
| 200 const CompletionCallback& callback, |
| 201 IOBuffer* buf) { |
| 202 DCHECK(callback_.is_null()); |
| 203 callback_ = callback; |
| 204 in_flight_buf_ = buf; // Hold until the async operation ends. |
| 205 async_in_progress_ = true; |
| 206 } |
| 207 |
| 208 void FileStream::Context::OnIOCompleted(MessageLoopForIO::IOContext* context, |
| 209 DWORD bytes_read, |
| 210 DWORD error) { |
| 211 DCHECK_EQ(&io_context_, context); |
| 212 DCHECK(!callback_.is_null()); |
| 213 DCHECK(async_in_progress_); |
| 214 |
| 215 async_in_progress_ = false; |
| 216 if (orphaned_) { |
| 217 callback_.Reset(); |
| 218 in_flight_buf_ = NULL; |
| 219 CloseAndDelete(); |
| 220 return; |
| 221 } |
| 222 |
| 223 int result = static_cast<int>(bytes_read); |
| 224 if (error && error != ERROR_HANDLE_EOF) |
| 225 result = RecordAndMapError(error, error_source_); |
| 226 |
| 227 if (bytes_read) |
| 228 IncrementOffset(&io_context_.overlapped, bytes_read); |
| 229 |
| 230 CompletionCallback temp_callback = callback_; |
| 231 callback_.Reset(); |
| 232 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_; |
| 233 in_flight_buf_ = NULL; |
| 234 temp_callback.Run(result); |
| 235 } |
| 236 |
| 237 } // namespace net |
OLD | NEW |