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