Home | History | Annotate | Download | only in fileapi
      1 // Copyright (c) 2013 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 STORAGE_BROWSER_FILEAPI_RECURSIVE_OPERATION_DELEGATE_H_
      6 #define STORAGE_BROWSER_FILEAPI_RECURSIVE_OPERATION_DELEGATE_H_
      7 
      8 #include <queue>
      9 #include <stack>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/callback.h"
     13 #include "base/memory/weak_ptr.h"
     14 #include "storage/browser/fileapi/file_system_operation.h"
     15 #include "storage/browser/fileapi/file_system_url.h"
     16 
     17 namespace storage {
     18 
     19 class FileSystemContext;
     20 class FileSystemOperationRunner;
     21 
     22 // A base class for recursive operation delegates.
     23 //
     24 // In short, each subclass should override ProcessFile and ProcessDirectory
     25 // to process a directory or a file. To start the recursive operation it
     26 // should also call StartRecursiveOperation.
     27 class STORAGE_EXPORT RecursiveOperationDelegate
     28     : public base::SupportsWeakPtr<RecursiveOperationDelegate> {
     29  public:
     30   typedef FileSystemOperation::StatusCallback StatusCallback;
     31   typedef FileSystemOperation::FileEntryList FileEntryList;
     32 
     33   virtual ~RecursiveOperationDelegate();
     34 
     35   // This is called when the consumer of this instance starts a non-recursive
     36   // operation.
     37   virtual void Run() = 0;
     38 
     39   // This is called when the consumer of this instance starts a recursive
     40   // operation.
     41   virtual void RunRecursively() = 0;
     42 
     43   // This is called each time a file is found while recursively
     44   // performing an operation.
     45   virtual void ProcessFile(const FileSystemURL& url,
     46                            const StatusCallback& callback) = 0;
     47 
     48   // This is called each time a directory is found while recursively
     49   // performing an operation.
     50   virtual void ProcessDirectory(const FileSystemURL& url,
     51                                 const StatusCallback& callback) = 0;
     52 
     53 
     54   // This is called each time after files and subdirectories for a
     55   // directory is processed while recursively performing an operation.
     56   virtual void PostProcessDirectory(const FileSystemURL& url,
     57                                     const StatusCallback& callback) = 0;
     58 
     59   // Cancels the currently running operation.
     60   void Cancel();
     61 
     62  protected:
     63   explicit RecursiveOperationDelegate(FileSystemContext* file_system_context);
     64 
     65   // Starts to process files/directories recursively from the given |root|.
     66   // This will call ProcessFile and ProcessDirectory on each file or directory.
     67   //
     68   // First, this tries to call ProcessFile with |root| regardless whether it is
     69   // actually a file or a directory. If it is a directory, ProcessFile should
     70   // return File::FILE_NOT_A_FILE.
     71   //
     72   // For each directory, the recursive operation works as follows:
     73   // ProcessDirectory is called first for the directory.
     74   // Then the directory contents are read (to obtain its sub directories and
     75   // files in it).
     76   // ProcessFile is called for found files. This may run in parallel.
     77   // The same step is recursively applied to each subdirectory.
     78   // After all files and subdirectories in a directory are processed,
     79   // PostProcessDirectory is called for the directory.
     80   // Here is an example;
     81   // a_dir/ -+- b1_dir/ -+- c1_dir/ -+- d1_file
     82   //         |           |           |
     83   //         |           +- c2_file  +- d2_file
     84   //         |
     85   //         +- b2_dir/ --- e_dir/
     86   //         |
     87   //         +- b3_file
     88   //         |
     89   //         +- b4_file
     90   // Then traverse order is:
     91   // ProcessFile(a_dir) (This should return File::FILE_NOT_A_FILE).
     92   // ProcessDirectory(a_dir).
     93   // ProcessFile(b3_file), ProcessFile(b4_file). (in parallel).
     94   // ProcessDirectory(b1_dir).
     95   // ProcessFile(c2_file)
     96   // ProcessDirectory(c1_dir).
     97   // ProcessFile(d1_file), ProcessFile(d2_file). (in parallel).
     98   // PostProcessDirectory(c1_dir)
     99   // PostProcessDirectory(b1_dir).
    100   // ProcessDirectory(b2_dir)
    101   // ProcessDirectory(e_dir)
    102   // PostProcessDirectory(e_dir)
    103   // PostProcessDirectory(b2_dir)
    104   // PostProcessDirectory(a_dir)
    105   //
    106   // |callback| is fired with base::File::FILE_OK when every file/directory
    107   // under |root| is processed, or fired earlier when any suboperation fails.
    108   void StartRecursiveOperation(const FileSystemURL& root,
    109                                const StatusCallback& callback);
    110 
    111   FileSystemContext* file_system_context() { return file_system_context_; }
    112   const FileSystemContext* file_system_context() const {
    113     return file_system_context_;
    114   }
    115 
    116   FileSystemOperationRunner* operation_runner();
    117 
    118   // Called when Cancel() is called. This is a hook to do something more
    119   // in a derived class. By default, do nothing.
    120   virtual void OnCancel();
    121 
    122  private:
    123   void DidTryProcessFile(const FileSystemURL& root,
    124                          base::File::Error error);
    125   void ProcessNextDirectory();
    126   void DidProcessDirectory(base::File::Error error);
    127   void DidReadDirectory(const FileSystemURL& parent,
    128                         base::File::Error error,
    129                         const FileEntryList& entries,
    130                         bool has_more);
    131   void ProcessPendingFiles();
    132   void DidProcessFile(base::File::Error error);
    133   void ProcessSubDirectory();
    134   void DidPostProcessDirectory(base::File::Error error);
    135 
    136   // Called when all recursive operation is done (or an error occurs).
    137   void Done(base::File::Error error);
    138 
    139   FileSystemContext* file_system_context_;
    140   StatusCallback callback_;
    141   std::stack<FileSystemURL> pending_directories_;
    142   std::stack<std::queue<FileSystemURL> > pending_directory_stack_;
    143   std::queue<FileSystemURL> pending_files_;
    144   int inflight_operations_;
    145   bool canceled_;
    146 
    147   DISALLOW_COPY_AND_ASSIGN(RecursiveOperationDelegate);
    148 };
    149 
    150 }  // namespace storage
    151 
    152 #endif  // STORAGE_BROWSER_FILEAPI_RECURSIVE_OPERATION_DELEGATE_H_
    153