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