Best "explained" with an example void walk(const unsigned char *sha1) { struct pv4_tree_desc desc; /* * Start pv4_tree_desc from an SHA-1. If it's a v4 tree, v4 walker * will be used. Otherwise v2 is walked. */ pv4_tree_desc_from_sha1(&desc, sha1, 0); recurse(&desc); pv4_release_tree_desc(&desc); } void recurse(struct pv4_tree_desc *desc) { /* * Then you can go over entries, one by one, similar to the * current tree walker. Current entry is in desc->v2.entry. * Pathlen in desc->pathlen. Do not use tree_entry_len() because * that one is only correct for v2 entries */ while (pv4_get_entry(desc)) { printf("%s %s\n", sha1_to_hex(desc->v2.entry.sha1), desc->v2.entry.path); /* * Once you have an initialized pv4_tree_desc you may skip the * SHA-1 lookup step if the next tree is in the same pack. */ if (S_ISDIR(desc->v2.entry.mode)) { struct pv4_tree_desc new_desc; pv4_tree_desc_from_entry(&new_desc, desc); recurse(&new_desc); /* Finally release everything */ pv4_release_tree_desc(&new_desc); } } } Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- packv4-parse.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ packv4-parse.h | 12 +++++++++ 2 files changed, 92 insertions(+) diff --git a/packv4-parse.c b/packv4-parse.c index f222456..7d257af 100644 --- a/packv4-parse.c +++ b/packv4-parse.c @@ -732,3 +732,83 @@ unsigned long pv4_unpack_object_header_buffer(const unsigned char *base, *sizep = val >> 4; return cp - base; } + +int pv4_tree_desc_from_sha1(struct pv4_tree_desc *desc, + const unsigned char *sha1, + unsigned flags) +{ + unsigned long size; + enum object_type type; + void *data; + struct object_info oi; + + assert(!(flags & ~0xff) && + "you are not supposed to set these from outside!"); + + memset(desc, 0, sizeof(*desc)); + strbuf_init(&desc->buf, 0); + + memset(&oi, 0, sizeof(oi)); + if (!sha1_object_info_extended(sha1, &oi) && + oi.whence == OI_PACKED && + oi.u.packed.real_type == OBJ_PV4_TREE && + oi.u.packed.pack->version >= 4) { + desc->p = oi.u.packed.pack; + desc->obj_offset = oi.u.packed.offset; + desc->flags = flags; + return 0; + } + + data = read_sha1_file(sha1, &type, &size); + if (!data || type != OBJ_TREE) { + free(data); + return -1; + } + desc->flags = flags; + desc->flags |= PV4_TREE_CANONICAL; + init_tree_desc(&desc->v2, data, size); + /* + * we can attach to strbuf because read_sha1_file always + * appends NUL at the end + */ + strbuf_attach(&desc->buf, data, size, size + 1); + return 0; +} + +int pv4_tree_desc_from_entry(struct pv4_tree_desc *desc, + const struct pv4_tree_desc *src, + unsigned flags) +{ + if (!src->sha1_index) + return pv4_tree_desc_from_sha1(desc, + src->v2.entry.sha1, + flags); + assert(!(flags & ~0xff) && + "you are not supposed to set these from outside!"); + memset(desc, 0, sizeof(*desc)); + strbuf_init(&desc->buf, 0); + desc->p = src->p; + desc->obj_offset = + nth_packed_object_offset(desc->p, src->sha1_index - 1); + desc->flags = flags; + return 0; +} + +void pv4_release_tree_desc(struct pv4_tree_desc *desc) +{ + strbuf_release(&desc->buf); + unuse_pack(&desc->w_curs); +} + +int pv4_tree_entry(struct pv4_tree_desc *desc) +{ + if (desc->flags & PV4_TREE_CANONICAL) { + if (!desc->v2.size) + return 0; + if (desc->start) + update_tree_entry(&desc->v2); + desc->start++; + return 1; + } + return !decode_entries(desc, desc->obj_offset, desc->start++, 1); +} diff --git a/packv4-parse.h b/packv4-parse.h index fe0ea38..874f57c 100644 --- a/packv4-parse.h +++ b/packv4-parse.h @@ -36,6 +36,8 @@ struct pv4_tree_desc { /* v4 entry */ struct packed_git *p; struct pack_window *w_curs; + off_t obj_offset; + unsigned start; unsigned int sha1_index; int pathlen; @@ -46,4 +48,14 @@ struct pv4_tree_desc { struct strbuf buf; }; +int pv4_tree_desc_from_sha1(struct pv4_tree_desc *desc, + const unsigned char *sha1, + unsigned flags); +int pv4_tree_desc_from_entry(struct pv4_tree_desc *desc, + const struct pv4_tree_desc *src, + unsigned flags); +void pv4_release_tree_desc(struct pv4_tree_desc *desc); + +int pv4_tree_entry(struct pv4_tree_desc *desc); + #endif -- 1.8.2.83.gc99314b -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html