• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2006-2010 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/lazy_instance.h"
9 #include "base/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);
~MyOverlapped__anonbc214d8e0111::MyOverlapped19   ~MyOverlapped() {}
overlapped__anonbc214d8e0111::MyOverlapped20   OVERLAPPED* overlapped() {
21     return &context_.overlapped;
22   }
23 
24   MessageLoopForIO::IOContext context_;
25   scoped_refptr<disk_cache::File> file_;
26   disk_cache::FileIOCallback* callback_;
27 };
28 
29 COMPILE_ASSERT(!offsetof(MyOverlapped, context_), starts_with_overlapped);
30 
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);
35 };
36 
37 static base::LazyInstance<CompletionHandler> g_completion_handler(
38     base::LINKER_INITIALIZED);
39 
OnIOCompleted(MessageLoopForIO::IOContext * context,DWORD actual_bytes,DWORD error)40 void CompletionHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
41                                       DWORD actual_bytes, DWORD error) {
42   MyOverlapped* data = reinterpret_cast<MyOverlapped*>(context);
43 
44   if (error) {
45     DCHECK(!actual_bytes);
46     actual_bytes = static_cast<DWORD>(net::ERR_CACHE_READ_FAILURE);
47     NOTREACHED();
48   }
49 
50   if (data->callback_)
51     data->callback_->OnFileIOComplete(static_cast<int>(actual_bytes));
52 
53   delete data;
54 }
55 
MyOverlapped(disk_cache::File * file,size_t offset,disk_cache::FileIOCallback * callback)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);
61   file_ = file;
62   callback_ = callback;
63 }
64 
65 }  // namespace
66 
67 namespace disk_cache {
68 
File(base::PlatformFile file)69 File::File(base::PlatformFile file)
70     : init_(true), mixed_(true), platform_file_(INVALID_HANDLE_VALUE),
71       sync_platform_file_(file) {
72 }
73 
Init(const FilePath & name)74 bool File::Init(const FilePath& name) {
75   DCHECK(!init_);
76   if (init_)
77     return false;
78 
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);
83 
84   if (INVALID_HANDLE_VALUE == platform_file_)
85     return false;
86 
87   MessageLoopForIO::current()->RegisterIOHandler(
88       platform_file_, g_completion_handler.Pointer());
89 
90   init_ = true;
91   sync_platform_file_  = CreateFile(name.value().c_str(), access, sharing, NULL,
92                                     OPEN_EXISTING, 0, NULL);
93 
94   if (INVALID_HANDLE_VALUE == sync_platform_file_)
95     return false;
96 
97   return true;
98 }
99 
~File()100 File::~File() {
101   if (!init_)
102     return;
103 
104   if (INVALID_HANDLE_VALUE != platform_file_)
105     CloseHandle(platform_file_);
106   if (INVALID_HANDLE_VALUE != sync_platform_file_)
107     CloseHandle(sync_platform_file_);
108 }
109 
platform_file() const110 base::PlatformFile File::platform_file() const {
111   DCHECK(init_);
112   return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ :
113                                                     platform_file_;
114 }
115 
IsValid() const116 bool File::IsValid() const {
117   if (!init_)
118     return false;
119   return (INVALID_HANDLE_VALUE != platform_file_ ||
120           INVALID_HANDLE_VALUE != sync_platform_file_);
121 }
122 
Read(void * buffer,size_t buffer_len,size_t offset)123 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
124   DCHECK(init_);
125   if (buffer_len > ULONG_MAX || offset > LONG_MAX)
126     return false;
127 
128   DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
129                              NULL, FILE_BEGIN);
130   if (INVALID_SET_FILE_POINTER == ret)
131     return false;
132 
133   DWORD actual;
134   DWORD size = static_cast<DWORD>(buffer_len);
135   if (!ReadFile(sync_platform_file_, buffer, size, &actual, NULL))
136     return false;
137   return actual == size;
138 }
139 
Write(const void * buffer,size_t buffer_len,size_t offset)140 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
141   DCHECK(init_);
142   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
143     return false;
144 
145   DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
146                              NULL, FILE_BEGIN);
147   if (INVALID_SET_FILE_POINTER == ret)
148     return false;
149 
150   DWORD actual;
151   DWORD size = static_cast<DWORD>(buffer_len);
152   if (!WriteFile(sync_platform_file_, buffer, size, &actual, NULL))
153     return false;
154   return actual == size;
155 }
156 
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).
Read(void * buffer,size_t buffer_len,size_t offset,FileIOCallback * callback,bool * completed)160 bool File::Read(void* buffer, size_t buffer_len, size_t offset,
161                 FileIOCallback* callback, bool* completed) {
162   DCHECK(init_);
163   if (!callback) {
164     if (completed)
165       *completed = true;
166     return Read(buffer, buffer_len, offset);
167   }
168 
169   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
170     return false;
171 
172   MyOverlapped* data = new MyOverlapped(this, offset, callback);
173   DWORD size = static_cast<DWORD>(buffer_len);
174 
175   DWORD actual;
176   if (!ReadFile(platform_file_, buffer, size, &actual, data->overlapped())) {
177     *completed = false;
178     if (GetLastError() == ERROR_IO_PENDING)
179       return true;
180     delete data;
181     return false;
182   }
183 
184   // The operation completed already. We'll be called back anyway.
185   *completed = (actual == size);
186   DCHECK(actual == size);
187   data->callback_ = NULL;
188   data->file_ = NULL;  // There is no reason to hold on to this anymore.
189   return *completed;
190 }
191 
Write(const void * buffer,size_t buffer_len,size_t offset,FileIOCallback * callback,bool * completed)192 bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
193                  FileIOCallback* callback, bool* completed) {
194   DCHECK(init_);
195   if (!callback) {
196     if (completed)
197       *completed = true;
198     return Write(buffer, buffer_len, offset);
199   }
200 
201   return AsyncWrite(buffer, buffer_len, offset, callback, completed);
202 }
203 
AsyncWrite(const void * buffer,size_t buffer_len,size_t offset,FileIOCallback * callback,bool * completed)204 bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
205                       FileIOCallback* callback, bool* completed) {
206   DCHECK(init_);
207   DCHECK(callback);
208   DCHECK(completed);
209   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
210     return false;
211 
212   MyOverlapped* data = new MyOverlapped(this, offset, callback);
213   DWORD size = static_cast<DWORD>(buffer_len);
214 
215   DWORD actual;
216   if (!WriteFile(platform_file_, buffer, size, &actual, data->overlapped())) {
217     *completed = false;
218     if (GetLastError() == ERROR_IO_PENDING)
219       return true;
220     delete data;
221     return false;
222   }
223 
224   // The operation completed already. We'll be called back anyway.
225   *completed = (actual == size);
226   DCHECK(actual == size);
227   data->callback_ = NULL;
228   data->file_ = NULL;  // There is no reason to hold on to this anymore.
229   return *completed;
230 }
231 
SetLength(size_t length)232 bool File::SetLength(size_t length) {
233   DCHECK(init_);
234   if (length > ULONG_MAX)
235     return false;
236 
237   DWORD size = static_cast<DWORD>(length);
238   HANDLE file = platform_file();
239   if (INVALID_SET_FILE_POINTER == SetFilePointer(file, size, NULL, FILE_BEGIN))
240     return false;
241 
242   return TRUE == SetEndOfFile(file);
243 }
244 
GetLength()245 size_t File::GetLength() {
246   DCHECK(init_);
247   LARGE_INTEGER size;
248   HANDLE file = platform_file();
249   if (!GetFileSizeEx(file, &size))
250     return 0;
251   if (size.HighPart)
252     return ULONG_MAX;
253 
254   return static_cast<size_t>(size.LowPart);
255 }
256 
257 // Static.
WaitForPendingIO(int * num_pending_io)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);
264   }
265 }
266 
267 }  // namespace disk_cache
268