"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
fix cloning from git9 server
To:
gameoftrees@openbsd.org
Date:
Tue, 28 May 2024 19:39:23 +0200

Download raw body.

Thread
  • Stefan Sperling:

    fix cloning from git9 server

As pointed out by Lucas on IRC, got clone is failing against the
git9 server implementation:

  $ got clone -b master  git://shithub.us/ori/mc
  Connecting to git://shithub.us/ori/mc
  11.8M fetchedgot-fetch-pack: unexpected end of file
  got: unexpected end of file

(The above won't work without '-b master' because of a different error.
git9 doesn't announce the HEAD symref yet, so Got cannot determine a
default branch name without -b.)

The git9 server does not use sidebands during the pack file transfer,
and handling of this case is broken in got-fetch-pack.
The bug is that our no-sidebands code path expects pack file sizes to be
in multiples of 20 because sizeof(buf) is specified as minimum read size
via got_pkt_readn(). Instead, read as many bytes at possible between 1
and sizeof(buf), leaving the last 20 bytes for the SHA1 checksum as usual.
This makes it work, and tests keep passing.

ok?

diff /home/stsp/src/got
commit - 5061349db34001800b847dde0b0652dc2c08fcc9
path + /home/stsp/src/got
blob - 7410ec56e191326b2f490dfc214b907874ff03ca
file + libexec/got-fetch-pack/got-fetch-pack.c
--- libexec/got-fetch-pack/got-fetch-pack.c
+++ libexec/got-fetch-pack/got-fetch-pack.c
@@ -51,6 +51,7 @@
 #include "got_lib_privsep.h"
 #include "got_lib_pack.h"
 #include "got_lib_pkt.h"
+#include "got_lib_poll.h"
 #include "got_lib_gitproto.h"
 #include "got_lib_ratelimit.h"
 
@@ -341,7 +342,7 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 	char hashstr[SHA1_DIGEST_STRING_LENGTH];
 	struct got_object_id *have, *want;
 	int is_firstpkt = 1, nref = 0, refsz = 16;
-	int i, n, nwant = 0, nhave = 0, acked = 0;
+	int i, n, nwant = 0, nhave = 0, acked = 0, eof = 0;
 	off_t packsz = 0, last_reported_packsz = 0;
 	char *id_str = NULL, *default_id_str = NULL, *refname = NULL;
 	char *server_capabilities = NULL, *my_capabilities = NULL;
@@ -648,7 +649,7 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 	    strstr(my_capabilities, GOT_CAPA_SIDE_BAND_64K) != NULL)
 		have_sidebands = 1;
 
-	while (1) {
+	while (!eof) {
 		ssize_t r = 0;
 		int datalen = -1;
 
@@ -740,11 +741,16 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 			}
 		} else {
 			/* No sideband channel. Every byte is packfile data. */
-			err = got_pkt_readn(&r, fd, buf, sizeof buf, INFTIM);
-			if (err)
-				goto done;
-			if (r <= 0)
-				break;
+			size_t n = 0;
+			err = got_poll_read_full_timeout(fd, &n,
+			    buf, sizeof buf, 1, INFTIM);
+			if (err) {
+				if (err->code != GOT_ERR_EOF)
+					goto done;
+				r = 0;
+				eof = 1;
+			} else
+				r = n;
 		}
 
 		/*
@@ -753,8 +759,6 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 		 * keep SHA1_DIGEST_LENGTH bytes buffered and avoid mixing
 		 * those bytes into our SHA1 checksum computation until we
 		 * know for sure that additional pack file data bytes follow.
-		 *
-		 * We can assume r > 0 since otherwise the loop would exit.
 		 */
 		if (r < SHA1_DIGEST_LENGTH) {
 			if (sha1_buf_len < SHA1_DIGEST_LENGTH) {
@@ -778,7 +782,7 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 				/* Buffer potential checksum bytes. */
 				memcpy(sha1_buf + sha1_buf_len, buf, r);
 				sha1_buf_len += r;
-			} else {
+			} else if (r > 0) {
 				/*
 				 * Mix in previously buffered bytes which
 				 * are not part of the checksum after all.