summaryrefslogtreecommitdiff
path: root/upload-pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'upload-pack.c')
-rw-r--r--upload-pack.c84
1 files changed, 49 insertions, 35 deletions
diff --git a/upload-pack.c b/upload-pack.c
index bc7e3ca..da1f749 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -173,13 +173,52 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
return 0;
}
+struct output_state {
+ char buffer[8193];
+ int used;
+};
+
+static int relay_pack_data(int pack_objects_out, struct output_state *os,
+ int use_sideband)
+{
+ /*
+ * We keep the last byte to ourselves
+ * in case we detect broken rev-list, so that we
+ * can leave the stream corrupted. This is
+ * unfortunate -- unpack-objects would happily
+ * accept a valid packdata with trailing garbage,
+ * so appending garbage after we pass all the
+ * pack data is not good enough to signal
+ * breakage to downstream.
+ */
+ ssize_t readsz;
+
+ readsz = xread(pack_objects_out, os->buffer + os->used,
+ sizeof(os->buffer) - os->used);
+ if (readsz < 0) {
+ return readsz;
+ }
+ os->used += readsz;
+
+ if (os->used > 1) {
+ send_client_data(1, os->buffer, os->used - 1, use_sideband);
+ os->buffer[0] = os->buffer[os->used - 1];
+ os->used = 1;
+ } else {
+ send_client_data(1, os->buffer, os->used, use_sideband);
+ os->used = 0;
+ }
+
+ return readsz;
+}
+
static void create_pack_file(struct upload_pack_data *pack_data)
{
struct child_process pack_objects = CHILD_PROCESS_INIT;
- char data[8193], progress[128];
+ struct output_state output_state = { { 0 } };
+ char progress[128];
char abort_msg[] = "aborting due to possible repository "
"corruption on the remote side.";
- int buffered = -1;
ssize_t sz;
int i;
FILE *pipe_fd;
@@ -312,40 +351,16 @@ static void create_pack_file(struct upload_pack_data *pack_data)
continue;
}
if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
- /* Data ready; we keep the last byte to ourselves
- * in case we detect broken rev-list, so that we
- * can leave the stream corrupted. This is
- * unfortunate -- unpack-objects would happily
- * accept a valid packdata with trailing garbage,
- * so appending garbage after we pass all the
- * pack data is not good enough to signal
- * breakage to downstream.
- */
- char *cp = data;
- ssize_t outsz = 0;
- if (0 <= buffered) {
- *cp++ = buffered;
- outsz++;
- }
- sz = xread(pack_objects.out, cp,
- sizeof(data) - outsz);
- if (0 < sz)
- ;
- else if (sz == 0) {
+ int result = relay_pack_data(pack_objects.out,
+ &output_state,
+ pack_data->use_sideband);
+
+ if (result == 0) {
close(pack_objects.out);
pack_objects.out = -1;
- }
- else
+ } else if (result < 0) {
goto fail;
- sz += outsz;
- if (1 < sz) {
- buffered = data[sz-1] & 0xFF;
- sz--;
}
- else
- buffered = -1;
- send_client_data(1, data, sz,
- pack_data->use_sideband);
}
/*
@@ -370,9 +385,8 @@ static void create_pack_file(struct upload_pack_data *pack_data)
}
/* flush the data */
- if (0 <= buffered) {
- data[0] = buffered;
- send_client_data(1, data, 1,
+ if (output_state.used > 0) {
+ send_client_data(1, output_state.buffer, output_state.used,
pack_data->use_sideband);
fprintf(stderr, "flushed.\n");
}