Skip to content

Commit 40e2524

Browse files
committed
Merge branch 'js/upload-pack'
* js/upload-pack: upload-pack: Use finish_{command,async}() instead of waitpid().
2 parents 52b9b48 + 4c324c0 commit 40e2524

File tree

2 files changed

+152
-115
lines changed

2 files changed

+152
-115
lines changed

t/t5530-upload-pack-error.sh

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/bin/sh
2+
3+
test_description='errors in upload-pack'
4+
5+
. ./test-lib.sh
6+
7+
D=`pwd`
8+
9+
corrupt_repo () {
10+
object_sha1=$(git rev-parse "$1") &&
11+
ob=$(expr "$object_sha1" : "\(..\)") &&
12+
ject=$(expr "$object_sha1" : "..\(..*\)") &&
13+
rm -f ".git/objects/$ob/$ject"
14+
}
15+
16+
test_expect_success 'setup and corrupt repository' '
17+
18+
echo file >file &&
19+
git add file &&
20+
git rev-parse :file &&
21+
git commit -a -m original &&
22+
test_tick &&
23+
echo changed >file &&
24+
git commit -a -m changed &&
25+
corrupt_repo HEAD:file
26+
27+
'
28+
29+
test_expect_failure 'fsck fails' '
30+
31+
git fsck
32+
'
33+
34+
test_expect_success 'upload-pack fails due to error in pack-objects' '
35+
36+
! echo "0032want $(git rev-parse HEAD)
37+
00000009done
38+
0000" | git-upload-pack . > /dev/null 2> output.err &&
39+
grep "pack-objects died" output.err
40+
'
41+
42+
test_expect_success 'corrupt repo differently' '
43+
44+
git hash-object -w file &&
45+
corrupt_repo HEAD^^{tree}
46+
47+
'
48+
49+
test_expect_failure 'fsck fails' '
50+
51+
git fsck
52+
'
53+
test_expect_success 'upload-pack fails due to error in rev-list' '
54+
55+
! echo "0032want $(git rev-parse HEAD)
56+
00000009done
57+
0000" | git-upload-pack . > /dev/null 2> output.err &&
58+
grep "waitpid (async) failed" output.err
59+
'
60+
61+
test_expect_success 'create empty repository' '
62+
63+
mkdir foo &&
64+
cd foo &&
65+
git init
66+
67+
'
68+
69+
test_expect_failure 'fetch fails' '
70+
71+
git fetch .. master
72+
73+
'
74+
75+
test_done

upload-pack.c

Lines changed: 77 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ static void create_pack_file(void)
144144
char abort_msg[] = "aborting due to possible repository "
145145
"corruption on the remote side.";
146146
int buffered = -1;
147+
ssize_t sz;
147148
const char *argv[10];
148149
int arg = 0;
149150

@@ -168,22 +169,15 @@ static void create_pack_file(void)
168169
pack_objects.git_cmd = 1;
169170
pack_objects.argv = argv;
170171

171-
if (start_command(&pack_objects)) {
172-
/* daemon sets things up to ignore TERM */
173-
kill(rev_list.pid, SIGKILL);
172+
if (start_command(&pack_objects))
174173
die("git-upload-pack: unable to fork git-pack-objects");
175-
}
176174

177175
/* We read from pack_objects.err to capture stderr output for
178176
* progress bar, and pack_objects.out to capture the pack data.
179177
*/
180178

181179
while (1) {
182-
const char *who;
183180
struct pollfd pfd[2];
184-
pid_t pid;
185-
int status;
186-
ssize_t sz;
187181
int pe, pu, pollsize;
188182

189183
reset_timeout();
@@ -204,123 +198,91 @@ static void create_pack_file(void)
204198
pollsize++;
205199
}
206200

207-
if (pollsize) {
208-
if (poll(pfd, pollsize, -1) < 0) {
209-
if (errno != EINTR) {
210-
error("poll failed, resuming: %s",
211-
strerror(errno));
212-
sleep(1);
213-
}
214-
continue;
215-
}
216-
if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
217-
/* Data ready; we keep the last byte
218-
* to ourselves in case we detect
219-
* broken rev-list, so that we can
220-
* leave the stream corrupted. This
221-
* is unfortunate -- unpack-objects
222-
* would happily accept a valid pack
223-
* data with trailing garbage, so
224-
* appending garbage after we pass all
225-
* the pack data is not good enough to
226-
* signal breakage to downstream.
227-
*/
228-
char *cp = data;
229-
ssize_t outsz = 0;
230-
if (0 <= buffered) {
231-
*cp++ = buffered;
232-
outsz++;
233-
}
234-
sz = xread(pack_objects.out, cp,
235-
sizeof(data) - outsz);
236-
if (0 < sz)
237-
;
238-
else if (sz == 0) {
239-
close(pack_objects.out);
240-
pack_objects.out = -1;
241-
}
242-
else
243-
goto fail;
244-
sz += outsz;
245-
if (1 < sz) {
246-
buffered = data[sz-1] & 0xFF;
247-
sz--;
248-
}
249-
else
250-
buffered = -1;
251-
sz = send_client_data(1, data, sz);
252-
if (sz < 0)
253-
goto fail;
254-
}
255-
if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) {
256-
/* Status ready; we ship that in the side-band
257-
* or dump to the standard error.
258-
*/
259-
sz = xread(pack_objects.err, progress,
260-
sizeof(progress));
261-
if (0 < sz)
262-
send_client_data(2, progress, sz);
263-
else if (sz == 0) {
264-
close(pack_objects.err);
265-
pack_objects.err = -1;
266-
}
267-
else
268-
goto fail;
201+
if (!pollsize)
202+
break;
203+
204+
if (poll(pfd, pollsize, -1) < 0) {
205+
if (errno != EINTR) {
206+
error("poll failed, resuming: %s",
207+
strerror(errno));
208+
sleep(1);
269209
}
210+
continue;
270211
}
271-
272-
/* See if the children are still there */
273-
if (rev_list.pid || pack_objects.pid) {
274-
pid = waitpid(-1, &status, WNOHANG);
275-
if (!pid)
276-
continue;
277-
who = ((pid == rev_list.pid) ? "git-rev-list" :
278-
(pid == pack_objects.pid) ? "git-pack-objects" :
279-
NULL);
280-
if (!who) {
281-
if (pid < 0) {
282-
error("git-upload-pack: %s",
283-
strerror(errno));
284-
goto fail;
285-
}
286-
error("git-upload-pack: we weren't "
287-
"waiting for %d", pid);
288-
continue;
212+
if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
213+
/* Data ready; we keep the last byte to ourselves
214+
* in case we detect broken rev-list, so that we
215+
* can leave the stream corrupted. This is
216+
* unfortunate -- unpack-objects would happily
217+
* accept a valid packdata with trailing garbage,
218+
* so appending garbage after we pass all the
219+
* pack data is not good enough to signal
220+
* breakage to downstream.
221+
*/
222+
char *cp = data;
223+
ssize_t outsz = 0;
224+
if (0 <= buffered) {
225+
*cp++ = buffered;
226+
outsz++;
227+
}
228+
sz = xread(pack_objects.out, cp,
229+
sizeof(data) - outsz);
230+
if (0 < sz)
231+
;
232+
else if (sz == 0) {
233+
close(pack_objects.out);
234+
pack_objects.out = -1;
289235
}
290-
if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) {
291-
error("git-upload-pack: %s died with error.",
292-
who);
236+
else
293237
goto fail;
238+
sz += outsz;
239+
if (1 < sz) {
240+
buffered = data[sz-1] & 0xFF;
241+
sz--;
294242
}
295-
if (pid == rev_list.pid)
296-
rev_list.pid = 0;
297-
if (pid == pack_objects.pid)
298-
pack_objects.pid = 0;
299-
if (rev_list.pid || pack_objects.pid)
300-
continue;
301-
}
302-
303-
/* both died happily */
304-
if (pollsize)
305-
continue;
306-
307-
/* flush the data */
308-
if (0 <= buffered) {
309-
data[0] = buffered;
310-
sz = send_client_data(1, data, 1);
243+
else
244+
buffered = -1;
245+
sz = send_client_data(1, data, sz);
311246
if (sz < 0)
312247
goto fail;
313-
fprintf(stderr, "flushed.\n");
314248
}
315-
if (use_sideband)
316-
packet_flush(1);
317-
return;
249+
if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) {
250+
/* Status ready; we ship that in the side-band
251+
* or dump to the standard error.
252+
*/
253+
sz = xread(pack_objects.err, progress,
254+
sizeof(progress));
255+
if (0 < sz)
256+
send_client_data(2, progress, sz);
257+
else if (sz == 0) {
258+
close(pack_objects.err);
259+
pack_objects.err = -1;
260+
}
261+
else
262+
goto fail;
263+
}
264+
}
265+
266+
if (finish_command(&pack_objects)) {
267+
error("git-upload-pack: git-pack-objects died with error.");
268+
goto fail;
269+
}
270+
if (finish_async(&rev_list))
271+
goto fail; /* error was already reported */
272+
273+
/* flush the data */
274+
if (0 <= buffered) {
275+
data[0] = buffered;
276+
sz = send_client_data(1, data, 1);
277+
if (sz < 0)
278+
goto fail;
279+
fprintf(stderr, "flushed.\n");
318280
}
281+
if (use_sideband)
282+
packet_flush(1);
283+
return;
284+
319285
fail:
320-
if (pack_objects.pid)
321-
kill(pack_objects.pid, SIGKILL);
322-
if (rev_list.pid)
323-
kill(rev_list.pid, SIGKILL);
324286
send_client_data(3, abort_msg, sizeof(abort_msg));
325287
die("git-upload-pack: %s", abort_msg);
326288
}

0 commit comments

Comments
 (0)