The existing odb_helper_get_object() is renamed
odb_helper_get_git_object() and a new odb_helper_get_raw_object()
is introduced to deal with external objects that are not in Git format.

Signed-off-by: Christian Couder <chrisc...@tuxfamily.org>
---
 odb-helper.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 111 insertions(+), 2 deletions(-)

diff --git a/odb-helper.c b/odb-helper.c
index 39d20fdfd7..1f4666b349 100644
--- a/odb-helper.c
+++ b/odb-helper.c
@@ -221,8 +221,107 @@ int odb_helper_has_object(struct odb_helper *o, const 
unsigned char *sha1)
        return !!odb_helper_lookup(o, sha1);
 }
 
-int odb_helper_get_object(struct odb_helper *o, const unsigned char *sha1,
-                           int fd)
+static int odb_helper_get_raw_object(struct odb_helper *o,
+                                    const unsigned char *sha1,
+                                    int fd)
+{
+       struct odb_helper_object *obj;
+       struct odb_helper_cmd cmd;
+       unsigned long total_got = 0;
+
+       char hdr[32];
+       int hdrlen;
+
+       int ret = Z_STREAM_END;
+       unsigned char compressed[4096];
+       git_zstream stream;
+       git_SHA_CTX hash;
+       unsigned char real_sha1[20];
+
+       obj = odb_helper_lookup(o, sha1);
+       if (!obj)
+               return -1;
+
+       if (odb_helper_start(o, &cmd, 0, "get_raw_obj %s", sha1_to_hex(sha1)) < 
0)
+               return -1;
+
+       /* Set it up */
+       git_deflate_init(&stream, zlib_compression_level);
+       stream.next_out = compressed;
+       stream.avail_out = sizeof(compressed);
+       git_SHA1_Init(&hash);
+
+       /* First header.. */
+       hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(obj->type), 
obj->size) + 1;
+       stream.next_in = (unsigned char *)hdr;
+       stream.avail_in = hdrlen;
+       while (git_deflate(&stream, 0) == Z_OK)
+               ; /* nothing */
+       git_SHA1_Update(&hash, hdr, hdrlen);
+
+       for (;;) {
+               unsigned char buf[4096];
+               int r;
+
+               r = xread(cmd.child.out, buf, sizeof(buf));
+               if (r < 0) {
+                       error("unable to read from odb helper '%s': %s",
+                             o->name, strerror(errno));
+                       close(cmd.child.out);
+                       odb_helper_finish(o, &cmd);
+                       git_deflate_end(&stream);
+                       return -1;
+               }
+               if (r == 0)
+                       break;
+
+               total_got += r;
+
+               /* Then the data itself.. */
+               stream.next_in = (void *)buf;
+               stream.avail_in = r;
+               do {
+                       unsigned char *in0 = stream.next_in;
+                       ret = git_deflate(&stream, Z_FINISH);
+                       git_SHA1_Update(&hash, in0, stream.next_in - in0);
+                       write_or_die(fd, compressed, stream.next_out - 
compressed);
+                       stream.next_out = compressed;
+                       stream.avail_out = sizeof(compressed);
+               } while (ret == Z_OK);
+       }
+
+       close(cmd.child.out);
+       if (ret != Z_STREAM_END) {
+               warning("bad zlib data from odb helper '%s' for %s",
+                       o->name, sha1_to_hex(sha1));
+               return -1;
+       }
+       ret = git_deflate_end_gently(&stream);
+       if (ret != Z_OK) {
+               warning("deflateEnd on object %s from odb helper '%s' failed 
(%d)",
+                       sha1_to_hex(sha1), o->name, ret);
+               return -1;
+       }
+       git_SHA1_Final(real_sha1, &hash);
+       if (hashcmp(sha1, real_sha1)) {
+               warning("sha1 mismatch from odb helper '%s' for %s (got %s)",
+                       o->name, sha1_to_hex(sha1), sha1_to_hex(real_sha1));
+               return -1;
+       }
+       if (odb_helper_finish(o, &cmd))
+               return -1;
+       if (total_got != obj->size) {
+               warning("size mismatch from odb helper '%s' for %s (%lu != 
%lu)",
+                       o->name, sha1_to_hex(sha1), total_got, obj->size);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int odb_helper_get_git_object(struct odb_helper *o,
+                                    const unsigned char *sha1,
+                                    int fd)
 {
        struct odb_helper_object *obj;
        struct odb_helper_cmd cmd;
@@ -326,6 +425,16 @@ int odb_helper_get_object(struct odb_helper *o, const 
unsigned char *sha1,
        return 0;
 }
 
+int odb_helper_get_object(struct odb_helper *o,
+                         const unsigned char *sha1,
+                         int fd)
+{
+       if (o->supported_capabilities & ODB_HELPER_CAP_GET_RAW_OBJ)
+               return odb_helper_get_raw_object(o, sha1, fd);
+       else
+               return odb_helper_get_git_object(o, sha1, fd);
+}
+
 int odb_helper_put_object(struct odb_helper *o,
                          const void *buf, size_t len,
                          const char *type, unsigned char *sha1)
-- 
2.14.1.576.g3f707d88cd

Reply via email to