File: recursive_operation_delegate.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (167 lines) | stat: -rw-r--r-- 6,593 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef STORAGE_BROWSER_FILE_SYSTEM_RECURSIVE_OPERATION_DELEGATE_H_
#define STORAGE_BROWSER_FILE_SYSTEM_RECURSIVE_OPERATION_DELEGATE_H_

#include "base/component_export.h"
#include "base/containers/queue.h"
#include "base/containers/stack.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "storage/browser/file_system/file_system_operation.h"
#include "storage/browser/file_system/file_system_url.h"

namespace storage {

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 COMPONENT_EXPORT(STORAGE_BROWSER) RecursiveOperationDelegate {
 public:
  using StatusCallback = FileSystemOperation::StatusCallback;
  using FileEntryList = FileSystemOperation::FileEntryList;
  using ErrorBehavior = FileSystemOperation::ErrorBehavior;

  RecursiveOperationDelegate(const RecursiveOperationDelegate&) = delete;
  RecursiveOperationDelegate& operator=(const RecursiveOperationDelegate&) =
      delete;

  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,
                           StatusCallback callback) = 0;

  // This is called each time a directory is found while recursively
  // performing an operation.
  virtual void ProcessDirectory(const FileSystemURL& url,
                                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,
                                    StatusCallback callback) = 0;

  // Cancels the currently running operation.
  void Cancel();

  // This should be implemented by the outermost concrete class.
  virtual base::WeakPtr<RecursiveOperationDelegate> AsWeakPtr() = 0;

 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.
  // 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).
  // ProcessDirectory(b1_dir).
  // ProcessFile(c2_file)
  // ProcessDirectory(c1_dir).
  // ProcessFile(d1_file).
  // ProcessFile(d2_file).
  // PostProcessDirectory(c1_dir)
  // PostProcessDirectory(b1_dir).
  // ProcessDirectory(b2_dir)
  // ProcessDirectory(e_dir)
  // PostProcessDirectory(e_dir)
  // PostProcessDirectory(b2_dir)
  // PostProcessDirectory(a_dir)
  //
  // `error_behavior` is to specify how this behaves when an operation have
  // failed.
  // `callback` is fired with `base::File::FILE_OK` when every file/directory
  // under `root` is processed, or fired earlier when any suboperation fails.
  //
  // For `ERROR_BEHAVIOR_SKIP`, `callback` is fired at the end of the operation
  // or when an unrecoverable error occurs. `callback` is called with the last
  // error or `base::File::FILE_OK` if no error occurred.
  void StartRecursiveOperation(const FileSystemURL& root,
                               ErrorBehavior error_behavior,
                               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 TryProcessFile(const FileSystemURL& root);
  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,
                        FileEntryList entries,
                        bool has_more);
  void ProcessPendingFiles();
  void DidProcessFile(const FileSystemURL& url, base::File::Error error);
  void ProcessSubDirectory();
  void DidPostProcessDirectory(base::File::Error error);
  void SetPreviousError(base::File::Error error);

  // Called when all recursive operation is done (or an error occurs).
  void Done(base::File::Error error);

  raw_ptr<FileSystemContext, DanglingUntriaged> file_system_context_;
  StatusCallback callback_;
  base::stack<FileSystemURL> pending_directories_;
  base::stack<base::queue<FileSystemURL>> pending_directory_stack_;
  base::queue<FileSystemURL> pending_files_;
  bool canceled_ = false;
  ErrorBehavior error_behavior_ = ErrorBehavior::ERROR_BEHAVIOR_ABORT;
  base::File::Error previous_error_ = base::File::FILE_OK;
};

}  // namespace storage

#endif  // STORAGE_BROWSER_FILE_SYSTEM_RECURSIVE_OPERATION_DELEGATE_H_