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