Merge branch 'sb/unpack-trees-grammofix' into maint
[gitweb.git] / tree-walk.c
index ce278424391b03d1d4e41eb3fc14750f70908fe5..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.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,7 +102,7 @@ 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.oid->hash + 20;
@@ -81,13 +110,36 @@ void update_tree_entry(struct tree_desc *desc)
        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);