33adf8f55b810026cd010d575482edfec13415fa
[oweals/busybox.git] / cp_mv.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini `cp' and `mv' implementation for BusyBox.
4  *
5  *
6  * Copyright (C) 1999 by Lineo, inc.
7  * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
8  *
9  * Copyright (C) 2000 by BitterSweet Enterprises, LLC. (GPL)
10  * Extensively modified and rewritten by  Karl M. Hegbloom <karlheg@debian.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25  *
26  */
27
28 #include "internal.h"
29 #define BB_DECLARE_EXTERN
30 #define bb_need_name_too_long
31 #define bb_need_omitting_directory
32 #define bb_need_not_a_directory
33 #include "messages.c"
34
35 #include <stdio.h>
36 #include <time.h>
37 #include <utime.h>
38 #include <dirent.h>
39 #include <sys/param.h>
40
41 #define is_cp 0
42 #define is_mv 1
43 static const char *dz;                  /* dollar zero, .bss */
44 static int dz_i;                                /* index,       .bss */
45 static const char *cp_mv_usage[] =      /* .rodata */
46 {
47         "cp [OPTION]... SOURCE DEST\n"
48                 "   or: cp [OPTION]... SOURCE... DIRECTORY\n\n"
49                 "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n"
50                 "\n"
51                 "\t-a\tsame as -dpR\n"
52                 "\t-d\tpreserve links\n"
53                 "\t-p\tpreserve file attributes if possible\n"
54                 "\t-R\tcopy directories recursively\n",
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
61 extern 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                 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         }
92
93         int fileAction(const char *fileName, struct stat *statbuf) {
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);
121
122           return_false:
123                 return FALSE;
124         }
125
126         int rmfileAction(const char *fileName, struct stat *statbuf) {
127                 if (unlink(fileName) < 0) {
128                         perror(fileName);
129                         return FALSE;
130                 }
131                 return TRUE;
132         }
133
134         int rmdirAction(const char *fileName, struct stat *statbuf) {
135                 if (rmdir(fileName) < 0) {
136                         perror(fileName);
137                         return FALSE;
138                 }
139                 return TRUE;
140         }
141
142         if ((dz = strrchr(*argv, '/')) == NULL)
143                 dz = *argv;
144         else
145                 dz++;
146         if (*dz == 'c' && *(dz + 1) == 'p')
147                 dz_i = is_cp;
148         else
149                 dz_i = is_mv;
150         if (argc < 3)
151                 usage(cp_mv_usage[dz_i]);
152         argc--;
153         argv++;
154
155         if (dz_i == is_cp) {
156                 recursiveFlag = preserveFlag = FALSE;
157                 followLinks = TRUE;
158                 while (**argv == '-') {
159                         while (*++(*argv)) {
160                                 switch (**argv) {
161                                 case 'a':
162                                         followLinks = FALSE;
163                                         preserveFlag = TRUE;
164                                         recursiveFlag = TRUE;
165                                         break;
166                                 case 'd':
167                                         followLinks = FALSE;
168                                         break;
169                                 case 'p':
170                                         preserveFlag = TRUE;
171                                         break;
172                                 case 'R':
173                                         recursiveFlag = TRUE;
174                                         break;
175                                 default:
176                                         usage(cp_mv_usage[is_cp]);
177                                 }
178                         }
179                         argc--;
180                         argv++;
181                 }
182         } else {                                        /* (dz_i == is_mv) */
183
184                 recursiveFlag = preserveFlag = TRUE;
185                 followLinks = FALSE;
186         }
187
188         if (strlen(argv[argc - 1]) > PATH_MAX) {
189                 fprintf(stderr, name_too_long, "cp");
190                 goto exit_false;
191         }
192         strcpy(baseDestName, argv[argc - 1]);
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         }
202
203         while (argc-- > 1) {
204                 size_t srcLen;
205                 int flags_memo;
206
207                 baseSrcName = *(argv++);
208
209                 if ((srcLen = strlen(baseSrcName)) > PATH_MAX)
210                         goto name_too_long__exit;
211
212                 if (srcLen == 0)
213                         continue;
214
215                 srcDirFlag = isDirectory(baseSrcName, followLinks);
216
217                 if ((flags_memo = (recursiveFlag == TRUE &&
218                                                    srcDirFlag == TRUE && destDirFlag == TRUE))) {
219                         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';
234         }
235
236         exit TRUE;
237
238   name_too_long__exit:
239         fprintf(stderr, name_too_long, "cp");
240   exit_false:
241         exit FALSE;
242 }
243
244 // Local Variables:
245 // c-file-style: "k&r"
246 // c-basic-offset: 4
247 // End: