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

Unified Diff: base/files/file_enumerator_win.cc

Issue 2892173003: Add recursive pattern matching for subfolders in file_enumerator. (Closed)
Patch Set: Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: base/files/file_enumerator_win.cc
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
index 402a07209a8a24443d750481b75b9025540c2153..c59622183f822b5fa9d04b5262704685fdee04e3 100644
--- a/base/files/file_enumerator_win.cc
+++ b/base/files/file_enumerator_win.cc
@@ -4,6 +4,8 @@
#include "base/files/file_enumerator.h"
+#include <Shlwapi.h>
Mark Mentovai 2017/05/19 17:16:12 We always use lowercase names for these.
ivafanas 2017/05/22 04:42:28 Done.
+
Mark Mentovai 2017/05/19 17:16:12 Why the blank line?
ivafanas 2017/05/22 04:42:28 Done.
#include <stdint.h>
#include <string.h>
@@ -13,6 +15,36 @@
namespace base {
+namespace {
+
+HANDLE FindFirstFileImpl(const FilePath& src, WIN32_FIND_DATA* find_data) {
+ if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
Mark Mentovai 2017/05/19 17:16:12 Isn’t this our minimum anyway?
ivafanas 2017/05/22 04:42:28 Done.
+ return FindFirstFileEx(src.value().c_str(),
+ FindExInfoBasic, // Omit short name.
+ find_data, FindExSearchNameMatch, NULL,
Mark Mentovai 2017/05/19 17:16:12 nullptr instead of NULL
+ FIND_FIRST_EX_LARGE_FETCH);
+ } else {
+ return FindFirstFile(src.value().c_str(), find_data);
+ }
+}
+
+FilePath BuildSearchFilter(FileEnumerator::FolderSearchPolicy policy,
+ const FilePath& root_path,
+ const FilePath::StringType& pattern) {
+ // MATCH_ONLY policy filters incoming files by pattern on OS side. ALL policy
+ // collects all files and filters them manually.
+ switch (policy) {
+ case FileEnumerator::FolderSearchPolicy::MATCH_ONLY:
+ return root_path.Append(pattern);
+ case FileEnumerator::FolderSearchPolicy::ALL:
+ return root_path.AppendASCII("*");
+ }
+ NOTREACHED();
+ return {};
+}
+
+} // namespace
+
// FileEnumerator::FileInfo ----------------------------------------------------
FileEnumerator::FileInfo::FileInfo() {
@@ -45,25 +77,31 @@ base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
int file_type)
- : has_find_data_(false),
- find_handle_(INVALID_HANDLE_VALUE),
- recursive_(recursive),
- file_type_(file_type) {
- // INCLUDE_DOT_DOT must not be specified if recursive.
- DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
- memset(&find_data_, 0, sizeof(find_data_));
- pending_paths_.push(root_path);
-}
+ : FileEnumerator(root_path,
+ recursive,
+ file_type,
+ FilePath::StringType(),
+ FolderSearchPolicy::MATCH_ONLY) {}
FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
int file_type,
const FilePath::StringType& pattern)
- : has_find_data_(false),
- find_handle_(INVALID_HANDLE_VALUE),
- recursive_(recursive),
+ : FileEnumerator(root_path,
+ recursive,
+ file_type,
+ pattern,
+ FolderSearchPolicy::MATCH_ONLY) {}
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+ bool recursive,
+ int file_type,
+ const FilePath::StringType& pattern,
+ FolderSearchPolicy folder_search_policy)
+ : recursive_(recursive),
file_type_(file_type),
- pattern_(pattern) {
+ pattern_(!pattern.empty() ? pattern : FILE_PATH_LITERAL("*")),
+ folder_search_policy_(folder_search_policy) {
// INCLUDE_DOT_DOT must not be specified if recursive.
DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
memset(&find_data_, 0, sizeof(find_data_));
@@ -95,25 +133,9 @@ FilePath FileEnumerator::Next() {
pending_paths_.pop();
// Start a new find operation.
- FilePath src = root_path_;
-
- if (pattern_.empty())
- src = src.Append(L"*"); // No pattern = match everything.
- else
- src = src.Append(pattern_);
-
- if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
- // Use a "large fetch" on newer Windows which should speed up large
- // enumerations (we seldom abort in the middle).
- find_handle_ = FindFirstFileEx(src.value().c_str(),
- FindExInfoBasic, // Omit short name.
- &find_data_,
- FindExSearchNameMatch,
- NULL,
- FIND_FIRST_EX_LARGE_FETCH);
- } else {
- find_handle_ = FindFirstFile(src.value().c_str(), &find_data_);
- }
+ const auto src =
+ BuildSearchFilter(folder_search_policy_, root_path_, pattern_);
+ find_handle_ = FindFirstFileImpl(src, &find_data_);
has_find_data_ = true;
} else {
// Search for the next file/directory.
@@ -126,41 +148,59 @@ FilePath FileEnumerator::Next() {
if (INVALID_HANDLE_VALUE == find_handle_) {
has_find_data_ = false;
- // This is reached when we have finished a directory and are advancing to
- // the next one in the queue. We applied the pattern (if any) to the files
- // in the root search directory, but for those directories which were
- // matched, we want to enumerate all files inside them. This will happen
- // when the handle is empty.
- pattern_ = FilePath::StringType();
+ // MATCH_ONLY policy clears pattern for matched subfolders. ALL policy
+ // applies pattern for all subfolders.
+ if (folder_search_policy_ == FolderSearchPolicy::MATCH_ONLY) {
+ // This is reached when we have finished a directory and are advancing
+ // to the next one in the queue. We applied the pattern (if any) to the
+ // files in the root search directory, but for those directories which
+ // were matched, we want to enumerate all files inside them. This will
+ // happen when the handle is empty.
+ pattern_ = FILE_PATH_LITERAL("*");
+ }
continue;
}
- FilePath cur_file(find_data_.cFileName);
- if (ShouldSkip(cur_file))
+ const FilePath filename(find_data_.cFileName);
+ if (ShouldSkip(filename))
continue;
- // Construct the absolute filename.
- cur_file = root_path_.Append(find_data_.cFileName);
-
- if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- if (recursive_) {
- // If |cur_file| is a directory, and we are doing recursive searching,
- // add it to pending_paths_ so we scan it after we finish scanning this
- // directory. However, don't do recursion through reparse points or we
- // may end up with an infinite cycle.
- DWORD attributes = GetFileAttributes(cur_file.value().c_str());
- if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT))
- pending_paths_.push(cur_file);
- }
- if (file_type_ & FileEnumerator::DIRECTORIES)
- return cur_file;
- } else if (file_type_ & FileEnumerator::FILES) {
- return cur_file;
+ const bool is_dir =
+ (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ const auto abs_path = root_path_.Append(filename);
+
+ // Check if directory should be processed recursive.
+ if (is_dir && recursive_) {
+ // If |cur_file| is a directory, and we are doing recursive searching,
+ // add it to pending_paths_ so we scan it after we finish scanning this
+ // directory. However, don't do recursion through reparse points or we
+ // may end up with an infinite cycle.
+ DWORD attributes = GetFileAttributes(abs_path.value().c_str());
+ if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT))
+ pending_paths_.push(abs_path);
}
- }
+ if (IsTypeMatched(is_dir) && IsPatternMatched(filename))
+ return abs_path;
+ }
return FilePath();
}
+bool FileEnumerator::IsPatternMatched(const FilePath& src) const {
+ switch (folder_search_policy_) {
+ case FolderSearchPolicy::MATCH_ONLY:
+ // MATCH_ONLY policy filters by pattern on search request, so all found
+ // files already fits to pattern.
+ return true;
+ case FolderSearchPolicy::ALL:
+ // ALL policy enumerates all files, we need to check pattern match
+ // manually.
+ return pattern_.empty() ||
+ PathMatchSpec(src.value().c_str(), pattern_.c_str()) == TRUE;
+ }
+ NOTREACHED();
+ return false;
+}
+
} // namespace base
« base/files/file_enumerator_posix.cc ('K') | « base/files/file_enumerator_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698