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

Unified Diff: base/files/file_enumerator_posix.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, 6 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
« no previous file with comments | « base/files/file_enumerator.cc ('k') | base/files/file_enumerator_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/files/file_enumerator_posix.cc
diff --git a/base/files/file_enumerator_posix.cc b/base/files/file_enumerator_posix.cc
index a1b4949c796a5d242d77329039c476ecc5fdbf62..bc5c3cc5498062f3a37d4d491e130e8075441c85 100644
--- a/base/files/file_enumerator_posix.cc
+++ b/base/files/file_enumerator_posix.cc
@@ -8,12 +8,29 @@
#include <errno.h>
#include <fnmatch.h>
#include <stdint.h>
+#include <string.h>
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
namespace base {
+namespace {
+
+void GetStat(const FilePath& path, bool show_links, struct stat* st) {
+ DCHECK(st);
+ const int res = show_links ? lstat(path.value().c_str(), st)
+ : stat(path.value().c_str(), st);
+ if (res < 0) {
+ // Print the stat() error message unless it was ENOENT and we're following
+ // symlinks.
+ if (!(errno == ENOENT && !show_links))
+ DPLOG(ERROR) << "Couldn't stat" << path.value();
+ memset(st, 0, sizeof(*st));
+ }
+}
+
+} // namespace
// FileEnumerator::FileInfo ----------------------------------------------------
@@ -42,31 +59,36 @@ base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
int file_type)
- : current_directory_entry_(0),
- root_path_(root_path),
- recursive_(recursive),
- file_type_(file_type) {
- // INCLUDE_DOT_DOT must not be specified if recursive.
- DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
- 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)
+ : 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)
: current_directory_entry_(0),
root_path_(root_path),
recursive_(recursive),
file_type_(file_type),
- pattern_(root_path.Append(pattern).value()) {
+ pattern_(pattern),
+ folder_search_policy_(folder_search_policy) {
// INCLUDE_DOT_DOT must not be specified if recursive.
DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
- // The Windows version of this code appends the pattern to the root_path,
- // potentially only matching against items in the top-most directory.
- // Do the same here.
- if (pattern.empty())
- pattern_ = FilePath::StringType();
+
pending_paths_.push(root_path);
}
@@ -74,6 +96,8 @@ FileEnumerator::~FileEnumerator() {
}
FilePath FileEnumerator::Next() {
+ base::ThreadRestrictions::AssertIOAllowed();
+
++current_directory_entry_;
// While we've exhausted the entries in the current directory, do the next
@@ -85,29 +109,66 @@ FilePath FileEnumerator::Next() {
root_path_ = root_path_.StripTrailingSeparators();
pending_paths_.pop();
- std::vector<FileInfo> entries;
- if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
+ DIR* dir = opendir(root_path_.value().c_str());
+ if (!dir)
continue;
directory_entries_.clear();
+
+#if defined(OS_FUCHSIA)
+ // Fuchsia does not support .. on the file system server side, see
+ // https://fuchsia.googlesource.com/docs/+/master/dotdot.md and
+ // https://crbug.com/735540. However, for UI purposes, having the parent
+ // directory show up in directory listings makes sense, so we add it here to
+ // match the expectation on other operating systems. In cases where this
+ // is useful it should be resolvable locally.
+ FileInfo dotdot;
+ dotdot.stat_.st_mode = S_IFDIR;
+ dotdot.filename_ = FilePath("..");
+ directory_entries_->push_back(dotdot);
+#endif // OS_FUCHSIA
+
current_directory_entry_ = 0;
- for (std::vector<FileInfo>::const_iterator i = entries.begin();
- i != entries.end(); ++i) {
- FilePath full_path = root_path_.Append(i->filename_);
- if (ShouldSkip(full_path))
+ struct dirent* dent;
+ while ((dent = readdir(dir))) {
+ FileInfo info;
+ info.filename_ = FilePath(dent->d_name);
+
+ if (ShouldSkip(info.filename_))
continue;
- if (pattern_.size() &&
- fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE))
+ const bool is_pattern_matched = IsPatternMatched(info.filename_);
+
+ // MATCH_ONLY policy enumerates files and directories which matching
+ // pattern only. So we can early skip further checks.
+ if (folder_search_policy_ == FolderSearchPolicy::MATCH_ONLY &&
+ !is_pattern_matched)
continue;
- if (recursive_ && S_ISDIR(i->stat_.st_mode))
+ // Do not call OS stat/lstat if there is no sense to do it. If pattern is
+ // not matched (file will not appear in results) and search is not
+ // recursive (possible directory will not be added to pending paths) -
+ // there is no sense to obtain item below.
+ if (!recursive_ && !is_pattern_matched)
+ continue;
+
+ const FilePath full_path = root_path_.Append(info.filename_);
+ GetStat(full_path, file_type_ & SHOW_SYM_LINKS, &info.stat_);
+
+ const bool is_dir = S_ISDIR(info.stat_.st_mode);
+
+ if (recursive_ && is_dir)
pending_paths_.push(full_path);
- if ((S_ISDIR(i->stat_.st_mode) && (file_type_ & DIRECTORIES)) ||
- (!S_ISDIR(i->stat_.st_mode) && (file_type_ & FILES)))
- directory_entries_.push_back(*i);
+ if (is_pattern_matched && IsTypeMatched(is_dir))
+ directory_entries_.push_back(std::move(info));
}
+ closedir(dir);
+
+ // MATCH_ONLY policy enumerates files in matched subfolders by "*" pattern.
+ // ALL policy enumerates files in all subfolders by origin pattern.
+ if (folder_search_policy_ == FolderSearchPolicy::MATCH_ONLY)
+ pattern_.clear();
}
return root_path_.Append(
@@ -118,51 +179,9 @@ FileEnumerator::FileInfo FileEnumerator::GetInfo() const {
return directory_entries_[current_directory_entry_];
}
-bool FileEnumerator::ReadDirectory(std::vector<FileInfo>* entries,
- const FilePath& source, bool show_links) {
- base::ThreadRestrictions::AssertIOAllowed();
- DIR* dir = opendir(source.value().c_str());
- if (!dir)
- return false;
-
-#if defined(OS_FUCHSIA)
- // Fuchsia does not support .. on the file system server side, see
- // https://fuchsia.googlesource.com/docs/+/master/dotdot.md and
- // https://crbug.com/735540. However, for UI purposes, having the parent
- // directory show up in directory listings makes sense, so we add it here to
- // match the expectation on other operating systems. In cases where this
- // is useful it should be resolvable locally.
- FileInfo dotdot;
- dotdot.stat_.st_mode = S_IFDIR;
- dotdot.filename_ = FilePath("..");
- entries->push_back(dotdot);
-#endif // OS_FUCHSIA
-
- struct dirent* dent;
- while ((dent = readdir(dir))) {
- FileInfo info;
- info.filename_ = FilePath(dent->d_name);
-
- FilePath full_name = source.Append(dent->d_name);
- int ret;
- if (show_links)
- ret = lstat(full_name.value().c_str(), &info.stat_);
- else
- ret = stat(full_name.value().c_str(), &info.stat_);
- if (ret < 0) {
- // Print the stat() error message unless it was ENOENT and we're
- // following symlinks.
- if (!(errno == ENOENT && !show_links)) {
- DPLOG(ERROR) << "Couldn't stat "
- << source.Append(dent->d_name).value();
- }
- memset(&info.stat_, 0, sizeof(info.stat_));
- }
- entries->push_back(info);
- }
-
- closedir(dir);
- return true;
+bool FileEnumerator::IsPatternMatched(const FilePath& path) const {
+ return pattern_.empty() ||
+ !fnmatch(pattern_.c_str(), path.value().c_str(), FNM_NOESCAPE);
}
} // namespace base
« no previous file with comments | « base/files/file_enumerator.cc ('k') | base/files/file_enumerator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698