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.h" 13 #include "net/base/io_buffer.h" 14 #include "net/base/net_errors.h" 15 16 namespace net { 17 18 namespace { 19 20 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { 21 overlapped->Offset = offset.LowPart; 22 overlapped->OffsetHigh = offset.HighPart; 23 } 24 25 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 } // namespace 34 35 FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner) 36 : io_context_(), 37 async_in_progress_(false), 38 orphaned_(false), 39 task_runner_(task_runner) { 40 io_context_.handler = this; 41 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped)); 42 } 43 44 FileStream::Context::Context(base::File file, 45 const scoped_refptr<base::TaskRunner>& task_runner) 46 : io_context_(), 47 file_(file.Pass()), 48 async_in_progress_(false), 49 orphaned_(false), 50 task_runner_(task_runner) { 51 io_context_.handler = this; 52 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped)); 53 if (file_.IsValid()) { 54 // TODO(hashimoto): Check that file_ is async. 55 OnFileOpened(); 56 } 57 } 58 59 FileStream::Context::~Context() { 60 } 61 62 int FileStream::Context::Read(IOBuffer* buf, 63 int buf_len, 64 const CompletionCallback& callback) { 65 DCHECK(!async_in_progress_); 66 67 DWORD bytes_read; 68 if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len, 69 &bytes_read, &io_context_.overlapped)) { 70 IOResult error = IOResult::FromOSError(GetLastError()); 71 if (error.os_error == ERROR_IO_PENDING) { 72 IOCompletionIsPending(callback, buf); 73 } else if (error.os_error == ERROR_HANDLE_EOF) { 74 return 0; // Report EOF by returning 0 bytes read. 75 } else { 76 LOG(WARNING) << "ReadFile failed: " << error.os_error; 77 } 78 return error.result; 79 } 80 81 IOCompletionIsPending(callback, buf); 82 return ERR_IO_PENDING; 83 } 84 85 int FileStream::Context::Write(IOBuffer* buf, 86 int buf_len, 87 const CompletionCallback& callback) { 88 DWORD bytes_written = 0; 89 if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len, 90 &bytes_written, &io_context_.overlapped)) { 91 IOResult error = IOResult::FromOSError(GetLastError()); 92 if (error.os_error == ERROR_IO_PENDING) { 93 IOCompletionIsPending(callback, buf); 94 } else { 95 LOG(WARNING) << "WriteFile failed: " << error.os_error; 96 } 97 return error.result; 98 } 99 100 IOCompletionIsPending(callback, buf); 101 return ERR_IO_PENDING; 102 } 103 104 FileStream::Context::IOResult FileStream::Context::SeekFileImpl( 105 base::File::Whence whence, 106 int64 offset) { 107 LARGE_INTEGER result; 108 result.QuadPart = file_.Seek(whence, offset); 109 if (result.QuadPart >= 0) { 110 SetOffset(&io_context_.overlapped, result); 111 return IOResult(result.QuadPart, 0); 112 } 113 114 return IOResult::FromOSError(GetLastError()); 115 } 116 117 void FileStream::Context::OnFileOpened() { 118 base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(), 119 this); 120 } 121 122 void FileStream::Context::IOCompletionIsPending( 123 const CompletionCallback& callback, 124 IOBuffer* buf) { 125 DCHECK(callback_.is_null()); 126 callback_ = callback; 127 in_flight_buf_ = buf; // Hold until the async operation ends. 128 async_in_progress_ = true; 129 } 130 131 void FileStream::Context::OnIOCompleted( 132 base::MessageLoopForIO::IOContext* context, 133 DWORD bytes_read, 134 DWORD error) { 135 DCHECK_EQ(&io_context_, context); 136 DCHECK(!callback_.is_null()); 137 DCHECK(async_in_progress_); 138 139 async_in_progress_ = false; 140 if (orphaned_) { 141 callback_.Reset(); 142 in_flight_buf_ = NULL; 143 CloseAndDelete(); 144 return; 145 } 146 147 int result; 148 if (error == ERROR_HANDLE_EOF) { 149 result = 0; 150 } else if (error) { 151 IOResult error_result = IOResult::FromOSError(error); 152 result = error_result.result; 153 } else { 154 result = bytes_read; 155 IncrementOffset(&io_context_.overlapped, bytes_read); 156 } 157 158 CompletionCallback temp_callback = callback_; 159 callback_.Reset(); 160 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_; 161 in_flight_buf_ = NULL; 162 temp_callback.Run(result); 163 } 164 165 } // namespace net 166