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