ignore: don't leak rules into higher directories A rule "src" in src/.gitignore must only match subdirectories of src/. The current code does not include this context in the match rule and would thus consider this rule to match the top-level src/ directory instead of the intended src/src/. Keep track fo the context in which the rule was defined so we can perform a prefix match.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
diff --git a/src/attr_file.c b/src/attr_file.c
index 5620752..e3692ce 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -347,6 +347,21 @@ bool git_attr_fnmatch__match(
const char *filename;
int flags = 0;
+ /*
+ * If the rule was generated in a subdirectory, we must only
+ * use it for paths inside that directory. We can thus return
+ * a non-match if the prefixes don't match.
+ */
+ if (match->containing_dir) {
+ if (match->flags & GIT_ATTR_FNMATCH_ICASE) {
+ if (git__strncasecmp(path->path, match->containing_dir, match->containing_dir_length))
+ return 0;
+ } else {
+ if (git__prefixcmp(path->path, match->containing_dir))
+ return 0;
+ }
+ }
+
if (match->flags & GIT_ATTR_FNMATCH_ICASE)
flags |= FNM_CASEFOLD;
if (match->flags & GIT_ATTR_FNMATCH_LEADINGDIR)
@@ -588,6 +603,17 @@ int git_attr_fnmatch__parse(
/* leave FULLPATH match on, however */
}
+ if (context) {
+ char *slash = strchr(context, '/');
+ size_t len;
+ if (slash) {
+ /* include the slash for easier matching */
+ len = slash - context + 1;
+ spec->containing_dir = git_pool_strndup(pool, context, len);
+ spec->containing_dir_length = len;
+ }
+ }
+
if ((spec->flags & GIT_ATTR_FNMATCH_FULLPATH) != 0 &&
context != NULL && git_path_root(pattern) < 0)
{
diff --git a/src/attr_file.h b/src/attr_file.h
index 87cde7e..93de84d 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -52,6 +52,8 @@ extern const char *git_attr__unset;
typedef struct {
char *pattern;
size_t length;
+ char *containing_dir;
+ size_t containing_dir_length;
unsigned int flags;
} git_attr_fnmatch;