Merge branch 'lt/abbrev-auto'
[gitweb.git] / tree-walk.c
index cd4bb2c38bdf40f497ece781ce3a9e61de6b4399..828f4356be039bc07ec09665ac725341515a36ea 100644 (file)
@@ -22,31 +22,60 @@ static const char *get_mode(const char *str, unsigned int *modep)
        return str;
 }
 
-static void decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size)
+static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size, struct strbuf *err)
 {
        const char *path;
        unsigned int mode, len;
 
-       if (size < 24 || buf[size - 21])
-               die("corrupt tree file");
+       if (size < 23 || buf[size - 21]) {
+               strbuf_addstr(err, _("too-short tree object"));
+               return -1;
+       }
 
        path = get_mode(buf, &mode);
-       if (!path || !*path)
-               die("corrupt tree file");
+       if (!path) {
+               strbuf_addstr(err, _("malformed mode in tree entry"));
+               return -1;
+       }
+       if (!*path) {
+               strbuf_addstr(err, _("empty filename in tree entry"));
+               return -1;
+       }
        len = strlen(path) + 1;
 
        /* Initialize the descriptor entry */
        desc->entry.path = path;
        desc->entry.mode = canon_mode(mode);
-       desc->entry.sha1 = (const unsigned char *)(path + len);
+       desc->entry.oid  = (const struct object_id *)(path + len);
+
+       return 0;
 }
 
-void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size)
+static int init_tree_desc_internal(struct tree_desc *desc, const void *buffer, unsigned long size, struct strbuf *err)
 {
        desc->buffer = buffer;
        desc->size = size;
        if (size)
-               decode_tree_entry(desc, buffer, size);
+               return decode_tree_entry(desc, buffer, size, err);
+       return 0;
+}
+
+void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size)
+{
+       struct strbuf err = STRBUF_INIT;
+       if (init_tree_desc_internal(desc, buffer, size, &err))
+               die("%s", err.buf);
+       strbuf_release(&err);
+}
+
+int init_tree_desc_gently(struct tree_desc *desc, const void *buffer, unsigned long size)
+{
+       struct strbuf err = STRBUF_INIT;
+       int result = init_tree_desc_internal(desc, buffer, size, &err);
+       if (result)
+               error("%s", err.buf);
+       strbuf_release(&err);
+       return result;
 }
 
 void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
@@ -73,21 +102,44 @@ static void entry_extract(struct tree_desc *t, struct name_entry *a)
        *a = t->entry;
 }
 
-void update_tree_entry(struct tree_desc *desc)
+static int update_tree_entry_internal(struct tree_desc *desc, struct strbuf *err)
 {
        const void *buf = desc->buffer;
-       const unsigned char *end = desc->entry.sha1 + 20;
+       const unsigned char *end = desc->entry.oid->hash + 20;
        unsigned long size = desc->size;
        unsigned long len = end - (const unsigned char *)buf;
 
        if (size < len)
-               die("corrupt tree file");
+               die(_("too-short tree file"));
        buf = end;
        size -= len;
        desc->buffer = buf;
        desc->size = size;
        if (size)
-               decode_tree_entry(desc, buf, size);
+               return decode_tree_entry(desc, buf, size, err);
+       return 0;
+}
+
+void update_tree_entry(struct tree_desc *desc)
+{
+       struct strbuf err = STRBUF_INIT;
+       if (update_tree_entry_internal(desc, &err))
+               die("%s", err.buf);
+       strbuf_release(&err);
+}
+
+int update_tree_entry_gently(struct tree_desc *desc)
+{
+       struct strbuf err = STRBUF_INIT;
+       if (update_tree_entry_internal(desc, &err)) {
+               error("%s", err.buf);
+               strbuf_release(&err);
+               /* Stop processing this tree after error */
+               desc->size = 0;
+               return -1;
+       }
+       strbuf_release(&err);
+       return 0;
 }
 
 int tree_entry(struct tree_desc *desc, struct name_entry *entry)
@@ -100,6 +152,17 @@ int tree_entry(struct tree_desc *desc, struct name_entry *entry)
        return 1;
 }
 
+int tree_entry_gently(struct tree_desc *desc, struct name_entry *entry)
+{
+       if (!desc->size)
+               return 0;
+
+       *entry = desc->entry;
+       if (update_tree_entry_gently(desc))
+               return 0;
+       return 1;
+}
+
 void setup_traverse_info(struct traverse_info *info, const char *base)
 {
        int pathlen = strlen(base);
@@ -110,7 +173,7 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
                pathlen--;
        info->pathlen = pathlen ? pathlen + 1 : 0;
        info->name.path = base;
-       info->name.sha1 = (void *)(base + pathlen + 1);
+       info->name.oid = (void *)(base + pathlen + 1);
        if (pathlen)
                info->prev = &dummy;
 }
@@ -433,10 +496,10 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
        int namelen = strlen(name);
        while (t->size) {
                const char *entry;
-               const unsigned char *sha1;
+               const struct object_id *oid;
                int entrylen, cmp;
 
-               sha1 = tree_entry_extract(t, &entry, mode);
+               oid = tree_entry_extract(t, &entry, mode);
                entrylen = tree_entry_len(&t->entry);
                update_tree_entry(t);
                if (entrylen > namelen)
@@ -447,7 +510,7 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
                if (cmp < 0)
                        break;
                if (entrylen == namelen) {
-                       hashcpy(result, sha1);
+                       hashcpy(result, oid->hash);
                        return 0;
                }
                if (name[entrylen] != '/')
@@ -455,10 +518,10 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
                if (!S_ISDIR(*mode))
                        break;
                if (++entrylen == namelen) {
-                       hashcpy(result, sha1);
+                       hashcpy(result, oid->hash);
                        return 0;
                }
-               return get_tree_entry(sha1, name + entrylen, result, mode);
+               return get_tree_entry(oid->hash, name + entrylen, result, mode);
        }
        return -1;
 }