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 "content/child/fileapi/file_system_dispatcher.h"
6
7 #include "base/callback.h"
8 #include "base/file_util.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/process/process.h"
11 #include "content/child/child_thread.h"
12 #include "content/common/fileapi/file_system_messages.h"
13 #include "webkit/common/fileapi/file_system_info.h"
14
15 namespace content {
16
17 class FileSystemDispatcher::CallbackDispatcher {
18 public:
19 typedef CallbackDispatcher self;
20 typedef FileSystemDispatcher::StatusCallback StatusCallback;
21 typedef FileSystemDispatcher::MetadataCallback MetadataCallback;
22 typedef FileSystemDispatcher::ReadDirectoryCallback ReadDirectoryCallback;
23 typedef FileSystemDispatcher::OpenFileSystemCallback OpenFileSystemCallback;
24 typedef FileSystemDispatcher::ResolveURLCallback ResolveURLCallback;
25 typedef FileSystemDispatcher::WriteCallback WriteCallback;
26 typedef FileSystemDispatcher::OpenFileCallback OpenFileCallback;
27
Create(const StatusCallback & callback)28 static CallbackDispatcher* Create(const StatusCallback& callback) {
29 CallbackDispatcher* dispatcher = new CallbackDispatcher;
30 dispatcher->status_callback_ = callback;
31 dispatcher->error_callback_ = callback;
32 return dispatcher;
33 }
Create(const MetadataCallback & callback,const StatusCallback & error_callback)34 static CallbackDispatcher* Create(const MetadataCallback& callback,
35 const StatusCallback& error_callback) {
36 CallbackDispatcher* dispatcher = new CallbackDispatcher;
37 dispatcher->metadata_callback_ = callback;
38 dispatcher->error_callback_ = error_callback;
39 return dispatcher;
40 }
Create(const CreateSnapshotFileCallback & callback,const StatusCallback & error_callback)41 static CallbackDispatcher* Create(const CreateSnapshotFileCallback& callback,
42 const StatusCallback& error_callback) {
43 CallbackDispatcher* dispatcher = new CallbackDispatcher;
44 dispatcher->snapshot_callback_ = callback;
45 dispatcher->error_callback_ = error_callback;
46 return dispatcher;
47 }
Create(const ReadDirectoryCallback & callback,const StatusCallback & error_callback)48 static CallbackDispatcher* Create(const ReadDirectoryCallback& callback,
49 const StatusCallback& error_callback) {
50 CallbackDispatcher* dispatcher = new CallbackDispatcher;
51 dispatcher->directory_callback_ = callback;
52 dispatcher->error_callback_ = error_callback;
53 return dispatcher;
54 }
Create(const OpenFileSystemCallback & callback,const StatusCallback & error_callback)55 static CallbackDispatcher* Create(const OpenFileSystemCallback& callback,
56 const StatusCallback& error_callback) {
57 CallbackDispatcher* dispatcher = new CallbackDispatcher;
58 dispatcher->filesystem_callback_ = callback;
59 dispatcher->error_callback_ = error_callback;
60 return dispatcher;
61 }
Create(const ResolveURLCallback & callback,const StatusCallback & error_callback)62 static CallbackDispatcher* Create(const ResolveURLCallback& callback,
63 const StatusCallback& error_callback) {
64 CallbackDispatcher* dispatcher = new CallbackDispatcher;
65 dispatcher->resolve_callback_ = callback;
66 dispatcher->error_callback_ = error_callback;
67 return dispatcher;
68 }
Create(const WriteCallback & callback,const StatusCallback & error_callback)69 static CallbackDispatcher* Create(const WriteCallback& callback,
70 const StatusCallback& error_callback) {
71 CallbackDispatcher* dispatcher = new CallbackDispatcher;
72 dispatcher->write_callback_ = callback;
73 dispatcher->error_callback_ = error_callback;
74 return dispatcher;
75 }
76
~CallbackDispatcher()77 ~CallbackDispatcher() {}
78
DidSucceed()79 void DidSucceed() {
80 status_callback_.Run(base::File::FILE_OK);
81 }
82
DidFail(base::File::Error error_code)83 void DidFail(base::File::Error error_code) {
84 error_callback_.Run(error_code);
85 }
86
DidReadMetadata(const base::File::Info & file_info)87 void DidReadMetadata(
88 const base::File::Info& file_info) {
89 metadata_callback_.Run(file_info);
90 }
91
DidCreateSnapshotFile(const base::File::Info & file_info,const base::FilePath & platform_path,int request_id)92 void DidCreateSnapshotFile(
93 const base::File::Info& file_info,
94 const base::FilePath& platform_path,
95 int request_id) {
96 snapshot_callback_.Run(file_info, platform_path, request_id);
97 }
98
DidReadDirectory(const std::vector<fileapi::DirectoryEntry> & entries,bool has_more)99 void DidReadDirectory(
100 const std::vector<fileapi::DirectoryEntry>& entries,
101 bool has_more) {
102 directory_callback_.Run(entries, has_more);
103 }
104
DidOpenFileSystem(const std::string & name,const GURL & root)105 void DidOpenFileSystem(const std::string& name,
106 const GURL& root) {
107 filesystem_callback_.Run(name, root);
108 }
109
DidResolveURL(const fileapi::FileSystemInfo & info,const base::FilePath & file_path,bool is_directory)110 void DidResolveURL(const fileapi::FileSystemInfo& info,
111 const base::FilePath& file_path,
112 bool is_directory) {
113 resolve_callback_.Run(info, file_path, is_directory);
114 }
115
DidWrite(int64 bytes,bool complete)116 void DidWrite(int64 bytes, bool complete) {
117 write_callback_.Run(bytes, complete);
118 }
119
DidOpenFile(base::PlatformFile file,int file_open_id,quota::QuotaLimitType quota_policy)120 void DidOpenFile(base::PlatformFile file,
121 int file_open_id,
122 quota::QuotaLimitType quota_policy) {
123 open_callback_.Run(file, file_open_id, quota_policy);
124 }
125
126 private:
CallbackDispatcher()127 CallbackDispatcher() {}
128
129 StatusCallback status_callback_;
130 MetadataCallback metadata_callback_;
131 CreateSnapshotFileCallback snapshot_callback_;
132 ReadDirectoryCallback directory_callback_;
133 OpenFileSystemCallback filesystem_callback_;
134 ResolveURLCallback resolve_callback_;
135 WriteCallback write_callback_;
136 OpenFileCallback open_callback_;
137
138 StatusCallback error_callback_;
139
140 DISALLOW_COPY_AND_ASSIGN(CallbackDispatcher);
141 };
142
FileSystemDispatcher()143 FileSystemDispatcher::FileSystemDispatcher() {
144 }
145
~FileSystemDispatcher()146 FileSystemDispatcher::~FileSystemDispatcher() {
147 // Make sure we fire all the remaining callbacks.
148 for (IDMap<CallbackDispatcher, IDMapOwnPointer>::iterator
149 iter(&dispatchers_); !iter.IsAtEnd(); iter.Advance()) {
150 int request_id = iter.GetCurrentKey();
151 CallbackDispatcher* dispatcher = iter.GetCurrentValue();
152 DCHECK(dispatcher);
153 dispatcher->DidFail(base::File::FILE_ERROR_ABORT);
154 dispatchers_.Remove(request_id);
155 }
156 }
157
OnMessageReceived(const IPC::Message & msg)158 bool FileSystemDispatcher::OnMessageReceived(const IPC::Message& msg) {
159 bool handled = true;
160 IPC_BEGIN_MESSAGE_MAP(FileSystemDispatcher, msg)
161 IPC_MESSAGE_HANDLER(FileSystemMsg_DidOpenFileSystem, OnDidOpenFileSystem)
162 IPC_MESSAGE_HANDLER(FileSystemMsg_DidResolveURL, OnDidResolveURL)
163 IPC_MESSAGE_HANDLER(FileSystemMsg_DidSucceed, OnDidSucceed)
164 IPC_MESSAGE_HANDLER(FileSystemMsg_DidReadDirectory, OnDidReadDirectory)
165 IPC_MESSAGE_HANDLER(FileSystemMsg_DidReadMetadata, OnDidReadMetadata)
166 IPC_MESSAGE_HANDLER(FileSystemMsg_DidCreateSnapshotFile,
167 OnDidCreateSnapshotFile)
168 IPC_MESSAGE_HANDLER(FileSystemMsg_DidFail, OnDidFail)
169 IPC_MESSAGE_HANDLER(FileSystemMsg_DidWrite, OnDidWrite)
170 IPC_MESSAGE_HANDLER(FileSystemMsg_DidOpenFile, OnDidOpenFile)
171 IPC_MESSAGE_UNHANDLED(handled = false)
172 IPC_END_MESSAGE_MAP()
173 return handled;
174 }
175
OpenFileSystem(const GURL & origin_url,fileapi::FileSystemType type,const OpenFileSystemCallback & success_callback,const StatusCallback & error_callback)176 void FileSystemDispatcher::OpenFileSystem(
177 const GURL& origin_url,
178 fileapi::FileSystemType type,
179 const OpenFileSystemCallback& success_callback,
180 const StatusCallback& error_callback) {
181 int request_id = dispatchers_.Add(
182 CallbackDispatcher::Create(success_callback, error_callback));
183 ChildThread::current()->Send(new FileSystemHostMsg_OpenFileSystem(
184 request_id, origin_url, type));
185 }
186
ResolveURL(const GURL & filesystem_url,const ResolveURLCallback & success_callback,const StatusCallback & error_callback)187 void FileSystemDispatcher::ResolveURL(
188 const GURL& filesystem_url,
189 const ResolveURLCallback& success_callback,
190 const StatusCallback& error_callback) {
191 int request_id = dispatchers_.Add(
192 CallbackDispatcher::Create(success_callback, error_callback));
193 ChildThread::current()->Send(new FileSystemHostMsg_ResolveURL(
194 request_id, filesystem_url));
195 }
196
DeleteFileSystem(const GURL & origin_url,fileapi::FileSystemType type,const StatusCallback & callback)197 void FileSystemDispatcher::DeleteFileSystem(
198 const GURL& origin_url,
199 fileapi::FileSystemType type,
200 const StatusCallback& callback) {
201 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
202 ChildThread::current()->Send(new FileSystemHostMsg_DeleteFileSystem(
203 request_id, origin_url, type));
204 }
205
Move(const GURL & src_path,const GURL & dest_path,const StatusCallback & callback)206 void FileSystemDispatcher::Move(
207 const GURL& src_path,
208 const GURL& dest_path,
209 const StatusCallback& callback) {
210 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
211 ChildThread::current()->Send(new FileSystemHostMsg_Move(
212 request_id, src_path, dest_path));
213 }
214
Copy(const GURL & src_path,const GURL & dest_path,const StatusCallback & callback)215 void FileSystemDispatcher::Copy(
216 const GURL& src_path,
217 const GURL& dest_path,
218 const StatusCallback& callback) {
219 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
220 ChildThread::current()->Send(new FileSystemHostMsg_Copy(
221 request_id, src_path, dest_path));
222 }
223
Remove(const GURL & path,bool recursive,const StatusCallback & callback)224 void FileSystemDispatcher::Remove(
225 const GURL& path,
226 bool recursive,
227 const StatusCallback& callback) {
228 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
229 ChildThread::current()->Send(
230 new FileSystemHostMsg_Remove(request_id, path, recursive));
231 }
232
ReadMetadata(const GURL & path,const MetadataCallback & success_callback,const StatusCallback & error_callback)233 void FileSystemDispatcher::ReadMetadata(
234 const GURL& path,
235 const MetadataCallback& success_callback,
236 const StatusCallback& error_callback) {
237 int request_id = dispatchers_.Add(
238 CallbackDispatcher::Create(success_callback, error_callback));
239 ChildThread::current()->Send(
240 new FileSystemHostMsg_ReadMetadata(request_id, path));
241 }
242
CreateFile(const GURL & path,bool exclusive,const StatusCallback & callback)243 void FileSystemDispatcher::CreateFile(
244 const GURL& path,
245 bool exclusive,
246 const StatusCallback& callback) {
247 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
248 ChildThread::current()->Send(new FileSystemHostMsg_Create(
249 request_id, path, exclusive,
250 false /* is_directory */, false /* recursive */));
251 }
252
CreateDirectory(const GURL & path,bool exclusive,bool recursive,const StatusCallback & callback)253 void FileSystemDispatcher::CreateDirectory(
254 const GURL& path,
255 bool exclusive,
256 bool recursive,
257 const StatusCallback& callback) {
258 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
259 ChildThread::current()->Send(new FileSystemHostMsg_Create(
260 request_id, path, exclusive, true /* is_directory */, recursive));
261 }
262
Exists(const GURL & path,bool is_directory,const StatusCallback & callback)263 void FileSystemDispatcher::Exists(
264 const GURL& path,
265 bool is_directory,
266 const StatusCallback& callback) {
267 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
268 ChildThread::current()->Send(
269 new FileSystemHostMsg_Exists(request_id, path, is_directory));
270 }
271
ReadDirectory(const GURL & path,const ReadDirectoryCallback & success_callback,const StatusCallback & error_callback)272 void FileSystemDispatcher::ReadDirectory(
273 const GURL& path,
274 const ReadDirectoryCallback& success_callback,
275 const StatusCallback& error_callback) {
276 int request_id = dispatchers_.Add(
277 CallbackDispatcher::Create(success_callback, error_callback));
278 ChildThread::current()->Send(
279 new FileSystemHostMsg_ReadDirectory(request_id, path));
280 }
281
Truncate(const GURL & path,int64 offset,int * request_id_out,const StatusCallback & callback)282 void FileSystemDispatcher::Truncate(
283 const GURL& path,
284 int64 offset,
285 int* request_id_out,
286 const StatusCallback& callback) {
287 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
288 ChildThread::current()->Send(
289 new FileSystemHostMsg_Truncate(request_id, path, offset));
290
291 if (request_id_out)
292 *request_id_out = request_id;
293 }
294
Write(const GURL & path,const std::string & blob_id,int64 offset,int * request_id_out,const WriteCallback & success_callback,const StatusCallback & error_callback)295 void FileSystemDispatcher::Write(
296 const GURL& path,
297 const std::string& blob_id,
298 int64 offset,
299 int* request_id_out,
300 const WriteCallback& success_callback,
301 const StatusCallback& error_callback) {
302 int request_id = dispatchers_.Add(
303 CallbackDispatcher::Create(success_callback, error_callback));
304 ChildThread::current()->Send(
305 new FileSystemHostMsg_Write(request_id, path, blob_id, offset));
306
307 if (request_id_out)
308 *request_id_out = request_id;
309 }
310
Cancel(int request_id_to_cancel,const StatusCallback & callback)311 void FileSystemDispatcher::Cancel(
312 int request_id_to_cancel,
313 const StatusCallback& callback) {
314 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
315 ChildThread::current()->Send(new FileSystemHostMsg_CancelWrite(
316 request_id, request_id_to_cancel));
317 }
318
TouchFile(const GURL & path,const base::Time & last_access_time,const base::Time & last_modified_time,const StatusCallback & callback)319 void FileSystemDispatcher::TouchFile(
320 const GURL& path,
321 const base::Time& last_access_time,
322 const base::Time& last_modified_time,
323 const StatusCallback& callback) {
324 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
325 ChildThread::current()->Send(
326 new FileSystemHostMsg_TouchFile(
327 request_id, path, last_access_time, last_modified_time));
328 }
329
CreateSnapshotFile(const GURL & file_path,const CreateSnapshotFileCallback & success_callback,const StatusCallback & error_callback)330 void FileSystemDispatcher::CreateSnapshotFile(
331 const GURL& file_path,
332 const CreateSnapshotFileCallback& success_callback,
333 const StatusCallback& error_callback) {
334 int request_id = dispatchers_.Add(
335 CallbackDispatcher::Create(success_callback, error_callback));
336 ChildThread::current()->Send(
337 new FileSystemHostMsg_CreateSnapshotFile(
338 request_id, file_path));
339 }
340
OnDidOpenFileSystem(int request_id,const std::string & name,const GURL & root)341 void FileSystemDispatcher::OnDidOpenFileSystem(int request_id,
342 const std::string& name,
343 const GURL& root) {
344 DCHECK(root.is_valid());
345 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
346 DCHECK(dispatcher);
347 dispatcher->DidOpenFileSystem(name, root);
348 dispatchers_.Remove(request_id);
349 }
350
OnDidResolveURL(int request_id,const fileapi::FileSystemInfo & info,const base::FilePath & file_path,bool is_directory)351 void FileSystemDispatcher::OnDidResolveURL(int request_id,
352 const fileapi::FileSystemInfo& info,
353 const base::FilePath& file_path,
354 bool is_directory) {
355 DCHECK(info.root_url.is_valid());
356 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
357 DCHECK(dispatcher);
358 dispatcher->DidResolveURL(info, file_path, is_directory);
359 dispatchers_.Remove(request_id);
360 }
361
OnDidSucceed(int request_id)362 void FileSystemDispatcher::OnDidSucceed(int request_id) {
363 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
364 DCHECK(dispatcher);
365 dispatcher->DidSucceed();
366 dispatchers_.Remove(request_id);
367 }
368
OnDidReadMetadata(int request_id,const base::File::Info & file_info)369 void FileSystemDispatcher::OnDidReadMetadata(
370 int request_id, const base::File::Info& file_info) {
371 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
372 DCHECK(dispatcher);
373 dispatcher->DidReadMetadata(file_info);
374 dispatchers_.Remove(request_id);
375 }
376
OnDidCreateSnapshotFile(int request_id,const base::File::Info & file_info,const base::FilePath & platform_path)377 void FileSystemDispatcher::OnDidCreateSnapshotFile(
378 int request_id, const base::File::Info& file_info,
379 const base::FilePath& platform_path) {
380 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
381 DCHECK(dispatcher);
382 dispatcher->DidCreateSnapshotFile(file_info, platform_path, request_id);
383 dispatchers_.Remove(request_id);
384 }
385
OnDidReadDirectory(int request_id,const std::vector<fileapi::DirectoryEntry> & entries,bool has_more)386 void FileSystemDispatcher::OnDidReadDirectory(
387 int request_id,
388 const std::vector<fileapi::DirectoryEntry>& entries,
389 bool has_more) {
390 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
391 DCHECK(dispatcher);
392 dispatcher->DidReadDirectory(entries, has_more);
393 if (!has_more)
394 dispatchers_.Remove(request_id);
395 }
396
OnDidFail(int request_id,base::File::Error error_code)397 void FileSystemDispatcher::OnDidFail(
398 int request_id, base::File::Error error_code) {
399 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
400 DCHECK(dispatcher);
401 dispatcher->DidFail(error_code);
402 dispatchers_.Remove(request_id);
403 }
404
OnDidWrite(int request_id,int64 bytes,bool complete)405 void FileSystemDispatcher::OnDidWrite(
406 int request_id, int64 bytes, bool complete) {
407 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
408 DCHECK(dispatcher);
409 dispatcher->DidWrite(bytes, complete);
410 if (complete)
411 dispatchers_.Remove(request_id);
412 }
413
OnDidOpenFile(int request_id,IPC::PlatformFileForTransit file,int file_open_id,quota::QuotaLimitType quota_policy)414 void FileSystemDispatcher::OnDidOpenFile(
415 int request_id,
416 IPC::PlatformFileForTransit file,
417 int file_open_id,
418 quota::QuotaLimitType quota_policy) {
419 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id);
420 DCHECK(dispatcher);
421 dispatcher->DidOpenFile(IPC::PlatformFileForTransitToPlatformFile(file),
422 file_open_id,
423 quota_policy);
424 dispatchers_.Remove(request_id);
425 }
426
427 } // namespace content
428