summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--attr.c51
-rw-r--r--builtin-check-attr.c6
-rwxr-xr-xt/t0020-crlf.sh2
3 files changed, 52 insertions, 7 deletions
diff --git a/attr.c b/attr.c
index 410bca6..60fe48f 100644
--- a/attr.c
+++ b/attr.c
@@ -36,6 +36,27 @@ static unsigned hash_name(const char *name, int namelen)
return val;
}
+static int invalid_attr_name(const char *name, int namelen)
+{
+ /*
+ * Attribute name cannot begin with '-' and from
+ * [-A-Za-z0-9_.]. We'd specifically exclude '=' for now,
+ * as we might later want to allow non-binary value for
+ * attributes, e.g. "*.svg merge=special-merge-program-for-svg"
+ */
+ if (*name == '-')
+ return -1;
+ while (namelen--) {
+ char ch = *name++;
+ if (! (ch == '-' || ch == '.' || ch == '_' ||
+ ('0' <= ch && ch <= '9') ||
+ ('a' <= ch && ch <= 'z') ||
+ ('A' <= ch && ch <= 'Z')) )
+ return -1;
+ }
+ return 0;
+}
+
struct git_attr *git_attr(const char *name, int len)
{
unsigned hval = hash_name(name, len);
@@ -48,6 +69,9 @@ struct git_attr *git_attr(const char *name, int len)
return a;
}
+ if (invalid_attr_name(name, len))
+ return NULL;
+
a = xmalloc(sizeof(*a) + len + 1);
memcpy(a->name, name, len);
a->name[len] = 0;
@@ -68,7 +92,7 @@ struct git_attr *git_attr(const char *name, int len)
* (1) glob pattern.
* (2) whitespace
* (3) whitespace separated list of attribute names, each of which
- * could be prefixed with '!' to mean "not set".
+ * could be prefixed with '-' to mean "not set".
*/
struct attr_state {
@@ -114,6 +138,12 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
name += strlen(ATTRIBUTE_MACRO_PREFIX);
name += strspn(name, blank);
namelen = strcspn(name, blank);
+ if (invalid_attr_name(name, namelen)) {
+ fprintf(stderr,
+ "%.*s is not a valid attribute name: %s:%d\n",
+ namelen, name, src, lineno);
+ return NULL;
+ }
}
else
is_macro = 0;
@@ -126,11 +156,21 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
while (*cp) {
const char *ep;
ep = cp + strcspn(cp, blank);
- if (pass) {
+ if (!pass) {
+ if (*cp == '-')
+ cp++;
+ if (invalid_attr_name(cp, ep - cp)) {
+ fprintf(stderr,
+ "%.*s is not a valid attribute name: %s:%d\n",
+ (int)(ep - cp), cp,
+ src, lineno);
+ return NULL;
+ }
+ } else {
struct attr_state *e;
e = &(res->state[num_attr]);
- if (*cp == '!') {
+ if (*cp == '-') {
e->unset = 1;
cp++;
}
@@ -146,8 +186,9 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
sizeof(*res) +
sizeof(struct attr_state) * num_attr +
(is_macro ? 0 : namelen + 1));
- if (is_macro)
+ if (is_macro) {
res->u.attr = git_attr(name, namelen);
+ }
else {
res->u.pattern = (char*)&(res->state[num_attr]);
memcpy(res->u.pattern, name, namelen);
@@ -194,7 +235,7 @@ static void free_attr_elem(struct attr_stack *e)
}
static const char *builtin_attr[] = {
- "[attr]binary !diff !crlf",
+ "[attr]binary -diff -crlf",
NULL,
};
diff --git a/builtin-check-attr.c b/builtin-check-attr.c
index 47b0721..634be9e 100644
--- a/builtin-check-attr.c
+++ b/builtin-check-attr.c
@@ -29,8 +29,12 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
check = xcalloc(cnt, sizeof(*check));
for (i = 0; i < cnt; i++) {
const char *name;
+ struct git_attr *a;
name = argv[i + 1];
- check[i].attr = git_attr(name, strlen(name));
+ a = git_attr(name, strlen(name));
+ if (!a)
+ return error("%s: not a valid attribute name", name);
+ check[i].attr = a;
}
for (i = doubledash; i < argc; i++) {
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 600dcd3..cf84f0a 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -216,7 +216,7 @@ test_expect_success 'apply patch --index (autocrlf=true)' '
test_expect_success '.gitattributes says two is binary' '
- echo "two !crlf" >.gitattributes &&
+ echo "two -crlf" >.gitattributes &&
rm -f tmp one dir/two &&
git repo-config core.autocrlf true &&
git read-tree --reset -u HEAD &&