summaryrefslogtreecommitdiff
path: root/src/mv.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2000-01-02 08:51:39 +0000
committerJim Meyering <jim@meyering.net>2000-01-02 08:51:39 +0000
commit70cc36958837c577308aba7c9f32b936640fa432 (patch)
tree9e9c37e9b1eb9d0f6fc40f3f3b08b82d6b3f949d /src/mv.c
parentb3faf79a759deab4258a4ade6383aff851b2869d (diff)
downloadcoreutils-70cc36958837c577308aba7c9f32b936640fa432.tar.xz
New option: --strip-trailing-slashes.
Diffstat (limited to 'src/mv.c')
-rw-r--r--src/mv.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/src/mv.c b/src/mv.c
index 2a63ea1fe..bd54bd4c3 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -70,7 +70,8 @@
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
{
- TARGET_DIRECTORY_OPTION = CHAR_MAX + 1
+ TARGET_DIRECTORY_OPTION = CHAR_MAX + 1,
+ STRIP_TRAILING_SLASHES_OPTION
};
int euidaccess ();
@@ -82,11 +83,14 @@ int yesno ();
/* The name this program was run with. */
char *program_name;
+static int remove_trailing_slashes;
+
static struct option const long_options[] =
{
{"backup", optional_argument, NULL, 'b'},
{"force", no_argument, NULL, 'f'},
{"interactive", no_argument, NULL, 'i'},
+ {"strip-trailing-slash", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
{"suffix", required_argument, NULL, 'S'},
{"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
{"update", no_argument, NULL, 'u'},
@@ -288,6 +292,36 @@ movefile (char *source, char *dest, int dest_is_dir,
int dest_had_trailing_slash = strip_trailing_slashes_2 (dest);
int fail;
+ /* This code was introduced to handle the ambiguity in the semantics
+ of mv that is induced by the varying semantics of the rename function.
+ Some systems (e.g., Linux) have a rename function that honors a
+ trailing slash, while others (like Solaris 5,6,7) have a rename
+ function that ignores a trailing slash. I believe the Linux
+ rename semantics are POSIX and susv2 compliant. */
+
+ if (remove_trailing_slashes)
+ {
+ strip_trailing_slashes_2 (source);
+ }
+ else
+ {
+ char *src_copy = xstrdup (source);
+ int src_has_trailing_slash = strip_trailing_slashes_2 (src_copy);
+ if (src_has_trailing_slash)
+ {
+ /* See if lstat says the trailing-slash-free src_copy
+ is a symbolic link. */
+ struct stat stat_buf;
+ if (lstat (src_copy, &stat_buf) == 0 && S_ISLNK (stat_buf.st_mode)
+ && stat (src_copy, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode))
+ {
+ error (0, 0, _("%s: warning: moving a symlink-to-directory\
+ referenced with a\ntrailing slash may move the directory, not the symlink"),
+ source);
+ }
+ }
+ }
+
/* In addition to when DEST is a directory, if DEST has a trailing
slash and neither SOURCE nor DEST is a directory, presume the target
is DEST/`basename source`. This converts `mv x y/' to `mv x y/x'.
@@ -342,6 +376,8 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\
-b, --backup[=CONTROL] make backup before removal\n\
-f, --force remove existing destinations, never prompt\n\
-i, --interactive prompt before overwrite\n\
+ --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\
+ argument\n\
-S, --suffix=SUFFIX override the usual backup suffix\n\
--target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\
-u, --update move only older or brand new non-directories\n\
@@ -421,6 +457,9 @@ main (int argc, char **argv)
x.interactive = 1;
x.force = 0;
break;
+ case STRIP_TRAILING_SLASHES_OPTION:
+ remove_trailing_slashes = 1;
+ break;
case TARGET_DIRECTORY_OPTION:
target_directory = optarg;
break;