Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(256)

Side by Side Diff: base/files/file_enumerator_win.cc

Issue 2892173003: Add recursive pattern matching for subfolders in file_enumerator. (Closed)
Patch Set: Add recursive pattern matching for subfolders in file_enumerator Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/files/file_enumerator_unittest.cc ('k') | chrome_elf/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/files/file_enumerator.h" 5 #include "base/files/file_enumerator.h"
6 6
7 #include <shlwapi.h>
7 #include <stdint.h> 8 #include <stdint.h>
8 #include <string.h> 9 #include <string.h>
9 10
10 #include "base/logging.h" 11 #include "base/logging.h"
11 #include "base/threading/thread_restrictions.h" 12 #include "base/threading/thread_restrictions.h"
12 13
13 namespace base { 14 namespace base {
14 15
16 namespace {
17
18 FilePath BuildSearchFilter(FileEnumerator::FolderSearchPolicy policy,
19 const FilePath& root_path,
20 const FilePath::StringType& pattern) {
21 // MATCH_ONLY policy filters incoming files by pattern on OS side. ALL policy
22 // collects all files and filters them manually.
23 switch (policy) {
24 case FileEnumerator::FolderSearchPolicy::MATCH_ONLY:
25 return root_path.Append(pattern);
26 case FileEnumerator::FolderSearchPolicy::ALL:
27 return root_path.Append(L"*");
28 }
29 NOTREACHED();
30 return {};
31 }
32
33 } // namespace
34
15 // FileEnumerator::FileInfo ---------------------------------------------------- 35 // FileEnumerator::FileInfo ----------------------------------------------------
16 36
17 FileEnumerator::FileInfo::FileInfo() { 37 FileEnumerator::FileInfo::FileInfo() {
18 memset(&find_data_, 0, sizeof(find_data_)); 38 memset(&find_data_, 0, sizeof(find_data_));
19 } 39 }
20 40
21 bool FileEnumerator::FileInfo::IsDirectory() const { 41 bool FileEnumerator::FileInfo::IsDirectory() const {
22 return (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; 42 return (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
23 } 43 }
24 44
(...skipping 12 matching lines...) Expand all
37 57
38 base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const { 58 base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
39 return base::Time::FromFileTime(find_data_.ftLastWriteTime); 59 return base::Time::FromFileTime(find_data_.ftLastWriteTime);
40 } 60 }
41 61
42 // FileEnumerator -------------------------------------------------------------- 62 // FileEnumerator --------------------------------------------------------------
43 63
44 FileEnumerator::FileEnumerator(const FilePath& root_path, 64 FileEnumerator::FileEnumerator(const FilePath& root_path,
45 bool recursive, 65 bool recursive,
46 int file_type) 66 int file_type)
47 : has_find_data_(false), 67 : FileEnumerator(root_path,
48 find_handle_(INVALID_HANDLE_VALUE), 68 recursive,
49 recursive_(recursive), 69 file_type,
50 file_type_(file_type) { 70 FilePath::StringType(),
51 // INCLUDE_DOT_DOT must not be specified if recursive. 71 FolderSearchPolicy::MATCH_ONLY) {}
52 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
53 memset(&find_data_, 0, sizeof(find_data_));
54 pending_paths_.push(root_path);
55 }
56 72
57 FileEnumerator::FileEnumerator(const FilePath& root_path, 73 FileEnumerator::FileEnumerator(const FilePath& root_path,
58 bool recursive, 74 bool recursive,
59 int file_type, 75 int file_type,
60 const FilePath::StringType& pattern) 76 const FilePath::StringType& pattern)
61 : has_find_data_(false), 77 : FileEnumerator(root_path,
62 find_handle_(INVALID_HANDLE_VALUE), 78 recursive,
63 recursive_(recursive), 79 file_type,
80 pattern,
81 FolderSearchPolicy::MATCH_ONLY) {}
82
83 FileEnumerator::FileEnumerator(const FilePath& root_path,
84 bool recursive,
85 int file_type,
86 const FilePath::StringType& pattern,
87 FolderSearchPolicy folder_search_policy)
88 : recursive_(recursive),
64 file_type_(file_type), 89 file_type_(file_type),
65 pattern_(pattern) { 90 pattern_(!pattern.empty() ? pattern : L"*"),
91 folder_search_policy_(folder_search_policy) {
66 // INCLUDE_DOT_DOT must not be specified if recursive. 92 // INCLUDE_DOT_DOT must not be specified if recursive.
67 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 93 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
68 memset(&find_data_, 0, sizeof(find_data_)); 94 memset(&find_data_, 0, sizeof(find_data_));
69 pending_paths_.push(root_path); 95 pending_paths_.push(root_path);
70 } 96 }
71 97
72 FileEnumerator::~FileEnumerator() { 98 FileEnumerator::~FileEnumerator() {
73 if (find_handle_ != INVALID_HANDLE_VALUE) 99 if (find_handle_ != INVALID_HANDLE_VALUE)
74 FindClose(find_handle_); 100 FindClose(find_handle_);
75 } 101 }
(...skipping 11 matching lines...) Expand all
87 FilePath FileEnumerator::Next() { 113 FilePath FileEnumerator::Next() {
88 base::ThreadRestrictions::AssertIOAllowed(); 114 base::ThreadRestrictions::AssertIOAllowed();
89 115
90 while (has_find_data_ || !pending_paths_.empty()) { 116 while (has_find_data_ || !pending_paths_.empty()) {
91 if (!has_find_data_) { 117 if (!has_find_data_) {
92 // The last find FindFirstFile operation is done, prepare a new one. 118 // The last find FindFirstFile operation is done, prepare a new one.
93 root_path_ = pending_paths_.top(); 119 root_path_ = pending_paths_.top();
94 pending_paths_.pop(); 120 pending_paths_.pop();
95 121
96 // Start a new find operation. 122 // Start a new find operation.
97 FilePath src = root_path_; 123 const FilePath src =
98 124 BuildSearchFilter(folder_search_policy_, root_path_, pattern_);
99 if (pattern_.empty())
100 src = src.Append(L"*"); // No pattern = match everything.
101 else
102 src = src.Append(pattern_);
103
104 // Use a "large fetch" which should speed up large enumerations (we seldom
105 // abort in the middle).
106 find_handle_ = FindFirstFileEx(src.value().c_str(), 125 find_handle_ = FindFirstFileEx(src.value().c_str(),
107 FindExInfoBasic, // Omit short name. 126 FindExInfoBasic, // Omit short name.
108 &find_data_, 127 &find_data_, FindExSearchNameMatch,
109 FindExSearchNameMatch, 128 nullptr, FIND_FIRST_EX_LARGE_FETCH);
110 NULL,
111 FIND_FIRST_EX_LARGE_FETCH);
112 has_find_data_ = true; 129 has_find_data_ = true;
113 } else { 130 } else {
114 // Search for the next file/directory. 131 // Search for the next file/directory.
115 if (!FindNextFile(find_handle_, &find_data_)) { 132 if (!FindNextFile(find_handle_, &find_data_)) {
116 FindClose(find_handle_); 133 FindClose(find_handle_);
117 find_handle_ = INVALID_HANDLE_VALUE; 134 find_handle_ = INVALID_HANDLE_VALUE;
118 } 135 }
119 } 136 }
120 137
121 if (INVALID_HANDLE_VALUE == find_handle_) { 138 if (INVALID_HANDLE_VALUE == find_handle_) {
122 has_find_data_ = false; 139 has_find_data_ = false;
123 140
124 // This is reached when we have finished a directory and are advancing to 141 // MATCH_ONLY policy clears pattern for matched subfolders. ALL policy
125 // the next one in the queue. We applied the pattern (if any) to the files 142 // applies pattern for all subfolders.
126 // in the root search directory, but for those directories which were 143 if (folder_search_policy_ == FolderSearchPolicy::MATCH_ONLY) {
127 // matched, we want to enumerate all files inside them. This will happen 144 // This is reached when we have finished a directory and are advancing
128 // when the handle is empty. 145 // to the next one in the queue. We applied the pattern (if any) to the
129 pattern_ = FilePath::StringType(); 146 // files in the root search directory, but for those directories which
147 // were matched, we want to enumerate all files inside them. This will
148 // happen when the handle is empty.
149 pattern_ = L"*";
150 }
130 151
131 continue; 152 continue;
132 } 153 }
133 154
134 FilePath cur_file(find_data_.cFileName); 155 const FilePath filename(find_data_.cFileName);
135 if (ShouldSkip(cur_file)) 156 if (ShouldSkip(filename))
136 continue; 157 continue;
137 158
138 // Construct the absolute filename. 159 const bool is_dir =
139 cur_file = root_path_.Append(find_data_.cFileName); 160 (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
161 const FilePath abs_path = root_path_.Append(filename);
140 162
141 if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 163 // Check if directory should be processed recursive.
142 if (recursive_) { 164 if (is_dir && recursive_) {
143 // If |cur_file| is a directory, and we are doing recursive searching, 165 // If |cur_file| is a directory, and we are doing recursive searching,
144 // add it to pending_paths_ so we scan it after we finish scanning this 166 // add it to pending_paths_ so we scan it after we finish scanning this
145 // directory. However, don't do recursion through reparse points or we 167 // directory. However, don't do recursion through reparse points or we
146 // may end up with an infinite cycle. 168 // may end up with an infinite cycle.
147 DWORD attributes = GetFileAttributes(cur_file.value().c_str()); 169 DWORD attributes = GetFileAttributes(abs_path.value().c_str());
148 if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT)) 170 if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT))
149 pending_paths_.push(cur_file); 171 pending_paths_.push(abs_path);
150 }
151 if (file_type_ & FileEnumerator::DIRECTORIES)
152 return cur_file;
153 } else if (file_type_ & FileEnumerator::FILES) {
154 return cur_file;
155 } 172 }
173
174 if (IsTypeMatched(is_dir) && IsPatternMatched(filename))
175 return abs_path;
156 } 176 }
157
158 return FilePath(); 177 return FilePath();
159 } 178 }
160 179
180 bool FileEnumerator::IsPatternMatched(const FilePath& src) const {
181 switch (folder_search_policy_) {
182 case FolderSearchPolicy::MATCH_ONLY:
183 // MATCH_ONLY policy filters by pattern on search request, so all found
184 // files already fits to pattern.
185 return true;
186 case FolderSearchPolicy::ALL:
187 // ALL policy enumerates all files, we need to check pattern match
188 // manually.
189 return PathMatchSpec(src.value().c_str(), pattern_.c_str()) == TRUE;
190 }
191 NOTREACHED();
192 return false;
193 }
194
161 } // namespace base 195 } // namespace base
OLDNEW
« no previous file with comments | « base/files/file_enumerator_unittest.cc ('k') | chrome_elf/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698