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
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(const std::vector<storage::DirectoryEntry>& entries,
100                        bool has_more) {
101    directory_callback_.Run(entries, has_more);
102  }
103
104  void DidOpenFileSystem(const std::string& name,
105                         const GURL& root) {
106    filesystem_callback_.Run(name, root);
107  }
108
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
115  void DidWrite(int64 bytes, bool complete) {
116    write_callback_.Run(bytes, complete);
117  }
118
119 private:
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
135FileSystemDispatcher::FileSystemDispatcher() {
136}
137
138FileSystemDispatcher::~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
150bool 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
167void 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
178void 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
188void 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
196void 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
205void 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
214void 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
223void 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
233void 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
243void 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
253void 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
262void 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
272void 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
285void 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
301void 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
309void 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
320void 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
331void 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
341void 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
352void 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
359void 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
367void 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
376void 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
387void 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
395void 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