ln -s -f fails with ENOTDIR when the destination's parent path is a symlink. This is a regression in 0.12.0.
$ mkdir -p modules dst
$ ln -s -f "$PWD/modules" dst/ucc # ok: dst/ucc -> modules
$ ln -s -f "$PWD/modules" dst/ucc # ok, but creates modules/modules -> modules
$ ln -s -f "$PWD/modules" dst/ucc # fails
ln: failed to create symbolic link 'dst/ucc/modules': Not a directory
Expected (GNU, uutils 0.11.0): The third command succeeds. The forced replacement unlinks and recreates the link.
The cause seems to be replace_link() introduced in #14623. In replace_link(), the initial symlinkat() fails with EEXIST because modules/modules already exists, and the fallback then opens the destination's parent with O_NOFOLLOW | O_DIRECTORY. Since the parent ends in a symlink, the open fails with ENOTDIR.
ln -s -f fails with
ENOTDIRwhen the destination's parent path is a symlink. This is a regression in 0.12.0.Expected (GNU, uutils 0.11.0): The third command succeeds. The forced replacement unlinks and recreates the link.
The cause seems to be
replace_link()introduced in #14623. Inreplace_link(), the initialsymlinkat()fails withEEXISTbecausemodules/modulesalready exists, and the fallback then opens the destination's parent withO_NOFOLLOW | O_DIRECTORY. Since the parent ends in a symlink, the open fails withENOTDIR.