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/blockfile/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"
15 // Structure used for asynchronous operations.
17 MyOverlapped(disk_cache::File
* file
, size_t offset
,
18 disk_cache::FileIOCallback
* callback
);
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 static_assert(offsetof(MyOverlapped
, context_
) == 0,
30 "should start with overlapped");
32 // Helper class to handle the IO completion notifications from the message loop.
33 class CompletionHandler
: public base::MessageLoopForIO::IOHandler
{
34 void OnIOCompleted(base::MessageLoopForIO::IOContext
* context
,
36 DWORD error
) override
;
39 static base::LazyInstance
<CompletionHandler
> g_completion_handler
=
40 LAZY_INSTANCE_INITIALIZER
;
42 void CompletionHandler::OnIOCompleted(
43 base::MessageLoopForIO::IOContext
* context
,
46 MyOverlapped
* data
= reinterpret_cast<MyOverlapped
*>(context
);
49 DCHECK(!actual_bytes
);
50 actual_bytes
= static_cast<DWORD
>(net::ERR_CACHE_READ_FAILURE
);
55 data
->callback_
->OnFileIOComplete(static_cast<int>(actual_bytes
));
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
);
71 namespace disk_cache
{
73 File::File(base::File file
)
76 sync_base_file_(file
.Pass()) {
79 bool File::Init(const base::FilePath
& name
) {
84 DWORD sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
85 DWORD access
= GENERIC_READ
| GENERIC_WRITE
| DELETE
;
87 base::File(CreateFile(name
.value().c_str(), access
, sharing
, NULL
,
88 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, NULL
));
90 if (!base_file_
.IsValid())
93 base::MessageLoopForIO::current()->RegisterIOHandler(
94 base_file_
.GetPlatformFile(), g_completion_handler
.Pointer());
98 base::File(CreateFile(name
.value().c_str(), access
, sharing
, NULL
,
99 OPEN_EXISTING
, 0, NULL
));
101 if (!sync_base_file_
.IsValid())
107 bool File::IsValid() const {
110 return base_file_
.IsValid() || sync_base_file_
.IsValid();
113 bool File::Read(void* buffer
, size_t buffer_len
, size_t offset
) {
115 if (buffer_len
> ULONG_MAX
|| offset
> LONG_MAX
)
118 int ret
= sync_base_file_
.Read(offset
, static_cast<char*>(buffer
),
120 return static_cast<int>(buffer_len
) == ret
;
123 bool File::Write(const void* buffer
, size_t buffer_len
, size_t offset
) {
125 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
128 int ret
= sync_base_file_
.Write(offset
, static_cast<const char*>(buffer
),
130 return static_cast<int>(buffer_len
) == ret
;
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
) {
142 return Read(buffer
, buffer_len
, offset
);
145 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
148 MyOverlapped
* data
= new MyOverlapped(this, offset
, callback
);
149 DWORD size
= static_cast<DWORD
>(buffer_len
);
152 if (!ReadFile(base_file_
.GetPlatformFile(), buffer
, size
, &actual
,
153 data
->overlapped())) {
155 if (GetLastError() == ERROR_IO_PENDING
)
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.
169 bool File::Write(const void* buffer
, size_t buffer_len
, size_t offset
,
170 FileIOCallback
* callback
, bool* completed
) {
175 return Write(buffer
, buffer_len
, offset
);
178 return AsyncWrite(buffer
, buffer_len
, offset
, callback
, completed
);
184 base::PlatformFile
File::platform_file() const {
186 return base_file_
.IsValid() ? base_file_
.GetPlatformFile() :
187 sync_base_file_
.GetPlatformFile();
190 bool File::AsyncWrite(const void* buffer
, size_t buffer_len
, size_t offset
,
191 FileIOCallback
* callback
, bool* completed
) {
195 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
198 MyOverlapped
* data
= new MyOverlapped(this, offset
, callback
);
199 DWORD size
= static_cast<DWORD
>(buffer_len
);
202 if (!WriteFile(base_file_
.GetPlatformFile(), buffer
, size
, &actual
,
203 data
->overlapped())) {
205 if (GetLastError() == ERROR_IO_PENDING
)
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.
219 bool File::SetLength(size_t length
) {
221 if (length
> ULONG_MAX
)
224 DWORD size
= static_cast<DWORD
>(length
);
225 HANDLE file
= platform_file();
226 if (INVALID_SET_FILE_POINTER
== SetFilePointer(file
, size
, NULL
, FILE_BEGIN
))
229 return TRUE
== SetEndOfFile(file
);
232 size_t File::GetLength() {
235 HANDLE file
= platform_file();
236 if (!GetFileSizeEx(file
, &size
))
241 return static_cast<size_t>(size
.LowPart
);
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
);
255 void File::DropPendingIO() {
258 } // namespace disk_cache