1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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/containers/stack.h"
14 #include "base/files/file_path.h"
15 #include "base/macros.h"
16 #include "util/build_config.h"
17 #include "util/ticks.h"
18 
19 #if defined(OS_WIN)
20 #include <windows.h>
21 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #endif
25 
26 namespace base {
27 
28 // A class for enumerating the files in a provided path. The order of the
29 // results is not guaranteed.
30 //
31 // This is blocking. Do not use on critical threads.
32 //
33 // Example:
34 //
35 //   base::FileEnumerator enum(my_dir, false, base::FileEnumerator::FILES,
36 //                             FILE_PATH_LITERAL("*.txt"));
37 //   for (base::FilePath name = enum.Next(); !name.empty(); name = enum.Next())
38 //     ...
39 class FileEnumerator {
40  public:
41   // Note: copy & assign supported.
42   class FileInfo {
43    public:
44     FileInfo();
45     ~FileInfo();
46 
47     bool IsDirectory() const;
48 
49     // The name of the file. This will not include any path information. This
50     // is in constrast to the value returned by FileEnumerator.Next() which
51     // includes the |root_path| passed into the FileEnumerator constructor.
52     FilePath GetName() const;
53 
54     int64_t GetSize() const;
55     Ticks GetLastModifiedTime() const;
56 
57 #if defined(OS_WIN)
58     // Note that the cAlternateFileName (used to hold the "short" 8.3 name)
59     // of the WIN32_FIND_DATA will be empty. Since we don't use short file
60     // names, we tell Windows to omit it which speeds up the query slightly.
find_data()61     const WIN32_FIND_DATA& find_data() const { return find_data_; }
62 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
stat()63     const struct stat& stat() const { return stat_; }
64 #endif
65 
66    private:
67     friend class FileEnumerator;
68 
69 #if defined(OS_WIN)
70     WIN32_FIND_DATA find_data_;
71 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
72     struct stat stat_;
73     FilePath filename_;
74 #endif
75   };
76 
77   enum FileType {
78     FILES = 1 << 0,
79     DIRECTORIES = 1 << 1,
80     INCLUDE_DOT_DOT = 1 << 2,
81 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
82     SHOW_SYM_LINKS = 1 << 4,
83 #endif
84   };
85 
86   // Search policy for intermediate folders.
87   enum class FolderSearchPolicy {
88     // Recursive search will pass through folders whose names match the
89     // pattern. Inside each one, all files will be returned. Folders with names
90     // that do not match the pattern will be ignored within their interior.
91     MATCH_ONLY,
92     // Recursive search will pass through every folder and perform pattern
93     // matching inside each one.
94     ALL,
95   };
96 
97   // |root_path| is the starting directory to search for. It may or may not end
98   // in a slash.
99   //
100   // If |recursive| is true, this will enumerate all matches in any
101   // subdirectories matched as well. It does a breadth-first search, so all
102   // files in one directory will be returned before any files in a
103   // subdirectory.
104   //
105   // |file_type|, a bit mask of FileType, specifies whether the enumerator
106   // should match files, directories, or both.
107   //
108   // |pattern| is an optional pattern for which files to match. This
109   // works like shell globbing. For example, "*.txt" or "Foo???.doc".
110   // However, be careful in specifying patterns that aren't cross platform
111   // since the underlying code uses OS-specific matching routines.  In general,
112   // Windows matching is less featureful than others, so test there first.
113   // If unspecified, this will match all files.
114   FileEnumerator(const FilePath& root_path, bool recursive, int file_type);
115   FileEnumerator(const FilePath& root_path,
116                  bool recursive,
117                  int file_type,
118                  const FilePath::StringType& pattern);
119   FileEnumerator(const FilePath& root_path,
120                  bool recursive,
121                  int file_type,
122                  const FilePath::StringType& pattern,
123                  FolderSearchPolicy folder_search_policy);
124   ~FileEnumerator();
125 
126   // Returns the next file or an empty string if there are no more results.
127   //
128   // The returned path will incorporate the |root_path| passed in the
129   // constructor: "<root_path>/file_name.txt". If the |root_path| is absolute,
130   // then so will be the result of Next().
131   FilePath Next();
132 
133   // Write the file info into |info|.
134   FileInfo GetInfo() const;
135 
136  private:
137   // Returns true if the given path should be skipped in enumeration.
138   bool ShouldSkip(const FilePath& path);
139 
140   bool IsTypeMatched(bool is_dir) const;
141 
142   bool IsPatternMatched(const FilePath& src) const;
143 
144 #if defined(OS_WIN)
145   // True when find_data_ is valid.
146   bool has_find_data_ = false;
147   WIN32_FIND_DATA find_data_;
148   HANDLE find_handle_ = INVALID_HANDLE_VALUE;
149 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
150   // The files in the current directory
151   std::vector<FileInfo> directory_entries_;
152 
153   // The next entry to use from the directory_entries_ vector
154   size_t current_directory_entry_;
155 #endif
156   FilePath root_path_;
157   const bool recursive_;
158   const int file_type_;
159   FilePath::StringType pattern_;
160   const FolderSearchPolicy folder_search_policy_;
161 
162   // A stack that keeps track of which subdirectories we still need to
163   // enumerate in the breadth-first search.
164   base::stack<FilePath> pending_paths_;
165 
166   DISALLOW_COPY_AND_ASSIGN(FileEnumerator);
167 };
168 
169 }  // namespace base
170 
171 #endif  // BASE_FILES_FILE_ENUMERATOR_H_
172