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:
M | cmd/ln.c | 48 | ++++++++++++++++++++++++++++-------------------- |
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;