Skip to content

fix: don't stat negative patterns in static reads - #505

Open
abhu85 wants to merge 1 commit into
mrmlnc:masterfrom
abhu85:fix/499-static-reader-negative-patterns
Open

fix: don't stat negative patterns in static reads#505
abhu85 wants to merge 1 commit into
mrmlnc:masterfrom
abhu85:fix/499-static-reader-negative-patterns

Conversation

@abhu85

@abhu85 abhu85 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

Fixes #499 — for a static pattern combined with an ignore pattern, fast-glob calls lstat on a bogus path such as !*.bup.txt. This is silently swallowed as ENOENT in most environments, but surfaces as EIO in some (e.g. Podman/Hyper-V on Windows, where the literal * in the path is invalid).

const fastGlob = require("fast-glob");
fastGlob.sync("foo.txt", { ignore: ["*.bup.txt"] });
// correct result ['foo.txt'], but internally lstats `<cwd>/!*.bup.txt`

What changes did you make? (Give an overview)

Root cause: convertPatternGroupToTask builds task.patterns = positive + negative (negatives re-encoded as !...). The static providers passed task.patterns to reader.static(), which lstats every entry — including the negative patterns.

Fix: pass task.positive to the static reader instead of task.patterns, in all three providers (sync/async/stream). Negative patterns are exclusion filters, not candidate paths — ignore handling is already applied via entryFilter, which Provider#_getReaderOptions builds from task.positive and task.negative independently of what is passed to the reader. So only real candidate paths are now stat'd, and ignore semantics are unchanged. The dynamic path was never affected (it walks the base directory and filters).

Tests: added a regression to each provider spec asserting the static reader receives only task.positive (not the negative patterns). Verified behaviorally that ignore still excludes static matches (fastGlob.sync("foo.bup.txt", { ignore: ["*.bup.txt"] })[]).

  • Unit suite: 256 passing.
  • Lint: clean.
  • (Pre-existing, unrelated to this change: 3 CaseSensitiveMatch e2e tests fail on case-insensitive filesystems; they involve no ignore patterns.)

Static providers passed `task.patterns` (positive patterns plus the
negative/ignore patterns re-encoded as `!...`) to the static reader,
which lstats each one. For a static pattern combined with an `ignore`
pattern this produced an lstat on a bogus path such as `!*.bup.txt`,
yielding ENOENT in most environments (silently swallowed) and EIO in
some (e.g. Podman/Hyper-V on Windows), where the literal `*` is invalid.

Negative patterns are exclusion filters, not paths: ignore handling is
already applied via `entryFilter`, which is built from `task.positive`
and `task.negative` independently of what is passed to the reader. Pass
`task.positive` to the static reader so only real candidate paths are
stat'd. Dynamic reads were unaffected.

Fixes mrmlnc#499
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lstat on invalid path for static pattern + ignore pattern leads to EIO in some environments

1 participant