logo

utils-std

Collection of commonly available Unix tools
commit: 2bd2c87f99d9925c90c4f5cc6c3f5180bfa9b8c6
parent 3c38e0ef8a875dfb0449c77be9a05f6ff464cb11
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun,  5 May 2024 01:19:32 +0200

cmd/ln: Fix for FreeBSD returning EMLINK instead of ENOTDIR/ELOOP

Diffstat:

Mcmd/ln.c48++++++++++++++++++++++++++++--------------------
1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/cmd/ln.c b/cmd/ln.c @@ -59,35 +59,43 @@ do_link(char *src, char *dest) errno = 0; int dirfd = open(dest, open_dir_flags); - if(dirfd < 0 && errno != ENOTDIR) + if(dirfd < 0) { - fprintf( - stderr, "ln: Failed opening destination as directory '%s': %s\n", dest, strerror(errno)); - return -1; - } + assert(errno != 0); - if(errno == ENOTDIR) - { - if(!force) + // ENOTDIR: Found but not a directory + // ELOOP: POSIX return code when O_NOFOLLOW encounters a symbolic link + // EMLINK: Same as ELOOP but FreeBSD *sigh* + if(errno == ENOTDIR || errno == ELOOP || errno == EMLINK) { - fprintf(stderr, "ln: Error: Destination '%s' already exists\n", dest); - return -1; - } + if(!force) + { + fprintf(stderr, "ln: Error: Destination '%s' already exists\n", dest); + return -1; + } - errno = 0; + errno = 0; - dirfd = AT_FDCWD; + dirfd = AT_FDCWD; - if(unlink(dest) < 0) - { - fprintf(stderr, - "ln: Failed removing already existing destination '%s': %s\n", - dest, - strerror(errno)); - return -1; + if(unlink(dest) < 0) + { + fprintf(stderr, + "ln: Failed removing already existing destination '%s': %s\n", + dest, + strerror(errno)); + return -1; + } } } + if(errno != 0) + { + fprintf( + stderr, "ln: Failed opening destination as directory '%s': %s\n", dest, strerror(errno)); + return -1; + } + if(opt_s) { if(symlinkat(src, dirfd, dest) == 0) goto cleanup;