Revision 7d09fbe4ab7f080a8f8f5dcef7e0f3edf5e26019 authored by Serge E. Hallyn on 18 April 2006, 13:11:06 UTC, committed by Junio C Hamano on 25 April 2006, 06:07:54 UTC
The set_reuse_addr() error case was the only error case in
socklist() where we returned rather than continued.  Not sure
why.  Either we must free the socklist, or continue.  This patch
continues on error.

Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
(cherry picked from 0032d548db56eac9ea09b4ba05843365f6325b85 commit)
1 parent 1ab661d
Raw File
fetch-clone.c
#include "cache.h"
#include "exec_cmd.h"
#include <sys/wait.h>
#include <sys/time.h>

static int finish_pack(const char *pack_tmp_name, const char *me)
{
	int pipe_fd[2];
	pid_t pid;
	char idx[PATH_MAX];
	char final[PATH_MAX];
	char hash[41];
	unsigned char sha1[20];
	char *cp;
	int err = 0;

	if (pipe(pipe_fd) < 0)
		die("%s: unable to set up pipe", me);

	strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
	cp = strrchr(idx, '/');
	memcpy(cp, "/pidx", 5);

	pid = fork();
	if (pid < 0)
		die("git-clone-pack: unable to fork off git-index-pack");
	if (!pid) {
		close(0);
		dup2(pipe_fd[1], 1);
		close(pipe_fd[0]);
		close(pipe_fd[1]);
		execl_git_cmd("index-pack", "-o", idx, pack_tmp_name, NULL);
		error("cannot exec git-index-pack <%s> <%s>",
		      idx, pack_tmp_name);
		exit(1);
	}
	close(pipe_fd[1]);
	if (read(pipe_fd[0], hash, 40) != 40) {
		error("%s: unable to read from git-index-pack", me);
		err = 1;
	}
	close(pipe_fd[0]);

	for (;;) {
		int status, code;
		int retval = waitpid(pid, &status, 0);

		if (retval < 0) {
			if (errno == EINTR)
				continue;
			error("waitpid failed (%s)", strerror(errno));
			goto error_die;
		}
		if (WIFSIGNALED(status)) {
			int sig = WTERMSIG(status);
			error("git-index-pack died of signal %d", sig);
			goto error_die;
		}
		if (!WIFEXITED(status)) {
			error("git-index-pack died of unnatural causes %d",
			      status);
			goto error_die;
		}
		code = WEXITSTATUS(status);
		if (code) {
			error("git-index-pack died with error code %d", code);
			goto error_die;
		}
		if (err)
			goto error_die;
		break;
	}
	hash[40] = 0;
	if (get_sha1_hex(hash, sha1)) {
		error("git-index-pack reported nonsense '%s'", hash);
		goto error_die;
	}
	/* Now we have pack in pack_tmp_name[], and
	 * idx in idx[]; rename them to their final names.
	 */
	snprintf(final, sizeof(final),
		 "%s/pack/pack-%s.pack", get_object_directory(), hash);
	move_temp_to_file(pack_tmp_name, final);
	chmod(final, 0444);
	snprintf(final, sizeof(final),
		 "%s/pack/pack-%s.idx", get_object_directory(), hash);
	move_temp_to_file(idx, final);
	chmod(final, 0444);
	return 0;

 error_die:
	unlink(idx);
	unlink(pack_tmp_name);
	exit(1);
}

int receive_unpack_pack(int fd[2], const char *me, int quiet)
{
	int status;
	pid_t pid;

	pid = fork();
	if (pid < 0)
		die("%s: unable to fork off git-unpack-objects", me);
	if (!pid) {
		dup2(fd[0], 0);
		close(fd[0]);
		close(fd[1]);
		execl_git_cmd("unpack-objects", quiet ? "-q" : NULL, NULL);
		die("git-unpack-objects exec failed");
	}
	close(fd[0]);
	close(fd[1]);
	while (waitpid(pid, &status, 0) < 0) {
		if (errno != EINTR)
			die("waiting for git-unpack-objects: %s",
			    strerror(errno));
	}
	if (WIFEXITED(status)) {
		int code = WEXITSTATUS(status);
		if (code)
			die("git-unpack-objects died with error code %d",
			    code);
		return 0;
	}
	if (WIFSIGNALED(status)) {
		int sig = WTERMSIG(status);
		die("git-unpack-objects died of signal %d", sig);
	}
	die("git-unpack-objects died of unnatural causes %d", status);
}

/*
 * We average out the download speed over this many "events", where
 * an event is a minimum of about half a second. That way, we get
 * a reasonably stable number.
 */
#define NR_AVERAGE (4)

/*
 * A "binary msec" is a power-of-two-msec, aka 1/1024th of a second.
 * Keeing the time in that format means that "bytes / msecs" means
 * is the same as kB/s (modulo rounding).
 *
 * 1000512 is a magic number (usecs in a second, rounded up by half
 * of 1024, to make "rounding" come out right ;)
 */
#define usec_to_binarymsec(x) ((int)(x) / (1000512 >> 10))

int receive_keep_pack(int fd[2], const char *me, int quiet)
{
	char tmpfile[PATH_MAX];
	int ofd, ifd;
	unsigned long total;
	static struct timeval prev_tv;
	struct average {
		unsigned long bytes;
		unsigned long time;
	} download[NR_AVERAGE] = { {0, 0}, };
	unsigned long avg_bytes, avg_time;
	int idx = 0;

	ifd = fd[0];
	snprintf(tmpfile, sizeof(tmpfile),
		 "%s/pack/tmp-XXXXXX", get_object_directory());
	ofd = mkstemp(tmpfile);
	if (ofd < 0)
		return error("unable to create temporary file %s", tmpfile);

	gettimeofday(&prev_tv, NULL);
	total = 0;
	avg_bytes = 0;
	avg_time = 0;
	while (1) {
		char buf[8192];
		ssize_t sz, wsz, pos;
		sz = read(ifd, buf, sizeof(buf));
		if (sz == 0)
			break;
		if (sz < 0) {
			if (errno != EINTR && errno != EAGAIN) {
				error("error reading pack (%s)", strerror(errno));
				close(ofd);
				unlink(tmpfile);
				return -1;
			}
			sz = 0;
		}
		pos = 0;
		while (pos < sz) {
			wsz = write(ofd, buf + pos, sz - pos);
			if (wsz < 0) {
				error("error writing pack (%s)",
				      strerror(errno));
				close(ofd);
				unlink(tmpfile);
				return -1;
			}
			pos += wsz;
		}
		total += sz;
		if (!quiet) {
			static unsigned long last;
			struct timeval tv;
			unsigned long diff = total - last;
			/* not really "msecs", but a power-of-two millisec (1/1024th of a sec) */
			unsigned long msecs;

			gettimeofday(&tv, NULL);
			msecs = tv.tv_sec - prev_tv.tv_sec;
			msecs <<= 10;
			msecs += usec_to_binarymsec(tv.tv_usec - prev_tv.tv_usec);

			if (msecs > 500) {
				prev_tv = tv;
				last = total;

				/* Update averages ..*/
				avg_bytes += diff;
				avg_time += msecs;
				avg_bytes -= download[idx].bytes;
				avg_time -= download[idx].time;
				download[idx].bytes = diff;
				download[idx].time = msecs;
				idx++;
				if (idx >= NR_AVERAGE)
					idx = 0;

				fprintf(stderr, "%4lu.%03luMB  (%lu kB/s)      \r",
					total >> 20,
					1000*((total >> 10) & 1023)>>10,
					avg_bytes / avg_time );
			}
		}
	}
	close(ofd);
	return finish_pack(tmpfile, me);
}
back to top