logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/
commit: 0320e0b9c5421835fb612a6dc25fd455827997d0
parent 8990b1c0acc2bc5035351c1ff33ba2acaf59868f
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Mon,  4 Aug 2025 06:52:59 +0200

cmd/ln: only omit O_NOFOLLOW when disambiguating target argument

Diffstat:

Mcmd/ln.c7++++---
Mtest-cmd/ln.sh17++++++++++++-----
2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/cmd/ln.c b/cmd/ln.c @@ -23,7 +23,8 @@ const char *argv0 = "ln"; static bool opt_s = false, force = false; static int link_flags = 0; -static int open_dest_flags = O_RDONLY | O_PATH; +static int open_target_flags = O_RDONLY | O_PATH; +static int open_dest_flags = O_RDONLY | O_PATH | O_NOFOLLOW; static struct stat dest_stat; static int @@ -182,7 +183,7 @@ main(int argc, char *argv[]) force = true; break; case 'n': - FIELD_SET(open_dest_flags, O_NOFOLLOW); + FIELD_SET(open_target_flags, O_NOFOLLOW); break; case 's': opt_s = true; @@ -221,7 +222,7 @@ main(int argc, char *argv[]) } else if(argc == 2) { - int targetfd = open(target, open_dest_flags); + int targetfd = open(target, open_target_flags); if(targetfd >= 0) { if(fstat(targetfd, &dest_stat) < 0) diff --git a/test-cmd/ln.sh b/test-cmd/ln.sh @@ -2,7 +2,7 @@ # SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> # SPDX-License-Identifier: MPL-2.0 -plans=59 +plans=63 WD=$(dirname "$0") target="${WD}/../cmd/ln" . "${WD}/tap.sh" @@ -94,9 +94,16 @@ t_args 'implicit_dest' '' -sn //example.org t_readlink ./example.org //example.org t_cmd '' '' rm ./example.org -t_args 'dest_broken_symlink:create' '' -s /var/empty/e/no/ent dest_broken_symlink +t_args 'target_broken_symlink:create' '' -s /var/empty/e/no/ent target_broken_symlink +t_args --exit=1 'target_broken_symlink' "\ +ln: error: Destination 'target_broken_symlink' already exists +" -s //example.org target_broken_symlink +t_args 'target_broken_symlink:force' '' -sf //example.org target_broken_symlink +t_cmd 'target_broken_symlink:cleanup' '' rm target_broken_symlink + +t_args 'dest_broken_symlink:create' '' -s /foo/bar/dest_broken_symlink ./ t_args --exit=1 'dest_broken_symlink' "\ -ln: error: Destination 'dest_broken_symlink' already exists -" -s //example.org dest_broken_symlink -t_args 'dest_broken_symlink:force' '' -sf //example.org dest_broken_symlink +ln: error: Destination './/dest_broken_symlink' already exists +" -s /foo/bar/dest_broken_symlink ./ +t_args 'dest_broken_symlink:force' '' -sf /foo/bar/dest_broken_symlink ./ t_cmd 'dest_broken_symlink:cleanup' '' rm dest_broken_symlink