This adds a configuration option odb.<helper>.plainObjects and the corresponding boolean variable called 'store_plain_objects' in 'struct odb_helper' to make it possible for external object databases to store object as plain objects instead of Git objects. The existing odb_helper_fetch_object() is renamed odb_helper_fetch_git_object() and a new odb_helper_fetch_plain_object() is introduce to deal with external objects that are not in Git format. Signed-off-by: Christian Couder <chriscool@xxxxxxxxxxxxx> --- external-odb.c | 2 + odb-helper.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- odb-helper.h | 1 + 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/external-odb.c b/external-odb.c index a88837feda..d11fc98719 100644 --- a/external-odb.c +++ b/external-odb.c @@ -36,6 +36,8 @@ static int external_odb_config(const char *var, const char *value, void *data) if (!strcmp(key, "command")) return git_config_string(&o->cmd, var, value); + if (!strcmp(key, "plainobjects")) + o->store_plain_objects = git_config_bool(var, value); return 0; } diff --git a/odb-helper.c b/odb-helper.c index af7cc55ca2..b33ee81c97 100644 --- a/odb-helper.c +++ b/odb-helper.c @@ -159,8 +159,107 @@ int odb_helper_has_object(struct odb_helper *o, const unsigned char *sha1) return !!odb_helper_lookup(o, sha1); } -int odb_helper_fetch_object(struct odb_helper *o, const unsigned char *sha1, - int fd) +static int odb_helper_fetch_plain_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 %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_fetch_git_object(struct odb_helper *o, + const unsigned char *sha1, + int fd) { struct odb_helper_object *obj; struct odb_helper_cmd cmd; @@ -248,6 +347,16 @@ int odb_helper_fetch_object(struct odb_helper *o, const unsigned char *sha1, return 0; } +int odb_helper_fetch_object(struct odb_helper *o, + const unsigned char *sha1, + int fd) +{ + if (o->store_plain_objects) + return odb_helper_fetch_plain_object(o, sha1, fd); + else + return odb_helper_fetch_git_object(o, sha1, fd); +} + int odb_helper_for_each_object(struct odb_helper *o, each_external_object_fn fn, void *data) diff --git a/odb-helper.h b/odb-helper.h index 4e321195e8..3953b9bbaf 100644 --- a/odb-helper.h +++ b/odb-helper.h @@ -6,6 +6,7 @@ struct odb_helper { const char *name; const char *cmd; + int store_plain_objects; struct odb_helper_object { unsigned char sha1[20]; -- 2.13.1.565.gbfcd7a9048