| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef WEBKIT_BROWSER_FILEAPI_RECURSIVE_OPERATION_DELEGATE_H_ |
| #define WEBKIT_BROWSER_FILEAPI_RECURSIVE_OPERATION_DELEGATE_H_ |
| |
| #include <queue> |
| #include <stack> |
| |
| #include "base/basictypes.h" |
| #include "base/callback.h" |
| #include "base/memory/weak_ptr.h" |
| #include "webkit/browser/fileapi/file_system_operation.h" |
| #include "webkit/browser/fileapi/file_system_url.h" |
| |
| namespace fileapi { |
| |
| class FileSystemContext; |
| class FileSystemOperationRunner; |
| |
| // A base class for recursive operation delegates. |
| // |
| // In short, each subclass should override ProcessFile and ProcessDirectory |
| // to process a directory or a file. To start the recursive operation it |
| // should also call StartRecursiveOperation. |
| class WEBKIT_STORAGE_BROWSER_EXPORT RecursiveOperationDelegate |
| : public base::SupportsWeakPtr<RecursiveOperationDelegate> { |
| public: |
| typedef FileSystemOperation::StatusCallback StatusCallback; |
| typedef FileSystemOperation::FileEntryList FileEntryList; |
| |
| virtual ~RecursiveOperationDelegate(); |
| |
| // This is called when the consumer of this instance starts a non-recursive |
| // operation. |
| virtual void Run() = 0; |
| |
| // This is called when the consumer of this instance starts a recursive |
| // operation. |
| virtual void RunRecursively() = 0; |
| |
| // This is called each time a file is found while recursively |
| // performing an operation. |
| virtual void ProcessFile(const FileSystemURL& url, |
| const StatusCallback& callback) = 0; |
| |
| // This is called each time a directory is found while recursively |
| // performing an operation. |
| virtual void ProcessDirectory(const FileSystemURL& url, |
| const StatusCallback& callback) = 0; |
| |
| |
| // This is called each time after files and subdirectories for a |
| // directory is processed while recursively performing an operation. |
| virtual void PostProcessDirectory(const FileSystemURL& url, |
| const StatusCallback& callback) = 0; |
| |
| // Cancels the currently running operation. |
| void Cancel(); |
| |
| protected: |
| explicit RecursiveOperationDelegate(FileSystemContext* file_system_context); |
| |
| // Starts to process files/directories recursively from the given |root|. |
| // This will call ProcessFile and ProcessDirectory on each file or directory. |
| // |
| // First, this tries to call ProcessFile with |root| regardless whether it is |
| // actually a file or a directory. If it is a directory, ProcessFile should |
| // return File::FILE_NOT_A_FILE. |
| // |
| // For each directory, the recursive operation works as follows: |
| // ProcessDirectory is called first for the directory. |
| // Then the directory contents are read (to obtain its sub directories and |
| // files in it). |
| // ProcessFile is called for found files. This may run in parallel. |
| // The same step is recursively applied to each subdirectory. |
| // After all files and subdirectories in a directory are processed, |
| // PostProcessDirectory is called for the directory. |
| // Here is an example; |
| // a_dir/ -+- b1_dir/ -+- c1_dir/ -+- d1_file |
| // | | | |
| // | +- c2_file +- d2_file |
| // | |
| // +- b2_dir/ --- e_dir/ |
| // | |
| // +- b3_file |
| // | |
| // +- b4_file |
| // Then traverse order is: |
| // ProcessFile(a_dir) (This should return File::FILE_NOT_A_FILE). |
| // ProcessDirectory(a_dir). |
| // ProcessFile(b3_file), ProcessFile(b4_file). (in parallel). |
| // ProcessDirectory(b1_dir). |
| // ProcessFile(c2_file) |
| // ProcessDirectory(c1_dir). |
| // ProcessFile(d1_file), ProcessFile(d2_file). (in parallel). |
| // PostProcessDirectory(c1_dir) |
| // PostProcessDirectory(b1_dir). |
| // ProcessDirectory(b2_dir) |
| // ProcessDirectory(e_dir) |
| // PostProcessDirectory(e_dir) |
| // PostProcessDirectory(b2_dir) |
| // PostProcessDirectory(a_dir) |
| // |
| // |callback| is fired with base::File::FILE_OK when every file/directory |
| // under |root| is processed, or fired earlier when any suboperation fails. |
| void StartRecursiveOperation(const FileSystemURL& root, |
| const StatusCallback& callback); |
| |
| FileSystemContext* file_system_context() { return file_system_context_; } |
| const FileSystemContext* file_system_context() const { |
| return file_system_context_; |
| } |
| |
| FileSystemOperationRunner* operation_runner(); |
| |
| // Called when Cancel() is called. This is a hook to do something more |
| // in a derived class. By default, do nothing. |
| virtual void OnCancel(); |
| |
| private: |
| void DidTryProcessFile(const FileSystemURL& root, |
| base::File::Error error); |
| void ProcessNextDirectory(); |
| void DidProcessDirectory(base::File::Error error); |
| void DidReadDirectory(const FileSystemURL& parent, |
| base::File::Error error, |
| const FileEntryList& entries, |
| bool has_more); |
| void ProcessPendingFiles(); |
| void DidProcessFile(base::File::Error error); |
| void ProcessSubDirectory(); |
| void DidPostProcessDirectory(base::File::Error error); |
| |
| // Called when all recursive operation is done (or an error occurs). |
| void Done(base::File::Error error); |
| |
| FileSystemContext* file_system_context_; |
| StatusCallback callback_; |
| std::stack<FileSystemURL> pending_directories_; |
| std::stack<std::queue<FileSystemURL> > pending_directory_stack_; |
| std::queue<FileSystemURL> pending_files_; |
| int inflight_operations_; |
| bool canceled_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RecursiveOperationDelegate); |
| }; |
| |
| } // namespace fileapi |
| |
| #endif // WEBKIT_BROWSER_FILEAPI_RECURSIVE_OPERATION_DELEGATE_H_ |