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