• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/disk_cache/blockfile/file.h"
6 
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"
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__anon6c3639600111::MyOverlapped19   ~MyOverlapped() {}
overlapped__anon6c3639600111::MyOverlapped20   OVERLAPPED* overlapped() {
21     return &context_.overlapped;
22   }
23 
24   base::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 base::MessageLoopForIO::IOHandler {
33   virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
34                              DWORD actual_bytes,
35                              DWORD error);
36 };
37 
38 static base::LazyInstance<CompletionHandler> g_completion_handler =
39     LAZY_INSTANCE_INITIALIZER;
40 
OnIOCompleted(base::MessageLoopForIO::IOContext * context,DWORD actual_bytes,DWORD error)41 void CompletionHandler::OnIOCompleted(
42     base::MessageLoopForIO::IOContext* context,
43     DWORD actual_bytes,
44     DWORD error) {
45   MyOverlapped* data = reinterpret_cast<MyOverlapped*>(context);
46 
47   if (error) {
48     DCHECK(!actual_bytes);
49     actual_bytes = static_cast<DWORD>(net::ERR_CACHE_READ_FAILURE);
50     NOTREACHED();
51   }
52 
53   if (data->callback_)
54     data->callback_->OnFileIOComplete(static_cast<int>(actual_bytes));
55 
56   delete data;
57 }
58 
MyOverlapped(disk_cache::File * file,size_t offset,disk_cache::FileIOCallback * callback)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;
66 }
67 
68 }  // namespace
69 
70 namespace disk_cache {
71 
File(base::File file)72 File::File(base::File file)
73     : init_(true),
74       mixed_(true),
75       sync_base_file_(file.Pass()) {
76 }
77 
Init(const base::FilePath & name)78 bool File::Init(const base::FilePath& name) {
79   DCHECK(!init_);
80   if (init_)
81     return false;
82 
83   DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
84   DWORD access = GENERIC_READ | GENERIC_WRITE | DELETE;
85   base_file_ =
86       base::File(CreateFile(name.value().c_str(), access, sharing, NULL,
87                             OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL));
88 
89   if (!base_file_.IsValid())
90     return false;
91 
92   base::MessageLoopForIO::current()->RegisterIOHandler(
93       base_file_.GetPlatformFile(), g_completion_handler.Pointer());
94 
95   init_ = true;
96   sync_base_file_  =
97     base::File(CreateFile(name.value().c_str(), access, sharing, NULL,
98                           OPEN_EXISTING, 0, NULL));
99 
100   if (!sync_base_file_.IsValid())
101     return false;
102 
103   return true;
104 }
105 
IsValid() const106 bool File::IsValid() const {
107   if (!init_)
108     return false;
109   return base_file_.IsValid() || sync_base_file_.IsValid();
110 }
111 
Read(void * buffer,size_t buffer_len,size_t offset)112 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
113   DCHECK(init_);
114   if (buffer_len > ULONG_MAX || offset > LONG_MAX)
115     return false;
116 
117   int ret = sync_base_file_.Read(offset, static_cast<char*>(buffer),
118                                  buffer_len);
119   return static_cast<int>(buffer_len) == ret;
120 }
121 
Write(const void * buffer,size_t buffer_len,size_t offset)122 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
123   DCHECK(init_);
124   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
125     return false;
126 
127   int ret = sync_base_file_.Write(offset, static_cast<const char*>(buffer),
128                                  buffer_len);
129   return static_cast<int>(buffer_len) == ret;
130 }
131 
132 // We have to increase the ref counter of the file before performing the IO to
133 // prevent the completion to happen with an invalid handle (if the file is
134 // closed while the IO is in flight).
Read(void * buffer,size_t buffer_len,size_t offset,FileIOCallback * callback,bool * completed)135 bool File::Read(void* buffer, size_t buffer_len, size_t offset,
136                 FileIOCallback* callback, bool* completed) {
137   DCHECK(init_);
138   if (!callback) {
139     if (completed)
140       *completed = true;
141     return Read(buffer, buffer_len, offset);
142   }
143 
144   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
145     return false;
146 
147   MyOverlapped* data = new MyOverlapped(this, offset, callback);
148   DWORD size = static_cast<DWORD>(buffer_len);
149 
150   DWORD actual;
151   if (!ReadFile(base_file_.GetPlatformFile(), buffer, size, &actual,
152                 data->overlapped())) {
153     *completed = false;
154     if (GetLastError() == ERROR_IO_PENDING)
155       return true;
156     delete data;
157     return false;
158   }
159 
160   // The operation completed already. We'll be called back anyway.
161   *completed = (actual == size);
162   DCHECK_EQ(size, actual);
163   data->callback_ = NULL;
164   data->file_ = NULL;  // There is no reason to hold on to this anymore.
165   return *completed;
166 }
167 
Write(const void * buffer,size_t buffer_len,size_t offset,FileIOCallback * callback,bool * completed)168 bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
169                  FileIOCallback* callback, bool* completed) {
170   DCHECK(init_);
171   if (!callback) {
172     if (completed)
173       *completed = true;
174     return Write(buffer, buffer_len, offset);
175   }
176 
177   return AsyncWrite(buffer, buffer_len, offset, callback, completed);
178 }
179 
~File()180 File::~File() {
181 }
182 
platform_file() const183 base::PlatformFile File::platform_file() const {
184   DCHECK(init_);
185   return base_file_.IsValid() ? base_file_.GetPlatformFile() :
186                                 sync_base_file_.GetPlatformFile();
187 }
188 
AsyncWrite(const void * buffer,size_t buffer_len,size_t offset,FileIOCallback * callback,bool * completed)189 bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
190                       FileIOCallback* callback, bool* completed) {
191   DCHECK(init_);
192   DCHECK(callback);
193   DCHECK(completed);
194   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
195     return false;
196 
197   MyOverlapped* data = new MyOverlapped(this, offset, callback);
198   DWORD size = static_cast<DWORD>(buffer_len);
199 
200   DWORD actual;
201   if (!WriteFile(base_file_.GetPlatformFile(), buffer, size, &actual,
202                  data->overlapped())) {
203     *completed = false;
204     if (GetLastError() == ERROR_IO_PENDING)
205       return true;
206     delete data;
207     return false;
208   }
209 
210   // The operation completed already. We'll be called back anyway.
211   *completed = (actual == size);
212   DCHECK_EQ(size, actual);
213   data->callback_ = NULL;
214   data->file_ = NULL;  // There is no reason to hold on to this anymore.
215   return *completed;
216 }
217 
SetLength(size_t length)218 bool File::SetLength(size_t length) {
219   DCHECK(init_);
220   if (length > ULONG_MAX)
221     return false;
222 
223   DWORD size = static_cast<DWORD>(length);
224   HANDLE file = platform_file();
225   if (INVALID_SET_FILE_POINTER == SetFilePointer(file, size, NULL, FILE_BEGIN))
226     return false;
227 
228   return TRUE == SetEndOfFile(file);
229 }
230 
GetLength()231 size_t File::GetLength() {
232   DCHECK(init_);
233   LARGE_INTEGER size;
234   HANDLE file = platform_file();
235   if (!GetFileSizeEx(file, &size))
236     return 0;
237   if (size.HighPart)
238     return ULONG_MAX;
239 
240   return static_cast<size_t>(size.LowPart);
241 }
242 
243 // Static.
WaitForPendingIO(int * num_pending_io)244 void File::WaitForPendingIO(int* num_pending_io) {
245   while (*num_pending_io) {
246     // Asynchronous IO operations may be in flight and the completion may end
247     // up calling us back so let's wait for them.
248     base::MessageLoopForIO::IOHandler* handler = g_completion_handler.Pointer();
249     base::MessageLoopForIO::current()->WaitForIOCompletion(100, handler);
250   }
251 }
252 
253 // Static.
DropPendingIO()254 void File::DropPendingIO() {
255 }
256 
257 }  // namespace disk_cache
258