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

From:
James Cook <falsifian@falsifian.org>
Subject:
got-portable: Fix "could not parse reference data" on NetBSD
To:
gameoftrees@openbsd.org
Date:
Wed, 19 Mar 2025 16:26:22 +0000

Download raw body.

Thread
I found many commands, e.g. 'got br -l', would complain:
	got: could not parse reference data

It seems parse_ref_file() assumes getline() will produce an error
if the file is a directory, e.g. "refs/heads". But on NetBSD
it will (at least sometimes) instead produce binary data that
got tries to parse as a reference.

The below patch explicitly checks whether the ref is a directory.
Maybe this should go in non-portable got too, at least to keep
the codebases more similar.

(By the way, I noticed that if fstat fails, parse_ref_file doesn't
call get_lockfile_unlock in the cleanup path. Is that an oversight,
or is it that way because we know the program's going to stop soon
anyway, or is it something else? Every other "goto done;" unlocks,
so if it's okay to unlock in that case too, the unlock could be
moved to "done:" to make the code a bit tidier.)

-- 
James

diff /home/falsifian/co/got-portable
path + /home/falsifian/co/got-portable
commit - a86933943ecf60552fe7c1bbb4b44fbf56a7118a
blob - 5d1c2e817373f8450d2af8dc48ea04aeada52476
file + lib/reference.c
--- lib/reference.c
+++ lib/reference.c
@@ -206,15 +206,19 @@ parse_ref_file(struct got_reference **ref, const char 
 		err = got_error_from_errno2("fstat", abspath);
 		goto done;
 	}
+	if (S_ISDIR(sb.st_mode)) {
+		err = got_error(GOT_ERR_NOT_REF);
+		if (lock)
+			got_lockfile_unlock(lf, -1);
+		goto done;
+	}
 
 	linelen = getline(&line, &linesize, f);
 	if (linelen == -1) {
 		if (feof(f))
 			err = NULL; /* ignore empty files (could be locks) */
 		else {
-			if (errno == EISDIR)
-				err = got_error(GOT_ERR_NOT_REF);
-			else if (ferror(f))
+			if (ferror(f))
 				err = got_ferror(f, GOT_ERR_IO);
 			else
 				err = got_error_from_errno2("getline", abspath);