summaryrefslogtreecommitdiff
path: root/src/mv.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1998-05-11 04:12:51 +0000
committerJim Meyering <jim@meyering.net>1998-05-11 04:12:51 +0000
commit0d7fe8a4dedd8ea4a379d9391fb587ca3cb1c933 (patch)
tree0ff8fa5c2439ad09d8e1abfdc70717e5f0a1a07b /src/mv.c
parent841c6fbfe01ec9d33c4aa8b2b734959a6905b42d (diff)
downloadcoreutils-0d7fe8a4dedd8ea4a379d9391fb587ca3cb1c933.tar.xz
(do_move): Remove lots of code that was duplicated in
copy.c (copy), now that copy() has better support for mv. This fixes a bug with cross-filesystem `mv -i' whereby you could get two prompts for the same destination file and eventually remove the destination file even though one of the responses was negative. Reported by Dirk Lattermann.
Diffstat (limited to 'src/mv.c')
-rw-r--r--src/mv.c151
1 files changed, 38 insertions, 113 deletions
diff --git a/src/mv.c b/src/mv.c
index 1c4a9fde2..ad1f4b110 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -127,6 +127,7 @@ cp_option_init (struct cp_options *x)
x->failed_unlink_is_fatal = 1;
x->hard_link = 0;
x->interactive = 0;
+ x->move_mode = 1;
x->myeuid = geteuid ();
x->one_file_system = 0;
x->preserve_owner_and_group = 1;
@@ -167,135 +168,59 @@ is_real_dir (const char *path)
static int
do_move (const char *source, const char *dest, const struct cp_options *x)
{
- char *dest_backup = NULL;
- struct stat source_stats;
- struct stat dest_stats;
- int nonexistent_dst;
+ static int first = 1;
+ int copy_into_self;
+ int rename_succeeded;
int fail;
- if (lstat (source, &source_stats) != 0)
+ if (first)
{
- error (0, errno, "%s", source);
- return 1;
- }
+ first = 0;
- nonexistent_dst = 1;
- if (lstat (dest, &dest_stats) == 0)
- {
- nonexistent_dst = 0;
+ /* Allocate space for remembering copied and created files. */
+ hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
+ }
- if (source_stats.st_dev == dest_stats.st_dev
- && source_stats.st_ino == dest_stats.st_ino)
- {
- error (0, 0, _("`%s' and `%s' are the same file"), source, dest);
- return 1;
- }
+ fail = copy (source, dest, 0, x,
+ &copy_into_self, &rename_succeeded);
- if (S_ISDIR (dest_stats.st_mode))
+ if (!fail)
+ {
+ if (copy_into_self)
{
- error (0, 0, _("%s: cannot overwrite directory"), dest);
- return 1;
+ /* Do *not* remove SOURCE if it is the same as or a parent
+ of DEST. Otherwise, mv would be removing the original
+ *and* the copy. */
}
-
- if (!S_ISDIR (source_stats.st_mode) && x->update
- && source_stats.st_mtime <= dest_stats.st_mtime)
- return 0;
-
- if (!x->force && (x->interactive || stdin_tty)
- && euidaccess (dest, W_OK))
+ else if (rename_succeeded)
{
- fprintf (stderr, _("%s: replace `%s', overriding mode %04o? "),
- program_name, dest,
- (unsigned int) (dest_stats.st_mode & 07777));
- if (!yesno ())
- return 0;
+ /* No need to remove anything. SOURCE was successfully
+ renamed to DEST. */
}
- else if (x->interactive)
+ else
{
- fprintf (stderr, _("%s: replace `%s'? "), program_name, dest);
- if (!yesno ())
- return 0;
- }
+ /* This may mean SOURCE and DEST referred to different devices.
+ It may also conceivably mean that even though they referred
+ to the same device, rename wasn't implemented for that device.
- if (x->backup_type != none)
- {
- char *tmp_backup = find_backup_file_name (dest, x->backup_type);
- if (tmp_backup == NULL)
- error (1, 0, _("virtual memory exhausted"));
- dest_backup = (char *) alloca (strlen (tmp_backup) + 1);
- strcpy (dest_backup, tmp_backup);
- free (tmp_backup);
- if (rename (dest, dest_backup))
- {
- if (errno != ENOENT)
- {
- error (0, errno, _("cannot backup `%s'"), dest);
- return 1;
- }
- else
- dest_backup = NULL;
- }
- }
- }
- else if (errno != ENOENT)
- {
- error (0, errno, "%s", dest);
- return 1;
- }
+ E.g., (from Joel N. Weber),
+ [...] there might someday be cases where you can't rename
+ but you can copy where the device name is the same, especially
+ on Hurd. Consider an ftpfs with a primitive ftp server that
+ supports uploading, downloading and deleting, but not renaming.
- if (x->verbose)
- printf ("%s -> %s\n", source, dest);
+ Also, note that comparing device numbers is not a reliable
+ check for `can-rename'. Some systems can be set up so that
+ files from many different physical devices all have the same
+ st_dev field. This is a feature of some NFS mounting
+ configurations.
- /* Always try rename first. */
- fail = rename (source, dest);
+ We reach this point if SOURCE has been successfully copied
+ to DEST. Now we have to remove SOURCE.
- if (fail)
- {
- /* This may mean SOURCE and DEST are on different devices.
- It may also (conceivably) mean that even though they are
- on the same device, rename isn't implemented for that device.
+ This function used to resort to copying only when rename
+ failed and set errno to EXDEV. */
- E.g., (from Joel N. Weber),
- [...] there might someday be cases where you can't rename but you
- can copy where the device name is the same, especially on Hurd.
- Consider an ftpfs with a primitive ftp server that supports
- uploading, downloading and deleting, but not renaming.
-
- Also, note that comparing device numbers is not a reliable check
- for `can-rename'. Some systems can be set up so that files from
- many different physical devices all have the same st_dev field.
- This is a feature of some NFS mounting configurations.
-
- Try copying-then-removing SOURCE instead.
-
- This function used to resort to copying only when rename failed
- and set errno to EXDEV. */
-
- static int first = 1;
- int copy_into_self;
-
- if (first)
- {
- first = 0;
-
- /* Allocate space for remembering copied and created files. */
- hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
- }
-
- fail = copy (source, dest, nonexistent_dst, x, &copy_into_self);
- if (fail)
- {
- /* Restore original destination file DEST if made a backup. */
- if (dest_backup && rename (dest_backup, dest))
- error (0, errno, _("cannot un-backup `%s'"), dest);
- }
- else if (copy_into_self)
- {
- /* Do *not* remove SOURCE if it is the same as or a parent of DEST.
- Otherwise, mv would be removing the original *and* the copy. */
- }
- else
- {
struct rm_options rm_options;
struct File_spec fs;
enum RM_status status;