a1b6719cc8ed58229b1f574ad2733698e45ecc4e
[platform/upstream/coreutils.git] / src / mv.c
1 /* mv -- move or rename files
2    Copyright (C) 86, 89, 90, 91, 1995-2003 Free Software Foundation, Inc.
3
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)
7    any later version.
8
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.
13
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.  */
17
18 /* Written by Mike Parker, David MacKenzie, and Jim Meyering */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24 #include <assert.h>
25
26 #include "system.h"
27 #include "argmatch.h"
28 #include "backupfile.h"
29 #include "copy.h"
30 #include "cp-hash.h"
31 #include "dirname.h"
32 #include "error.h"
33 #include "path-concat.h"
34 #include "quote.h"
35 #include "remove.h"
36
37 /* The official name of this program (e.g., no `g' prefix).  */
38 #define PROGRAM_NAME "mv"
39
40 #define WRITTEN_BY _("Written by Mike Parker, David MacKenzie, and Jim Meyering.")
41
42 /* Initial number of entries in each hash table entry's table of inodes.  */
43 #define INITIAL_HASH_MODULE 100
44
45 /* Initial number of entries in the inode hash table.  */
46 #define INITIAL_ENTRY_TAB_SIZE 70
47
48 /* For long options that have no equivalent short option, use a
49    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
50 enum
51 {
52   TARGET_DIRECTORY_OPTION = CHAR_MAX + 1,
53   STRIP_TRAILING_SLASHES_OPTION,
54   REPLY_OPTION
55 };
56
57 int isdir ();
58 int lstat ();
59
60 /* The name this program was run with. */
61 char *program_name;
62
63 /* Remove any trailing slashes from each SOURCE argument.  */
64 static int remove_trailing_slashes;
65
66 /* Valid arguments to the `--reply' option. */
67 static char const* const reply_args[] =
68 {
69   "yes", "no", "query", 0
70 };
71
72 /* The values that correspond to the above strings. */
73 static int const reply_vals[] =
74 {
75   I_ALWAYS_YES, I_ALWAYS_NO, I_ASK_USER
76 };
77
78 static struct option const long_options[] =
79 {
80   {"backup", optional_argument, NULL, 'b'},
81   {"force", no_argument, NULL, 'f'},
82   {"interactive", no_argument, NULL, 'i'},
83   {"reply", required_argument, NULL, REPLY_OPTION},
84   {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
85   {"suffix", required_argument, NULL, 'S'},
86   {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
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},
92   {NULL, 0, NULL, 0}
93 };
94
95 static void
96 rm_option_init (struct rm_options *x)
97 {
98   x->unlink_dirs = 0;
99
100   x->ignore_missing_files = 0;
101
102   x->recursive = 1;
103
104   /* Should we prompt for removal, too?  No.  Prompting for the `move'
105      part is enough.  It implies removal.  */
106   x->interactive = 0;
107   x->stdin_tty = 0;
108
109   x->verbose = 0;
110 }
111
112 static void
113 cp_option_init (struct cp_options *x)
114 {
115   x->copy_as_regular = 0;  /* FIXME: maybe make this an option */
116   x->dereference = DEREF_NEVER;
117   x->unlink_dest_before_opening = 0;
118   x->unlink_dest_after_failed_open = 0;
119   x->hard_link = 0;
120   x->interactive = I_UNSPECIFIED;
121   x->move_mode = 1;
122   x->myeuid = geteuid ();
123   x->one_file_system = 0;
124   x->preserve_ownership = 1;
125   x->preserve_links = 1;
126   x->preserve_mode = 1;
127   x->preserve_timestamps = 1;
128   x->require_preserve = 0;  /* FIXME: maybe make this an option */
129   x->recursive = 1;
130   x->sparse_mode = SPARSE_AUTO;  /* FIXME: maybe make this an option */
131   x->symbolic_link = 0;
132   x->set_mode = 0;
133   x->mode = 0;
134   x->stdin_tty = isatty (STDIN_FILENO);
135
136   /* Find out the current file creation mask, to knock the right bits
137      when using chmod.  The creation mask is set to be liberal, so
138      that created directories can be written, even if it would not
139      have been allowed with the mask this process was started with.  */
140   x->umask_kill = ~ umask (0);
141
142   x->update = 0;
143   x->verbose = 0;
144   x->xstat = lstat;
145   x->dest_info = NULL;
146   x->src_info = NULL;
147 }
148
149 /* If PATH is an existing directory, return nonzero, else 0.  */
150
151 static int
152 is_real_dir (const char *path)
153 {
154   struct stat stats;
155
156   return lstat (path, &stats) == 0 && S_ISDIR (stats.st_mode);
157 }
158
159 /* Move SOURCE onto DEST.  Handles cross-filesystem moves.
160    If SOURCE is a directory, DEST must not exist.
161    Return 0 if successful, non-zero if an error occurred.  */
162
163 static int
164 do_move (const char *source, const char *dest, const struct cp_options *x)
165 {
166   static int first = 1;
167   int copy_into_self;
168   int rename_succeeded;
169   int fail;
170
171   if (first)
172     {
173       first = 0;
174
175       /* Allocate space for remembering copied and created files.  */
176       hash_init ();
177     }
178
179   fail = copy (source, dest, 0, x, &copy_into_self, &rename_succeeded);
180
181   if (!fail)
182     {
183       char const *dir_to_remove;
184       if (copy_into_self)
185         {
186           /* In general, when copy returns with copy_into_self set, SOURCE is
187              the same as, or a parent of DEST.  In this case we know it's a
188              parent.  It doesn't make sense to move a directory into itself, and
189              besides in some situations doing so would give highly nonintuitive
190              results.  Run this `mkdir b; touch a c; mv * b' in an empty
191              directory.  Here's the result of running echo `find b -print`:
192              b b/a b/b b/b/a b/c.  Notice that only file `a' was copied
193              into b/b.  Handle this by giving a diagnostic, removing the
194              copied-into-self directory, DEST (`b/b' in the example),
195              and failing.  */
196
197           dir_to_remove = NULL;
198           fail = 1;
199         }
200       else if (rename_succeeded)
201         {
202           /* No need to remove anything.  SOURCE was successfully
203              renamed to DEST.  Or the user declined to rename a file.  */
204           dir_to_remove = NULL;
205         }
206       else
207         {
208           /* This may mean SOURCE and DEST referred to different devices.
209              It may also conceivably mean that even though they referred
210              to the same device, rename wasn't implemented for that device.
211
212              E.g., (from Joel N. Weber),
213              [...] there might someday be cases where you can't rename
214              but you can copy where the device name is the same, especially
215              on Hurd.  Consider an ftpfs with a primitive ftp server that
216              supports uploading, downloading and deleting, but not renaming.
217
218              Also, note that comparing device numbers is not a reliable
219              check for `can-rename'.  Some systems can be set up so that
220              files from many different physical devices all have the same
221              st_dev field.  This is a feature of some NFS mounting
222              configurations.
223
224              We reach this point if SOURCE has been successfully copied
225              to DEST.  Now we have to remove SOURCE.
226
227              This function used to resort to copying only when rename
228              failed and set errno to EXDEV.  */
229
230           dir_to_remove = source;
231         }
232
233       if (dir_to_remove != NULL)
234         {
235           struct rm_options rm_options;
236           enum RM_status status;
237
238           rm_option_init (&rm_options);
239           rm_options.verbose = x->verbose;
240
241           status = rm (1, &dir_to_remove, &rm_options);
242           assert (VALID_STATUS (status));
243           if (status == RM_ERROR)
244             fail = 1;
245         }
246     }
247
248   return fail;
249 }
250
251 /* Move file SOURCE onto DEST.  Handles the case when DEST is a directory.
252    DEST_IS_DIR must be nonzero when DEST is a directory or a symlink to a
253    directory and zero otherwise.
254    Return 0 if successful, non-zero if an error occurred.  */
255
256 static int
257 movefile (char *source, char *dest, int dest_is_dir,
258           const struct cp_options *x)
259 {
260   int dest_had_trailing_slash = strip_trailing_slashes (dest);
261   int fail;
262
263   /* This code was introduced to handle the ambiguity in the semantics
264      of mv that is induced by the varying semantics of the rename function.
265      Some systems (e.g., Linux) have a rename function that honors a
266      trailing slash, while others (like Solaris 5,6,7) have a rename
267      function that ignores a trailing slash.  I believe the Linux
268      rename semantics are POSIX and susv2 compliant.  */
269
270   if (remove_trailing_slashes)
271     strip_trailing_slashes (source);
272
273   /* In addition to when DEST is a directory, if DEST has a trailing
274      slash and neither SOURCE nor DEST is a directory, presume the target
275      is DEST/`basename source`.  This converts `mv x y/' to `mv x y/x'.
276      This change means that the command `mv any file/' will now fail
277      rather than performing the move.  The case when SOURCE is a
278      directory and DEST is not is properly diagnosed by do_move.  */
279
280   if (dest_is_dir || (dest_had_trailing_slash && !is_real_dir (source)))
281     {
282       /* DEST is a directory; build full target filename. */
283       char const *src_basename = base_name (source);
284       char *new_dest = path_concat (dest, src_basename, NULL);
285       if (new_dest == NULL)
286         xalloc_die ();
287       strip_trailing_slashes (new_dest);
288       fail = do_move (source, new_dest, x);
289       free (new_dest);
290     }
291   else
292     {
293       fail = do_move (source, dest, x);
294     }
295
296   return fail;
297 }
298
299 void
300 usage (int status)
301 {
302   if (status != 0)
303     fprintf (stderr, _("Try `%s --help' for more information.\n"),
304              program_name);
305   else
306     {
307       printf (_("\
308 Usage: %s [OPTION]... SOURCE DEST\n\
309   or:  %s [OPTION]... SOURCE... DIRECTORY\n\
310   or:  %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\
311 "),
312               program_name, program_name, program_name);
313       fputs (_("\
314 Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\
315 \n\
316 "), stdout);
317       fputs (_("\
318 Mandatory arguments to long options are mandatory for short options too.\n\
319 "), stdout);
320       fputs (_("\
321       --backup[=CONTROL]       make a backup of each existing destination file\n\
322   -b                           like --backup but does not accept an argument\n\
323   -f, --force                  do not prompt before overwriting\n\
324                                  (equivalent to --reply=yes)\n\
325   -i, --interactive            prompt before overwrite\n\
326                                  (equivalent to --reply=query)\n\
327 "), stdout);
328       fputs (_("\
329       --reply={yes,no,query}   specify how to handle the prompt about an\n\
330                                  existing destination file\n\
331       --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\
332                                  argument\n\
333   -S, --suffix=SUFFIX          override the usual backup suffix\n\
334 "), stdout);
335       fputs (_("\
336       --target-directory=DIRECTORY  move all SOURCE arguments into DIRECTORY\n\
337   -u, --update                 move only when the SOURCE file is newer\n\
338                                  than the destination file or when the\n\
339                                  destination file is missing\n\
340   -v, --verbose                explain what is being done\n\
341 "), stdout);
342       fputs (HELP_OPTION_DESCRIPTION, stdout);
343       fputs (VERSION_OPTION_DESCRIPTION, stdout);
344       fputs (_("\
345 \n\
346 The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
347 The version control method may be selected via the --backup option or through\n\
348 the VERSION_CONTROL environment variable.  Here are the values:\n\
349 \n\
350 "), stdout);
351       fputs (_("\
352   none, off       never make backups (even if --backup is given)\n\
353   numbered, t     make numbered backups\n\
354   existing, nil   numbered if numbered backups exist, simple otherwise\n\
355   simple, never   always make simple backups\n\
356 "), stdout);
357       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
358     }
359   exit (status);
360 }
361
362 int
363 main (int argc, char **argv)
364 {
365   int c;
366   int errors;
367   int make_backups = 0;
368   int dest_is_dir;
369   char *backup_suffix_string;
370   char *version_control_string = NULL;
371   struct cp_options x;
372   char *target_directory = NULL;
373   int target_directory_specified;
374   unsigned int n_files;
375   char **file;
376
377   initialize_main (&argc, &argv);
378   program_name = argv[0];
379   setlocale (LC_ALL, "");
380   bindtextdomain (PACKAGE, LOCALEDIR);
381   textdomain (PACKAGE);
382
383   atexit (close_stdout);
384
385   cp_option_init (&x);
386
387   /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
388      we'll actually use backup_suffix_string.  */
389   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
390
391   errors = 0;
392
393   while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, NULL)) != -1)
394     {
395       switch (c)
396         {
397         case 0:
398           break;
399
400         case 'V':  /* FIXME: this is deprecated.  Remove it in 2001.  */
401           error (0, 0,
402                  _("warning: --version-control (-V) is obsolete;  support for\
403  it\nwill be removed in some future release.  Use --backup=%s instead."
404                    ), optarg);
405           /* Fall through.  */
406
407         case 'b':
408           make_backups = 1;
409           if (optarg)
410             version_control_string = optarg;
411           break;
412         case 'f':
413           x.interactive = I_ALWAYS_YES;
414           break;
415         case 'i':
416           x.interactive = I_ASK_USER;
417           break;
418         case REPLY_OPTION:
419           x.interactive = XARGMATCH ("--reply", optarg,
420                                      reply_args, reply_vals);
421           break;
422         case STRIP_TRAILING_SLASHES_OPTION:
423           remove_trailing_slashes = 1;
424           break;
425         case TARGET_DIRECTORY_OPTION:
426           target_directory = optarg;
427           break;
428         case 'u':
429           x.update = 1;
430           break;
431         case 'v':
432           x.verbose = 1;
433           break;
434         case 'S':
435           make_backups = 1;
436           backup_suffix_string = optarg;
437           break;
438         case_GETOPT_HELP_CHAR;
439         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, WRITTEN_BY);
440         default:
441           usage (EXIT_FAILURE);
442         }
443     }
444
445   n_files = (optind < argc ? argc - optind : 0);
446   file = argv + optind;
447
448   target_directory_specified = (target_directory != NULL);
449   if (target_directory == NULL && n_files != 0)
450     target_directory = file[n_files - 1];
451
452   dest_is_dir = (n_files > 0 && isdir (target_directory));
453
454   if (n_files == 0 || (n_files == 1 && !target_directory_specified))
455     {
456       error (0, 0, _("missing file argument"));
457       usage (EXIT_FAILURE);
458     }
459
460   if (target_directory_specified)
461     {
462       if (!dest_is_dir)
463         {
464           error (0, 0, _("specified target, %s is not a directory"),
465                  quote (target_directory));
466           usage (EXIT_FAILURE);
467         }
468     }
469   else if (n_files > 2 && !dest_is_dir)
470     {
471       error (0, 0,
472             _("when moving multiple files, last argument must be a directory"));
473       usage (EXIT_FAILURE);
474     }
475
476   if (backup_suffix_string)
477     simple_backup_suffix = xstrdup (backup_suffix_string);
478
479   x.backup_type = (make_backups
480                    ? xget_version (_("backup type"),
481                                    version_control_string)
482                    : none);
483
484   /* Move each arg but the last into the target_directory.  */
485   {
486     unsigned int last_file_idx = (target_directory_specified
487                                   ? n_files - 1
488                                   : n_files - 2);
489     unsigned int i;
490
491     /* Initialize the hash table only if we'll need it.
492        The problem it is used to detect can arise only if there are
493        two or more files to move.  */
494     if (last_file_idx)
495       dest_info_init (&x);
496
497     for (i = 0; i <= last_file_idx; ++i)
498       errors |= movefile (file[i], target_directory, dest_is_dir, &x);
499   }
500
501   exit (errors);
502 }