unpack-objects: fix --strict handling
[gitweb.git] / attr.c
diff --git a/attr.c b/attr.c
index 8d778f1d26bfc0e861415b381a23b2f82fa84e10..64b77b16636482d3448027d7823e5dc07861faa5 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -160,12 +160,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
                else if (!equals)
                        e->setto = ATTR__TRUE;
                else {
-                       char *value;
-                       int vallen = ep - equals;
-                       value = xmalloc(vallen);
-                       memcpy(value, equals+1, vallen-1);
-                       value[vallen-1] = 0;
-                       e->setto = value;
+                       e->setto = xmemdupz(equals + 1, ep - equals - 1);
                }
                e->attr = git_attr(cp, len);
        }
@@ -214,8 +209,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
                num_attr = 0;
                cp = name + namelen;
                cp = cp + strspn(cp, blank);
-               while (*cp)
+               while (*cp) {
                        cp = parse_attr(src, lineno, cp, &num_attr, res);
+                       if (!cp)
+                               return NULL;
+               }
                if (pass)
                        break;
                res = xcalloc(1,
@@ -336,13 +334,70 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
        return res;
 }
 
+static void *read_index_data(const char *path)
+{
+       int pos, len;
+       unsigned long sz;
+       enum object_type type;
+       void *data;
+
+       len = strlen(path);
+       pos = cache_name_pos(path, len);
+       if (pos < 0) {
+               /*
+                * We might be in the middle of a merge, in which
+                * case we would read stage #2 (ours).
+                */
+               int i;
+               for (i = -pos - 1;
+                    (pos < 0 && i < active_nr &&
+                     !strcmp(active_cache[i]->name, path));
+                    i++)
+                       if (ce_stage(active_cache[i]) == 2)
+                               pos = i;
+       }
+       if (pos < 0)
+               return NULL;
+       data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
+       if (!data || type != OBJ_BLOB) {
+               free(data);
+               return NULL;
+       }
+       return data;
+}
+
 static struct attr_stack *read_attr(const char *path, int macro_ok)
 {
        struct attr_stack *res;
+       char *buf, *sp;
+       int lineno = 0;
 
        res = read_attr_from_file(path, macro_ok);
-       if (!res)
-               res = xcalloc(1, sizeof(*res));
+       if (res)
+               return res;
+
+       res = xcalloc(1, sizeof(*res));
+
+       /*
+        * There is no checked out .gitattributes file there, but
+        * we might have it in the index.  We allow operation in a
+        * sparsely checked out work tree, so read from it.
+        */
+       buf = read_index_data(path);
+       if (!buf)
+               return res;
+
+       for (sp = buf; *sp; ) {
+               char *ep;
+               int more;
+               for (ep = sp; *ep && *ep != '\n'; ep++)
+                       ;
+               more = (*ep == '\n');
+               *ep = '\0';
+               handle_attr_line(res, sp, path, ++lineno, macro_ok);
+               sp = ep + more;
+       }
+       free(buf);
        return res;
 }
 
@@ -351,7 +406,7 @@ static void debug_info(const char *what, struct attr_stack *elem)
 {
        fprintf(stderr, "%s: %s\n", what, elem->origin ? elem->origin : "()");
 }
-static void debug_set(const char *what, const char *match, struct git_attr *attr, void *v)
+static void debug_set(const char *what, const char *match, struct git_attr *attr, const void *v)
 {
        const char *value = v;
 
@@ -488,10 +543,10 @@ static int path_matches(const char *pathname, int pathlen,
        if (*pattern == '/')
                pattern++;
        if (pathlen < baselen ||
-           (baselen && pathname[baselen - 1] != '/') ||
+           (baselen && pathname[baselen] != '/') ||
            strncmp(pathname, base, baselen))
                return 0;
-       return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;
+       return fnmatch(pattern, pathname + baselen + 1, FNM_PATHNAME) == 0;
 }
 
 static int fill_one(const char *what, struct match_attr *a, int rem)