git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
To: git@vger.kernel.org
Cc: "Junio C Hamano" <gitster@pobox.com>, "Jeff King" <peff@peff.net>,
	"Han-Wen Nienhuys" <hanwen@google.com>,
	"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
Subject: [PATCH 04/20] refs API: make parse_loose_ref_contents() not set errno
Date: Thu, 14 Oct 2021 02:06:16 +0200	[thread overview]
Message-ID: <patch-04.20-758c761abcf-20211013T235900Z-avarab@gmail.com> (raw)
In-Reply-To: <cover-00.20-00000000000-20211013T235900Z-avarab@gmail.com>

From: Han-Wen Nienhuys <hanwen@google.com>

Change the parse_loose_ref_contents() function to stop setting "errno"
and failure, and to instead pass up a "failure_errno" via a
parameter. This requires changing its callers to do the same.

The EINVAL error from parse_loose_ref_contents is used in files-backend
to create a custom error message.

In untangling this we discovered a tricky edge case. The
refs_read_special_head() function was relying on
parse_loose_ref_contents() setting EINVAL.

By converting it to use "saved_errno" we can migrate away from "errno"
in this part of the code entirely, and do away with an existing
"save_errno" pattern, its only purpose was to not clobber the "errno"
we previously needed at the end of files_read_raw_ref().

Let's assert that we can do that by not having files_read_raw_ref()
itself operate on *failure_errno in addition to passing it on. Instead
we'll assert that if we return non-zero we actually do set errno, thus
assuring ourselves and callers that they can trust the resulting
"failure_errno".

Signed-off-by: Han-Wen Nienhuys <hanwen@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 refs.c               |  8 +++++---
 refs/files-backend.c | 31 ++++++++++++++++++++-----------
 refs/refs-internal.h |  6 ++++--
 t/t3200-branch.sh    |  1 +
 4 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/refs.c b/refs.c
index acc5d5fa578..b1640b5d582 100644
--- a/refs.c
+++ b/refs.c
@@ -1647,7 +1647,8 @@ int for_each_fullref_in_prefixes(const char *namespace,
 
 static int refs_read_special_head(struct ref_store *ref_store,
 				  const char *refname, struct object_id *oid,
-				  struct strbuf *referent, unsigned int *type)
+				  struct strbuf *referent, unsigned int *type,
+				  int *failure_errno)
 {
 	struct strbuf full_path = STRBUF_INIT;
 	struct strbuf content = STRBUF_INIT;
@@ -1657,7 +1658,8 @@ static int refs_read_special_head(struct ref_store *ref_store,
 	if (strbuf_read_file(&content, full_path.buf, 0) < 0)
 		goto done;
 
-	result = parse_loose_ref_contents(content.buf, oid, referent, type);
+	result = parse_loose_ref_contents(content.buf, oid, referent, type,
+					  failure_errno);
 
 done:
 	strbuf_release(&full_path);
@@ -1672,7 +1674,7 @@ int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
 	assert(failure_errno);
 	if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) {
 		return refs_read_special_head(ref_store, refname, oid, referent,
-					      type);
+					      type, failure_errno);
 	}
 
 	return ref_store->be->read_raw_ref(ref_store, refname, oid, referent,
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 94c194665ed..c73ffd1ca33 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -355,6 +355,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 	int fd;
 	int ret = -1;
 	int remaining_retries = 3;
+	int myerr = 0;
 
 	*type = 0;
 	strbuf_reset(&sb_path);
@@ -382,11 +383,13 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 
 	if (lstat(path, &st) < 0) {
 		int ignore_errno;
-		if (errno != ENOENT)
+		myerr = errno;
+		errno = 0;
+		if (myerr != ENOENT)
 			goto out;
 		if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
 				      referent, type, &ignore_errno)) {
-			errno = ENOENT;
+			myerr = ENOENT;
 			goto out;
 		}
 		ret = 0;
@@ -397,7 +400,9 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 	if (S_ISLNK(st.st_mode)) {
 		strbuf_reset(&sb_contents);
 		if (strbuf_readlink(&sb_contents, path, st.st_size) < 0) {
-			if (errno == ENOENT || errno == EINVAL)
+			myerr = errno;
+			errno = 0;
+			if (myerr == ENOENT || myerr == EINVAL)
 				/* inconsistent with lstat; retry */
 				goto stat_ref;
 			else
@@ -427,7 +432,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 		 */
 		if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
 				      referent, type, &ignore_errno)) {
-			errno = EISDIR;
+			myerr = EISDIR;
 			goto out;
 		}
 		ret = 0;
@@ -440,7 +445,8 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 	 */
 	fd = open(path, O_RDONLY);
 	if (fd < 0) {
-		if (errno == ENOENT && !S_ISLNK(st.st_mode))
+		myerr = errno;
+		if (myerr == ENOENT && !S_ISLNK(st.st_mode))
 			/* inconsistent with lstat; retry */
 			goto stat_ref;
 		else
@@ -448,26 +454,29 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 	}
 	strbuf_reset(&sb_contents);
 	if (strbuf_read(&sb_contents, fd, 256) < 0) {
-		int save_errno = errno;
+		myerr = errno;
 		close(fd);
-		errno = save_errno;
 		goto out;
 	}
 	close(fd);
 	strbuf_rtrim(&sb_contents);
 	buf = sb_contents.buf;
 
-	ret = parse_loose_ref_contents(buf, oid, referent, type);
+	ret = parse_loose_ref_contents(buf, oid, referent, type, &myerr);
 
 out:
-	*failure_errno = errno;
+	if (ret && !myerr)
+		BUG("returning non-zero %d, should have set myerr!", ret);
+	*failure_errno = myerr;
+
 	strbuf_release(&sb_path);
 	strbuf_release(&sb_contents);
 	return ret;
 }
 
 int parse_loose_ref_contents(const char *buf, struct object_id *oid,
-			     struct strbuf *referent, unsigned int *type)
+			     struct strbuf *referent, unsigned int *type,
+			     int *failure_errno)
 {
 	const char *p;
 	if (skip_prefix(buf, "ref:", &buf)) {
@@ -486,7 +495,7 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid,
 	if (parse_oid_hex(buf, oid, &p) ||
 	    (*p != '\0' && !isspace(*p))) {
 		*type |= REF_ISBROKEN;
-		errno = EINVAL;
+		*failure_errno = EINVAL;
 		return -1;
 	}
 	return 0;
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index c87f1135e5b..121b8fdad08 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -706,10 +706,12 @@ struct ref_store {
 };
 
 /*
- * Parse contents of a loose ref file.
+ * Parse contents of a loose ref file. *failure_errno maybe be set to EINVAL for
+ * invalid contents.
  */
 int parse_loose_ref_contents(const char *buf, struct object_id *oid,
-			     struct strbuf *referent, unsigned int *type);
+			     struct strbuf *referent, unsigned int *type,
+			     int *failure_errno);
 
 /*
  * Fill in the generic part of refs and add it to our collection of
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index b5242719159..7486688d292 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -745,6 +745,7 @@ test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' '
 	) &&
 	git --git-dir subdir/.git/ branch rename-src &&
 	git rev-parse rename-src >expect &&
+	# Tests a BUG() assertion in files_read_raw_ref()
 	git --git-dir subdir/.git/ branch -m rename-src rename-dest &&
 	git rev-parse rename-dest >actual &&
 	test_cmp expect actual &&
-- 
2.33.1.1346.g48288c3c089


  parent reply	other threads:[~2021-10-14  0:07 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-14  0:06 [PATCH 00/20] refs: stop having the API set "errno" Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 01/20] branch tests: test for errno propagating on failing read Ævar Arnfjörð Bjarmason
2021-10-14  1:57   ` Eric Sunshine
2021-10-14  0:06 ` [PATCH 02/20] refs API: add a version of refs_resolve_ref_unsafe() with "errno" Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 03/20] refs API: make refs_read_raw_ref() not set errno Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` Ævar Arnfjörð Bjarmason [this message]
2021-10-14  0:06 ` [PATCH 05/20] refs API: make refs_rename_ref_available() static Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 06/20] refs/files: remove "name exist?" check in lock_ref_oid_basic() Ævar Arnfjörð Bjarmason
2021-10-14 20:53   ` Junio C Hamano
2021-10-14  0:06 ` [PATCH 07/20] refs API: remove refs_read_ref_full() wrapper Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 08/20] refs API: make resolve_gitlink_ref() not set errno Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 09/20] refs API: make loose_fill_ref_dir() " Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 10/20] refs API: make files_copy_or_rename_ref() et al " Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 11/20] refs API: ignore errno in worktree.c's add_head_info() Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 12/20] refs API: ignore errno in worktree.c's find_shared_symref() Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 13/20] refs tests: ignore ignore errno in test-ref-store helper Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 14/20] refs API: make refs_resolve_refdup() not set errno Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 15/20] refs API: make refs_ref_exists() " Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 16/20] refs API: make resolve_ref_unsafe() " Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 17/20] refs API: make expand_ref() & repo_dwim_log() " Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 18/20] refs API: don't expose "errno" in run_transaction_hook() Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 19/20] refs API: post-migration API renaming [1/2] Ævar Arnfjörð Bjarmason
2021-10-14  0:06 ` [PATCH 20/20] refs API: post-migration API renaming [2/2] Ævar Arnfjörð Bjarmason
2021-10-16  9:39 ` [PATCH v2 00/21] refs: stop having the API set "errno" Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 01/21] branch tests: test for errno propagating on failing read Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 02/21] refs API: add a version of refs_resolve_ref_unsafe() with "errno" Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 03/21] refs API: make refs_read_raw_ref() not set errno Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 04/21] refs API: make parse_loose_ref_contents() " Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 05/21] refs API: make refs_rename_ref_available() static Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 06/21] reflog tests: add --updateref tests Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 07/21] refs/files: remove "name exist?" check in lock_ref_oid_basic() Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 08/21] refs API: remove refs_read_ref_full() wrapper Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 09/21] refs API: make resolve_gitlink_ref() not set errno Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 10/21] refs API: make loose_fill_ref_dir() " Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 11/21] refs API: make files_copy_or_rename_ref() et al " Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 12/21] refs API: ignore errno in worktree.c's add_head_info() Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 13/21] refs API: ignore errno in worktree.c's find_shared_symref() Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 14/21] refs tests: ignore ignore errno in test-ref-store helper Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 15/21] refs API: make refs_resolve_refdup() not set errno Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 16/21] refs API: make refs_ref_exists() " Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 17/21] refs API: make resolve_ref_unsafe() " Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 18/21] refs API: make expand_ref() & repo_dwim_log() " Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 19/21] refs API: don't expose "errno" in run_transaction_hook() Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 20/21] refs API: post-migration API renaming [1/2] Ævar Arnfjörð Bjarmason
2021-10-16  9:39   ` [PATCH v2 21/21] refs API: post-migration API renaming [2/2] Ævar Arnfjörð Bjarmason

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=patch-04.20-758c761abcf-20211013T235900Z-avarab@gmail.com \
    --to=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=hanwen@google.com \
    --cc=peff@peff.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).