+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/poll.h>
#include "cache.h"
#include "refs.h"
#include "pkt-line.h"
#include "object.h"
#include "commit.h"
#include "exec_cmd.h"
-#include <signal.h>
-#include <sys/poll.h>
-#include <sys/wait.h>
static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
static unsigned char has_sha1[MAX_HAS][20];
static unsigned char needs_sha1[MAX_NEEDS][20];
static unsigned int timeout = 0;
+static int use_sideband = 0;
static void reset_timeout(void)
{
return len;
}
+#define PACKET_MAX 1000
+static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
+{
+ ssize_t ssz;
+ const char *p;
+
+ if (!data) {
+ if (!use_sideband)
+ return 0;
+ packet_flush(1);
+ }
+
+ if (!use_sideband) {
+ if (fd == 3)
+ /* emergency quit */
+ fd = 2;
+ if (fd == 2) {
+ xwrite(fd, data, sz);
+ return sz;
+ }
+ return safe_write(fd, data, sz);
+ }
+ p = data;
+ ssz = sz;
+ while (sz) {
+ unsigned n;
+ char hdr[5];
+
+ n = sz;
+ if (PACKET_MAX - 5 < n)
+ n = PACKET_MAX - 5;
+ sprintf(hdr, "%04x", n + 5);
+ hdr[4] = fd;
+ safe_write(1, hdr, 5);
+ safe_write(1, p, n);
+ p += n;
+ sz -= n;
+ }
+ return ssz;
+}
+
static void create_pack_file(void)
{
/* Pipes between rev-list to pack-objects, pack-objects to us
pid_t pid_rev_list, pid_pack_objects;
int create_full_pack = (nr_our_refs == nr_needs && !nr_has);
char data[8193], progress[128];
+ char abort_msg[] = "aborting due to possible repository "
+ "corruption on the remote side.";
int buffered = -1;
if (pipe(lp_pipe) < 0)
int i;
int args;
const char **argv;
+ const char **p;
char *buf;
- char **p;
if (create_full_pack) {
args = 10;
while (1) {
const char *who;
- char *cp;
struct pollfd pfd[2];
pid_t pid;
int status;
ssize_t sz;
int pe, pu, pollsize;
+ reset_timeout();
+
pollsize = 0;
pe = pu = -1;
}
else
buffered = -1;
- sz = xwrite(1, data, sz);
+ sz = send_client_data(1, data, sz);
if (sz < 0)
goto fail;
}
if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) {
- /* Status ready; we do not use it for now,
- * but later we will add side-band to send it
- * to the other side.
+ /* Status ready; we ship that in the side-band
+ * or dump to the standard error.
*/
sz = read(pe_pipe[0], progress,
sizeof(progress));
if (0 < sz)
- write(2, progress, sz);
+ send_client_data(2, progress, sz);
else if (sz == 0) {
close(pe_pipe[0]);
pe_pipe[0] = -1;
/* flush the data */
if (0 <= buffered) {
data[0] = buffered;
- sz = xwrite(1, data, 1);
+ sz = send_client_data(1, data, 1);
if (sz < 0)
goto fail;
fprintf(stderr, "flushed.\n");
}
+ send_client_data(1, NULL, 0);
return;
}
fail:
kill(pid_pack_objects, SIGKILL);
if (pid_rev_list)
kill(pid_rev_list, SIGKILL);
- die("git-upload-pack: aborting due to possible repository corruption on the remote side.");
+ send_client_data(3, abort_msg, sizeof(abort_msg));
+ die("git-upload-pack: %s", abort_msg);
}
static int got_sha1(char *hex, unsigned char *sha1)
o = parse_object(sha1);
if (!o)
die("oops (%s)", sha1_to_hex(sha1));
- if (o->type == TYPE_COMMIT) {
+ if (o->type == OBJ_COMMIT) {
struct commit_list *parents;
if (o->flags & THEY_HAVE)
return 0;
multi_ack = 1;
if (strstr(line+45, "thin-pack"))
use_thin_pack = 1;
+ if (strstr(line+45, "side-band"))
+ use_sideband = 1;
/* We have sent all our refs already, and the other end
* should have chosen out of them; otherwise they are
static int send_ref(const char *refname, const unsigned char *sha1)
{
- static char *capabilities = "multi_ack thin-pack";
+ static const char *capabilities = "multi_ack thin-pack side-band";
struct object *o = parse_object(sha1);
if (!o)
o->flags |= OUR_REF;
nr_our_refs++;
}
- if (o->type == TYPE_TAG) {
+ if (o->type == OBJ_TAG) {
o = deref_tag(o, refname, 0);
packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
}