1#include "cache.h"
2#include "exec_cmd.h"
3#include "pkt-line.h"
4#include <sys/wait.h>
5#include <sys/time.h>
67
static int finish_pack(const char *pack_tmp_name, const char *me)
8{
9int pipe_fd[2];
10pid_t pid;
11char idx[PATH_MAX];
12char final[PATH_MAX];
13char hash[41];
14unsigned char sha1[20];
15char *cp;
16int err = 0;
1718
if (pipe(pipe_fd) < 0)
19die("%s: unable to set up pipe", me);
2021
strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
22cp = strrchr(idx, '/');
23memcpy(cp, "/pidx", 5);
2425
pid = fork();
26if (pid < 0)
27die("%s: unable to fork off git-index-pack", me);
28if (!pid) {
29close(0);
30dup2(pipe_fd[1], 1);
31close(pipe_fd[0]);
32close(pipe_fd[1]);
33execl_git_cmd("index-pack", "-o", idx, pack_tmp_name, NULL);
34error("cannot exec git-index-pack <%s> <%s>",
35idx, pack_tmp_name);
36exit(1);
37}
38close(pipe_fd[1]);
39if (read(pipe_fd[0], hash, 40) != 40) {
40error("%s: unable to read from git-index-pack", me);
41err = 1;
42}
43close(pipe_fd[0]);
4445
for (;;) {
46int status, code;
4748
if (waitpid(pid, &status, 0) < 0) {
49if (errno == EINTR)
50continue;
51error("waitpid failed (%s)", strerror(errno));
52goto error_die;
53}
54if (WIFSIGNALED(status)) {
55int sig = WTERMSIG(status);
56error("git-index-pack died of signal %d", sig);
57goto error_die;
58}
59if (!WIFEXITED(status)) {
60error("git-index-pack died of unnatural causes %d",
61status);
62goto error_die;
63}
64code = WEXITSTATUS(status);
65if (code) {
66error("git-index-pack died with error code %d", code);
67goto error_die;
68}
69if (err)
70goto error_die;
71break;
72}
73hash[40] = 0;
74if (get_sha1_hex(hash, sha1)) {
75error("git-index-pack reported nonsense '%s'", hash);
76goto error_die;
77}
78/* Now we have pack in pack_tmp_name[], and
79* idx in idx[]; rename them to their final names.
80*/
81snprintf(final, sizeof(final),
82"%s/pack/pack-%s.pack", get_object_directory(), hash);
83move_temp_to_file(pack_tmp_name, final);
84chmod(final, 0444);
85snprintf(final, sizeof(final),
86"%s/pack/pack-%s.idx", get_object_directory(), hash);
87move_temp_to_file(idx, final);
88chmod(final, 0444);
89return 0;
9091
error_die:
92unlink(idx);
93unlink(pack_tmp_name);
94exit(1);
95}
9697
static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2])
98{
99pid_t side_pid;
100101
if (!sideband) {
102fd[0] = xd[0];
103fd[1] = xd[1];
104return 0;
105}
106/* xd[] is talking with upload-pack; subprocess reads from
107* xd[0], spits out band#2 to stderr, and feeds us band#1
108* through our fd[0].
109*/
110if (pipe(fd) < 0)
111die("%s: unable to set up pipe", me);
112side_pid = fork();
113if (side_pid < 0)
114die("%s: unable to fork off sideband demultiplexer", me);
115if (!side_pid) {
116/* subprocess */
117close(fd[0]);
118if (xd[0] != xd[1])
119close(xd[1]);
120while (1) {
121char buf[1024];
122int len = packet_read_line(xd[0], buf, sizeof(buf));
123if (len == 0)
124break;
125if (len < 1)
126die("%s: protocol error: no band designator",
127me);
128len--;
129switch (buf[0] & 0xFF) {
130case 3:
131safe_write(2, "remote: ", 8);
132safe_write(2, buf+1, len);
133safe_write(2, "\n", 1);
134exit(1);
135case 2:
136safe_write(2, "remote: ", 8);
137safe_write(2, buf+1, len);
138continue;
139case 1:
140safe_write(fd[1], buf+1, len);
141continue;
142default:
143die("%s: protocol error: bad band #%d",
144me, (buf[0] & 0xFF));
145}
146}
147exit(0);
148}
149close(xd[0]);
150close(fd[1]);
151fd[1] = xd[1];
152return side_pid;
153}
154155
int receive_unpack_pack(int xd[2], const char *me, int quiet, int sideband)
156{
157int status;
158pid_t pid, side_pid;
159int fd[2];
160161
side_pid = setup_sideband(sideband, me, fd, xd);
162pid = fork();
163if (pid < 0)
164die("%s: unable to fork off git-unpack-objects", me);
165if (!pid) {
166dup2(fd[0], 0);
167close(fd[0]);
168close(fd[1]);
169execl_git_cmd("unpack-objects", quiet ? "-q" : NULL, NULL);
170die("git-unpack-objects exec failed");
171}
172close(fd[0]);
173close(fd[1]);
174while (waitpid(pid, &status, 0) < 0) {
175if (errno != EINTR)
176die("waiting for git-unpack-objects: %s",
177strerror(errno));
178}
179if (WIFEXITED(status)) {
180int code = WEXITSTATUS(status);
181if (code)
182die("git-unpack-objects died with error code %d",
183code);
184return 0;
185}
186if (WIFSIGNALED(status)) {
187int sig = WTERMSIG(status);
188die("git-unpack-objects died of signal %d", sig);
189}
190die("git-unpack-objects died of unnatural causes %d", status);
191}
192193
/*
194* We average out the download speed over this many "events", where
195* an event is a minimum of about half a second. That way, we get
196* a reasonably stable number.
197*/
198#define NR_AVERAGE (4)
199200
/*
201* A "binary msec" is a power-of-two-msec, aka 1/1024th of a second.
202* Keeping the time in that format means that "bytes / msecs" means
203* the same as kB/s (modulo rounding).
204*
205* 1000512 is a magic number (usecs in a second, rounded up by half
206* of 1024, to make "rounding" come out right ;)
207*/
208#define usec_to_binarymsec(x) ((int)(x) / (1000512 >> 10))
209210
int receive_keep_pack(int xd[2], const char *me, int quiet, int sideband)
211{
212char tmpfile[PATH_MAX];
213int ofd, ifd, fd[2];
214unsigned long total;
215static struct timeval prev_tv;
216struct average {
217unsigned long bytes;
218unsigned long time;
219} download[NR_AVERAGE] = { {0, 0}, };
220unsigned long avg_bytes, avg_time;
221int idx = 0;
222223
setup_sideband(sideband, me, fd, xd);
224225
ifd = fd[0];
226snprintf(tmpfile, sizeof(tmpfile),
227"%s/pack/tmp-XXXXXX", get_object_directory());
228ofd = mkstemp(tmpfile);
229if (ofd < 0)
230return error("unable to create temporary file %s", tmpfile);
231232
gettimeofday(&prev_tv, NULL);
233total = 0;
234avg_bytes = 0;
235avg_time = 0;
236while (1) {
237char buf[8192];
238ssize_t sz, wsz, pos;
239sz = read(ifd, buf, sizeof(buf));
240if (sz == 0)
241break;
242if (sz < 0) {
243if (errno != EINTR && errno != EAGAIN) {
244error("error reading pack (%s)", strerror(errno));
245close(ofd);
246unlink(tmpfile);
247return -1;
248}
249sz = 0;
250}
251pos = 0;
252while (pos < sz) {
253wsz = write(ofd, buf + pos, sz - pos);
254if (wsz < 0) {
255error("error writing pack (%s)",
256strerror(errno));
257close(ofd);
258unlink(tmpfile);
259return -1;
260}
261pos += wsz;
262}
263total += sz;
264if (!quiet) {
265static unsigned long last;
266struct timeval tv;
267unsigned long diff = total - last;
268/* not really "msecs", but a power-of-two millisec (1/1024th of a sec) */
269unsigned long msecs;
270271
gettimeofday(&tv, NULL);
272msecs = tv.tv_sec - prev_tv.tv_sec;
273msecs <<= 10;
274msecs += usec_to_binarymsec(tv.tv_usec - prev_tv.tv_usec);
275276
if (msecs > 500) {
277prev_tv = tv;
278last = total;
279280
/* Update averages ..*/
281avg_bytes += diff;
282avg_time += msecs;
283avg_bytes -= download[idx].bytes;
284avg_time -= download[idx].time;
285download[idx].bytes = diff;
286download[idx].time = msecs;
287idx++;
288if (idx >= NR_AVERAGE)
289idx = 0;
290291
fprintf(stderr, "%4lu.%03luMB (%lu kB/s) \r",
292total >> 20,
2931000*((total >> 10) & 1023)>>10,
294avg_bytes / avg_time );
295}
296}
297}
298close(ofd);
299return finish_pack(tmpfile, me);
300}