Commit 47d6da0884d for nodejs
commit 47d6da0884dee87675e5f6e8bdf4a33b729cb744
Author: Gürgün Dayıoğlu <hey@gurgun.day>
Date: Sun Nov 15 22:15:27 2026 +0300
fs,path: fix glob globstar section bounds
The last start index of each globstar-delimited body section was
computed from the non-globstar prefix counts in reverse order. When
sections have different lengths, the bound is too tight, so paths
such as `a/b/c/d/e` failed to match `**/a/b/c/**/d/**`. This affected
`path.matchesGlob()` and `exclude` patterns in `fs.glob()`.
Compute the bound from the number of non-globstar parts in the
section and every section after it.
Signed-off-by: Gürgün Dayıoğlu <hey@gurgun.day>
PR-URL: https://github.com/nodejs/node/pull/66738
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Efe Karasakal <hi@efe.dev>
diff --git a/src/glob/glob_matcher.cc b/src/glob/glob_matcher.cc
index e0cca5cf43e..53d59fb8a35 100644
--- a/src/glob/glob_matcher.cc
+++ b/src/glob/glob_matcher.cc
@@ -673,12 +673,9 @@ class PathMatcher {
}
const ptrdiff_t file_length = static_cast<ptrdiff_t>(file.size()) -
static_cast<ptrdiff_t>(file_tail_match);
- {
- size_t i = sections.size() - 1;
- for (Section& s : sections) {
- s.after = file_length - (static_cast<ptrdiff_t>(sections[i--].non_gs) +
- static_cast<ptrdiff_t>(s.end - s.begin));
- }
+ // leave room for this section and every section after it
+ for (Section& s : sections) {
+ s.after = file_length - static_cast<ptrdiff_t>(non_gs - s.non_gs);
}
return MatchBodySections(
file, pattern, sections, fi, 0, 0, file_tail_match != 0);
diff --git a/test/parallel/test-path-glob.js b/test/parallel/test-path-glob.js
index 11633f52245..6b53e26bdd6 100644
--- a/test/parallel/test-path-glob.js
+++ b/test/parallel/test-path-glob.js
@@ -16,6 +16,9 @@ const globs = {
['foo\\bar\\baz\\boo', 'foo\\[bc-r]ar\\baz\\*', true], // Matches 'bar' or 'car' in 'foo\\bar'
['foo\\bar\\baz', 'foo/**', true], // Matches anything in 'foo'
['foo\\bar\\baz', '*', false], // No match
+ ['a\\b\\c\\d\\e', '**/a/b/c/**/d/**', true], // Globstar sections of different lengths
+ ['x\\a\\b\\c\\d\\e', '**/a/b/c/**/d/**/e', true], // Globstar sections of different lengths
+ ['a\\b\\c\\d', '**/a/b/c/**/d/**', false], // Trailing globstar needs a segment
],
posix: [
['foo/bar/baz', 'foo/[bcr]ar/baz', true], // Matches 'bar' or 'car' in 'foo/bar'
@@ -28,6 +31,9 @@ const globs = {
['foo/bar/baz/boo', 'foo/[bc-r]ar/baz/*', true], // Matches 'bar' or 'car' in 'foo/bar'
['foo/bar/baz', 'foo/**', true], // Matches anything in 'foo'
['foo/bar/baz', '*', false], // No match
+ ['a/b/c/d/e', '**/a/b/c/**/d/**', true], // Globstar sections of different lengths
+ ['x/a/b/c/d/e', '**/a/b/c/**/d/**/e', true], // Globstar sections of different lengths
+ ['a/b/c/d', '**/a/b/c/**/d/**', false], // Trailing globstar needs a segment
],
};