Signed-off-by: Christian Couder <[email protected]>
---
odb-helper.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 118 insertions(+), 1 deletion(-)
diff --git a/odb-helper.c b/odb-helper.c
index a27208463c..b2d86a7928 100644
--- a/odb-helper.c
+++ b/odb-helper.c
@@ -142,6 +142,121 @@ static int check_object_process_error(int err,
return err;
}
+static struct odb_helper_object *odb_helper_lookup(struct odb_helper *o,
+ const unsigned char *sha1);
+
+static ssize_t read_packetized_plain_object_to_fd(struct odb_helper *o,
+ const unsigned char *sha1,
+ int fd_in, int fd_out)
+{
+ ssize_t total_read = 0;
+ unsigned long total_got = 0;
+ int packet_len;
+
+ 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];
+
+ off_t size;
+ enum object_type type;
+ const char *s;
+ int pkt_size;
+ char *size_buf;
+
+ size_buf = packet_read_line(fd_in, &pkt_size);
+ if (!skip_prefix(size_buf, "size=", &s))
+ return error("odb helper '%s' did not send size of plain
object", o->name);
+ size = strtoumax(s, NULL, 10);
+ if (!skip_prefix(packet_read_line(fd_in, NULL), "kind=", &s))
+ return error("odb helper '%s' did not send kind of plain
object", o->name);
+ /* Check if the object is not available */
+ if (!strcmp(s, "none"))
+ return -1;
+ type = type_from_string_gently(s, strlen(s), 1);
+ if (type < 0)
+ return error("odb helper '%s' sent bad type '%s'", o->name, s);
+
+ /* 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(type), 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 (;;) {
+ /* packet_read() writes a '\0' extra byte at the end */
+ char buf[LARGE_PACKET_DATA_MAX + 1];
+
+ packet_len = packet_read(fd_in, NULL, NULL,
+ buf, LARGE_PACKET_DATA_MAX + 1,
+ PACKET_READ_GENTLE_ON_EOF);
+
+ if (packet_len <= 0)
+ break;
+
+ total_got += packet_len;
+
+ /* Then the data itself.. */
+ stream.next_in = (void *)buf;
+ stream.avail_in = packet_len;
+ 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_out, compressed, stream.next_out -
compressed);
+ stream.next_out = compressed;
+ stream.avail_out = sizeof(compressed);
+ } while (ret == Z_OK);
+
+ total_read += packet_len;
+ }
+
+ if (packet_len < 0) {
+ error("unable to read from odb helper '%s': %s",
+ o->name, strerror(errno));
+ git_deflate_end(&stream);
+ return packet_len;
+ }
+
+ 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 (total_got != size) {
+ warning("size mismatch from odb helper '%s' for %s (%lu !=
%lu)",
+ o->name, sha1_to_hex(sha1), total_got, size);
+ return -1;
+ }
+
+ return total_read;
+}
+
static ssize_t read_packetized_git_object_to_fd(struct odb_helper *o,
const unsigned char *sha1,
int fd_in, int fd_out)
@@ -250,7 +365,9 @@ static int read_object_process(struct odb_helper *o, const
unsigned char *sha1,
if (err)
goto done;
- if (o->fetch_kind != ODB_FETCH_KIND_FAULT_IN)
+ if (o->fetch_kind == ODB_FETCH_KIND_PLAIN_OBJECT)
+ err = read_packetized_plain_object_to_fd(o, sha1, process->out,
fd) < 0;
+ else if (o->fetch_kind == ODB_FETCH_KIND_GIT_OBJECT)
err = read_packetized_git_object_to_fd(o, sha1, process->out,
fd) < 0;
subprocess_read_status(process->out, &status);
--
2.13.1.565.gbfcd7a9048