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