1 // Copyright (c) 2006-2008 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/disk_cache/file.h" 6 7 #include "base/file_path.h" 8 #include "base/message_loop.h" 9 #include "base/singleton.h" 10 #include "net/disk_cache/disk_cache.h" 11 12 namespace { 13 14 // Structure used for asynchronous operations. 15 struct MyOverlapped { 16 MyOverlapped(disk_cache::File* file, size_t offset, 17 disk_cache::FileIOCallback* callback); 18 ~MyOverlapped(); 19 OVERLAPPED* overlapped() { 20 return &context_.overlapped; 21 } 22 23 MessageLoopForIO::IOContext context_; 24 scoped_refptr<disk_cache::File> file_; 25 disk_cache::FileIOCallback* callback_; 26 const void* buffer_; 27 bool delete_buffer_; // Delete the user buffer at completion. 28 }; 29 30 COMPILE_ASSERT(!offsetof(MyOverlapped, context_), starts_with_overlapped); 31 32 // Helper class to handle the IO completion notifications from the message loop. 33 class CompletionHandler : public MessageLoopForIO::IOHandler { 34 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, 35 DWORD actual_bytes, DWORD error); 36 }; 37 38 void CompletionHandler::OnIOCompleted(MessageLoopForIO::IOContext* context, 39 DWORD actual_bytes, DWORD error) { 40 MyOverlapped* data = reinterpret_cast<MyOverlapped*>(context); 41 42 if (error) { 43 DCHECK(!actual_bytes); 44 actual_bytes = static_cast<DWORD>(-1); 45 NOTREACHED(); 46 } 47 48 if (data->callback_) 49 data->callback_->OnFileIOComplete(static_cast<int>(actual_bytes)); 50 51 delete data; 52 } 53 54 MyOverlapped::MyOverlapped(disk_cache::File* file, size_t offset, 55 disk_cache::FileIOCallback* callback) { 56 memset(this, 0, sizeof(*this)); 57 context_.handler = Singleton<CompletionHandler>::get(); 58 context_.overlapped.Offset = static_cast<DWORD>(offset); 59 file_ = file; 60 callback_ = callback; 61 } 62 63 MyOverlapped::~MyOverlapped() { 64 if (delete_buffer_) { 65 DCHECK(!callback_); 66 // This whole thing could be updated to use IOBuffer, but PostWrite is not 67 // used at the moment. TODO(rvargas): remove or update this code. 68 delete[] reinterpret_cast<const char*>(buffer_); 69 } 70 } 71 72 } // namespace 73 74 namespace disk_cache { 75 76 File::File(base::PlatformFile file) 77 : init_(true), mixed_(true), platform_file_(INVALID_HANDLE_VALUE), 78 sync_platform_file_(file) { 79 } 80 81 bool File::Init(const FilePath& name) { 82 DCHECK(!init_); 83 if (init_) 84 return false; 85 86 platform_file_ = CreateFile(name.value().c_str(), 87 GENERIC_READ | GENERIC_WRITE, 88 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 89 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); 90 91 if (INVALID_HANDLE_VALUE == platform_file_) 92 return false; 93 94 MessageLoopForIO::current()->RegisterIOHandler( 95 platform_file_, Singleton<CompletionHandler>::get()); 96 97 init_ = true; 98 sync_platform_file_ = CreateFile(name.value().c_str(), 99 GENERIC_READ | GENERIC_WRITE, 100 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 101 OPEN_EXISTING, 0, NULL); 102 103 if (INVALID_HANDLE_VALUE == sync_platform_file_) 104 return false; 105 106 return true; 107 } 108 109 File::~File() { 110 if (!init_) 111 return; 112 113 if (INVALID_HANDLE_VALUE != platform_file_) 114 CloseHandle(platform_file_); 115 if (INVALID_HANDLE_VALUE != sync_platform_file_) 116 CloseHandle(sync_platform_file_); 117 } 118 119 base::PlatformFile File::platform_file() const { 120 DCHECK(init_); 121 return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ : 122 platform_file_; 123 } 124 125 bool File::IsValid() const { 126 if (!init_) 127 return false; 128 return (INVALID_HANDLE_VALUE != platform_file_ || 129 INVALID_HANDLE_VALUE != sync_platform_file_); 130 } 131 132 bool File::Read(void* buffer, size_t buffer_len, size_t offset) { 133 DCHECK(init_); 134 if (buffer_len > ULONG_MAX || offset > LONG_MAX) 135 return false; 136 137 DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset), 138 NULL, FILE_BEGIN); 139 if (INVALID_SET_FILE_POINTER == ret) 140 return false; 141 142 DWORD actual; 143 DWORD size = static_cast<DWORD>(buffer_len); 144 if (!ReadFile(sync_platform_file_, buffer, size, &actual, NULL)) 145 return false; 146 return actual == size; 147 } 148 149 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) { 150 DCHECK(init_); 151 if (buffer_len > ULONG_MAX || offset > ULONG_MAX) 152 return false; 153 154 DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset), 155 NULL, FILE_BEGIN); 156 if (INVALID_SET_FILE_POINTER == ret) 157 return false; 158 159 DWORD actual; 160 DWORD size = static_cast<DWORD>(buffer_len); 161 if (!WriteFile(sync_platform_file_, buffer, size, &actual, NULL)) 162 return false; 163 return actual == size; 164 } 165 166 // We have to increase the ref counter of the file before performing the IO to 167 // prevent the completion to happen with an invalid handle (if the file is 168 // closed while the IO is in flight). 169 bool File::Read(void* buffer, size_t buffer_len, size_t offset, 170 FileIOCallback* callback, bool* completed) { 171 DCHECK(init_); 172 if (!callback) { 173 if (completed) 174 *completed = true; 175 return Read(buffer, buffer_len, offset); 176 } 177 178 if (buffer_len > ULONG_MAX || offset > ULONG_MAX) 179 return false; 180 181 MyOverlapped* data = new MyOverlapped(this, offset, callback); 182 DWORD size = static_cast<DWORD>(buffer_len); 183 184 DWORD actual; 185 if (!ReadFile(platform_file_, buffer, size, &actual, data->overlapped())) { 186 *completed = false; 187 if (GetLastError() == ERROR_IO_PENDING) 188 return true; 189 delete data; 190 return false; 191 } 192 193 // The operation completed already. We'll be called back anyway. 194 *completed = (actual == size); 195 DCHECK(actual == size); 196 data->callback_ = NULL; 197 data->file_ = NULL; // There is no reason to hold on to this anymore. 198 return *completed; 199 } 200 201 bool File::Write(const void* buffer, size_t buffer_len, size_t offset, 202 FileIOCallback* callback, bool* completed) { 203 DCHECK(init_); 204 if (!callback) { 205 if (completed) 206 *completed = true; 207 return Write(buffer, buffer_len, offset); 208 } 209 210 return AsyncWrite(buffer, buffer_len, offset, true, callback, completed); 211 } 212 213 bool File::PostWrite(const void* buffer, size_t buffer_len, size_t offset) { 214 DCHECK(init_); 215 return AsyncWrite(buffer, buffer_len, offset, false, NULL, NULL); 216 } 217 218 bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset, 219 bool notify, FileIOCallback* callback, bool* completed) { 220 DCHECK(init_); 221 if (buffer_len > ULONG_MAX || offset > ULONG_MAX) 222 return false; 223 224 MyOverlapped* data = new MyOverlapped(this, offset, callback); 225 bool dummy_completed; 226 if (!callback) { 227 DCHECK(!notify); 228 data->delete_buffer_ = true; 229 data->buffer_ = buffer; 230 completed = &dummy_completed; 231 } 232 233 DWORD size = static_cast<DWORD>(buffer_len); 234 235 DWORD actual; 236 if (!WriteFile(platform_file_, buffer, size, &actual, data->overlapped())) { 237 *completed = false; 238 if (GetLastError() == ERROR_IO_PENDING) 239 return true; 240 delete data; 241 return false; 242 } 243 244 // The operation completed already. We'll be called back anyway. 245 *completed = (actual == size); 246 DCHECK(actual == size); 247 data->callback_ = NULL; 248 data->file_ = NULL; // There is no reason to hold on to this anymore. 249 return *completed; 250 } 251 252 bool File::SetLength(size_t length) { 253 DCHECK(init_); 254 if (length > ULONG_MAX) 255 return false; 256 257 DWORD size = static_cast<DWORD>(length); 258 HANDLE file = platform_file(); 259 if (INVALID_SET_FILE_POINTER == SetFilePointer(file, size, NULL, FILE_BEGIN)) 260 return false; 261 262 return TRUE == SetEndOfFile(file); 263 } 264 265 size_t File::GetLength() { 266 DCHECK(init_); 267 LARGE_INTEGER size; 268 HANDLE file = platform_file(); 269 if (!GetFileSizeEx(file, &size)) 270 return 0; 271 if (size.HighPart) 272 return ULONG_MAX; 273 274 return static_cast<size_t>(size.LowPart); 275 } 276 277 // Static. 278 void File::WaitForPendingIO(int* num_pending_io) { 279 while (*num_pending_io) { 280 // Asynchronous IO operations may be in flight and the completion may end 281 // up calling us back so let's wait for them. 282 MessageLoopForIO::IOHandler* handler = Singleton<CompletionHandler>::get(); 283 MessageLoopForIO::current()->WaitForIOCompletion(100, handler); 284 } 285 } 286 287 } // namespace disk_cache 288