From 0d7fe8a4dedd8ea4a379d9391fb587ca3cb1c933 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Mon, 11 May 1998 04:12:51 +0000 Subject: (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. --- src/mv.c | 151 ++++++++++++++++----------------------------------------------- 1 file changed, 38 insertions(+), 113 deletions(-) (limited to 'src/mv.c') 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, + ©_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, ©_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; -- cgit v1.2.3-54-g00ecf