From: dongshengyuan <545258830@qq.com> Date: Fri, 17 Jul 2026 10:20:18 +0000 (+0800) Subject: rename: honor no-overwrite for dangling symlinks X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=f41e11e93085e4c3529b34cd72a89840303cce6c;p=thirdparty%2Futil-linux.git rename: honor no-overwrite for dangling symlinks Change: Use lstat() for destination existence checks. Treat dangling symlinks as existing entries. Before: rename --no-overwrite replaced the dangling symlink. rename --copy --no-overwrite followed it and created target. Follow: eb4aea8a4756be04655f31b286bc33b593f2689f d021e24bc185cca05cf81a257648ec5d2d94f0e4 --- diff --git a/misc-utils/rename.c b/misc-utils/rename.c index 4a18b061c..9269dabb7 100644 --- a/misc-utils/rename.c +++ b/misc-utils/rename.c @@ -227,7 +227,7 @@ static int do_file(char *from, char *to, char *s, int verbose, int noact, if (string_replace(from, to, s, &newname) != 0) return 0; - if ((nooverwrite || interactive) && access(newname, F_OK) != 0) + if ((nooverwrite || interactive) && lstat(newname, &sb) != 0) nooverwrite = interactive = 0; if (nooverwrite || (interactive && (noact || ask(newname) != 0))) { @@ -265,7 +265,7 @@ static int do_copy(char *from, char *to, char *s, int verbose, int noact, if (string_replace(from, to, s, &newname) != 0) return 0; - if ((nooverwrite || interactive) && access(newname, F_OK) != 0) + if ((nooverwrite || interactive) && lstat(newname, &sb) != 0) nooverwrite = interactive = 0; if (nooverwrite || (interactive && (noact || ask(newname) != 0))) { diff --git a/tests/expected/rename/overwrite b/tests/expected/rename/overwrite index b16f799c3..28b889891 100644 --- a/tests/expected/rename/overwrite +++ b/tests/expected/rename/overwrite @@ -1 +1,3 @@ Skipping existing file: `rename_to' +Skipping existing file: `rename_dangling_to' +Skipping existing file: `rename_copy_to' diff --git a/tests/ts/rename/overwrite b/tests/ts/rename/overwrite index c9891ee8b..fb975451b 100755 --- a/tests/ts/rename/overwrite +++ b/tests/ts/rename/overwrite @@ -28,4 +28,29 @@ touch rename_from rename_to $TS_CMD_RENAME -v --no-overwrite from to rename_from >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" rm rename_from rename_to >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" +touch rename_dangling_from +ln -s rename_missing_target rename_dangling_to +$TS_CMD_RENAME -v --no-overwrite dangling_from dangling_to rename_dangling_from >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" +if [ ! -e rename_dangling_from ]; then + echo "error: original file was renamed despite --no-overwrite" >> "$TS_OUTPUT" +fi +if [ ! -L rename_dangling_to ]; then + echo "error: dangling symlink was overwritten despite --no-overwrite" >> "$TS_OUTPUT" +fi +rm rename_dangling_from rename_dangling_to >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" + +echo "data" > rename_copy_from +ln -s rename_copy_missing rename_copy_to +$TS_CMD_RENAME -v --copy --no-overwrite copy_from copy_to rename_copy_from >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" +if [ ! -e rename_copy_from ]; then + echo "error: original file was removed by --copy" >> "$TS_OUTPUT" +fi +if [ ! -L rename_copy_to ]; then + echo "error: dangling symlink was overwritten by --copy --no-overwrite" >> "$TS_OUTPUT" +fi +if [ -e rename_copy_missing ]; then + echo "error: --copy followed dangling destination symlink" >> "$TS_OUTPUT" +fi +rm rename_copy_from rename_copy_to >> "$TS_OUTPUT" 2>> "$TS_ERRLOG" + ts_finalize