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
15namespace content {
16
17class 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
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  }
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  }
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  }
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  }
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  }
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  }
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
77  ~CallbackDispatcher() {}
78
79  void DidSucceed() {
80    status_callback_.Run(base::File::FILE_OK);
81  }
82
83  void DidFail(base::File::Error error_code) {
84    error_callback_.Run(error_code);
85  }
86
87  void DidReadMetadata(
88      const base::File::Info& file_info) {
89    metadata_callback_.Run(file_info);
90  }
91
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
99  void DidReadDirectory(
100      const std::vector<fileapi::DirectoryEntry>& entries,
101      bool has_more) {
102    directory_callback_.Run(entries, has_more);
103  }
104
105  void DidOpenFileSystem(const std::string& name,
106                         const GURL& root) {
107    filesystem_callback_.Run(name, root);
108  }
109
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
116  void DidWrite(int64 bytes, bool complete) {
117    write_callback_.Run(bytes, complete);
118  }
119
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:
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
143FileSystemDispatcher::FileSystemDispatcher() {
144}
145
146FileSystemDispatcher::~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
158bool 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
176void 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
187void 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
197void 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
206void 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
215void 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
224void 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
233void 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
243void 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
253void 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
263void 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
272void 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
282void 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
295void 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
311void 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
319void 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
330void 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
341void 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
351void 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
362void 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
369void 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
377void 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
386void 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
397void 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
405void 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
414void 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