blob: 2ba8662b914fc23afef5522a1cf92fcb7bd51544 [file] [log] [blame]
Erik Andersenfac10d72000-02-07 05:29:42 +00001/*
2 * Mini `cp' and `mv' implementation for BusyBox.
3 *
4 *
5 * Copyright (C) 1999 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * Copyright (C) 2000 by BitterSweet Enterprises, LLC. (GPL)
9 * Extensively modified and rewritten by Karl M. Hegbloom <karlheg@debian.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27#include "internal.h"
28#define BB_DECLARE_EXTERN
29#define bb_need_name_too_long
30#define bb_need_omitting_directory
31#define bb_need_not_a_directory
32#include "messages.c"
33
34#include <stdio.h>
35#include <time.h>
36#include <utime.h>
37#include <dirent.h>
38#include <sys/param.h>
39
40#define is_cp 0
41#define is_mv 1
42static const char *dz; /* dollar zero, .bss */
43static int dz_i; /* index, .bss */
44static const char *cp_mv_usage[] = /* .rodata */
45{
46 "cp [OPTION]... SOURCE DEST\n"
47 " or: cp [OPTION]... SOURCE... DIRECTORY\n\n"
48 "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n"
49 "\n"
50 "\t-a\tsame as -dpR\n"
51 "\t-d\tpreserve links\n"
52 "\t-p\tpreserve file attributes if possible\n"
53 "\t-R\tcopy directories recursively\n"
54 ,
55 "mv SOURCE DEST\n"
56 " or: mv SOURCE... DIRECTORY\n\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"
59};
60
61extern int cp_mv_main(int argc, char **argv)
62{
63 __label__ name_too_long__exit;
64 __label__ exit_false;
65
66 int recursiveFlag;
67 int followLinks;
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 {
79 const char *srcBasename;
80 if ((srcBasename = strrchr(baseSrcName, '/')) == NULL)
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 }
89 }
90 if (*_buflen + strlen(srcBasename) > PATH_MAX)
91 goto name_too_long__exit;
92 strcat(_buf, srcBasename);
93 return;
94 }
95
96 int fileAction(const char *fileName, struct stat *statbuf)
97 {
98 __label__ return_false;
99 char destName[PATH_MAX + 1];
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 }
120 strcat(destName, srcBasename);
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 }
135
136 int rmfileAction(const char *fileName, struct stat* statbuf)
137 {
138 if (unlink(fileName) < 0 ) {
139 perror(fileName);
140 return FALSE;
141 }
142 return TRUE;
143 }
144
145 int rmdirAction(const char *fileName, struct stat* statbuf)
146 {
147 if (rmdir(fileName) < 0 ) {
148 perror(fileName);
149 return FALSE;
150 }
151 return TRUE;
152 }
153
154 if ((dz = strrchr(*argv, '/')) == NULL) dz = *argv; else dz++;
155 if (*dz == 'c' && *(dz + 1) == 'p') dz_i = is_cp; else dz_i = is_mv;
156 if (argc < 3) usage(cp_mv_usage[dz_i]);
157 argc--;
158 argv++;
159
160 if (dz_i == is_cp)
161 {
162 recursiveFlag = preserveFlag = FALSE;
163 followLinks = TRUE;
164 while (**argv == '-')
165 {
166 while (*++(*argv))
167 {
168 switch (**argv)
169 {
170 case 'a':
171 followLinks = FALSE;
172 preserveFlag = TRUE;
173 recursiveFlag = TRUE;
174 break;
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 }
187 }
188 argc--;
189 argv++;
190 }
191 }
192 else /* (dz_i == is_mv) */
193 {
194 recursiveFlag = preserveFlag = TRUE;
195 followLinks = FALSE;
196 }
197
198 if (strlen(argv[argc - 1]) > PATH_MAX)
199 {
200 fprintf(stderr, name_too_long, "cp");
201 goto exit_false;
202 }
203 strcpy(baseDestName, argv[argc - 1]);
204 baseDestLen = strlen(baseDestName);
205 if (baseDestLen == 0) goto exit_false;
206
207 destDirFlag = isDirectory(baseDestName, TRUE);
208 if ((argc > 3) && destDirFlag == FALSE)
209 {
210 fprintf(stderr, not_a_directory, "cp", baseDestName);
211 goto exit_false;
212 }
213
214 while (argc-- > 1)
215 {
216 size_t srcLen;
217 int flags_memo;
218
219 baseSrcName = *(argv++);
220
221 if ((srcLen = strlen(baseSrcName)) > PATH_MAX)
222 goto name_too_long__exit;
223
224 if (srcLen == 0) continue;
225
226 srcDirFlag = isDirectory(baseSrcName, followLinks);
227
228 if ((flags_memo = (recursiveFlag == TRUE &&
229 srcDirFlag == TRUE && destDirFlag == TRUE)))
230 {
231 fill_baseDest_buf(&baseDestName[0], &baseDestLen);
232 }
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
244 if (flags_memo) *(baseDestName + baseDestLen) = '\0';
245 }
246
247 exit TRUE;
248
249 name_too_long__exit:
250 fprintf(stderr, name_too_long, "cp");
251 exit_false:
252 exit FALSE;
253}
254
255// Local Variables:
256// c-file-style: "k&r"
257// c-basic-offset: 4
258// End: