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.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 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 MessageLoopForIO::IOHandler
{
33 virtual void OnIOCompleted(MessageLoopForIO::IOContext
* context
,
34 DWORD actual_bytes
, DWORD error
);
37 static base::LazyInstance
<CompletionHandler
> g_completion_handler
=
38 LAZY_INSTANCE_INITIALIZER
;
40 void CompletionHandler::OnIOCompleted(MessageLoopForIO::IOContext
* context
,
41 DWORD actual_bytes
, DWORD error
) {
42 MyOverlapped
* data
= reinterpret_cast<MyOverlapped
*>(context
);
45 DCHECK(!actual_bytes
);
46 actual_bytes
= static_cast<DWORD
>(net::ERR_CACHE_READ_FAILURE
);
51 data
->callback_
->OnFileIOComplete(static_cast<int>(actual_bytes
));
56 MyOverlapped::MyOverlapped(disk_cache::File
* file
, size_t offset
,
57 disk_cache::FileIOCallback
* callback
) {
58 memset(this, 0, sizeof(*this));
59 context_
.handler
= g_completion_handler
.Pointer();
60 context_
.overlapped
.Offset
= static_cast<DWORD
>(offset
);
67 namespace disk_cache
{
69 File::File(base::PlatformFile file
)
70 : init_(true), mixed_(true), platform_file_(INVALID_HANDLE_VALUE
),
71 sync_platform_file_(file
) {
74 bool File::Init(const base::FilePath
& name
) {
79 DWORD sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
80 DWORD access
= GENERIC_READ
| GENERIC_WRITE
| DELETE
;
81 platform_file_
= CreateFile(name
.value().c_str(), access
, sharing
, NULL
,
82 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, NULL
);
84 if (INVALID_HANDLE_VALUE
== platform_file_
)
87 MessageLoopForIO::current()->RegisterIOHandler(
88 platform_file_
, g_completion_handler
.Pointer());
91 sync_platform_file_
= CreateFile(name
.value().c_str(), access
, sharing
, NULL
,
92 OPEN_EXISTING
, 0, NULL
);
94 if (INVALID_HANDLE_VALUE
== sync_platform_file_
)
104 if (INVALID_HANDLE_VALUE
!= platform_file_
)
105 CloseHandle(platform_file_
);
106 if (INVALID_HANDLE_VALUE
!= sync_platform_file_
)
107 CloseHandle(sync_platform_file_
);
110 base::PlatformFile
File::platform_file() const {
112 return (INVALID_HANDLE_VALUE
== platform_file_
) ? sync_platform_file_
:
116 bool File::IsValid() const {
119 return (INVALID_HANDLE_VALUE
!= platform_file_
||
120 INVALID_HANDLE_VALUE
!= sync_platform_file_
);
123 bool File::Read(void* buffer
, size_t buffer_len
, size_t offset
) {
125 if (buffer_len
> ULONG_MAX
|| offset
> LONG_MAX
)
128 DWORD ret
= SetFilePointer(sync_platform_file_
, static_cast<LONG
>(offset
),
130 if (INVALID_SET_FILE_POINTER
== ret
)
134 DWORD size
= static_cast<DWORD
>(buffer_len
);
135 if (!ReadFile(sync_platform_file_
, buffer
, size
, &actual
, NULL
))
137 return actual
== size
;
140 bool File::Write(const void* buffer
, size_t buffer_len
, size_t offset
) {
142 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
145 DWORD ret
= SetFilePointer(sync_platform_file_
, static_cast<LONG
>(offset
),
147 if (INVALID_SET_FILE_POINTER
== ret
)
151 DWORD size
= static_cast<DWORD
>(buffer_len
);
152 if (!WriteFile(sync_platform_file_
, buffer
, size
, &actual
, NULL
))
154 return actual
== size
;
157 // We have to increase the ref counter of the file before performing the IO to
158 // prevent the completion to happen with an invalid handle (if the file is
159 // closed while the IO is in flight).
160 bool File::Read(void* buffer
, size_t buffer_len
, size_t offset
,
161 FileIOCallback
* callback
, bool* completed
) {
166 return Read(buffer
, buffer_len
, offset
);
169 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
172 MyOverlapped
* data
= new MyOverlapped(this, offset
, callback
);
173 DWORD size
= static_cast<DWORD
>(buffer_len
);
176 if (!ReadFile(platform_file_
, buffer
, size
, &actual
, data
->overlapped())) {
178 if (GetLastError() == ERROR_IO_PENDING
)
184 // The operation completed already. We'll be called back anyway.
185 *completed
= (actual
== size
);
186 DCHECK_EQ(size
, actual
);
187 data
->callback_
= NULL
;
188 data
->file_
= NULL
; // There is no reason to hold on to this anymore.
192 bool File::Write(const void* buffer
, size_t buffer_len
, size_t offset
,
193 FileIOCallback
* callback
, bool* completed
) {
198 return Write(buffer
, buffer_len
, offset
);
201 return AsyncWrite(buffer
, buffer_len
, offset
, callback
, completed
);
204 bool File::AsyncWrite(const void* buffer
, size_t buffer_len
, size_t offset
,
205 FileIOCallback
* callback
, bool* completed
) {
209 if (buffer_len
> ULONG_MAX
|| offset
> ULONG_MAX
)
212 MyOverlapped
* data
= new MyOverlapped(this, offset
, callback
);
213 DWORD size
= static_cast<DWORD
>(buffer_len
);
216 if (!WriteFile(platform_file_
, buffer
, size
, &actual
, data
->overlapped())) {
218 if (GetLastError() == ERROR_IO_PENDING
)
224 // The operation completed already. We'll be called back anyway.
225 *completed
= (actual
== size
);
226 DCHECK_EQ(size
, actual
);
227 data
->callback_
= NULL
;
228 data
->file_
= NULL
; // There is no reason to hold on to this anymore.
232 bool File::SetLength(size_t length
) {
234 if (length
> ULONG_MAX
)
237 DWORD size
= static_cast<DWORD
>(length
);
238 HANDLE file
= platform_file();
239 if (INVALID_SET_FILE_POINTER
== SetFilePointer(file
, size
, NULL
, FILE_BEGIN
))
242 return TRUE
== SetEndOfFile(file
);
245 size_t File::GetLength() {
248 HANDLE file
= platform_file();
249 if (!GetFileSizeEx(file
, &size
))
254 return static_cast<size_t>(size
.LowPart
);
258 void File::WaitForPendingIO(int* num_pending_io
) {
259 while (*num_pending_io
) {
260 // Asynchronous IO operations may be in flight and the completion may end
261 // up calling us back so let's wait for them.
262 MessageLoopForIO::IOHandler
* handler
= g_completion_handler
.Pointer();
263 MessageLoopForIO::current()->WaitForIOCompletion(100, handler
);
268 void File::DropPendingIO() {
269 // Nothing to do here.
272 } // namespace disk_cache