Commit f25bc0b2e6d764a496047e4f033767303b35b27e

Russell Belfer 2014-08-08T14:51:36

Fix rejection of parent dir of negated ignores While scanning through a directory hierarchy, this prevents a positive ignore match on a parent directory from blocking the scan of a directory when a negative match rule exists for files inside the directory.

diff --git a/src/attr_file.c b/src/attr_file.c
index 3e95a21..2f09537 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -378,6 +378,18 @@ bool git_attr_fnmatch__match(
 		return (matchval != FNM_NOMATCH);
 	}
 
+	/* if path is a directory prefix of a negated pattern, then match */
+	if ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) && path->is_dir) {
+		size_t pathlen = strlen(path->path);
+		bool prefixed = (pathlen <= match->length) &&
+			((match->flags & GIT_ATTR_FNMATCH_ICASE) ?
+			 !strncasecmp(match->pattern, path->path, pathlen) :
+			 !strncmp(match->pattern, path->path, pathlen));
+
+		if (prefixed && git_path_at_end_of_segment(&match->pattern[pathlen]))
+			return true;
+	}
+
 	return (p_fnmatch(match->pattern, filename, flags) != FNM_NOMATCH);
 }
 
diff --git a/src/path.h b/src/path.h
index 2e86241..46d6efe 100644
--- a/src/path.h
+++ b/src/path.h
@@ -128,6 +128,14 @@ GIT_INLINE(int) git_path_is_relative(const char *p)
 	return (p[0] == '.' && (p[1] == '/' || (p[1] == '.' && p[2] == '/')));
 }
 
+/**
+ * Check if string is at end of path segment (i.e. looking at '/' or '\0')
+ */
+GIT_INLINE(int) git_path_at_end_of_segment(const char *p)
+{
+	return !*p || *p == '/';
+}
+
 extern int git__percent_decode(git_buf *decoded_out, const char *input);
 
 /**