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 <pclo...@gmail.com>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to