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