- add sources.
[platform/framework/web/crosswalk.git] / src / net / disk_cache / file_win.cc
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/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);
19   ~MyOverlapped() {}
20   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
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
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
72 File::File(base::PlatformFile file)
73     : init_(true), mixed_(true), platform_file_(INVALID_HANDLE_VALUE),
74       sync_platform_file_(file) {
75 }
76
77 bool File::Init(const base::FilePath& name) {
78   DCHECK(!init_);
79   if (init_)
80     return false;
81
82   DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
83   DWORD access = GENERIC_READ | GENERIC_WRITE | DELETE;
84   platform_file_ = CreateFile(name.value().c_str(), access, sharing, NULL,
85                               OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
86
87   if (INVALID_HANDLE_VALUE == platform_file_)
88     return false;
89
90   base::MessageLoopForIO::current()->RegisterIOHandler(
91       platform_file_, g_completion_handler.Pointer());
92
93   init_ = true;
94   sync_platform_file_  = CreateFile(name.value().c_str(), access, sharing, NULL,
95                                     OPEN_EXISTING, 0, NULL);
96
97   if (INVALID_HANDLE_VALUE == sync_platform_file_)
98     return false;
99
100   return true;
101 }
102
103 File::~File() {
104   if (!init_)
105     return;
106
107   if (INVALID_HANDLE_VALUE != platform_file_)
108     CloseHandle(platform_file_);
109   if (INVALID_HANDLE_VALUE != sync_platform_file_)
110     CloseHandle(sync_platform_file_);
111 }
112
113 base::PlatformFile File::platform_file() const {
114   DCHECK(init_);
115   return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ :
116                                                     platform_file_;
117 }
118
119 bool File::IsValid() const {
120   if (!init_)
121     return false;
122   return (INVALID_HANDLE_VALUE != platform_file_ ||
123           INVALID_HANDLE_VALUE != sync_platform_file_);
124 }
125
126 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
127   DCHECK(init_);
128   if (buffer_len > ULONG_MAX || offset > LONG_MAX)
129     return false;
130
131   DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
132                              NULL, FILE_BEGIN);
133   if (INVALID_SET_FILE_POINTER == ret)
134     return false;
135
136   DWORD actual;
137   DWORD size = static_cast<DWORD>(buffer_len);
138   if (!ReadFile(sync_platform_file_, buffer, size, &actual, NULL))
139     return false;
140   return actual == size;
141 }
142
143 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
144   DCHECK(init_);
145   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
146     return false;
147
148   DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
149                              NULL, FILE_BEGIN);
150   if (INVALID_SET_FILE_POINTER == ret)
151     return false;
152
153   DWORD actual;
154   DWORD size = static_cast<DWORD>(buffer_len);
155   if (!WriteFile(sync_platform_file_, buffer, size, &actual, NULL))
156     return false;
157   return actual == size;
158 }
159
160 // We have to increase the ref counter of the file before performing the IO to
161 // prevent the completion to happen with an invalid handle (if the file is
162 // closed while the IO is in flight).
163 bool File::Read(void* buffer, size_t buffer_len, size_t offset,
164                 FileIOCallback* callback, bool* completed) {
165   DCHECK(init_);
166   if (!callback) {
167     if (completed)
168       *completed = true;
169     return Read(buffer, buffer_len, offset);
170   }
171
172   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
173     return false;
174
175   MyOverlapped* data = new MyOverlapped(this, offset, callback);
176   DWORD size = static_cast<DWORD>(buffer_len);
177
178   DWORD actual;
179   if (!ReadFile(platform_file_, buffer, size, &actual, data->overlapped())) {
180     *completed = false;
181     if (GetLastError() == ERROR_IO_PENDING)
182       return true;
183     delete data;
184     return false;
185   }
186
187   // The operation completed already. We'll be called back anyway.
188   *completed = (actual == size);
189   DCHECK_EQ(size, actual);
190   data->callback_ = NULL;
191   data->file_ = NULL;  // There is no reason to hold on to this anymore.
192   return *completed;
193 }
194
195 bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
196                  FileIOCallback* callback, bool* completed) {
197   DCHECK(init_);
198   if (!callback) {
199     if (completed)
200       *completed = true;
201     return Write(buffer, buffer_len, offset);
202   }
203
204   return AsyncWrite(buffer, buffer_len, offset, callback, completed);
205 }
206
207 bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
208                       FileIOCallback* callback, bool* completed) {
209   DCHECK(init_);
210   DCHECK(callback);
211   DCHECK(completed);
212   if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
213     return false;
214
215   MyOverlapped* data = new MyOverlapped(this, offset, callback);
216   DWORD size = static_cast<DWORD>(buffer_len);
217
218   DWORD actual;
219   if (!WriteFile(platform_file_, buffer, size, &actual, data->overlapped())) {
220     *completed = false;
221     if (GetLastError() == ERROR_IO_PENDING)
222       return true;
223     delete data;
224     return false;
225   }
226
227   // The operation completed already. We'll be called back anyway.
228   *completed = (actual == size);
229   DCHECK_EQ(size, actual);
230   data->callback_ = NULL;
231   data->file_ = NULL;  // There is no reason to hold on to this anymore.
232   return *completed;
233 }
234
235 bool File::SetLength(size_t length) {
236   DCHECK(init_);
237   if (length > ULONG_MAX)
238     return false;
239
240   DWORD size = static_cast<DWORD>(length);
241   HANDLE file = platform_file();
242   if (INVALID_SET_FILE_POINTER == SetFilePointer(file, size, NULL, FILE_BEGIN))
243     return false;
244
245   return TRUE == SetEndOfFile(file);
246 }
247
248 size_t File::GetLength() {
249   DCHECK(init_);
250   LARGE_INTEGER size;
251   HANDLE file = platform_file();
252   if (!GetFileSizeEx(file, &size))
253     return 0;
254   if (size.HighPart)
255     return ULONG_MAX;
256
257   return static_cast<size_t>(size.LowPart);
258 }
259
260 // Static.
261 void File::WaitForPendingIO(int* num_pending_io) {
262   while (*num_pending_io) {
263     // Asynchronous IO operations may be in flight and the completion may end
264     // up calling us back so let's wait for them.
265     base::MessageLoopForIO::IOHandler* handler = g_completion_handler.Pointer();
266     base::MessageLoopForIO::current()->WaitForIOCompletion(100, handler);
267   }
268 }
269
270 }  // namespace disk_cache