xref: /aosp_15_r20/external/cronet/base/files/file_enumerator.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
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 BASE_FILES_FILE_ENUMERATOR_H_
6 #define BASE_FILES_FILE_ENUMERATOR_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <vector>
12 
13 #include "base/base_export.h"
14 #include "base/containers/stack.h"
15 #include "base/files/file.h"
16 #include "base/files/file_path.h"
17 #include "base/functional/function_ref.h"
18 #include "base/time/time.h"
19 #include "build/build_config.h"
20 
21 #if BUILDFLAG(IS_WIN)
22 #include "base/win/windows_types.h"
23 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <unordered_set>
27 #endif
28 
29 namespace base {
30 
31 // A class for enumerating the files in a provided path. The order of the
32 // results is not guaranteed.
33 //
34 // This is blocking. Do not use on critical threads.
35 //
36 // Example:
37 //
38 //   base::FileEnumerator e(my_dir, false, base::FileEnumerator::FILES,
39 //                          FILE_PATH_LITERAL("*.txt"));
40 // Using `ForEach` with a lambda:
41 //   e.ForEach([](const base::FilePath& item) {...});
42 // Using a `for` loop:
43 //   for (base::FilePath name = e.Next(); !name.empty(); name = e.Next())
44 //     ...
45 class BASE_EXPORT FileEnumerator {
46  public:
47   // Note: copy & assign supported.
48   class BASE_EXPORT FileInfo {
49    public:
50     FileInfo();
51     ~FileInfo();
52 
53     bool IsDirectory() const;
54 
55     // The name of the file. This will not include any path information. This
56     // is in constrast to the value returned by FileEnumerator.Next() which
57     // includes the |root_path| passed into the FileEnumerator constructor.
58     FilePath GetName() const;
59 
60     int64_t GetSize() const;
61 
62     // On POSIX systems, this is rounded down to the second.
63     Time GetLastModifiedTime() const;
64 
65 #if BUILDFLAG(IS_WIN)
66     // Note that the cAlternateFileName (used to hold the "short" 8.3 name)
67     // of the WIN32_FIND_DATA will be empty. Since we don't use short file
68     // names, we tell Windows to omit it which speeds up the query slightly.
find_data()69     const WIN32_FIND_DATA& find_data() const {
70       return *ChromeToWindowsType(&find_data_);
71     }
72 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
stat()73     const stat_wrapper_t& stat() const { return stat_; }
74 #endif
75 
76    private:
77     friend class FileEnumerator;
78 
79 #if BUILDFLAG(IS_WIN)
80     CHROME_WIN32_FIND_DATA find_data_;
81 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
82     stat_wrapper_t stat_;
83     FilePath filename_;
84 #endif
85   };
86 
87   enum FileType {
88     FILES = 1 << 0,
89     DIRECTORIES = 1 << 1,
90     INCLUDE_DOT_DOT = 1 << 2,
91 
92     // Report only the names of entries and not their type, size, or
93     // last-modified time. May only be used for non-recursive enumerations, and
94     // implicitly includes both files and directories (neither of which may be
95     // specified). When used, an enumerator's `GetInfo()` method must not be
96     // called.
97     NAMES_ONLY = 1 << 3,
98 
99 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
100     SHOW_SYM_LINKS = 1 << 4,
101 #endif
102   };
103 
104   // Search policy for intermediate folders.
105   enum class FolderSearchPolicy {
106     // Recursive search will pass through folders whose names match the
107     // pattern. Inside each one, all files will be returned. Folders with names
108     // that do not match the pattern will be ignored within their interior.
109     MATCH_ONLY,
110     // Recursive search will pass through every folder and perform pattern
111     // matching inside each one.
112     ALL,
113   };
114 
115   // Determines how a FileEnumerator handles errors encountered during
116   // enumeration. When no ErrorPolicy is explicitly set, FileEnumerator defaults
117   // to IGNORE_ERRORS.
118   enum class ErrorPolicy {
119     // Errors are ignored if possible and FileEnumerator returns as many files
120     // as it is able to enumerate.
121     IGNORE_ERRORS,
122 
123     // Any error encountered during enumeration will terminate the enumeration
124     // immediately. An error code indicating the nature of a failure can be
125     // retrieved from |GetError()|.
126     STOP_ENUMERATION,
127   };
128 
129   // |root_path| is the starting directory to search for. It may or may not end
130   // in a slash.
131   //
132   // If |recursive| is true, this will enumerate all matches in any
133   // subdirectories matched as well. It does a breadth-first search, so all
134   // files in one directory will be returned before any files in a
135   // subdirectory.
136   //
137   // |file_type|, a bit mask of FileType, specifies whether the enumerator
138   // should match files, directories, or both.
139   //
140   // |pattern| is an optional pattern for which files to match. This
141   // works like shell globbing. For example, "*.txt" or "Foo???.doc".
142   // However, be careful in specifying patterns that aren't cross platform
143   // since the underlying code uses OS-specific matching routines.  In general,
144   // Windows matching is less featureful than others, so test there first.
145   // If unspecified, this will match all files.
146   //
147   // |folder_search_policy| optionally specifies a search behavior. Refer to
148   // |FolderSearchPolicy| for a list of folder search policies and the meaning
149   // of them. If |recursive| is false, this parameter has no effect.
150   //
151   // |error_policy| optionally specifies the behavior when an error occurs.
152   // Refer to |ErrorPolicy| for a list of error policies and the meaning of
153   // them.
154   FileEnumerator(const FilePath& root_path, bool recursive, int file_type);
155   FileEnumerator(const FilePath& root_path,
156                  bool recursive,
157                  int file_type,
158                  const FilePath::StringType& pattern);
159   FileEnumerator(const FilePath& root_path,
160                  bool recursive,
161                  int file_type,
162                  const FilePath::StringType& pattern,
163                  FolderSearchPolicy folder_search_policy);
164   FileEnumerator(const FilePath& root_path,
165                  bool recursive,
166                  int file_type,
167                  const FilePath::StringType& pattern,
168                  FolderSearchPolicy folder_search_policy,
169                  ErrorPolicy error_policy);
170   FileEnumerator(const FileEnumerator&) = delete;
171   FileEnumerator& operator=(const FileEnumerator&) = delete;
172   ~FileEnumerator();
173 
174   // Calls `ref` synchronously for each path found by the `FileEnumerator`. Each
175   // path will incorporate the `root_path` passed in the constructor:
176   // "<root_path>/file_name.txt". If the `root_path` is absolute, then so will
177   // be the paths provided in the `ref` invocations.
178   void ForEach(FunctionRef<void(const FilePath& path)> ref);
179 
180   // Returns the next file or an empty string if there are no more results.
181   //
182   // The returned path will incorporate the |root_path| passed in the
183   // constructor: "<root_path>/file_name.txt". If the |root_path| is absolute,
184   // then so will be the result of Next().
185   FilePath Next();
186 
187   // Returns info about the file last returned by Next(). Note that on Windows
188   // and Fuchsia, GetInfo() does not play well with INCLUDE_DOT_DOT. In
189   // particular, the GetLastModifiedTime() for the .. directory is 1601-01-01
190   // on Fuchsia (https://crbug.com/1106172) and is equal to the last modified
191   // time of the current directory on Windows (https://crbug.com/1119546).
192   // Must not be used with FileType::NAMES_ONLY.
193   FileInfo GetInfo() const;
194 
195   // Once |Next()| returns an empty path, enumeration has been terminated. If
196   // termination was normal (i.e. no more results to enumerate) or ErrorPolicy
197   // is set to IGNORE_ERRORS, this returns FILE_OK. Otherwise it returns an
198   // error code reflecting why enumeration was stopped early.
GetError()199   File::Error GetError() const { return error_; }
200 
201  private:
202   // Returns true if the given path should be skipped in enumeration.
203   bool ShouldSkip(const FilePath& path);
204 
205   bool IsTypeMatched(bool is_dir) const;
206 
207   bool IsPatternMatched(const FilePath& src) const;
208 
209 #if BUILDFLAG(IS_WIN)
find_data()210   const WIN32_FIND_DATA& find_data() const {
211     return *ChromeToWindowsType(&find_data_);
212   }
213 
214   // True when find_data_ is valid.
215   bool has_find_data_ = false;
216   CHROME_WIN32_FIND_DATA find_data_;
217   HANDLE find_handle_ = INVALID_HANDLE_VALUE;
218 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
219   // The files in the current directory
220   std::vector<FileInfo> directory_entries_;
221 
222   // Set of visited directories. Used to prevent infinite looping along
223   // circular symlinks.
224   // The Android NDK (r23) does not declare `st_ino` as an `ino_t`, hence the
225   // need for the ugly decltype.
226   std::unordered_set<decltype(stat_wrapper_t::st_ino)> visited_directories_;
227 
228   // The next entry to use from the directory_entries_ vector
229   size_t current_directory_entry_;
230 #endif
231   FilePath root_path_;
232   const bool recursive_;
233   int file_type_;
234   FilePath::StringType pattern_;
235   const FolderSearchPolicy folder_search_policy_;
236   const ErrorPolicy error_policy_;
237   File::Error error_ = File::FILE_OK;
238 
239   // A stack that keeps track of which subdirectories we still need to
240   // enumerate in the breadth-first search.
241   base::stack<FilePath> pending_paths_;
242 };
243 
244 }  // namespace base
245 
246 #endif  // BASE_FILES_FILE_ENUMERATOR_H_
247