logo

utils-std

Collection of commonly available Unix tools
commit: 5c8c4b15d94ad55722d8c5e6a98bd5e87fedf992
parent 25b4d174ea465c365fd5356d7a73ef49fe72dc24
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun,  2 Jun 2024 07:53:30 +0200

cmd/mv: Drop first form when destination is a dir

Diffstat:

Mcmd/mv.112+++++++++---
Mcmd/mv.c6+++++-
Mtest-cmd/mv.t19+++++++------------
3 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/cmd/mv.1 b/cmd/mv.1 @@ -12,7 +12,7 @@ .Op Fl f Ns | Ns Fl i Ns | Ns Fl n .Op Fl v .Ar source -.Ar dest +.Ar destfile .Nm .Op Fl f Ns | Ns Fl i Ns | Ns Fl n .Op Fl v @@ -24,12 +24,18 @@ .Fl t Ar destdir .Ar source... .Sh DESCRIPTION -In the first form +In the first form, .Nm moves each given .Ar source to -.Ar dest . +.Ar destfile . +This form is assumed when +.Ar destfile +does not refers to an existing directory, or a symlink pointing to one. +Additionally, in this case a trailing slash and +.Ar source +not referring to a directory results in an error. .Pp In the second and third form, .Nm diff --git a/cmd/mv.c b/cmd/mv.c @@ -275,13 +275,17 @@ main(int argc, char *argv[]) fprintf(stderr, "mv: Not enough operands, %d given, expect >= 2\n", argc); return 1; } - else if(argc == 2) + + struct stat dest_status; + int ret_stat = fstatat(destdir.fd, argv[1], &dest_status, 0); + if(argc == 2 && (errno == ENOENT || (ret_stat == 0 && !S_ISDIR(dest_status.st_mode)))) { int ret = do_renameat(argv[0], destdir, argv[1]); consent_finish(); return ret < 0 ? 1 : 0; } + errno = 0; argc--; destdir.name = argv[argc]; diff --git a/test-cmd/mv.t b/test-cmd/mv.t @@ -9,12 +9,12 @@ POSIX, non-directory target with a trailing slash is an error $ touch nondir file $ mv file nondir/ - mv: Failed getting status for destination file './nondir/': Not a directory + mv: Failed opening destination directory 'nondir/': Not a directory [1] $ test -e file $ test -e nondir $ mv enoent nondir/ - mv: Failed getting status for destination file './nondir/': Not a directory + mv: Failed opening destination directory 'nondir/': Not a directory [1] $ rm nondir file @@ -85,23 +85,18 @@ Where destination is an existing directory $ mkdir destdir $ touch foo $ mv foo destdir - mv: Destination file './destdir' already exists. - [1] - $ test -f foo + $ test ! -e foo $ test -d destdir - $ test ! -e destdir/foo + $ test -f destdir/foo $ rm -r destdir $ mkdir destdir_trail/ $ touch foo_trail $ mv foo_trail destdir_trail/ - mv: Destination file './destdir_trail/' already exists. - [1] - $ test -f foo_trail + $ test ! -e foo_trail $ test -d destdir_trail - $ test ! -e destdir_trail/foo_trail + $ test -f destdir_trail/foo_trail $ rm -r destdir_trail - $ rm foo_trail Where destination is an existing file $ touch foo_file destfile @@ -119,7 +114,7 @@ Where destination is an existing file $ touch foo_file_trail destfile_trail $ mv foo_file_trail destfile_trail/ - mv: Failed getting status for destination file './destfile_trail/': Not a directory + mv: Failed opening destination directory 'destfile_trail/': Not a directory [1] $ test -f foo_file_trail $ test -f destfile_trail