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:
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