1 /* mv -- move or rename files
2 Copyright (C) 86, 89, 90, 91, 1995-1999 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 -f, --force Assume a 'y' answer to all questions it would
20 normally ask, and not ask the questions.
22 -i, --interactive Require confirmation from the user before
23 performing any move that would destroy an
26 -u, --update Do not move a nondirectory that has an
27 existing destination with the same or newer
30 -v, --verbose List the name of each file as it is moved, and
31 the name it is moved to.
38 Written by Mike Parker, David MacKenzie, and Jim Meyering */
47 #include <sys/types.h>
51 #include "backupfile.h"
55 #include "path-concat.h"
58 /* The official name of this program (e.g., no `g' prefix). */
59 #define PROGRAM_NAME "mv"
61 #define AUTHORS "Mike Parker, David MacKenzie, and Jim Meyering"
63 /* Initial number of entries in each hash table entry's table of inodes. */
64 #define INITIAL_HASH_MODULE 100
66 /* Initial number of entries in the inode hash table. */
67 #define INITIAL_ENTRY_TAB_SIZE 70
75 /* The name this program was run with. */
78 /* If nonzero, stdin is a tty. */
81 static struct option
const long_options
[] =
83 {"backup", no_argument
, NULL
, 'b'},
84 {"force", no_argument
, NULL
, 'f'},
85 {"interactive", no_argument
, NULL
, 'i'},
86 {"suffix", required_argument
, NULL
, 'S'},
87 {"update", no_argument
, NULL
, 'u'},
88 {"verbose", no_argument
, NULL
, 'v'},
89 {"version-control", required_argument
, NULL
, 'V'},
90 {GETOPT_HELP_OPTION_DECL
},
91 {GETOPT_VERSION_OPTION_DECL
},
96 rm_option_init (struct rm_options
*x
)
100 /* FIXME: maybe this should be 1. The POSIX spec doesn't specify. */
101 x
->ignore_missing_files
= 0;
105 /* Should we prompt for removal, too? No. Prompting for the `move'
106 part is enough. It implies removal. */
114 cp_option_init (struct cp_options
*x
)
116 x
->copy_as_regular
= 0; /* FIXME: maybe make this an option */
119 x
->failed_unlink_is_fatal
= 1;
123 x
->myeuid
= geteuid ();
124 x
->one_file_system
= 0;
125 x
->preserve_owner_and_group
= 1;
126 x
->preserve_chmod_bits
= 1;
127 x
->preserve_timestamps
= 1;
128 x
->require_preserve
= 0; /* FIXME: maybe make this an option */
130 x
->sparse_mode
= SPARSE_AUTO
; /* FIXME: maybe make this an option */
131 x
->symbolic_link
= 0;
135 /* Find out the current file creation mask, to knock the right bits
136 when using chmod. The creation mask is set to be liberal, so
137 that created directories can be written, even if it would not
138 have been allowed with the mask this process was started with. */
139 x
->umask_kill
= ~ umask (0);
146 /* If PATH is an existing directory, return nonzero, else 0. */
149 is_real_dir (const char *path
)
153 return lstat (path
, &stats
) == 0 && S_ISDIR (stats
.st_mode
);
156 /* Move SOURCE onto DEST. Handles cross-filesystem moves.
157 If SOURCE is a directory, DEST must not exist.
158 Return 0 if successful, non-zero if an error occurred. */
161 do_move (const char *source
, const char *dest
, const struct cp_options
*x
)
163 static int first
= 1;
165 int rename_succeeded
;
172 /* Allocate space for remembering copied and created files. */
173 hash_init (INITIAL_HASH_MODULE
, INITIAL_ENTRY_TAB_SIZE
);
176 fail
= copy (source
, dest
, 0, x
, ©_into_self
, &rename_succeeded
);
180 const char *dir_to_remove
;
183 /* In general, when copy returns with copy_into_self set, SOURCE is
184 the same as, or a parent of DEST. In this case we know it's a
185 parent. It doesn't make sense to move a directory into itself, and
186 besides in some situations doing so would give highly nonintuitive
187 results. Run this `mkdir b; touch a c; mv * b' in an empty
188 directory. Here's the result of running echo `find b -print`:
189 b b/a b/b b/b/a b/c. Notice that only file `a' was copied
190 into b/b. Handle this by giving a diagnostic, removing the
191 copied-into-self directory, DEST (`b/b' in the example),
194 dir_to_remove
= NULL
;
196 _("cannot move `%s' to a subdirectory of itself, `%s'"),
199 else if (rename_succeeded
)
201 /* No need to remove anything. SOURCE was successfully
203 dir_to_remove
= NULL
;
207 /* This may mean SOURCE and DEST referred to different devices.
208 It may also conceivably mean that even though they referred
209 to the same device, rename wasn't implemented for that device.
211 E.g., (from Joel N. Weber),
212 [...] there might someday be cases where you can't rename
213 but you can copy where the device name is the same, especially
214 on Hurd. Consider an ftpfs with a primitive ftp server that
215 supports uploading, downloading and deleting, but not renaming.
217 Also, note that comparing device numbers is not a reliable
218 check for `can-rename'. Some systems can be set up so that
219 files from many different physical devices all have the same
220 st_dev field. This is a feature of some NFS mounting
223 We reach this point if SOURCE has been successfully copied
224 to DEST. Now we have to remove SOURCE.
226 This function used to resort to copying only when rename
227 failed and set errno to EXDEV. */
229 dir_to_remove
= source
;
232 if (dir_to_remove
!= NULL
)
234 struct rm_options rm_options
;
236 enum RM_status status
;
238 rm_option_init (&rm_options
);
239 rm_options
.verbose
= x
->verbose
;
243 fspec_init_file (&fs
, dir_to_remove
);
244 status
= rm (&fs
, 1, &rm_options
);
245 assert (VALID_STATUS (status
));
246 if (status
== RM_ERROR
)
252 error (0, errno
, _("cannot remove `%s'"), dir_to_remove
);
263 strip_trailing_slashes_2 (char *path
)
265 char *end_p
= path
+ strlen (path
) - 1;
268 while (slash
> path
&& *slash
== '/')
271 return slash
< end_p
;
274 /* Move file SOURCE onto DEST. Handles the case when DEST is a directory.
275 DEST_IS_DIR must be nonzero when DEST is a directory or a symlink to a
276 directory and zero otherwise.
277 Return 0 if successful, non-zero if an error occurred. */
280 movefile (char *source
, char *dest
, int dest_is_dir
, const struct cp_options
*x
)
282 int dest_had_trailing_slash
= strip_trailing_slashes_2 (dest
);
285 /* In addition to when DEST is a directory, if DEST has a trailing
286 slash and neither SOURCE nor DEST is a directory, presume the target
287 is DEST/`basename source`. This converts `mv x y/' to `mv x y/x'.
288 This change means that the command `mv any file/' will now fail
289 rather than performing the move. The case when SOURCE is a
290 directory and DEST is not is properly diagnosed by do_move. */
292 if (dest_is_dir
|| (dest_had_trailing_slash
&& !is_real_dir (source
)))
294 /* DEST is a directory; build full target filename. */
298 /* Remove trailing slashes before taking base_name.
299 Otherwise, base_name ("a/") returns "". */
300 strip_trailing_slashes_2 (source
);
302 src_basename
= base_name (source
);
303 new_dest
= path_concat (dest
, src_basename
, NULL
);
304 if (new_dest
== NULL
)
305 error (1, 0, _("virtual memory exhausted"));
306 fail
= do_move (source
, new_dest
, x
);
308 /* Do not free new_dest. It may have been squirelled away by
309 the remember_copied function. */
313 fail
= do_move (source
, dest
, x
);
323 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
328 Usage: %s [OPTION]... SOURCE DEST\n\
329 or: %s [OPTION]... SOURCE... DIRECTORY\n\
331 program_name
, program_name
);
333 Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\
335 -b, --backup make backup before removal\n\
336 -f, --force remove existing destinations, never prompt\n\
337 -i, --interactive prompt before overwrite\n\
338 -S, --suffix=SUFFIX override the usual backup suffix\n\
339 -u, --update move only older or brand new non-directories\n\
340 -v, --verbose explain what is being done\n\
341 -V, --version-control=WORD override the usual version control\n\
342 --help display this help and exit\n\
343 --version output version information and exit\n\
347 The backup suffix is ~, unless set with SIMPLE_BACKUP_SUFFIX. The\n\
348 version control may be set with VERSION_CONTROL, values are:\n\
350 none, off never make backups (even if --backup is given)\n\
351 numbered, t make numbered backups\n\
352 existing, nil numbered if numbered backups exist, simple otherwise\n\
353 simple, never always make simple backups\n\
355 puts (_("\nReport bugs to <bug-fileutils@gnu.org>."));
362 main (int argc
, char **argv
)
366 int make_backups
= 0;
371 program_name
= argv
[0];
372 setlocale (LC_ALL
, "");
373 bindtextdomain (PACKAGE
, LOCALEDIR
);
374 textdomain (PACKAGE
);
378 /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
379 we'll actually use simple_backup_suffix. */
380 version
= getenv ("SIMPLE_BACKUP_SUFFIX");
382 simple_backup_suffix
= version
;
387 while ((c
= getopt_long (argc
, argv
, "bfiuvS:V:", long_options
, NULL
)) != -1)
411 simple_backup_suffix
= optarg
;
416 case_GETOPT_HELP_CHAR
;
417 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
423 if (argc
< optind
+ 2)
425 error (0, 0, "%s", (argc
== optind
426 ? _("missing file arguments")
427 : _("missing file argument")));
431 x
.backup_type
= (make_backups
432 ? xget_version (_("--version-control"), version
)
435 stdin_tty
= isatty (STDIN_FILENO
);
436 dest_is_dir
= isdir (argv
[argc
- 1]);
438 if (argc
> optind
+ 2 && !dest_is_dir
)
440 _("when moving multiple files, last argument must be a directory"));
442 /* Move each arg but the last onto the last. */
443 for (; optind
< argc
- 1; ++optind
)
444 errors
|= movefile (argv
[optind
], argv
[argc
- 1], dest_is_dir
, &x
);