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