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