path: root/send-pack.c
diff options
authorJeff King <>2016-06-08 19:42:16 (GMT)
committerJunio C Hamano <>2016-06-08 23:02:40 (GMT)
commitf0bca72dc77f62d61fc355bd6fe6e32b194950b8 (patch)
tree589fd55dff9a6068d5785ffd17de2d13110c94fa /send-pack.c
parent0b65a8dbdb38962e700ee16776a3042beb489060 (diff)
send-pack: use buffered I/O to talk to pack-objects
We start a pack-objects process and then write all of the positive and negative sha1s to it over a pipe. We do so by formatting each item into a fixed-size buffer and then writing each individually. This has two drawbacks: 1. There's some manual computation of the buffer size, which is not immediately obvious is correct (though it is). 2. We write() once per sha1, which means a lot more system calls than are necessary. We can solve both by wrapping the pipe descriptor in a stdio handle; this is the same technique used by upload-pack when serving fetches. Note that we can also simplify and improve the error handling here. The original detected a single write error and broke out of the loop (presumably to avoid writing the error message over and over), but never actually acted on seeing an error; we just fed truncated input and took whatever pack-objects returned. In practice, this probably didn't matter, as the likely errors would be caused by pack-objects dying (and we'd probably just die with SIGPIPE anyway). But we can easily make this simpler and more robust; the stdio handle keeps an error flag, which we can check at the end. Signed-off-by: Jeff King <> Signed-off-by: Junio C Hamano <>
Diffstat (limited to 'send-pack.c')
1 files changed, 16 insertions, 17 deletions
diff --git a/send-pack.c b/send-pack.c
index 37ee04e..299d303 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -36,18 +36,15 @@ int option_parse_push_signed(const struct option *opt,
die("bad %s argument: %s", opt->long_name, arg);
-static int feed_object(const unsigned char *sha1, int fd, int negative)
+static void feed_object(const unsigned char *sha1, FILE *fh, int negative)
- char buf[42];
if (negative && !has_sha1_file(sha1))
- return 1;
+ return;
- memcpy(buf + negative, sha1_to_hex(sha1), 40);
if (negative)
- buf[0] = '^';
- buf[40 + negative] = '\n';
- return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs");
+ putc('^', fh);
+ fputs(sha1_to_hex(sha1), fh);
+ putc('\n', fh);
@@ -73,6 +70,7 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
struct child_process po = CHILD_PROCESS_INIT;
+ FILE *po_in;
int i;
i = 4;
@@ -97,21 +95,22 @@ static int pack_objects(int fd, struct ref *refs, struct sha1_array *extra, stru
* We feed the pack-objects we just spawned with revision
* parameters by writing to the pipe.
+ po_in = xfdopen(, "w");
for (i = 0; i < extra->nr; i++)
- if (!feed_object(extra->sha1[i],, 1))
- break;
+ feed_object(extra->sha1[i], po_in, 1);
while (refs) {
- if (!is_null_oid(&refs->old_oid) &&
- !feed_object(refs->old_oid.hash,, 1))
- break;
- if (!is_null_oid(&refs->new_oid) &&
- !feed_object(refs->new_oid.hash,, 0))
- break;
+ if (!is_null_oid(&refs->old_oid))
+ feed_object(refs->old_oid.hash, po_in, 1);
+ if (!is_null_oid(&refs->new_oid))
+ feed_object(refs->new_oid.hash, po_in, 0);
refs = refs->next;
- close(;
+ fflush(po_in);
+ if (ferror(po_in))
+ die_errno("error writing to pack-objects");
+ fclose(po_in);
if (args->stateless_rpc) {
char *buf = xmalloc(LARGE_PACKET_MAX);