file_system_operation.h revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
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#ifndef WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_H_
6#define WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_H_
7
8#include <vector>
9
10#include "base/callback.h"
11#include "base/files/file_path.h"
12#include "base/platform_file.h"
13#include "base/process/process.h"
14#include "webkit/browser/fileapi/file_system_operation_context.h"
15#include "webkit/browser/webkit_storage_browser_export.h"
16#include "webkit/common/fileapi/directory_entry.h"
17
18namespace base {
19class Time;
20}
21
22namespace net {
23class URLRequest;
24}
25
26namespace webkit_blob {
27class ShareableFileReference;
28}
29
30class GURL;
31
32namespace fileapi {
33
34class FileSystemContext;
35class FileSystemURL;
36class FileWriterDelegate;
37
38// The interface class for FileSystemOperation implementations.
39//
40// This interface defines file system operations required to implement
41// "File API: Directories and System"
42// http://www.w3.org/TR/file-system-api/
43//
44// DESIGN NOTES
45//
46// This class is designed to
47//
48// 1) Serve one-time file system operation per instance.  Only one
49// method(CreateFile, CreateDirectory, Copy, Move, DirectoryExists,
50// GetMetadata, ReadDirectory and Remove) may be called during the
51// lifetime of this object and it should be called no more than once.
52//
53// 2) Deliver the results of operations to the client via the callback function
54// passed as the last parameter of the method.
55//
56// Note that it is valid to delete an operation while it is running.
57// The callback will NOT be fired if the operation is deleted before
58// it gets called.
59class FileSystemOperation {
60 public:
61  WEBKIT_STORAGE_BROWSER_EXPORT static FileSystemOperation* Create(
62      const FileSystemURL& url,
63      FileSystemContext* file_system_context,
64      scoped_ptr<FileSystemOperationContext> operation_context);
65
66  virtual ~FileSystemOperation() {}
67
68  // Used for CreateFile(), etc. |result| is the return code of the operation.
69  typedef base::Callback<void(base::PlatformFileError result)> StatusCallback;
70
71  // Used for GetMetadata(). |result| is the return code of the operation,
72  // |file_info| is the obtained file info.
73  typedef base::Callback<
74      void(base::PlatformFileError result,
75           const base::PlatformFileInfo& file_info)> GetMetadataCallback;
76
77  // Used for OpenFile(). |result| is the return code of the operation.
78  // |on_close_callback| will be called after the file is closed in the child
79  // process. It can be null, if no operation is needed on closing a file.
80  typedef base::Callback<
81      void(base::PlatformFileError result,
82           base::PlatformFile file,
83           const base::Closure& on_close_callback)> OpenFileCallback;
84
85  // Used for ReadDirectoryCallback.
86  typedef std::vector<DirectoryEntry> FileEntryList;
87
88  // Used for ReadDirectory(). |result| is the return code of the operation,
89  // |file_list| is the list of files read, and |has_more| is true if some files
90  // are yet to be read.
91  typedef base::Callback<
92      void(base::PlatformFileError result,
93           const FileEntryList& file_list,
94           bool has_more)> ReadDirectoryCallback;
95
96  // Used for CreateSnapshotFile(). (Please see the comment at
97  // CreateSnapshotFile() below for how the method is called)
98  // |result| is the return code of the operation.
99  // |file_info| is the metadata of the snapshot file created.
100  // |platform_path| is the path to the snapshot file created.
101  //
102  // The snapshot file could simply be of the local file pointed by the given
103  // filesystem URL in local filesystem cases; remote filesystems
104  // may want to download the file into a temporary snapshot file and then
105  // return the metadata of the temporary file.
106  //
107  // |file_ref| is used to manage the lifetime of the returned
108  // snapshot file.  It can be set to let the chromium backend take
109  // care of the life time of the snapshot file.  Otherwise (if the returned
110  // file does not require any handling) the implementation can just
111  // return NULL.  In a more complex case, the implementaiton can manage
112  // the lifetime of the snapshot file on its own (e.g. by its cache system)
113  // but also can be notified via the reference when the file becomes no
114  // longer necessary in the javascript world.
115  // Please see the comment for ShareableFileReference for details.
116  //
117  typedef base::Callback<
118      void(base::PlatformFileError result,
119           const base::PlatformFileInfo& file_info,
120           const base::FilePath& platform_path,
121           const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref)>
122          SnapshotFileCallback;
123
124  // Used for progress update callback for Copy().
125  //
126  // BEGIN_COPY_ENTRY is fired for each copy creation beginning (for both
127  // file and directory).
128  // The |source_url| is the URL of the source entry. |size| should not be
129  // used.
130  //
131  // END_COPY_ENTRY is fired for each copy creation finishing (for both
132  // file and directory).
133  // The |source_url| is the URL of the source entry. The |destination_url| is
134  // the URL of the destination entry. |size| should not be used.
135  //
136  // PROGRESS is fired periodically during file copying (not fired for
137  // directory copy).
138  // The |source_url| is the URL of the source file. |size| is the number
139  // of cumulative copied bytes for the currently copied file.
140  // Both at beginning and ending of file copying, PROGRESS event should be
141  // called. At beginning, |size| should be 0. At ending, |size| should be
142  // the size of the file.
143  //
144  // Here is an example callback sequence of recursive copy. Suppose
145  // there are a/b/c.txt (100 bytes) and a/b/d.txt (200 bytes), and trying to
146  // copy a to x recursively, then the progress update sequence will be:
147  //
148  // BEGIN_COPY_ENTRY a  (starting create "a" directory in x/).
149  // END_COPY_ENTRY a x/a (creating "a" directory in x/ is finished).
150  //
151  // BEGIN_COPY_ENTRY a/b (starting create "b" directory in x/a).
152  // END_COPY_ENTRY a/b x/a/b (creating "b" directory in x/a/ is finished).
153  //
154  // BEGIN_COPY_ENTRY a/b/c.txt (starting to copy "c.txt" in x/a/b/).
155  // PROGRESS a/b/c.txt 0 (The first PROGRESS's |size| should be 0).
156  // PROGRESS a/b/c.txt 10
157  //    :
158  // PROGRESS a/b/c.txt 90
159  // PROGRESS a/b/c.txt 100 (The last PROGRESS's |size| should be the size of
160  //                         the file).
161  // END_COPY_ENTRY a/b/c.txt x/a/b/c.txt (copying "c.txt" is finished).
162  //
163  // BEGIN_COPY_ENTRY a/b/d.txt (starting to copy "d.txt" in x/a/b).
164  // PROGRESS a/b/d.txt 0 (The first PROGRESS's |size| should be 0).
165  // PROGRESS a/b/d.txt 10
166  //    :
167  // PROGRESS a/b/d.txt 190
168  // PROGRESS a/b/d.txt 200 (The last PROGRESS's |size| should be the size of
169  //                         the file).
170  // END_COPY_ENTRY a/b/d.txt x/a/b/d.txt (copy "d.txt" is finished).
171  //
172  // Note that event sequence of a/b/c.txt and a/b/d.txt can be interlaced,
173  // because they can be done in parallel. Also PROGRESS events are optional,
174  // so they may not be appeared.
175  // All the progress callback invocation should be done before StatusCallback
176  // given to the Copy is called. Especially if an error is found before first
177  // progres callback invocation, the progress callback may NOT invoked for the
178  // copy.
179  //
180  // Note for future extension. Currently this callback is only supported on
181  // Copy(). We can extend this to Move(), because Move() is sometimes
182  // implemented as "copy then delete."
183  // In more precise, Move() usually can be implemented either 1) by updating
184  // the metadata of resource (e.g. root of moving directory tree), or 2) by
185  // copying directory tree and them removing the source tree.
186  // For 1)'s case, we can simply add BEGIN_MOVE_ENTRY and END_MOVE_ENTRY
187  // for root directory.
188  // For 2)'s case, we can add BEGIN_DELETE_ENTRY and END_DELETE_ENTRY for each
189  // entry.
190  // For both cases, we probably won't need to use PROGRESS event because
191  // these operations should be done quickly (at least much faster than copying
192  // usually).
193  enum CopyProgressType {
194    BEGIN_COPY_ENTRY,
195    END_COPY_ENTRY,
196    PROGRESS,
197  };
198  typedef base::Callback<void(CopyProgressType type,
199                              const FileSystemURL& source_url,
200                              const FileSystemURL& destination_url,
201                              int64 size)>
202      CopyProgressCallback;
203
204  // Used for CopyFileLocal() to report progress update.
205  // |size| is the cumulative copied bytes for the copy.
206  // At the beginning the progress callback should be called with |size| = 0,
207  // and also at the ending the progress callback should be called with |size|
208  // set to the copied file size.
209  typedef base::Callback<void(int64 size)> CopyFileProgressCallback;
210
211  // The option for copy or move operation.
212  enum CopyOrMoveOption {
213    // No additional operation.
214    OPTION_NONE,
215
216    // Preserves last modified time if possible. If the operation to update
217    // last modified time is not supported on the file system for the
218    // destination file, this option would be simply ignored (i.e. Copy would
219    // be successfully done without preserving last modified time).
220    OPTION_PRESERVE_LAST_MODIFIED,
221  };
222
223  // Used for Write().
224  typedef base::Callback<void(base::PlatformFileError result,
225                              int64 bytes,
226                              bool complete)> WriteCallback;
227
228  // Creates a file at |path|. If |exclusive| is true, an error is raised
229  // in case a file is already present at the URL.
230  virtual void CreateFile(const FileSystemURL& path,
231                          bool exclusive,
232                          const StatusCallback& callback) = 0;
233
234  // Creates a directory at |path|. If |exclusive| is true, an error is
235  // raised in case a directory is already present at the URL. If
236  // |recursive| is true, create parent directories as needed just like
237  // mkdir -p does.
238  virtual void CreateDirectory(const FileSystemURL& path,
239                               bool exclusive,
240                               bool recursive,
241                               const StatusCallback& callback) = 0;
242
243  // Copies a file or directory from |src_path| to |dest_path|. If
244  // |src_path| is a directory, the contents of |src_path| are copied to
245  // |dest_path| recursively. A new file or directory is created at
246  // |dest_path| as needed.
247  // |option| specifies the minor behavior of Copy(). See CopyOrMoveOption's
248  // comment for details.
249  // |progress_callback| is periodically called to report the progress
250  // update. See also the comment of CopyProgressCallback. This callback is
251  // optional.
252  //
253  // For recursive case this internally creates new FileSystemOperations and
254  // calls:
255  // - ReadDirectory, CopyFileLocal and CreateDirectory
256  //   for same-filesystem case, or
257  // - ReadDirectory and CreateSnapshotFile on source filesystem and
258  //   CopyInForeignFile and CreateDirectory on dest filesystem
259  //   for cross-filesystem case.
260  //
261  virtual void Copy(const FileSystemURL& src_path,
262                    const FileSystemURL& dest_path,
263                    CopyOrMoveOption option,
264                    const CopyProgressCallback& progress_callback,
265                    const StatusCallback& callback) = 0;
266
267  // Moves a file or directory from |src_path| to |dest_path|. A new file
268  // or directory is created at |dest_path| as needed.
269  // |option| specifies the minor behavior of Copy(). See CopyOrMoveOption's
270  // comment for details.
271  //
272  // For recursive case this internally creates new FileSystemOperations and
273  // calls:
274  // - ReadDirectory, MoveFileLocal, CreateDirectory and Remove
275  //   for same-filesystem case, or
276  // - ReadDirectory, CreateSnapshotFile and Remove on source filesystem and
277  //   CopyInForeignFile and CreateDirectory on dest filesystem
278  //   for cross-filesystem case.
279  //
280  virtual void Move(const FileSystemURL& src_path,
281                    const FileSystemURL& dest_path,
282                    CopyOrMoveOption option,
283                    const StatusCallback& callback) = 0;
284
285  // Checks if a directory is present at |path|.
286  virtual void DirectoryExists(const FileSystemURL& path,
287                               const StatusCallback& callback) = 0;
288
289  // Checks if a file is present at |path|.
290  virtual void FileExists(const FileSystemURL& path,
291                          const StatusCallback& callback) = 0;
292
293  // Gets the metadata of a file or directory at |path|.
294  virtual void GetMetadata(const FileSystemURL& path,
295                           const GetMetadataCallback& callback) = 0;
296
297  // Reads contents of a directory at |path|.
298  virtual void ReadDirectory(const FileSystemURL& path,
299                             const ReadDirectoryCallback& callback) = 0;
300
301  // Removes a file or directory at |path|. If |recursive| is true, remove
302  // all files and directories under the directory at |path| recursively.
303  virtual void Remove(const FileSystemURL& path, bool recursive,
304                      const StatusCallback& callback) = 0;
305
306  // Writes the data read from |blob_request| using |writer_delegate|.
307  virtual void Write(
308    const FileSystemURL& url,
309    scoped_ptr<FileWriterDelegate> writer_delegate,
310    scoped_ptr<net::URLRequest> blob_request,
311    const WriteCallback& callback) = 0;
312
313  // Truncates a file at |path| to |length|. If |length| is larger than
314  // the original file size, the file will be extended, and the extended
315  // part is filled with null bytes.
316  virtual void Truncate(const FileSystemURL& path, int64 length,
317                        const StatusCallback& callback) = 0;
318
319  // Tries to cancel the current operation [we support cancelling write or
320  // truncate only]. Reports failure for the current operation, then reports
321  // success for the cancel operation itself via the |cancel_dispatcher|.
322  //
323  // E.g. a typical cancel implementation would look like:
324  //
325  //   virtual void SomeOperationImpl::Cancel(
326  //       const StatusCallback& cancel_callback) {
327  //     // Abort the current inflight operation first.
328  //     ...
329  //
330  //     // Dispatch ABORT error for the current operation by invoking
331  //     // the callback function for the ongoing operation,
332  //     operation_callback.Run(base::PLATFORM_FILE_ERROR_ABORT, ...);
333  //
334  //     // Dispatch 'success' for the cancel (or dispatch appropriate
335  //     // error code with DidFail() if the cancel has somehow failed).
336  //     cancel_callback.Run(base::PLATFORM_FILE_OK);
337  //   }
338  //
339  // Note that, for reporting failure, the callback function passed to a
340  // cancellable operations are kept around with the operation instance
341  // (as |operation_callback_| in the code example).
342  virtual void Cancel(const StatusCallback& cancel_callback) = 0;
343
344  // Modifies timestamps of a file or directory at |path| with
345  // |last_access_time| and |last_modified_time|. The function DOES NOT
346  // create a file unlike 'touch' command on Linux.
347  //
348  // This function is used only by Pepper as of writing.
349  virtual void TouchFile(const FileSystemURL& path,
350                         const base::Time& last_access_time,
351                         const base::Time& last_modified_time,
352                         const StatusCallback& callback) = 0;
353
354  // Opens a file at |path| with |file_flags|, where flags are OR'ed
355  // values of base::PlatformFileFlags.
356  //
357  // This function is used only by Pepper as of writing.
358  virtual void OpenFile(const FileSystemURL& path,
359                        int file_flags,
360                        const OpenFileCallback& callback) = 0;
361
362  // Creates a local snapshot file for a given |path| and returns the
363  // metadata and platform path of the snapshot file via |callback|.
364  // In local filesystem cases the implementation may simply return
365  // the metadata of the file itself (as well as GetMetadata does),
366  // while in remote filesystem case the backend may want to download the file
367  // into a temporary snapshot file and return the metadata of the
368  // temporary file.  Or if the implementaiton already has the local cache
369  // data for |path| it can simply return the path to the cache.
370  virtual void CreateSnapshotFile(const FileSystemURL& path,
371                                  const SnapshotFileCallback& callback) = 0;
372
373  // Copies in a single file from a different filesystem.
374  //
375  // This returns:
376  // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_file_path|
377  //   or the parent directory of |dest_url| does not exist.
378  // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
379  //   is not a file.
380  // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and
381  //   its parent path is a file.
382  //
383  virtual void CopyInForeignFile(const base::FilePath& src_local_disk_path,
384                                 const FileSystemURL& dest_url,
385                                 const StatusCallback& callback) = 0;
386
387  // Removes a single file.
388  //
389  // This returns:
390  // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist.
391  // - PLATFORM_FILE_ERROR_NOT_A_FILE if |url| is not a file.
392  //
393  virtual void RemoveFile(const FileSystemURL& url,
394                          const StatusCallback& callback) = 0;
395
396  // Removes a single empty directory.
397  //
398  // This returns:
399  // - PLATFORM_FILE_ERROR_NOT_FOUND if |url| does not exist.
400  // - PLATFORM_FILE_ERROR_NOT_A_DIRECTORY if |url| is not a directory.
401  // - PLATFORM_FILE_ERROR_NOT_EMPTY if |url| is not empty.
402  //
403  virtual void RemoveDirectory(const FileSystemURL& url,
404                               const StatusCallback& callback) = 0;
405
406  // Copies a file from |src_url| to |dest_url|.
407  // This must be called for files that belong to the same filesystem
408  // (i.e. type() and origin() of the |src_url| and |dest_url| must match).
409  // |option| specifies the minor behavior of Copy(). See CopyOrMoveOption's
410  // comment for details.
411  // |progress_callback| is periodically called to report the progress
412  // update. See also the comment of CopyFileProgressCallback. This callback is
413  // optional.
414  //
415  // This returns:
416  // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url|
417  //   or the parent directory of |dest_url| does not exist.
418  // - PLATFORM_FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file.
419  // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
420  //   is not a file.
421  // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and
422  //   its parent path is a file.
423  //
424  virtual void CopyFileLocal(const FileSystemURL& src_url,
425                             const FileSystemURL& dest_url,
426                             CopyOrMoveOption option,
427                             const CopyFileProgressCallback& progress_callback,
428                             const StatusCallback& callback) = 0;
429
430  // Moves a local file from |src_url| to |dest_url|.
431  // This must be called for files that belong to the same filesystem
432  // (i.e. type() and origin() of the |src_url| and |dest_url| must match).
433  // |option| specifies the minor behavior of Copy(). See CopyOrMoveOption's
434  // comment for details.
435  //
436  // This returns:
437  // - PLATFORM_FILE_ERROR_NOT_FOUND if |src_url|
438  //   or the parent directory of |dest_url| does not exist.
439  // - PLATFORM_FILE_ERROR_NOT_A_FILE if |src_url| exists but is not a file.
440  // - PLATFORM_FILE_ERROR_INVALID_OPERATION if |dest_url| exists and
441  //   is not a file.
442  // - PLATFORM_FILE_ERROR_FAILED if |dest_url| does not exist and
443  //   its parent path is a file.
444  //
445  virtual void MoveFileLocal(const FileSystemURL& src_url,
446                             const FileSystemURL& dest_url,
447                             CopyOrMoveOption option,
448                             const StatusCallback& callback) = 0;
449
450  // Synchronously gets the platform path for the given |url|.
451  // This may fail if the given |url|'s filesystem type is neither
452  // temporary nor persistent.
453  // In such a case, base::PLATFORM_FILE_ERROR_INVALID_OPERATION will be
454  // returned.
455  virtual base::PlatformFileError SyncGetPlatformPath(
456      const FileSystemURL& url,
457      base::FilePath* platform_path) = 0;
458
459 protected:
460  // Used only for internal assertions.
461  enum OperationType {
462    kOperationNone,
463    kOperationCreateFile,
464    kOperationCreateDirectory,
465    kOperationCreateSnapshotFile,
466    kOperationCopy,
467    kOperationCopyInForeignFile,
468    kOperationMove,
469    kOperationDirectoryExists,
470    kOperationFileExists,
471    kOperationGetMetadata,
472    kOperationReadDirectory,
473    kOperationRemove,
474    kOperationWrite,
475    kOperationTruncate,
476    kOperationTouchFile,
477    kOperationOpenFile,
478    kOperationCloseFile,
479    kOperationGetLocalPath,
480    kOperationCancel,
481  };
482};
483
484}  // namespace fileapi
485
486#endif  // WEBKIT_BROWSER_FILEAPI_FILE_SYSTEM_OPERATION_H_
487