VirtualBox

source: kBuild/trunk/src/gmake/kmkbuiltin/cp.c@ 229

Last change on this file since 229 was 229, checked in by bird, 20 years ago

cp.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/*
2 * Copyright (c) 1988, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * David Hitz of Auspex Systems Inc.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#if 0
34#ifndef lint
35static char const copyright[] =
36"@(#) Copyright (c) 1988, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94";
42#endif /* not lint */
43#endif
44#include <sys/cdefs.h>
45//__FBSDID("$FreeBSD: src/bin/cp/cp.c,v 1.50 2004/04/06 20:06:44 markm Exp $");
46
47/*
48 * Cp copies source files to target files.
49 *
50 * The global PATH_T structure "to" always contains the path to the
51 * current target file. Since fts(3) does not change directories,
52 * this path can be either absolute or dot-relative.
53 *
54 * The basic algorithm is to initialize "to" and use fts(3) to traverse
55 * the file hierarchy rooted in the argument list. A trivial case is the
56 * case of 'cp file1 file2'. The more interesting case is the case of
57 * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
58 * path (relative to the root of the traversal) is appended to dir (stored
59 * in "to") to form the final target path.
60 */
61
62#include <sys/types.h>
63#include <sys/stat.h>
64
65#include <err.h>
66#include <errno.h>
67#include <fts.h>
68#include <limits.h>
69#include <signal.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <unistd.h>
74
75#include "cp_extern.h"
76
77#ifndef S_IFWHT
78#define S_IFWHT 0
79#define S_ISWHT(s) 0
80#define undelete(s) (-1)
81#endif
82
83#ifndef S_ISTXT
84#ifdef S_ISVTX
85#define S_ISTXT S_ISVTX
86#else
87#define S_ISTXT 0
88#endif
89#endif /* !S_ISTXT */
90
91
92#define STRIP_TRAILING_SLASH(p) { \
93 while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \
94 *--(p).p_end = 0; \
95}
96
97/* have wrappers for globals in cp_extern! */
98
99const char *cp_argv0;
100static char emptystring[] = "";
101
102PATH_T to = { to.p_path, emptystring, "" };
103
104int fflag, iflag, nflag, pflag, vflag;
105int Rflag, rflag;
106volatile sig_atomic_t info;
107
108enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
109
110static int copy(char *[], enum op, int);
111static int mastercmp(const FTSENT * const *, const FTSENT * const *);
112#ifdef SIGINFO
113static void siginfo(int __unused);
114#endif
115
116int
117kmk_builtin_cp(int argc, char *argv[])
118{
119 struct stat to_stat, tmp_stat;
120 enum op type;
121 int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash;
122 char *target;
123
124 argv0 = argv[0];
125 to.p_end = to.p_path;
126 to.target_end = emptystring;
127 memset(to.p_path, 0, sizeof(to.p_path));
128 fflag = iflag = nflag = pflag = vflag = Rflag = rflag = 0;
129 info = 0;
130 opterr = 1;
131 optarg = NULL;
132 optopt = 0;
133 optind = 0; /* init */
134
135 Hflag = Lflag = Pflag = 0;
136 while ((ch = getopt(argc, argv, "HLPRfinprv")) != -1)
137 switch (ch) {
138 case 'H':
139 Hflag = 1;
140 Lflag = Pflag = 0;
141 break;
142 case 'L':
143 Lflag = 1;
144 Hflag = Pflag = 0;
145 break;
146 case 'P':
147 Pflag = 1;
148 Hflag = Lflag = 0;
149 break;
150 case 'R':
151 Rflag = 1;
152 break;
153 case 'f':
154 fflag = 1;
155 iflag = nflag = 0;
156 break;
157 case 'i':
158 iflag = 1;
159 fflag = nflag = 0;
160 break;
161 case 'n':
162 nflag = 1;
163 fflag = iflag = 0;
164 break;
165 case 'p':
166 pflag = 1;
167 break;
168 case 'r':
169 rflag = 1;
170 break;
171 case 'v':
172 vflag = 1;
173 break;
174 default:
175 usage();
176 break;
177 }
178 argc -= optind;
179 argv += optind;
180
181 if (argc < 2)
182 usage();
183
184 fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
185 if (rflag) {
186 if (Rflag) {
187 fprintf(stderr,
188 "%s: the -R and -r options may not be specified together.\n", argv0);
189 return 1;
190 }
191 if (Hflag || Lflag || Pflag) {
192 fprintf(stderr, "%s: the -H, -L, and -P options may not be specified with the -r option.\n", argv0);
193 return 1;
194 }
195 fts_options &= ~FTS_PHYSICAL;
196 fts_options |= FTS_LOGICAL;
197 }
198 if (Rflag) {
199 if (Hflag)
200 fts_options |= FTS_COMFOLLOW;
201 if (Lflag) {
202 fts_options &= ~FTS_PHYSICAL;
203 fts_options |= FTS_LOGICAL;
204 }
205 } else {
206 fts_options &= ~FTS_PHYSICAL;
207 fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
208 }
209#ifdef SIGINFO
210 (void)signal(SIGINFO, siginfo);
211#endif
212
213 /* Save the target base in "to". */
214 target = argv[--argc];
215 if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) {
216 fprintf(stderr, "%s: %s: name too long\n", argv0, target);
217 return 1;
218 }
219 to.p_end = to.p_path + strlen(to.p_path);
220 if (to.p_path == to.p_end) {
221 *to.p_end++ = '.';
222 *to.p_end = 0;
223 }
224 have_trailing_slash = (to.p_end[-1] == '/');
225 if (have_trailing_slash)
226 STRIP_TRAILING_SLASH(to);
227 to.target_end = to.p_end;
228
229 /* Set end of argument list for fts(3). */
230 argv[argc] = NULL;
231
232 /*
233 * Cp has two distinct cases:
234 *
235 * cp [-R] source target
236 * cp [-R] source1 ... sourceN directory
237 *
238 * In both cases, source can be either a file or a directory.
239 *
240 * In (1), the target becomes a copy of the source. That is, if the
241 * source is a file, the target will be a file, and likewise for
242 * directories.
243 *
244 * In (2), the real target is not directory, but "directory/source".
245 */
246 r = stat(to.p_path, &to_stat);
247 if (r == -1 && errno != ENOENT) {
248 fprintf(stderr, "%s: %s: %s\n", argv0, to.p_path, strerror(errno));
249 }
250 if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
251 /*
252 * Case (1). Target is not a directory.
253 */
254 if (argc > 1) {
255 usage();
256 return 1;
257 }
258 /*
259 * Need to detect the case:
260 * cp -R dir foo
261 * Where dir is a directory and foo does not exist, where
262 * we want pathname concatenations turned on but not for
263 * the initial mkdir().
264 */
265 if (r == -1) {
266 if (rflag || (Rflag && (Lflag || Hflag)))
267 stat(*argv, &tmp_stat);
268 else
269 lstat(*argv, &tmp_stat);
270
271 if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
272 type = DIR_TO_DNE;
273 else
274 type = FILE_TO_FILE;
275 } else
276 type = FILE_TO_FILE;
277
278 if (have_trailing_slash && type == FILE_TO_FILE) {
279 if (r == -1)
280 fprintf(stderr, "%s: directory %s does not exist\n", argv0,
281 to.p_path);
282 else
283 fprintf(stderr, "%s: %s is not a directory\n", argv0, to.p_path);
284 return 1;
285 }
286 } else
287 /*
288 * Case (2). Target is a directory.
289 */
290 type = FILE_TO_DIR;
291
292 return copy(argv, type, fts_options);
293}
294
295static int
296copy(char *argv[], enum op type, int fts_options)
297{
298 struct stat to_stat;
299 FTS *ftsp;
300 FTSENT *curr;
301 int base = 0, dne, badcp, rval;
302 size_t nlen;
303 char *p, *target_mid;
304 mode_t mask, mode;
305
306 /*
307 * Keep an inverted copy of the umask, for use in correcting
308 * permissions on created directories when not using -p.
309 */
310 mask = ~umask(0777);
311 umask(~mask);
312
313 if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL) {
314 fprintf(stderr, "%s: fts_open: %s\n", argv0, strerror(errno));
315 return 1;
316 }
317 for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
318 switch (curr->fts_info) {
319 case FTS_NS:
320 case FTS_DNR:
321 case FTS_ERR:
322 fprintf(stderr, "%s: %s: %s\n",
323 argv0, curr->fts_path, strerror(curr->fts_errno));
324 badcp = rval = 1;
325 continue;
326 case FTS_DC: /* Warn, continue. */
327 fprintf(stderr, "%s: %s: directory causes a cycle\n", argv0, curr->fts_path);
328 badcp = rval = 1;
329 continue;
330 default:
331 ;
332 }
333
334 /*
335 * If we are in case (2) or (3) above, we need to append the
336 * source name to the target name.
337 */
338 if (type != FILE_TO_FILE) {
339 /*
340 * Need to remember the roots of traversals to create
341 * correct pathnames. If there's a directory being
342 * copied to a non-existent directory, e.g.
343 * cp -R a/dir noexist
344 * the resulting path name should be noexist/foo, not
345 * noexist/dir/foo (where foo is a file in dir), which
346 * is the case where the target exists.
347 *
348 * Also, check for "..". This is for correct path
349 * concatenation for paths ending in "..", e.g.
350 * cp -R .. /tmp
351 * Paths ending in ".." are changed to ".". This is
352 * tricky, but seems the easiest way to fix the problem.
353 *
354 * XXX
355 * Since the first level MUST be FTS_ROOTLEVEL, base
356 * is always initialized.
357 */
358 if (curr->fts_level == FTS_ROOTLEVEL) {
359 if (type != DIR_TO_DNE) {
360 p = strrchr(curr->fts_path, '/');
361 base = (p == NULL) ? 0 :
362 (int)(p - curr->fts_path + 1);
363
364 if (!strcmp(&curr->fts_path[base],
365 ".."))
366 base += 1;
367 } else
368 base = curr->fts_pathlen;
369 }
370
371 p = &curr->fts_path[base];
372 nlen = curr->fts_pathlen - base;
373 target_mid = to.target_end;
374 if (*p != '/' && target_mid[-1] != '/')
375 *target_mid++ = '/';
376 *target_mid = 0;
377 if (target_mid - to.p_path + nlen >= PATH_MAX) {
378 fprintf(stderr, "%s: %s%s: name too long (not copied)\n", argv0,
379 to.p_path, p);
380 badcp = rval = 1;
381 continue;
382 }
383 (void)strncat(target_mid, p, nlen);
384 to.p_end = target_mid + nlen;
385 *to.p_end = 0;
386 STRIP_TRAILING_SLASH(to);
387 }
388
389 if (curr->fts_info == FTS_DP) {
390 /*
391 * We are nearly finished with this directory. If we
392 * didn't actually copy it, or otherwise don't need to
393 * change its attributes, then we are done.
394 */
395 if (!curr->fts_number)
396 continue;
397 /*
398 * If -p is in effect, set all the attributes.
399 * Otherwise, set the correct permissions, limited
400 * by the umask. Optimise by avoiding a chmod()
401 * if possible (which is usually the case if we
402 * made the directory). Note that mkdir() does not
403 * honour setuid, setgid and sticky bits, but we
404 * normally want to preserve them on directories.
405 */
406 if (pflag) {
407 if (setfile(curr->fts_statp, -1))
408 rval = 1;
409 } else {
410 mode = curr->fts_statp->st_mode;
411 if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) ||
412 ((mode | S_IRWXU) & mask) != (mode & mask))
413 if (chmod(to.p_path, mode & mask) != 0){
414 fprintf(stderr, "%s: chmod: %s: %s\n", argv0, to.p_path, strerror(errno));
415 rval = 1;
416 }
417 }
418 continue;
419 }
420
421 /* Not an error but need to remember it happened */
422 if (stat(to.p_path, &to_stat) == -1)
423 dne = 1;
424 else {
425 if (to_stat.st_dev == curr->fts_statp->st_dev &&
426 to_stat.st_ino == curr->fts_statp->st_ino) {
427 fprintf(stderr, "%s: %s and %s are identical (not copied).\n",
428 argv0, to.p_path, curr->fts_path);
429 badcp = rval = 1;
430 if (S_ISDIR(curr->fts_statp->st_mode))
431 (void)fts_set(ftsp, curr, FTS_SKIP);
432 continue;
433 }
434 if (!S_ISDIR(curr->fts_statp->st_mode) &&
435 S_ISDIR(to_stat.st_mode)) {
436 fprintf(stderr,
437 "%s: cannot overwrite directory %s with "
438 "non-directory %s\n",
439 argv0, to.p_path, curr->fts_path);
440 badcp = rval = 1;
441 continue;
442 }
443 dne = 0;
444 }
445
446 switch (curr->fts_statp->st_mode & S_IFMT) {
447 case S_IFLNK:
448 /* Catch special case of a non-dangling symlink */
449 if ((fts_options & FTS_LOGICAL) ||
450 ((fts_options & FTS_COMFOLLOW) &&
451 curr->fts_level == 0)) {
452 if (copy_file(curr, dne))
453 badcp = rval = 1;
454 } else {
455 if (copy_link(curr, !dne))
456 badcp = rval = 1;
457 }
458 break;
459 case S_IFDIR:
460 if (!Rflag && !rflag) {
461 fprintf(stderr, "%s: %s is a directory (not copied).\n",
462 argv0, curr->fts_path);
463 (void)fts_set(ftsp, curr, FTS_SKIP);
464 badcp = rval = 1;
465 break;
466 }
467 /*
468 * If the directory doesn't exist, create the new
469 * one with the from file mode plus owner RWX bits,
470 * modified by the umask. Trade-off between being
471 * able to write the directory (if from directory is
472 * 555) and not causing a permissions race. If the
473 * umask blocks owner writes, we fail..
474 */
475 if (dne) {
476 if (mkdir(to.p_path,
477 curr->fts_statp->st_mode | S_IRWXU) < 0) {
478 fprintf(stderr, "%s: %s: %s\n", argv0, to.p_path, strerror(errno));
479 return 1;
480 }
481 } else if (!S_ISDIR(to_stat.st_mode)) {
482 errno = ENOTDIR;
483 fprintf(stderr, "%s: %s: %s\n", argv0, to.p_path, strerror(errno));
484 }
485 /*
486 * Arrange to correct directory attributes later
487 * (in the post-order phase) if this is a new
488 * directory, or if the -p flag is in effect.
489 */
490 curr->fts_number = pflag || dne;
491 break;
492 case S_IFBLK:
493 case S_IFCHR:
494 if (Rflag) {
495 if (copy_special(curr->fts_statp, !dne))
496 badcp = rval = 1;
497 } else {
498 if (copy_file(curr, dne))
499 badcp = rval = 1;
500 }
501 break;
502 case S_IFIFO:
503 if (Rflag) {
504 if (copy_fifo(curr->fts_statp, !dne))
505 badcp = rval = 1;
506 } else {
507 if (copy_file(curr, dne))
508 badcp = rval = 1;
509 }
510 break;
511 default:
512 if (copy_file(curr, dne))
513 badcp = rval = 1;
514 break;
515 }
516 if (vflag && !badcp)
517 (void)printf("%s -> %s\n", curr->fts_path, to.p_path);
518 }
519 if (errno) {
520 fprintf(stderr, "%s: fts_read: %s\n", argv0, strerror(errno));
521 }
522 return (rval);
523}
524
525/*
526 * mastercmp --
527 * The comparison function for the copy order. The order is to copy
528 * non-directory files before directory files. The reason for this
529 * is because files tend to be in the same cylinder group as their
530 * parent directory, whereas directories tend not to be. Copying the
531 * files first reduces seeking.
532 */
533static int
534mastercmp(const FTSENT * const *a, const FTSENT * const *b)
535{
536 int a_info, b_info;
537
538 a_info = (*a)->fts_info;
539 if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR)
540 return (0);
541 b_info = (*b)->fts_info;
542 if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR)
543 return (0);
544 if (a_info == FTS_D)
545 return (-1);
546 if (b_info == FTS_D)
547 return (1);
548 return (0);
549}
550
551#ifdef SIGINFO
552static void
553siginfo(int sig __unused)
554{
555
556 info = 1;
557}
558#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette