Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / disk_cache / file_win.cc
blobf284b50104582ecf26221991d1f828578417c56f
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.
5 #include "net/disk_cache/file.h"
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"
13 namespace {
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;
24 base::MessageLoopForIO::IOContext context_;
25 scoped_refptr<disk_cache::File> file_;
26 disk_cache::FileIOCallback* callback_;
29 COMPILE_ASSERT(!offsetof(MyOverlapped, context_), starts_with_overlapped);
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);
38 static base::LazyInstance<CompletionHandler> g_completion_handler =
39 LAZY_INSTANCE_INITIALIZER;
41 void CompletionHandler::OnIOCompleted(
42 base::MessageLoopForIO::IOContext* context,
43 DWORD actual_bytes,
44 DWORD error) {
45 MyOverlapped* data = reinterpret_cast<MyOverlapped*>(context);
47 if (error) {
48 DCHECK(!actual_bytes);
49 actual_bytes = static_cast<DWORD>(net::ERR_CACHE_READ_FAILURE);
50 NOTREACHED();
53 if (data->callback_)
54 data->callback_->OnFileIOComplete(static_cast<int>(actual_bytes));
56 delete data;
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;
68 } // namespace
70 namespace disk_cache {
72 File::File(base::PlatformFile file)
73 : init_(true), mixed_(true), platform_file_(INVALID_HANDLE_VALUE),
74 sync_platform_file_(file) {
77 bool File::Init(const base::FilePath& name) {
78 DCHECK(!init_);
79 if (init_)
80 return false;
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);
87 if (INVALID_HANDLE_VALUE == platform_file_)
88 return false;
90 base::MessageLoopForIO::current()->RegisterIOHandler(
91 platform_file_, g_completion_handler.Pointer());
93 init_ = true;
94 sync_platform_file_ = CreateFile(name.value().c_str(), access, sharing, NULL,
95 OPEN_EXISTING, 0, NULL);
97 if (INVALID_HANDLE_VALUE == sync_platform_file_)
98 return false;
100 return true;
103 File::~File() {
104 if (!init_)
105 return;
107 if (INVALID_HANDLE_VALUE != platform_file_)
108 CloseHandle(platform_file_);
109 if (INVALID_HANDLE_VALUE != sync_platform_file_)
110 CloseHandle(sync_platform_file_);
113 base::PlatformFile File::platform_file() const {
114 DCHECK(init_);
115 return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ :
116 platform_file_;
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_);
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;
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;
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;
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;
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;
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;
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);
172 if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
173 return false;
175 MyOverlapped* data = new MyOverlapped(this, offset, callback);
176 DWORD size = static_cast<DWORD>(buffer_len);
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;
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;
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);
204 return AsyncWrite(buffer, buffer_len, offset, callback, completed);
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;
215 MyOverlapped* data = new MyOverlapped(this, offset, callback);
216 DWORD size = static_cast<DWORD>(buffer_len);
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;
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;
235 bool File::SetLength(size_t length) {
236 DCHECK(init_);
237 if (length > ULONG_MAX)
238 return false;
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;
245 return TRUE == SetEndOfFile(file);
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;
257 return static_cast<size_t>(size.LowPart);
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);
270 // Static.
271 void File::DropPendingIO() {
272 // Nothing to do here.
275 } // namespace disk_cache