oneway_merge(): only lstat() when told to update worktree
[gitweb.git] / attr.c
diff --git a/attr.c b/attr.c
index 76b079f0f530e1372b2866f40cce21ec5266394c..887a9ae46b7044489845abf2072339271caf2d4a 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -301,11 +301,12 @@ static void free_attr_elem(struct attr_stack *e)
                }
                free(a);
        }
+       free(e->attrs);
        free(e);
 }
 
 static const char *builtin_attr[] = {
-       "[attr]binary -diff -text",
+       "[attr]binary -diff -merge -text",
        NULL,
 };
 
@@ -351,8 +352,11 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
        char buf[2048];
        int lineno = 0;
 
-       if (!fp)
+       if (!fp) {
+               if (errno != ENOENT && errno != ENOTDIR)
+                       warn_on_inaccessible(path);
                return NULL;
+       }
        res = xcalloc(1, sizeof(*res));
        while (fgets(buf, sizeof(buf), fp))
                handle_attr_line(res, buf, path, ++lineno, macro_ok);
@@ -495,47 +499,53 @@ static int git_attr_system(void)
 
 static void bootstrap_attr_stack(void)
 {
-       if (!attr_stack) {
-               struct attr_stack *elem;
+       struct attr_stack *elem;
+       char *xdg_attributes_file;
 
-               elem = read_attr_from_array(builtin_attr);
-               elem->origin = NULL;
-               elem->prev = attr_stack;
-               attr_stack = elem;
+       if (attr_stack)
+               return;
 
-               if (git_attr_system()) {
-                       elem = read_attr_from_file(git_etc_gitattributes(), 1);
-                       if (elem) {
-                               elem->origin = NULL;
-                               elem->prev = attr_stack;
-                               attr_stack = elem;
-                       }
-               }
+       elem = read_attr_from_array(builtin_attr);
+       elem->origin = NULL;
+       elem->prev = attr_stack;
+       attr_stack = elem;
 
-               if (git_attributes_file) {
-                       elem = read_attr_from_file(git_attributes_file, 1);
-                       if (elem) {
-                               elem->origin = NULL;
-                               elem->prev = attr_stack;
-                               attr_stack = elem;
-                       }
+       if (git_attr_system()) {
+               elem = read_attr_from_file(git_etc_gitattributes(), 1);
+               if (elem) {
+                       elem->origin = NULL;
+                       elem->prev = attr_stack;
+                       attr_stack = elem;
                }
+       }
 
-               if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
-                       elem = read_attr(GITATTRIBUTES_FILE, 1);
-                       elem->origin = xstrdup("");
+       if (!git_attributes_file) {
+               home_config_paths(NULL, &xdg_attributes_file, "attributes");
+               git_attributes_file = xdg_attributes_file;
+       }
+       if (git_attributes_file) {
+               elem = read_attr_from_file(git_attributes_file, 1);
+               if (elem) {
+                       elem->origin = NULL;
                        elem->prev = attr_stack;
                        attr_stack = elem;
-                       debug_push(elem);
                }
+       }
 
-               elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1);
-               if (!elem)
-                       elem = xcalloc(1, sizeof(*elem));
-               elem->origin = NULL;
+       if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
+               elem = read_attr(GITATTRIBUTES_FILE, 1);
+               elem->origin = xstrdup("");
                elem->prev = attr_stack;
                attr_stack = elem;
+               debug_push(elem);
        }
+
+       elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1);
+       if (!elem)
+               elem = xcalloc(1, sizeof(*elem));
+       elem->origin = NULL;
+       elem->prev = attr_stack;
+       attr_stack = elem;
 }
 
 static void prepare_attr_stack(const char *path)
@@ -575,14 +585,17 @@ static void prepare_attr_stack(const char *path)
 
        /*
         * Pop the ones from directories that are not the prefix of
-        * the path we are checking.
+        * the path we are checking. Break out of the loop when we see
+        * the root one (whose origin is an empty string "") or the builtin
+        * one (whose origin is NULL) without popping it.
         */
-       while (attr_stack && attr_stack->origin) {
+       while (attr_stack->origin) {
                int namelen = strlen(attr_stack->origin);
 
                elem = attr_stack;
                if (namelen <= dirlen &&
-                   !strncmp(elem->origin, path, namelen))
+                   !strncmp(elem->origin, path, namelen) &&
+                   (!namelen || path[namelen] == '/'))
                        break;
 
                debug_pop(elem);
@@ -594,8 +607,15 @@ static void prepare_attr_stack(const char *path)
         * Read from parent directories and push them down
         */
        if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
+               /*
+                * bootstrap_attr_stack() should have added, and the
+                * above loop should have stopped before popping, the
+                * root element whose attr_stack->origin is set to an
+                * empty string.
+                */
                struct strbuf pathbuf = STRBUF_INIT;
 
+               assert(attr_stack->origin);
                while (1) {
                        len = strlen(attr_stack->origin);
                        if (dirlen <= len)