mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-23 14:40:37 +08:00
wildcard: Use fstatat
This allows us to skip re-wcs2stringing the base_dir again and again by simply using the fd. It's about 10% faster in my testing. fstatat is defined by POSIX, so it should be available everywhere.
This commit is contained in:
parent
54369ba61b
commit
71a0d839a7
|
@ -761,6 +761,7 @@ void wildcard_expander_t::expand_intermediate_segment(const wcstring &base_dir,
|
||||||
const wchar_t *wc_remainder,
|
const wchar_t *wc_remainder,
|
||||||
const wcstring &prefix) {
|
const wcstring &prefix) {
|
||||||
wcstring name_str;
|
wcstring name_str;
|
||||||
|
int dir_fd = dirfd(base_dir_fp);
|
||||||
while (!interrupted_or_overflowed() && wreaddir_for_dirs(base_dir_fp, &name_str)) {
|
while (!interrupted_or_overflowed() && wreaddir_for_dirs(base_dir_fp, &name_str)) {
|
||||||
// Note that it's critical we ignore leading dots here, else we may descend into . and ..
|
// Note that it's critical we ignore leading dots here, else we may descend into . and ..
|
||||||
if (!wildcard_match(name_str, wc_segment, true)) {
|
if (!wildcard_match(name_str, wc_segment, true)) {
|
||||||
|
@ -768,9 +769,9 @@ void wildcard_expander_t::expand_intermediate_segment(const wcstring &base_dir,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring full_path = base_dir + name_str;
|
std::string narrow = wcs2string(name_str);
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
if (0 != wstat(full_path, &buf) || !S_ISDIR(buf.st_mode)) {
|
if (0 != fstatat(dir_fd, narrow.c_str(), &buf, 0) || !S_ISDIR(buf.st_mode)) {
|
||||||
// We either can't stat it, or we did but it's not a directory.
|
// We either can't stat it, or we did but it's not a directory.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -783,6 +784,7 @@ void wildcard_expander_t::expand_intermediate_segment(const wcstring &base_dir,
|
||||||
|
|
||||||
// We made it through. Perform normal wildcard expansion on this new directory, starting at
|
// We made it through. Perform normal wildcard expansion on this new directory, starting at
|
||||||
// our tail_wc, which includes the ANY_STRING_RECURSIVE guy.
|
// our tail_wc, which includes the ANY_STRING_RECURSIVE guy.
|
||||||
|
wcstring full_path = base_dir + name_str;
|
||||||
full_path.push_back(L'/');
|
full_path.push_back(L'/');
|
||||||
this->expand(full_path, wc_remainder, prefix + wc_segment + L'/');
|
this->expand(full_path, wc_remainder, prefix + wc_segment + L'/');
|
||||||
|
|
||||||
|
@ -803,6 +805,7 @@ void wildcard_expander_t::expand_literal_intermediate_segment_with_fuzz(const wc
|
||||||
// Mark that we are fuzzy for the duration of this function
|
// Mark that we are fuzzy for the duration of this function
|
||||||
const scoped_push<bool> scoped_fuzzy(&this->has_fuzzy_ancestor, true);
|
const scoped_push<bool> scoped_fuzzy(&this->has_fuzzy_ancestor, true);
|
||||||
|
|
||||||
|
int dir_fd = dirfd(base_dir_fp);
|
||||||
while (!interrupted_or_overflowed() && wreaddir_for_dirs(base_dir_fp, &name_str)) {
|
while (!interrupted_or_overflowed() && wreaddir_for_dirs(base_dir_fp, &name_str)) {
|
||||||
// Don't bother with . and ..
|
// Don't bother with . and ..
|
||||||
if (name_str == L"." || name_str == L"..") {
|
if (name_str == L"." || name_str == L"..") {
|
||||||
|
@ -814,10 +817,12 @@ void wildcard_expander_t::expand_literal_intermediate_segment_with_fuzz(const wc
|
||||||
const maybe_t<string_fuzzy_match_t> match = string_fuzzy_match_string(wc_segment, name_str);
|
const maybe_t<string_fuzzy_match_t> match = string_fuzzy_match_string(wc_segment, name_str);
|
||||||
if (!match || match->is_samecase_exact()) continue;
|
if (!match || match->is_samecase_exact()) continue;
|
||||||
|
|
||||||
wcstring new_full_path = base_dir + name_str;
|
std::string narrow = wcs2string(name_str);
|
||||||
new_full_path.push_back(L'/');
|
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
if (0 != wstat(new_full_path, &buf) || !S_ISDIR(buf.st_mode)) {
|
// Because we receive the path from readdir, we can assume it's
|
||||||
|
// not an absolute path, and because we skip ".." above
|
||||||
|
// we know it's not above the dir.
|
||||||
|
if (0 != fstatat(dir_fd, narrow.c_str(), &buf, 0) || !S_ISDIR(buf.st_mode)) {
|
||||||
/* We either can't stat it, or we did but it's not a directory */
|
/* We either can't stat it, or we did but it's not a directory */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -828,6 +833,9 @@ void wildcard_expander_t::expand_literal_intermediate_segment_with_fuzz(const wc
|
||||||
// segment with files found through fuzzy matching.
|
// segment with files found through fuzzy matching.
|
||||||
const wcstring child_prefix = prefix + name_str + L'/';
|
const wcstring child_prefix = prefix + name_str + L'/';
|
||||||
|
|
||||||
|
wcstring new_full_path = base_dir + name_str;
|
||||||
|
new_full_path.push_back(L'/');
|
||||||
|
|
||||||
// Ok, this directory matches. Recurse to it. Then mark each resulting completion as fuzzy.
|
// Ok, this directory matches. Recurse to it. Then mark each resulting completion as fuzzy.
|
||||||
const size_t before = this->resolved_completions->size();
|
const size_t before = this->resolved_completions->size();
|
||||||
this->expand(new_full_path, wc_remainder, child_prefix);
|
this->expand(new_full_path, wc_remainder, child_prefix);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user