diff options
Diffstat (limited to 'cp_mv.c')
-rw-r--r-- | cp_mv.c | 359 |
1 files changed, 174 insertions, 185 deletions
@@ -1,3 +1,4 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
1 | /* | 2 | /* |
2 | * Mini `cp' and `mv' implementation for BusyBox. | 3 | * Mini `cp' and `mv' implementation for BusyBox. |
3 | * | 4 | * |
@@ -39,217 +40,205 @@ | |||
39 | 40 | ||
40 | #define is_cp 0 | 41 | #define is_cp 0 |
41 | #define is_mv 1 | 42 | #define is_mv 1 |
42 | static const char *dz; /* dollar zero, .bss */ | 43 | static const char *dz; /* dollar zero, .bss */ |
43 | static int dz_i; /* index, .bss */ | 44 | static int dz_i; /* index, .bss */ |
44 | static const char *cp_mv_usage[] = /* .rodata */ | 45 | static const char *cp_mv_usage[] = /* .rodata */ |
45 | { | 46 | { |
46 | "cp [OPTION]... SOURCE DEST\n" | 47 | "cp [OPTION]... SOURCE DEST\n" |
47 | " or: cp [OPTION]... SOURCE... DIRECTORY\n\n" | 48 | " or: cp [OPTION]... SOURCE... DIRECTORY\n\n" |
48 | "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" | 49 | "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" |
49 | "\n" | 50 | "\n" |
50 | "\t-a\tsame as -dpR\n" | 51 | "\t-a\tsame as -dpR\n" |
51 | "\t-d\tpreserve links\n" | 52 | "\t-d\tpreserve links\n" |
52 | "\t-p\tpreserve file attributes if possible\n" | 53 | "\t-p\tpreserve file attributes if possible\n" |
53 | "\t-R\tcopy directories recursively\n" | 54 | "\t-R\tcopy directories recursively\n", |
54 | , | 55 | "mv SOURCE DEST\n" |
55 | "mv SOURCE DEST\n" | 56 | " or: mv SOURCE... DIRECTORY\n\n" |
56 | " or: mv SOURCE... DIRECTORY\n\n" | 57 | "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n" |
57 | "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n" | 58 | "Warning!! This is not GNU `mv'. It does not preserve hard links.\n" |
58 | "Warning!! This is not GNU `mv'. It does not preserve hard links.\n" | ||
59 | }; | 59 | }; |
60 | 60 | ||
61 | extern int cp_mv_main(int argc, char **argv) | 61 | extern int cp_mv_main(int argc, char **argv) |
62 | { | 62 | { |
63 | __label__ name_too_long__exit; | 63 | __label__ name_too_long__exit; |
64 | __label__ exit_false; | 64 | __label__ exit_false; |
65 | 65 | ||
66 | int recursiveFlag; | 66 | int recursiveFlag; |
67 | int followLinks; | 67 | int followLinks; |
68 | int preserveFlag; | 68 | int preserveFlag; |
69 | |||
70 | const char *baseSrcName; | ||
71 | int srcDirFlag; | ||
72 | |||
73 | char baseDestName[PATH_MAX + 1]; | ||
74 | size_t baseDestLen; | ||
75 | int destDirFlag; | ||
76 | |||
77 | void fill_baseDest_buf(char *_buf, size_t * _buflen) { | ||
78 | const char *srcBasename; | ||
79 | if ((srcBasename = strrchr(baseSrcName, '/')) == NULL) { | ||
80 | srcBasename = baseSrcName; | ||
81 | if (_buf[*_buflen - 1] != '/') { | ||
82 | if (++(*_buflen) > PATH_MAX) | ||
83 | goto name_too_long__exit; | ||
84 | strcat(_buf, "/"); | ||
85 | } | ||
86 | } | ||
87 | if (*_buflen + strlen(srcBasename) > PATH_MAX) | ||
88 | goto name_too_long__exit; | ||
89 | strcat(_buf, srcBasename); | ||
90 | return; | ||
91 | } | ||
69 | 92 | ||
70 | const char *baseSrcName; | 93 | int fileAction(const char *fileName, struct stat *statbuf) { |
71 | int srcDirFlag; | 94 | __label__ return_false; |
95 | char destName[PATH_MAX + 1]; | ||
96 | size_t destLen; | ||
97 | const char *srcBasename; | ||
98 | |||
99 | strcpy(destName, baseDestName); | ||
100 | destLen = strlen(destName); | ||
101 | |||
102 | if (srcDirFlag == TRUE) { | ||
103 | if (recursiveFlag == FALSE) { | ||
104 | fprintf(stderr, omitting_directory, "cp", baseSrcName); | ||
105 | return TRUE; | ||
106 | } | ||
107 | srcBasename = (strstr(fileName, baseSrcName) | ||
108 | + strlen(baseSrcName)); | ||
109 | |||
110 | if (destLen + strlen(srcBasename) > PATH_MAX) { | ||
111 | fprintf(stderr, name_too_long, "cp"); | ||
112 | goto return_false; | ||
113 | } | ||
114 | strcat(destName, srcBasename); | ||
115 | } else if (destDirFlag == TRUE) { | ||
116 | fill_baseDest_buf(&destName[0], &destLen); | ||
117 | } else { | ||
118 | srcBasename = baseSrcName; | ||
119 | } | ||
120 | return copyFile(fileName, destName, preserveFlag, followLinks); | ||
72 | 121 | ||
73 | char baseDestName[PATH_MAX + 1]; | 122 | return_false: |
74 | size_t baseDestLen; | 123 | return FALSE; |
75 | int destDirFlag; | 124 | } |
76 | 125 | ||
77 | void fill_baseDest_buf(char *_buf, size_t *_buflen) | 126 | int rmfileAction(const char *fileName, struct stat *statbuf) { |
78 | { | 127 | if (unlink(fileName) < 0) { |
79 | const char *srcBasename; | 128 | perror(fileName); |
80 | if ((srcBasename = strrchr(baseSrcName, '/')) == NULL) | 129 | return FALSE; |
81 | { | ||
82 | srcBasename = baseSrcName; | ||
83 | if (_buf[*_buflen - 1] != '/') | ||
84 | { | ||
85 | if (++(*_buflen) > PATH_MAX) | ||
86 | goto name_too_long__exit; | ||
87 | strcat(_buf, "/"); | ||
88 | } | 130 | } |
89 | } | 131 | return TRUE; |
90 | if (*_buflen + strlen(srcBasename) > PATH_MAX) | ||
91 | goto name_too_long__exit; | ||
92 | strcat(_buf, srcBasename); | ||
93 | return; | ||
94 | } | 132 | } |
95 | 133 | ||
96 | int fileAction(const char *fileName, struct stat *statbuf) | 134 | int rmdirAction(const char *fileName, struct stat *statbuf) { |
97 | { | 135 | if (rmdir(fileName) < 0) { |
98 | __label__ return_false; | 136 | perror(fileName); |
99 | char destName[PATH_MAX + 1]; | 137 | return FALSE; |
100 | size_t destLen; | ||
101 | const char *srcBasename; | ||
102 | |||
103 | strcpy(destName, baseDestName); | ||
104 | destLen = strlen(destName); | ||
105 | |||
106 | if (srcDirFlag == TRUE) | ||
107 | { | ||
108 | if (recursiveFlag == FALSE) | ||
109 | { | ||
110 | fprintf(stderr, omitting_directory, "cp", baseSrcName); | ||
111 | return TRUE; | ||
112 | } | ||
113 | srcBasename = (strstr(fileName, baseSrcName) | ||
114 | + strlen(baseSrcName)); | ||
115 | if (destLen + strlen(srcBasename) > PATH_MAX) | ||
116 | { | ||
117 | fprintf(stderr, name_too_long, "cp"); | ||
118 | goto return_false; | ||
119 | } | 138 | } |
120 | strcat(destName, srcBasename); | 139 | return TRUE; |
121 | } | ||
122 | else if (destDirFlag == TRUE) | ||
123 | { | ||
124 | fill_baseDest_buf(&destName[0], &destLen); | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | srcBasename = baseSrcName; | ||
129 | } | ||
130 | return copyFile(fileName, destName, preserveFlag, followLinks); | ||
131 | |||
132 | return_false: | ||
133 | return FALSE; | ||
134 | } | 140 | } |
135 | 141 | ||
136 | int rmfileAction(const char *fileName, struct stat* statbuf) | 142 | if ((dz = strrchr(*argv, '/')) == NULL) |
137 | { | 143 | dz = *argv; |
138 | if (unlink(fileName) < 0 ) { | 144 | else |
139 | perror(fileName); | 145 | dz++; |
140 | return FALSE; | 146 | if (*dz == 'c' && *(dz + 1) == 'p') |
141 | } | 147 | dz_i = is_cp; |
142 | return TRUE; | 148 | else |
143 | } | 149 | dz_i = is_mv; |
144 | 150 | if (argc < 3) | |
145 | int rmdirAction(const char *fileName, struct stat* statbuf) | 151 | usage(cp_mv_usage[dz_i]); |
146 | { | 152 | argc--; |
147 | if (rmdir(fileName) < 0 ) { | 153 | argv++; |
148 | perror(fileName); | 154 | |
149 | return FALSE; | 155 | if (dz_i == is_cp) { |
150 | } | 156 | recursiveFlag = preserveFlag = FALSE; |
151 | return TRUE; | 157 | followLinks = TRUE; |
152 | } | 158 | while (**argv == '-') { |
153 | 159 | while (*++(*argv)) { | |
154 | if ((dz = strrchr(*argv, '/')) == NULL) dz = *argv; else dz++; | 160 | switch (**argv) { |
155 | if (*dz == 'c' && *(dz + 1) == 'p') dz_i = is_cp; else dz_i = is_mv; | 161 | case 'a': |
156 | if (argc < 3) usage(cp_mv_usage[dz_i]); | 162 | followLinks = FALSE; |
157 | argc--; | 163 | preserveFlag = TRUE; |
158 | argv++; | 164 | recursiveFlag = TRUE; |
159 | 165 | break; | |
160 | if (dz_i == is_cp) | 166 | case 'd': |
161 | { | 167 | followLinks = FALSE; |
162 | recursiveFlag = preserveFlag = FALSE; | 168 | break; |
163 | followLinks = TRUE; | 169 | case 'p': |
164 | while (**argv == '-') | 170 | preserveFlag = TRUE; |
165 | { | 171 | break; |
166 | while (*++(*argv)) | 172 | case 'R': |
167 | { | 173 | recursiveFlag = TRUE; |
168 | switch (**argv) | 174 | break; |
169 | { | 175 | default: |
170 | case 'a': | 176 | usage(cp_mv_usage[is_cp]); |
171 | followLinks = FALSE; | 177 | } |
172 | preserveFlag = TRUE; | 178 | } |
173 | recursiveFlag = TRUE; | 179 | argc--; |
174 | break; | 180 | argv++; |
175 | case 'd': | ||
176 | followLinks = FALSE; | ||
177 | break; | ||
178 | case 'p': | ||
179 | preserveFlag = TRUE; | ||
180 | break; | ||
181 | case 'R': | ||
182 | recursiveFlag = TRUE; | ||
183 | break; | ||
184 | default: | ||
185 | usage(cp_mv_usage[is_cp]); | ||
186 | } | 181 | } |
187 | } | 182 | } else { /* (dz_i == is_mv) */ |
188 | argc--; | ||
189 | argv++; | ||
190 | } | ||
191 | } | ||
192 | else /* (dz_i == is_mv) */ | ||
193 | { | ||
194 | recursiveFlag = preserveFlag = TRUE; | ||
195 | followLinks = FALSE; | ||
196 | } | ||
197 | 183 | ||
198 | if (strlen(argv[argc - 1]) > PATH_MAX) | 184 | recursiveFlag = preserveFlag = TRUE; |
199 | { | 185 | followLinks = FALSE; |
200 | fprintf(stderr, name_too_long, "cp"); | 186 | } |
201 | goto exit_false; | ||
202 | } | ||
203 | strcpy(baseDestName, argv[argc - 1]); | ||
204 | baseDestLen = strlen(baseDestName); | ||
205 | if (baseDestLen == 0) goto exit_false; | ||
206 | 187 | ||
207 | destDirFlag = isDirectory(baseDestName, TRUE); | 188 | if (strlen(argv[argc - 1]) > PATH_MAX) { |
208 | if ((argc > 3) && destDirFlag == FALSE) | 189 | fprintf(stderr, name_too_long, "cp"); |
209 | { | 190 | goto exit_false; |
210 | fprintf(stderr, not_a_directory, "cp", baseDestName); | 191 | } |
211 | goto exit_false; | 192 | strcpy(baseDestName, argv[argc - 1]); |
212 | } | 193 | baseDestLen = strlen(baseDestName); |
194 | if (baseDestLen == 0) | ||
195 | goto exit_false; | ||
196 | |||
197 | destDirFlag = isDirectory(baseDestName, TRUE); | ||
198 | if ((argc > 3) && destDirFlag == FALSE) { | ||
199 | fprintf(stderr, not_a_directory, "cp", baseDestName); | ||
200 | goto exit_false; | ||
201 | } | ||
213 | 202 | ||
214 | while (argc-- > 1) | 203 | while (argc-- > 1) { |
215 | { | 204 | size_t srcLen; |
216 | size_t srcLen; | 205 | int flags_memo; |
217 | int flags_memo; | ||
218 | 206 | ||
219 | baseSrcName = *(argv++); | 207 | baseSrcName = *(argv++); |
220 | 208 | ||
221 | if ((srcLen = strlen(baseSrcName)) > PATH_MAX) | 209 | if ((srcLen = strlen(baseSrcName)) > PATH_MAX) |
222 | goto name_too_long__exit; | 210 | goto name_too_long__exit; |
223 | 211 | ||
224 | if (srcLen == 0) continue; | 212 | if (srcLen == 0) |
213 | continue; | ||
225 | 214 | ||
226 | srcDirFlag = isDirectory(baseSrcName, followLinks); | 215 | srcDirFlag = isDirectory(baseSrcName, followLinks); |
227 | 216 | ||
228 | if ((flags_memo = (recursiveFlag == TRUE && | 217 | if ((flags_memo = (recursiveFlag == TRUE && |
229 | srcDirFlag == TRUE && destDirFlag == TRUE))) | 218 | srcDirFlag == TRUE && destDirFlag == TRUE))) { |
230 | { | 219 | fill_baseDest_buf(&baseDestName[0], &baseDestLen); |
231 | fill_baseDest_buf(&baseDestName[0], &baseDestLen); | 220 | } |
221 | if (recursiveAction(baseSrcName, | ||
222 | recursiveFlag, followLinks, FALSE, | ||
223 | fileAction, fileAction) == FALSE) | ||
224 | goto exit_false; | ||
225 | |||
226 | if (dz_i == is_mv && | ||
227 | recursiveAction(baseSrcName, | ||
228 | recursiveFlag, followLinks, TRUE, | ||
229 | rmfileAction, rmdirAction) == FALSE) | ||
230 | goto exit_false; | ||
231 | |||
232 | if (flags_memo) | ||
233 | *(baseDestName + baseDestLen) = '\0'; | ||
232 | } | 234 | } |
233 | if (recursiveAction(baseSrcName, | ||
234 | recursiveFlag, followLinks, FALSE, | ||
235 | fileAction, fileAction) | ||
236 | == FALSE) goto exit_false; | ||
237 | |||
238 | if (dz_i == is_mv && | ||
239 | recursiveAction(baseSrcName, | ||
240 | recursiveFlag, followLinks, TRUE, | ||
241 | rmfileAction, rmdirAction) | ||
242 | == FALSE) goto exit_false; | ||
243 | 235 | ||
244 | if (flags_memo) *(baseDestName + baseDestLen) = '\0'; | 236 | exit TRUE; |
245 | } | ||
246 | 237 | ||
247 | exit TRUE; | 238 | name_too_long__exit: |
248 | 239 | fprintf(stderr, name_too_long, "cp"); | |
249 | name_too_long__exit: | 240 | exit_false: |
250 | fprintf(stderr, name_too_long, "cp"); | 241 | exit FALSE; |
251 | exit_false: | ||
252 | exit FALSE; | ||
253 | } | 242 | } |
254 | 243 | ||
255 | // Local Variables: | 244 | // Local Variables: |