Subject: Re: [PATCH] wrapper: Fix a errno discrepancy on NetBSD.

From: "brian m. carlson" <[email-masked]>
Date: Sat, 3 May 2025 00:57:11 +0000

On 2025-05-02 at 23:33:32, Collin Funk wrote:
> As documented on NetBSD's man page, open with the O_NOFOLLOW flag and a
> symlink returns -1 and sets errno to EFTYPE which differs from POSIX.
> This patch fixes the following test failure:
> 
> $ sh t0602-reffiles-fsck.sh --verbose
> --- expect	2025-05-02 23:05:23.920890147 +0000
> +++ err	2025-05-02 23:05:23.916794959 +0000
> @@ -1 +1 @@
> -error: packed-refs: badRefFiletype: not a regular file but a symlink
> +error: unable to open '.git/packed-refs': Inappropriate file type or format
> not ok 12 - the filetype of packed-refs should be checked
> 
> This portability issue was introduced in Commit
> cfea2f2da8 (packed-backend: check whether the "packed-refs" is regular file, 2025-02-28)
> 
> Signed-off-by: Collin Funk <[email-masked]>
> ---
>  wrapper.c | 14 +++++++++++++-
>  1 file changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/wrapper.c b/wrapper.c
> index 3c79778055..4d448d7c57 100644
> --- a/wrapper.c
> +++ b/wrapper.c
> @@ -737,7 +737,19 @@ int is_empty_or_missing_file(const char *filename)
>  int open_nofollow(const char *path, int flags)
>  {
>  #ifdef O_NOFOLLOW
> -	return open(path, flags | O_NOFOLLOW);
> +	int ret = open(path, flags | O_NOFOLLOW);
> +#ifdef __NetBSD__
> +	/*
> +	 * NetBSD sets errno to EFTYPE when path is a symlink. The only other
> +	 * time this errno occurs when O_REGULAR is used. Since we don't use
> +	 * it anywhere we can avoid an lstat here.
> +	 */
> +	if (ret < 0 && errno == EFTYPE) {
> +		errno = ELOOP;
> +		return -1;
> +	}
> +#endif
> +	return ret;

This patch seems reasonable and correct.  I don't use NetBSD, but I do
often test there, and I'm aware of this infelicity.  I'm surprised we
haven't hit it before.

I suspect we'll also hit this on FreeBSD, which has a similar issue in
that it returns `EMLINK` instead of `ELOOP`.  I do wish these two OSes
would provide an appropriate POSIX-compatible `open` call when set with
`_POSIX_SOURCE`, since this is one of the biggest portability problems
with them.
-- 
brian m. carlson (they/them)
Toronto, Ontario, CA