commit 27b75514d9b1c8e9f188ef9c483760647a8c1b72 from: Stefan Sperling date: Sat Aug 28 10:46:51 2021 UTC do not send a pack file when 'got send' is only deleting branches The git protocol spec says the client MUST NOT send a pack file if the only command used is 'delete'. Fixes 'got send -d' against Github's server which closed the session upon receiving the empty pack file we sent. This problem wasn't caught by regression tests since git-daemon does accept an empty pack file. Problem reported by jrick. commit - 2ae2891d0e4f8e66706be6eb6394c199f18b7691 commit + 27b75514d9b1c8e9f188ef9c483760647a8c1b72 blob - eaabe5b6cd871e178683532ded10fc75eb8f864d blob + f48598b57aa7474d4174c928c96d948834824f21 --- got/got.c +++ got/got.c @@ -7432,12 +7432,15 @@ send_progress(void *arg, off_t packfile_size, int ncom if (got_path_cmp(branchname, refname, strlen(branchname), strlen(refname)) == 0) { status = "deleted"; + a->sent_something = 1; break; } } } - printf("\nServer has %s %s", status, refname); + if (a->printed_something) + putchar('\n'); + printf("Server has %s %s", status, refname); a->printed_something = 1; return NULL; } blob - 52892c3decd6888c574c8cfa2ad91ff22a4df596 blob + 110f62e7d18931540ea150d0169e082cd0227e48 --- lib/send.c +++ lib/send.c @@ -453,7 +453,7 @@ got_send_pack(const char *remote_name, struct got_path struct got_object_id *my_id = NULL; int i, nours = 0, ntheirs = 0; size_t nalloc_ours = 0, nalloc_theirs = 0; - int refs_to_send = 0; + int refs_to_send = 0, refs_to_delete = 0; off_t bytes_sent = 0; struct pack_progress_arg ppa; uint8_t packsha1[SHA1_DIGEST_LENGTH]; @@ -746,37 +746,43 @@ got_send_pack(const char *remote_name, struct got_path TAILQ_FOREACH(pe, delete_branches, entry) { const char *branchname = pe->path; if (find_their_ref(&their_refs, branchname)) - refs_to_send++; + refs_to_delete++; } - if (refs_to_send == 0) { + if (refs_to_send == 0 && refs_to_delete == 0) { got_privsep_send_stop(imsg_sendfds[0]); goto done; } - memset(&ppa, 0, sizeof(ppa)); - ppa.progress_cb = progress_cb; - ppa.progress_arg = progress_arg; - err = got_pack_create(packsha1, packfile, their_ids, ntheirs, - our_ids, nours, repo, 0, 1, pack_progress, &ppa, - cancel_cb, cancel_arg); - if (err) - goto done; - - if (fflush(packfile) == -1) { - err = got_error_from_errno("fflush"); - goto done; - } + if (refs_to_send > 0) { + memset(&ppa, 0, sizeof(ppa)); + ppa.progress_cb = progress_cb; + ppa.progress_arg = progress_arg; + err = got_pack_create(packsha1, packfile, their_ids, ntheirs, + our_ids, nours, repo, 0, 1, pack_progress, &ppa, + cancel_cb, cancel_arg); + if (err) + goto done; - npackfd = dup(fileno(packfile)); - if (npackfd == -1) { - err = got_error_from_errno("dup"); - goto done; + if (fflush(packfile) == -1) { + err = got_error_from_errno("fflush"); + goto done; + } + + npackfd = dup(fileno(packfile)); + if (npackfd == -1) { + err = got_error_from_errno("dup"); + goto done; + } + err = got_privsep_send_packfd(&sendibuf, npackfd); + if (err != NULL) + goto done; + npackfd = -1; + } else { + err = got_privsep_send_packfd(&sendibuf, -1); + if (err != NULL) + goto done; } - err = got_privsep_send_packfd(&sendibuf, npackfd); - if (err != NULL) - goto done; - npackfd = -1; while (!done) { int success = 0; blob - 70cdbda2df02489a97ea03b27cca01f0e4d3fb10 blob + 2a886f297fcabe6e08a1841e95f3913286f75c86 --- libexec/got-send-pack/got-send-pack.c +++ libexec/got-send-pack/got-send-pack.c @@ -820,9 +820,11 @@ send_pack(int fd, struct got_pathlist_head *refs, if (err) goto done; - err = send_pack_file(fd, packfd, ibuf); - if (err) - goto done; + if (packfd != -1) { + err = send_pack_file(fd, packfd, ibuf); + if (err) + goto done; + } err = readpkt(&n, fd, buf, sizeof(buf)); if (err) blob - d8ab1acc4f17379f79f974897f8e33f9677871e2 blob + b7603c982431e0c17ae7aeb27a58df3481304608 --- regress/cmdline/send.sh +++ regress/cmdline/send.sh @@ -354,19 +354,15 @@ EOF fi got send -r $testroot/repo -d refs/heads/branch2 origin \ - > $testroot/stdout.raw 2>$testroot/stderr + > $testroot/stdout 2>$testroot/stderr ret="$?" if [ "$ret" != "0" ]; then echo "got send command failed unexpectedly" >&2 test_done "$testroot" "$ret" return 1 fi - tr -d '\r' < $testroot/stdout.raw > $testroot/stdout echo 'Connecting to "origin" 127.0.0.1' > $testroot/stdout.expected - echo -n "packing 0 references; 0 objects; deltify: 0%; " \ - >> $testroot/stdout.expected - echo "uploading pack: 32B 100%" >> $testroot/stdout.expected echo "Server has deleted refs/heads/branch2" \ >> $testroot/stdout.expected