From 0a97eb6aea6d9d5c95793cf1afabca1b53fb5b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCrg=C3=BCn=20Day=C4=B1o=C4=9Flu?= Date: Wed, 14 Oct 2026 18:19:23 +0200 Subject: [PATCH] fs,path: fix glob globstar section bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/glob/glob_matcher.cc | 10 ++++------ test/parallel/test-path-glob.js | 6 ++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/glob/glob_matcher.cc b/src/glob/glob_matcher.cc index 37da737dbe40..2710c715abe6 100644 --- a/src/glob/glob_matcher.cc +++ b/src/glob/glob_matcher.cc @@ -674,12 +674,10 @@ class PathMatcher { } const ptrdiff_t file_length = static_cast(file.size()) - static_cast(file_tail_match); - { - size_t i = sections.size() - 1; - for (Section& s : sections) { - s.after = file_length - (static_cast(non_gs_sums[i--]) + - static_cast(s.end - s.begin)); - } + // leave room for this section and every section after it + for (size_t i = 0; i < sections.size(); i++) { + sections[i].after = + file_length - static_cast(non_gs - non_gs_sums[i]); } 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 11633f52245e..6b53e26bdd6f 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 ], };