From d636f9c117d6383fedcc769661fa0fa4d372b153 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 11 Jun 2024 17:48:14 -0700 Subject: [PATCH] diff: port to FreeBSD, NetBSD Problem reported by Bruno Haible . * src/diff.c (NOFOLLOW_SYMLINK_ERRNO): New constant. (compare_files): Use it instead of ELOOP. When it is not ELOOP, treat ELOOP as a failure in resolving the parent directory; this saves a syscall in some situation. --- src/diff.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/diff.c b/src/diff.c index 76432ee..3abcb66 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1139,6 +1139,20 @@ dir_p (struct comparison const *pcmp, int f) return S_ISDIR (pcmp->file[f].stat.st_mode) != 0; } +/* If openat with O_NOFOLLOW fails because the file is a symlink, + this platform sets errno to NOFOLLOW_SYMLINK_ERRNO. + Although POSIX says errno must be ELOOP in that situation, + FreeBSD and NetBSD behave more usefully. */ +enum { NOFOLLOW_SYMLINK_ERRNO = +#ifdef __FreeBSD__ + EMLINK +#elif defined __NetBSD__ + EFTYPE +#else + ELOOP +#endif +}; + /* Compare two files with parent comparison PARENT. The two files are described by CMP, which has been prepped to contain the files' stat results, file types, and possibly descriptors. @@ -1485,10 +1499,14 @@ compare_files (struct comparison const *parent, enum detype const detype[2], err = 0; } - /* If it might be a symlink, play it safe and fstatat later. */ - if (err == ELOOP && no_dereference_symlinks - && (detype[f] == DE_UNKNOWN - || (detype[f] == DE_LNK && accmode == O_RDONLY))) + /* If it is a symlink, fstatat later. If it might be a + symlink, play it safe and fstatat later. */ + if (err == NOFOLLOW_SYMLINK_ERRNO + && (NOFOLLOW_SYMLINK_ERRNO != ELOOP + || (no_dereference_symlinks + && (detype[f] == DE_UNKNOWN + || (detype[f] == DE_LNK + && accmode == O_RDONLY))))) { fd = UNOPENED; err = 0; @@ -1561,11 +1579,12 @@ compare_files (struct comparison const *parent, enum detype const detype[2], : openat (dirfd, atname, O_RDONLY | oflags)); if (O_PATH_DEFINED && cmp.file[dir_arg].desc < 0 && (dir_detype == DE_LNK || dir_detype == DE_UNKNOWN) - && no_dereference_symlinks && errno == ELOOP) + && no_dereference_symlinks && errno == NOFOLLOW_SYMLINK_ERRNO) cmp.file[dir_arg].desc = openat (dirfd, atname, O_PATHSEARCH | oflags); if (cmp.file[dir_arg].desc < 0 - ? (O_PATH_DEFINED || !no_dereference_symlinks || errno != ELOOP + ? (O_PATH_DEFINED || !no_dereference_symlinks + || errno != NOFOLLOW_SYMLINK_ERRNO || (fstatat (dirfd, atname, &cmp.file[dir_arg].stat, AT_SYMLINK_NOFOLLOW) < 0)) -- 2.45.2