source: MondoRescue/branches/3.3/mindi-busybox/coreutils/mv.c@ 3906

Last change on this file since 3906 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 4.0 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mv implementation for busybox
4 *
5 * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */
10
11/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
12 *
13 * Size reduction and improved error checking.
14 */
15
16#include "libbb.h"
17#include "libcoreutils/coreutils.h"
18
19//usage:#define mv_trivial_usage
20//usage: "[-fin] SOURCE DEST\n"
21//usage: "or: mv [-fin] SOURCE... DIRECTORY"
22//usage:#define mv_full_usage "\n\n"
23//usage: "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n"
24//usage: "\n -f Don't prompt before overwriting"
25//usage: "\n -i Interactive, prompt before overwrite"
26//usage: "\n -n Don't overwrite an existing file"
27//usage:
28//usage:#define mv_example_usage
29//usage: "$ mv /tmp/foo /bin/bar\n"
30
31#if ENABLE_FEATURE_MV_LONG_OPTIONS
32static const char mv_longopts[] ALIGN1 =
33 "interactive\0" No_argument "i"
34 "force\0" No_argument "f"
35 "no-clobber\0" No_argument "n"
36 IF_FEATURE_VERBOSE(
37 "verbose\0" No_argument "v"
38 )
39 ;
40#endif
41
42#define OPT_FORCE (1 << 0)
43#define OPT_INTERACTIVE (1 << 1)
44#define OPT_NOCLOBBER (1 << 2)
45#define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE)
46
47
48int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
49int mv_main(int argc, char **argv)
50{
51 struct stat dest_stat;
52 const char *last;
53 const char *dest;
54 unsigned flags;
55 int dest_exists;
56 int status = 0;
57 int copy_flag = 0;
58
59#if ENABLE_FEATURE_MV_LONG_OPTIONS
60 applet_long_options = mv_longopts;
61#endif
62 /* Need at least two arguments.
63 * If more than one of -f, -i, -n is specified , only the final one
64 * takes effect (it unsets previous options).
65 */
66 opt_complementary = "-2:f-in:i-fn:n-fi";
67 flags = getopt32(argv, "finv");
68 argc -= optind;
69 argv += optind;
70 last = argv[argc - 1];
71
72 if (argc == 2) {
73 dest_exists = cp_mv_stat(last, &dest_stat);
74 if (dest_exists < 0) {
75 return EXIT_FAILURE;
76 }
77
78 if (!(dest_exists & 2)) { /* last is not a directory */
79 dest = last;
80 goto DO_MOVE;
81 }
82 }
83
84 do {
85 dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
86 dest_exists = cp_mv_stat(dest, &dest_stat);
87 if (dest_exists < 0) {
88 goto RET_1;
89 }
90
91 DO_MOVE:
92 if (dest_exists) {
93 if (flags & OPT_NOCLOBBER)
94 goto RET_0;
95 if (!(flags & OPT_FORCE)
96 && ((access(dest, W_OK) < 0 && isatty(0))
97 || (flags & OPT_INTERACTIVE))
98 ) {
99 if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) {
100 goto RET_1; /* Ouch! fprintf failed! */
101 }
102 if (!bb_ask_confirmation()) {
103 goto RET_0;
104 }
105 }
106 }
107
108 if (rename(*argv, dest) < 0) {
109 struct stat source_stat;
110 int source_exists;
111
112 if (errno != EXDEV
113 || (source_exists = cp_mv_stat2(*argv, &source_stat, lstat)) < 1
114 ) {
115 bb_perror_msg("can't rename '%s'", *argv);
116 } else {
117 static const char fmt[] ALIGN1 =
118 "can't overwrite %sdirectory with %sdirectory";
119
120 if (dest_exists) {
121 if (dest_exists == 3) {
122 if (source_exists != 3) {
123 bb_error_msg(fmt, "", "non-");
124 goto RET_1;
125 }
126 } else {
127 if (source_exists == 3) {
128 bb_error_msg(fmt, "non-", "");
129 goto RET_1;
130 }
131 }
132 if (unlink(dest) < 0) {
133 bb_perror_msg("can't remove '%s'", dest);
134 goto RET_1;
135 }
136 }
137 /* FILEUTILS_RECUR also prevents nasties like
138 * "read from device and write contents to dst"
139 * instead of "create same device node" */
140 copy_flag = FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS;
141#if ENABLE_SELINUX
142 copy_flag |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
143#endif
144 if ((copy_file(*argv, dest, copy_flag) >= 0)
145 && (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0)
146 ) {
147 goto RET_0;
148 }
149 }
150 RET_1:
151 status = 1;
152 }
153 RET_0:
154 if (flags & OPT_VERBOSE) {
155 printf("'%s' -> '%s'\n", *argv, dest);
156 }
157 if (dest != last) {
158 free((void *) dest);
159 }
160 } while (*++argv != last);
161
162 return status;
163}
Note: See TracBrowser for help on using the repository browser.