blob: 4c55e62d0b7f21d71a5b12039df153ad823d8c8b [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Erik Andersenfac10d72000-02-07 05:29:42 +00002/*
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
Erik Andersene49d5ec2000-02-08 19:58:47 +000043static const char *dz; /* dollar zero, .bss */
44static int dz_i; /* index, .bss */
45static const char *cp_mv_usage[] = /* .rodata */
Erik Andersenfac10d72000-02-07 05:29:42 +000046{
Erik Andersene49d5ec2000-02-08 19:58:47 +000047 "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"
Erik Andersenfac10d72000-02-07 05:29:42 +000059};
60
61extern int cp_mv_main(int argc, char **argv)
62{
Erik Andersene49d5ec2000-02-08 19:58:47 +000063 __label__ name_too_long__exit;
64 __label__ exit_false;
Erik Andersenfac10d72000-02-07 05:29:42 +000065
Erik Andersene49d5ec2000-02-08 19:58:47 +000066 int recursiveFlag;
67 int followLinks;
68 int preserveFlag;
Erik Andersenfac10d72000-02-07 05:29:42 +000069
Erik Andersene49d5ec2000-02-08 19:58:47 +000070 const char *baseSrcName;
71 int srcDirFlag;
Erik Andersen9ffdaa62000-02-11 21:55:04 +000072 struct stat srcStatBuf;
Erik Andersenfac10d72000-02-07 05:29:42 +000073
Erik Andersene49d5ec2000-02-08 19:58:47 +000074 char baseDestName[PATH_MAX + 1];
75 size_t baseDestLen;
76 int destDirFlag;
Erik Andersen9ffdaa62000-02-11 21:55:04 +000077 struct stat destStatBuf;
Erik Andersenfac10d72000-02-07 05:29:42 +000078
Erik Andersene49d5ec2000-02-08 19:58:47 +000079 void fill_baseDest_buf(char *_buf, size_t * _buflen) {
80 const char *srcBasename;
81 if ((srcBasename = strrchr(baseSrcName, '/')) == NULL) {
82 srcBasename = baseSrcName;
83 if (_buf[*_buflen - 1] != '/') {
84 if (++(*_buflen) > PATH_MAX)
85 goto name_too_long__exit;
86 strcat(_buf, "/");
87 }
88 }
89 if (*_buflen + strlen(srcBasename) > PATH_MAX)
90 goto name_too_long__exit;
91 strcat(_buf, srcBasename);
92 return;
93 }
94
95 int fileAction(const char *fileName, struct stat *statbuf) {
Erik Andersene49d5ec2000-02-08 19:58:47 +000096 char destName[PATH_MAX + 1];
97 size_t destLen;
98 const char *srcBasename;
99
100 strcpy(destName, baseDestName);
101 destLen = strlen(destName);
102
103 if (srcDirFlag == TRUE) {
104 if (recursiveFlag == FALSE) {
105 fprintf(stderr, omitting_directory, "cp", baseSrcName);
106 return TRUE;
107 }
108 srcBasename = (strstr(fileName, baseSrcName)
109 + strlen(baseSrcName));
110
111 if (destLen + strlen(srcBasename) > PATH_MAX) {
112 fprintf(stderr, name_too_long, "cp");
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000113 return FALSE;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000114 }
115 strcat(destName, srcBasename);
116 } else if (destDirFlag == TRUE) {
117 fill_baseDest_buf(&destName[0], &destLen);
118 } else {
119 srcBasename = baseSrcName;
120 }
121 return copyFile(fileName, destName, preserveFlag, followLinks);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000122 }
123
124 int rmfileAction(const char *fileName, struct stat *statbuf) {
125 if (unlink(fileName) < 0) {
126 perror(fileName);
127 return FALSE;
128 }
129 return TRUE;
130 }
131
132 int rmdirAction(const char *fileName, struct stat *statbuf) {
133 if (rmdir(fileName) < 0) {
134 perror(fileName);
135 return FALSE;
136 }
137 return TRUE;
138 }
139
140 if ((dz = strrchr(*argv, '/')) == NULL)
141 dz = *argv;
142 else
143 dz++;
144 if (*dz == 'c' && *(dz + 1) == 'p')
145 dz_i = is_cp;
146 else
147 dz_i = is_mv;
148 if (argc < 3)
149 usage(cp_mv_usage[dz_i]);
150 argc--;
151 argv++;
152
153 if (dz_i == is_cp) {
154 recursiveFlag = preserveFlag = FALSE;
155 followLinks = TRUE;
156 while (**argv == '-') {
157 while (*++(*argv)) {
158 switch (**argv) {
159 case 'a':
160 followLinks = FALSE;
161 preserveFlag = TRUE;
162 recursiveFlag = TRUE;
163 break;
164 case 'd':
165 followLinks = FALSE;
166 break;
167 case 'p':
168 preserveFlag = TRUE;
169 break;
170 case 'R':
171 recursiveFlag = TRUE;
172 break;
173 default:
174 usage(cp_mv_usage[is_cp]);
175 }
176 }
177 argc--;
178 argv++;
179 }
180 } else { /* (dz_i == is_mv) */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000181 recursiveFlag = preserveFlag = TRUE;
182 followLinks = FALSE;
183 }
184
185 if (strlen(argv[argc - 1]) > PATH_MAX) {
186 fprintf(stderr, name_too_long, "cp");
187 goto exit_false;
188 }
189 strcpy(baseDestName, argv[argc - 1]);
190 baseDestLen = strlen(baseDestName);
191 if (baseDestLen == 0)
192 goto exit_false;
193
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000194 destDirFlag = isDirectory(baseDestName, TRUE, &destStatBuf);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000195 if ((argc > 3) && destDirFlag == FALSE) {
196 fprintf(stderr, not_a_directory, "cp", baseDestName);
197 goto exit_false;
198 }
199
200 while (argc-- > 1) {
201 size_t srcLen;
202 int flags_memo;
203
204 baseSrcName = *(argv++);
205
206 if ((srcLen = strlen(baseSrcName)) > PATH_MAX)
Erik Andersenfac10d72000-02-07 05:29:42 +0000207 goto name_too_long__exit;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000208
209 if (srcLen == 0)
210 continue;
211
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000212 srcDirFlag = isDirectory(baseSrcName, followLinks, &srcStatBuf);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000213
214 if ((flags_memo = (recursiveFlag == TRUE &&
215 srcDirFlag == TRUE && destDirFlag == TRUE))) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000216 if ((destStatBuf.st_ino == srcStatBuf.st_ino) &&
217 (destStatBuf.st_rdev == srcStatBuf.st_rdev)) {
218 fprintf(stderr,
219 "%s: Cannot %s `%s' into a subdirectory of itself, `%s/%s'\n",
220 dz, dz, baseSrcName, baseDestName, baseSrcName);
221 continue;
222 }
223 fill_baseDest_buf(baseDestName, &baseDestLen);
Erik Andersenfac10d72000-02-07 05:29:42 +0000224 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000225 if (recursiveAction(baseSrcName,
226 recursiveFlag, followLinks, FALSE,
227 fileAction, fileAction) == FALSE)
228 goto exit_false;
229
230 if (dz_i == is_mv &&
231 recursiveAction(baseSrcName,
232 recursiveFlag, followLinks, TRUE,
233 rmfileAction, rmdirAction) == FALSE)
234 goto exit_false;
235
236 if (flags_memo)
237 *(baseDestName + baseDestLen) = '\0';
Erik Andersenfac10d72000-02-07 05:29:42 +0000238 }
239
Erik Andersene49d5ec2000-02-08 19:58:47 +0000240 exit TRUE;
Erik Andersenfac10d72000-02-07 05:29:42 +0000241
Erik Andersene49d5ec2000-02-08 19:58:47 +0000242 name_too_long__exit:
Erik Andersenfac10d72000-02-07 05:29:42 +0000243 fprintf(stderr, name_too_long, "cp");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000244 exit_false:
245 exit FALSE;
Erik Andersenfac10d72000-02-07 05:29:42 +0000246}
247
248// Local Variables:
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000249// c-file-style: "linux"
250// tab-width: 4
Erik Andersenfac10d72000-02-07 05:29:42 +0000251// End: