git-format-patch should show the correct version
[git.git] / tree.c
diff --git a/tree.c b/tree.c
index 315b6a5..e7a7b71 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -9,9 +9,16 @@ const char *tree_type = "tree";
 
 static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
 {
-       int len = strlen(pathname);
-       unsigned int size = cache_entry_size(baselen + len);
-       struct cache_entry *ce = xmalloc(size);
+       int len;
+       unsigned int size;
+       struct cache_entry *ce;
+
+       if (S_ISDIR(mode))
+               return READ_TREE_RECURSIVE;
+
+       len = strlen(pathname);
+       size = cache_entry_size(baselen + len);
+       ce = xmalloc(size);
 
        memset(ce, 0, size);
 
@@ -67,9 +74,10 @@ static int match_tree_entry(const char *base, int baselen, const char *path, uns
        return 0;
 }
 
-static int read_tree_recursive(void *buffer, unsigned long size,
-                              const char *base, int baselen,
-                              int stage, const char **match)
+int read_tree_recursive(void *buffer, unsigned long size,
+                       const char *base, int baselen,
+                       int stage, const char **match,
+                       read_tree_fn_t fn)
 {
        while (size) {
                int len = strlen(buffer)+1;
@@ -86,6 +94,14 @@ static int read_tree_recursive(void *buffer, unsigned long size,
                if (!match_tree_entry(base, baselen, path, mode, match))
                        continue;
 
+               switch (fn(sha1, base, baselen, path, mode, stage)) {
+               case 0:
+                       continue;
+               case READ_TREE_RECURSIVE:
+                       break;;
+               default:
+                       return -1;
+               }
                if (S_ISDIR(mode)) {
                        int retval;
                        int pathlen = strlen(path);
@@ -106,22 +122,20 @@ static int read_tree_recursive(void *buffer, unsigned long size,
                        retval = read_tree_recursive(eltbuf, eltsize,
                                                     newbase,
                                                     baselen + pathlen + 1,
-                                                    stage, match);
+                                                    stage, match, fn);
                        free(eltbuf);
                        free(newbase);
                        if (retval)
                                return -1;
                        continue;
                }
-               if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
-                       return -1;
        }
        return 0;
 }
 
 int read_tree(void *buffer, unsigned long size, int stage, const char **match)
 {
-       return read_tree_recursive(buffer, size, "", 0, stage, match);
+       return read_tree_recursive(buffer, size, "", 0, stage, match, read_one_entry);
 }
 
 struct tree *lookup_tree(const unsigned char *sha1)
@@ -148,6 +162,7 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
 {
        void *bufptr = buffer;
        struct tree_entry_list **list_p;
+       int n_refs = 0;
 
        if (item->object.parsed)
                return 0;
@@ -184,11 +199,20 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
                        obj = &entry->item.blob->object;
                }
                if (obj)
-                       add_ref(&item->object, obj);
-               entry->parent = NULL; /* needs to be filled by the user */
+                       n_refs++;
                *list_p = entry;
                list_p = &entry->next;
        }
+
+       if (track_object_refs) {
+               struct tree_entry_list *entry;
+               unsigned i = 0;
+               struct object_refs *refs = alloc_object_refs(n_refs);
+               for (entry = item->entries; entry; entry = entry->next)
+                       refs->ref[i++] = entry->item.any;
+               set_object_refs(&item->object, refs);
+       }
+
        return 0;
 }