[PATCH 4/4] attr.c: fix matching "subdir" without the trailing slash
- From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
- Date
- Mar 25, 2013, 06:05 UTC
- Message-ID
- <1364191510-8900-5-git-send-email-pclouds@gmail.com>
- In-Reply-To
- <1364191510-8900-1-git-send-email-pclouds@gmail.com>
The story goes back to 94bc671 (Add directory pattern matching to attributes - 2012-12-08). Before this commit, directories are passed to path_matches without the trailing slash. This is fine for matching pattern "subdir" with "foo/subdir".
Patterns like "subdir/" (i.e. match _directory_ subdir) won't work though. So paths are now passed to path_matches with the trailing slash (i.e. "subdir/"). The trailing slash is used as the directory indicator (similar to dtype in exclude case). This makes pattern "subdir/" match directory "subdir/". Pattern "subdir" no longer match subdir, which is now "subdir/".
As the trailing slash in pathname is the directory indicator, we do not need to keep it in the pathname for matching. The trailing slash should be turned to dtype "DT_DIR" and stripped out of pathname. This keeps the code pattern similar to exclude.
The same applies for the pattern "subdir/". The trailing slash is converted to flag EXC_FLAG_MUSTBEDIR and should not remain in the pattern, as noted in parse_exclude_pattern(). prepare_attr_stack() breaks this and keeps the trailing slash anyway.
To sum up, both patterns and pathnames should never have the trailing slash when it comes to match_basename.
Reported-and-analyzed-by: Jeff King <peff@peff.net> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> --- attr.c | 11 +++++++++-- t/t5002-archive-attr-pattern.sh | 6 ++++++ 2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/attr.c b/attr.c index 1818ba5..a95c837 100644 --- a/attr.c +++ b/attr.c @@ -256,7 +256,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, &res->u.pat.flags, &res->u.pat.nowildcardlen); if (res->u.pat.flags & EXC_FLAG_MUSTBEDIR) - res->u.pat.patternlen++; + p[res->u.pat.patternlen] = '\0'; if (res->u.pat.flags & EXC_FLAG_NEGATIVE) { warning(_("Negative patterns are ignored in git attributes\n" "Use '\\!' for literal leading exclamation.")); @@ -665,9 +665,16 @@ static int path_matches(const char *pathname, int pathlen, { const char *pattern = pat->pattern; int prefix = pat->nowildcardlen; + int dtype; + + if (pathlen && pathname[pathlen-1] == '/') { + dtype = DT_DIR; + pathlen--; + } else + dtype = DT_REG; if ((pat->flags & EXC_FLAG_MUSTBEDIR) && - ((!pathlen) || (pathname[pathlen-1] != '/'))) + dtype != DT_DIR) return 0; if (pat->flags & EXC_FLAG_NODIR) { diff --git a/t/t5002-archive-attr-pattern.sh b/t/t5002-archive-attr-pattern.sh index 0c847fb..98ccc3c 100755 --- a/t/t5002-archive-attr-pattern.sh +++ b/t/t5002-archive-attr-pattern.sh @@ -27,6 +27,10 @@ test_expect_success 'setup' ' echo ignored-only-if-dir/ export-ignore >>.git/info/attributes && git add ignored-only-if-dir && + mkdir -p ignored-without-slash && + echo ignored without slash >ignored-without-slash/foo && + git add ignored-without-slash/foo && + echo ignored-without-slash export-ignore >>.git/info/attributes && mkdir -p one-level-lower/two-levels-lower/ignored-only-if-dir && echo ignored by ignored dir >one-level-lower/two-levels-lower/ignored-only-if-dir/ignored-by-ignored-dir && @@ -49,6 +53,8 @@ test_expect_exists archive/not-ignored-dir/ignored-only-if-dir test_expect_exists archive/not-ignored-dir/ test_expect_missing archive/ignored-only-if-dir/ test_expect_missing archive/ignored-ony-if-dir/ignored-by-ignored-dir +test_expect_missing archive/ignored-without-slash/ && +test_expect_missing archive/ignored-without-slash/foo && test_expect_exists archive/one-level-lower/ test_expect_missing archive/one-level-lower/two-levels-lower/ignored-only-if-dir/ test_expect_missing archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir
-- 1.8.2.82.gc24b958