VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/cp.c

最後變更 在這個檔案是 3389,由 bird 提交於 5 年 前

kmk: Avoid setting umask just to get it, store the current value in a global variable (g_fUMask). The umask(0777) call in cp.c raced other code (kmk_append) that created files and directories, leaving us with read-only files sometimes.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 24.4 KB
 
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#include <sys/cdefs.h>
44__FBSDID("$FreeBSD: src/bin/cp/cp.c,v 1.50 2004/04/06 20:06:44 markm Exp $");
45#endif
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
63/*********************************************************************************************************************************
64* Header Files *
65*********************************************************************************************************************************/
66#define FAKES_NO_GETOPT_H /* bird */
67#include "config.h"
68#include <sys/types.h>
69#include <sys/stat.h>
70
71#include <assert.h>
72#include "err.h"
73#include <errno.h>
74#include "fts.h"
75#include <limits.h>
76#include <signal.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81#include "getopt_r.h"
82#include "k/kDefs.h"
83#ifdef _MSC_VER
84# include "mscfakes.h"
85#endif
86#include "cp_extern.h"
87#include "kmkbuiltin.h"
88#include "kbuild_protection.h"
89
90#if defined(_MSC_VER) || defined(__gnu_linux__) || defined(__linux__)
91extern size_t strlcpy(char *, const char *, size_t);
92#endif
93
94
95/*********************************************************************************************************************************
96* Defined Constants And Macros *
97*********************************************************************************************************************************/
98#ifndef S_IFWHT
99#define S_IFWHT 0
100#define S_ISWHT(s) 0
101#define undelete(s) (-1)
102#endif
103
104#ifndef S_ISTXT
105#ifdef S_ISVTX
106#define S_ISTXT S_ISVTX
107#else
108#define S_ISTXT 0
109#endif
110#endif /* !S_ISTXT */
111
112#ifndef __unused
113# define __unused
114#endif
115
116#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
117# define IS_SLASH(ch) ((ch) == '/' || (ch) == '\\')
118#else
119# define IS_SLASH(ch) ((ch) == '/')
120#endif
121
122#define STRIP_TRAILING_SLASH(p) { \
123 while ((p).p_end > (p).p_path + 1 && IS_SLASH((p).p_end[-1])) \
124 *--(p).p_end = 0; \
125}
126
127/*********************************************************************************************************************************
128* Structures and Typedefs *
129*********************************************************************************************************************************/
130typedef struct CPINSTANCE
131{
132 CPUTILSINSTANCE Utils;
133 int Rflag, rflag;
134 int cp_ignore_non_existing, cp_changed_only;
135 KBUILDPROTECTION g_ProtData;
136} CPINSTANCE;
137
138/* have wrappers for globals in cp_extern! */
139
140
141enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
142
143
144/*********************************************************************************************************************************
145* Global Variables *
146*********************************************************************************************************************************/
147enum cp_arg {
148 CP_OPT_HELP = 261,
149 CP_OPT_VERSION,
150 CP_OPT_IGNORE_NON_EXISTING,
151 CP_OPT_CHANGED,
152 CP_OPT_DISABLE_PROTECTION,
153 CP_OPT_ENABLE_PROTECTION,
154 CP_OPT_ENABLE_FULL_PROTECTION,
155 CP_OPT_DISABLE_FULL_PROTECTION,
156 CP_OPT_PROTECTION_DEPTH
157};
158
159static struct option long_options[] =
160{
161 { "help", no_argument, 0, CP_OPT_HELP },
162 { "version", no_argument, 0, CP_OPT_VERSION },
163 { "ignore-non-existing", no_argument, 0, CP_OPT_IGNORE_NON_EXISTING },
164 { "changed", no_argument, 0, CP_OPT_CHANGED },
165 { "disable-protection", no_argument, 0, CP_OPT_DISABLE_PROTECTION },
166 { "enable-protection", no_argument, 0, CP_OPT_ENABLE_PROTECTION },
167 { "enable-full-protection", no_argument, 0, CP_OPT_ENABLE_FULL_PROTECTION },
168 { "disable-full-protection", no_argument, 0, CP_OPT_DISABLE_FULL_PROTECTION },
169 { "protection-depth", required_argument, 0, CP_OPT_PROTECTION_DEPTH },
170 { 0, 0, 0, 0 },
171};
172
173static char emptystring[] = "";
174
175#if defined(SIGINFO) && defined(KMK_BUILTIN_STANDALONE)
176volatile sig_atomic_t g_cp_info;
177#endif
178
179extern mode_t g_fUMask;
180
181
182/*********************************************************************************************************************************
183* Internal Functions *
184*********************************************************************************************************************************/
185static int copy(CPINSTANCE *pThis, char * const *, enum op, int);
186#ifdef FTSCALL
187static int FTSCALL mastercmp(const FTSENT * const *, const FTSENT * const *);
188#else
189static int mastercmp(const FTSENT **, const FTSENT **);
190#endif
191#if defined(SIGINFO) && defined(KMK_BUILTIN_STANDALONE)
192static void siginfo(int __unused);
193#endif
194static int usage(PKMKBUILTINCTX, int);
195
196int
197kmk_builtin_cp(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
198{
199 CPINSTANCE This;
200 struct getopt_state_r gos;
201 struct stat to_stat, tmp_stat;
202 enum op type;
203 int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash, rc;
204 char *target;
205
206 /* init globals */
207 This.Utils.pCtx = pCtx;
208 This.Utils.to.p_end = This.Utils.to.p_path;
209 This.Utils.to.target_end = emptystring;
210 memset(This.Utils.to.p_path, 0, sizeof(This.Utils.to.p_path));
211 This.Utils.fflag = 0;
212 This.Utils.iflag = 0;
213 This.Utils.nflag = 0;
214 This.Utils.pflag = 0;
215 This.Utils.vflag = 0;
216 This.Rflag = 0;
217 This.rflag = 0;
218 This.cp_ignore_non_existing = This.cp_changed_only = 0;
219 kBuildProtectionInit(&This.g_ProtData, pCtx);
220
221 Hflag = Lflag = Pflag = 0;
222 getopt_initialize_r(&gos, argc, argv, "HLPRfinprv", long_options, envp, pCtx);
223 while ((ch = getopt_long_r(&gos, NULL)) != -1)
224 switch (ch) {
225 case 'H':
226 Hflag = 1;
227 Lflag = Pflag = 0;
228 break;
229 case 'L':
230 Lflag = 1;
231 Hflag = Pflag = 0;
232 break;
233 case 'P':
234 Pflag = 1;
235 Hflag = Lflag = 0;
236 break;
237 case 'R':
238 This.Rflag = 1;
239 break;
240 case 'f':
241 This.Utils.fflag = 1;
242 This.Utils.iflag = This.Utils.nflag = 0;
243 break;
244 case 'i':
245 This.Utils.iflag = 1;
246 This.Utils.fflag = This.Utils.nflag = 0;
247 break;
248 case 'n':
249 This.Utils.nflag = 1;
250 This.Utils.fflag = This.Utils.iflag = 0;
251 break;
252 case 'p':
253 This.Utils.pflag = 1;
254 break;
255 case 'r':
256 This.rflag = 1;
257 break;
258 case 'v':
259 This.Utils.vflag = 1;
260 break;
261 case CP_OPT_HELP:
262 usage(pCtx, 0);
263 kBuildProtectionTerm(&This.g_ProtData);
264 return 0;
265 case CP_OPT_VERSION:
266 kBuildProtectionTerm(&This.g_ProtData);
267 return kbuild_version(argv[0]);
268 case CP_OPT_IGNORE_NON_EXISTING:
269 This.cp_ignore_non_existing = 1;
270 break;
271 case CP_OPT_CHANGED:
272 This.cp_changed_only = 1;
273 break;
274 case CP_OPT_DISABLE_PROTECTION:
275 kBuildProtectionDisable(&This.g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
276 break;
277 case CP_OPT_ENABLE_PROTECTION:
278 kBuildProtectionEnable(&This.g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
279 break;
280 case CP_OPT_ENABLE_FULL_PROTECTION:
281 kBuildProtectionEnable(&This.g_ProtData, KBUILDPROTECTIONTYPE_FULL);
282 break;
283 case CP_OPT_DISABLE_FULL_PROTECTION:
284 kBuildProtectionDisable(&This.g_ProtData, KBUILDPROTECTIONTYPE_FULL);
285 break;
286 case CP_OPT_PROTECTION_DEPTH:
287 if (kBuildProtectionSetDepth(&This.g_ProtData, gos.optarg)) {
288 kBuildProtectionTerm(&This.g_ProtData);
289 return 1;
290 }
291 break;
292 default:
293 kBuildProtectionTerm(&This.g_ProtData);
294 return usage(pCtx, 1);
295 }
296 argc -= gos.optind;
297 argv += gos.optind;
298
299 if (argc < 2) {
300 kBuildProtectionTerm(&This.g_ProtData);
301 return usage(pCtx, 1);
302 }
303
304 fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
305 if (This.rflag) {
306 if (This.Rflag) {
307 kBuildProtectionTerm(&This.g_ProtData);
308 return errx(pCtx, 1,
309 "the -R and -r options may not be specified together.");
310 }
311 if (Hflag || Lflag || Pflag)
312 errx(pCtx, 1,
313 "the -H, -L, and -P options may not be specified with the -r option.");
314 fts_options &= ~FTS_PHYSICAL;
315 fts_options |= FTS_LOGICAL;
316 }
317 if (This.Rflag) {
318 if (Hflag)
319 fts_options |= FTS_COMFOLLOW;
320 if (Lflag) {
321 fts_options &= ~FTS_PHYSICAL;
322 fts_options |= FTS_LOGICAL;
323 }
324 } else {
325 fts_options &= ~FTS_PHYSICAL;
326 fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
327 }
328#if defined(SIGINFO) && defined(KMK_BUILTIN_STANDALONE)
329 (void)signal(SIGINFO, siginfo);
330#endif
331
332 /* Save the target base in "to". */
333 target = argv[--argc];
334 if (strlcpy(This.Utils.to.p_path, target, sizeof(This.Utils.to.p_path)) >= sizeof(This.Utils.to.p_path)) {
335 kBuildProtectionTerm(&This.g_ProtData);
336 return errx(pCtx, 1, "%s: name too long", target);
337 }
338 This.Utils.to.p_end = This.Utils.to.p_path + strlen(This.Utils.to.p_path);
339 if (This.Utils.to.p_path == This.Utils.to.p_end) {
340 *This.Utils.to.p_end++ = '.';
341 *This.Utils.to.p_end = 0;
342 }
343 have_trailing_slash = IS_SLASH(This.Utils.to.p_end[-1]);
344 if (have_trailing_slash)
345 STRIP_TRAILING_SLASH(This.Utils.to);
346 This.Utils.to.target_end = This.Utils.to.p_end;
347
348 /* Set end of argument list for fts(3). */
349 argv[argc] = NULL;
350
351 /*
352 * Cp has two distinct cases:
353 *
354 * cp [-R] source target
355 * cp [-R] source1 ... sourceN directory
356 *
357 * In both cases, source can be either a file or a directory.
358 *
359 * In (1), the target becomes a copy of the source. That is, if the
360 * source is a file, the target will be a file, and likewise for
361 * directories.
362 *
363 * In (2), the real target is not directory, but "directory/source".
364 */
365 r = stat(This.Utils.to.p_path, &to_stat);
366 if (r == -1 && errno != ENOENT) {
367 kBuildProtectionTerm(&This.g_ProtData);
368 return err(pCtx, 1, "stat: %s", This.Utils.to.p_path);
369 }
370 if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
371 /*
372 * Case (1). Target is not a directory.
373 */
374 if (argc > 1) {
375 kBuildProtectionTerm(&This.g_ProtData);
376 return usage(pCtx, 1);
377 }
378 /*
379 * Need to detect the case:
380 * cp -R dir foo
381 * Where dir is a directory and foo does not exist, where
382 * we want pathname concatenations turned on but not for
383 * the initial mkdir().
384 */
385 if (r == -1) {
386 if (This.rflag || (This.Rflag && (Lflag || Hflag)))
387 stat(*argv, &tmp_stat);
388 else
389 lstat(*argv, &tmp_stat);
390
391 if (S_ISDIR(tmp_stat.st_mode) && (This.Rflag || This.rflag))
392 type = DIR_TO_DNE;
393 else
394 type = FILE_TO_FILE;
395 } else
396 type = FILE_TO_FILE;
397
398 if (have_trailing_slash && type == FILE_TO_FILE) {
399 kBuildProtectionTerm(&This.g_ProtData);
400 if (r == -1)
401 return errx(pCtx, 1, "directory %s does not exist",
402 This.Utils.to.p_path);
403 else
404 return errx(pCtx, 1, "%s is not a directory", This.Utils.to.p_path);
405 }
406 } else
407 /*
408 * Case (2). Target is a directory.
409 */
410 type = FILE_TO_DIR;
411
412 /* Finally, check that the "to" directory isn't protected. */
413 rc = 1;
414 if (!kBuildProtectionScanEnv(&This.g_ProtData, envp, "KMK_CP_")
415 && !kBuildProtectionEnforce(&This.g_ProtData,
416 This.Rflag || This.rflag
417 ? KBUILDPROTECTIONTYPE_RECURSIVE
418 : KBUILDPROTECTIONTYPE_FULL,
419 This.Utils.to.p_path)) {
420 rc = copy(&This, argv, type, fts_options);
421 }
422
423 kBuildProtectionTerm(&This.g_ProtData);
424 return rc;
425}
426
427#ifdef KMK_BUILTIN_STANDALONE
428mode_t g_fUMask;
429int main(int argc, char **argv, char **envp)
430{
431 KMKBUILTINCTX Ctx = { "kmk_cp", NULL };
432 umask(g_fUMask = umask(0077));
433 return kmk_builtin_cp(argc, argv, envp, &Ctx);
434}
435#endif
436
437static int
438copy(CPINSTANCE *pThis, char * const *argv, enum op type, int fts_options)
439{
440 struct stat to_stat;
441 FTS *ftsp;
442 FTSENT *curr;
443 int base = 0, dne, badcp, rval;
444 size_t nlen;
445 char *p, *target_mid;
446 mode_t mask, mode;
447
448 /*
449 * Keep an inverted copy of the umask, for use in correcting
450 * permissions on created directories when not using -p.
451 */
452 mask = g_fUMask;
453 assert(mask == umask(mask));
454 mask = ~mask;
455
456 if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
457 return err(pThis->Utils.pCtx, 1, "fts_open");
458 for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
459 int copied = 0;
460
461 switch (curr->fts_info) {
462 case FTS_NS:
463 if ( pThis->cp_ignore_non_existing
464 && curr->fts_errno == ENOENT) {
465 if (pThis->Utils.vflag) {
466 warnx(pThis->Utils.pCtx, "fts: %s: %s", curr->fts_path,
467 strerror(curr->fts_errno));
468 }
469 continue;
470 }
471 /* fall thru */
472 case FTS_DNR:
473 case FTS_ERR:
474 warnx(pThis->Utils.pCtx, "fts: %s: %s",
475 curr->fts_path, strerror(curr->fts_errno));
476 badcp = rval = 1;
477 continue;
478 case FTS_DC: /* Warn, continue. */
479 warnx(pThis->Utils.pCtx, "%s: directory causes a cycle", curr->fts_path);
480 badcp = rval = 1;
481 continue;
482 default:
483 ;
484 }
485
486 /*
487 * If we are in case (2) or (3) above, we need to append the
488 * source name to the target name.
489 */
490 if (type != FILE_TO_FILE) {
491 /*
492 * Need to remember the roots of traversals to create
493 * correct pathnames. If there's a directory being
494 * copied to a non-existent directory, e.g.
495 * cp -R a/dir noexist
496 * the resulting path name should be noexist/foo, not
497 * noexist/dir/foo (where foo is a file in dir), which
498 * is the case where the target exists.
499 *
500 * Also, check for "..". This is for correct path
501 * concatenation for paths ending in "..", e.g.
502 * cp -R .. /tmp
503 * Paths ending in ".." are changed to ".". This is
504 * tricky, but seems the easiest way to fix the problem.
505 *
506 * XXX
507 * Since the first level MUST be FTS_ROOTLEVEL, base
508 * is always initialized.
509 */
510 if (curr->fts_level == FTS_ROOTLEVEL) {
511 if (type != DIR_TO_DNE) {
512 p = strrchr(curr->fts_path, '/');
513#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
514 if (strrchr(curr->fts_path, '\\') > p)
515 p = strrchr(curr->fts_path, '\\');
516#endif
517 base = (p == NULL) ? 0 :
518 (int)(p - curr->fts_path + 1);
519
520 if (!strcmp(&curr->fts_path[base],
521 ".."))
522 base += 1;
523 } else
524 base = curr->fts_pathlen;
525 }
526
527 p = &curr->fts_path[base];
528 nlen = curr->fts_pathlen - base;
529 target_mid = pThis->Utils.to.target_end;
530 if (!IS_SLASH(*p) && !IS_SLASH(target_mid[-1]))
531 *target_mid++ = '/';
532 *target_mid = 0;
533 if (target_mid - pThis->Utils.to.p_path + nlen >= PATH_MAX) {
534 warnx(pThis->Utils.pCtx, "%s%s: name too long (not copied)",
535 pThis->Utils.to.p_path, p);
536 badcp = rval = 1;
537 continue;
538 }
539 (void)strncat(target_mid, p, nlen);
540 pThis->Utils.to.p_end = target_mid + nlen;
541 *pThis->Utils.to.p_end = 0;
542 STRIP_TRAILING_SLASH(pThis->Utils.to);
543 }
544
545 if (curr->fts_info == FTS_DP) {
546 /*
547 * We are nearly finished with this directory. If we
548 * didn't actually copy it, or otherwise don't need to
549 * change its attributes, then we are done.
550 */
551 if (!curr->fts_number)
552 continue;
553 /*
554 * If -p is in effect, set all the attributes.
555 * Otherwise, set the correct permissions, limited
556 * by the umask. Optimise by avoiding a chmod()
557 * if possible (which is usually the case if we
558 * made the directory). Note that mkdir() does not
559 * honour setuid, setgid and sticky bits, but we
560 * normally want to preserve them on directories.
561 */
562 if (pThis->Utils.pflag) {
563 if (copy_file_attribs(&pThis->Utils, curr->fts_statp, -1))
564 rval = 1;
565 } else {
566 mode = curr->fts_statp->st_mode;
567 if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) ||
568 ((mode | S_IRWXU) & mask) != (mode & mask))
569 if (chmod(pThis->Utils.to.p_path, mode & mask) != 0){
570 warn(pThis->Utils.pCtx, "chmod: %s", pThis->Utils.to.p_path);
571 rval = 1;
572 }
573 }
574 continue;
575 }
576
577 /* Not an error but need to remember it happened */
578 if (stat(pThis->Utils.to.p_path, &to_stat) == -1)
579 dne = 1;
580 else {
581 if (to_stat.st_dev == curr->fts_statp->st_dev &&
582 to_stat.st_dev != 0 &&
583 to_stat.st_ino == curr->fts_statp->st_ino &&
584 to_stat.st_ino != 0) {
585 warnx(pThis->Utils.pCtx, "%s and %s are identical (not copied).",
586 pThis->Utils.to.p_path, curr->fts_path);
587 badcp = rval = 1;
588 if (S_ISDIR(curr->fts_statp->st_mode))
589 (void)fts_set(ftsp, curr, FTS_SKIP);
590 continue;
591 }
592 if (!S_ISDIR(curr->fts_statp->st_mode) &&
593 S_ISDIR(to_stat.st_mode)) {
594 warnx(pThis->Utils.pCtx, "cannot overwrite directory %s with "
595 "non-directory %s",
596 pThis->Utils.to.p_path, curr->fts_path);
597 badcp = rval = 1;
598 continue;
599 }
600 dne = 0;
601 }
602
603 switch (curr->fts_statp->st_mode & S_IFMT) {
604#ifdef S_IFLNK
605 case S_IFLNK:
606 /* Catch special case of a non-dangling symlink */
607 if ((fts_options & FTS_LOGICAL) ||
608 ((fts_options & FTS_COMFOLLOW) &&
609 curr->fts_level == 0)) {
610 if (copy_file(&pThis->Utils, curr, dne, pThis->cp_changed_only, &copied))
611 badcp = rval = 1;
612 } else {
613 if (copy_link(&pThis->Utils, curr, !dne))
614 badcp = rval = 1;
615 }
616 break;
617#endif
618 case S_IFDIR:
619 if (!pThis->Rflag && !pThis->rflag) {
620 warnx(pThis->Utils.pCtx, "%s is a directory (not copied).",
621 curr->fts_path);
622 (void)fts_set(ftsp, curr, FTS_SKIP);
623 badcp = rval = 1;
624 break;
625 }
626 /*
627 * If the directory doesn't exist, create the new
628 * one with the from file mode plus owner RWX bits,
629 * modified by the umask. Trade-off between being
630 * able to write the directory (if from directory is
631 * 555) and not causing a permissions race. If the
632 * umask blocks owner writes, we fail..
633 */
634 if (dne) {
635 if (mkdir(pThis->Utils.to.p_path,
636 curr->fts_statp->st_mode | S_IRWXU) < 0)
637 return err(pThis->Utils.pCtx, 1, "mkdir: %s", pThis->Utils.to.p_path);
638 } else if (!S_ISDIR(to_stat.st_mode)) {
639 errno = ENOTDIR;
640 return err(pThis->Utils.pCtx, 1, "to-mode: %s", pThis->Utils.to.p_path);
641 }
642 /*
643 * Arrange to correct directory attributes later
644 * (in the post-order phase) if this is a new
645 * directory, or if the -p flag is in effect.
646 */
647 curr->fts_number = pThis->Utils.pflag || dne;
648 break;
649#ifdef S_IFBLK
650 case S_IFBLK:
651#endif
652 case S_IFCHR:
653 if (pThis->Rflag) {
654 if (copy_special(&pThis->Utils, curr->fts_statp, !dne))
655 badcp = rval = 1;
656 } else {
657 if (copy_file(&pThis->Utils, curr, dne, pThis->cp_changed_only, &copied))
658 badcp = rval = 1;
659 }
660 break;
661#ifdef S_IFIFO
662 case S_IFIFO:
663#endif
664 if (pThis->Rflag) {
665 if (copy_fifo(&pThis->Utils, curr->fts_statp, !dne))
666 badcp = rval = 1;
667 } else {
668 if (copy_file(&pThis->Utils, curr, dne, pThis->cp_changed_only, &copied))
669 badcp = rval = 1;
670 }
671 break;
672 default:
673 if (copy_file(&pThis->Utils, curr, dne, pThis->cp_changed_only, &copied))
674 badcp = rval = 1;
675 break;
676 }
677 if (pThis->Utils.vflag && !badcp)
678 kmk_builtin_ctx_printf(pThis->Utils.pCtx, 0, copied ? "%s -> %s\n" : "%s matches %s - not copied\n",
679 curr->fts_path, pThis->Utils.to.p_path);
680 }
681 if (errno)
682 return err(pThis->Utils.pCtx, 1, "fts_read");
683 return (rval);
684}
685
686/*
687 * mastercmp --
688 * The comparison function for the copy order. The order is to copy
689 * non-directory files before directory files. The reason for this
690 * is because files tend to be in the same cylinder group as their
691 * parent directory, whereas directories tend not to be. Copying the
692 * files first reduces seeking.
693 */
694#ifdef FTSCALL
695static int FTSCALL mastercmp(const FTSENT * const *a, const FTSENT * const *b)
696#else
697static int mastercmp(const FTSENT **a, const FTSENT **b)
698#endif
699{
700 int a_info, b_info;
701
702 a_info = (*a)->fts_info;
703 if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR)
704 return (0);
705 b_info = (*b)->fts_info;
706 if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR)
707 return (0);
708 if (a_info == FTS_D)
709 return (-1);
710 if (b_info == FTS_D)
711 return (1);
712 return (0);
713}
714
715#if defined(SIGINFO) && defined(KMK_BUILTIN_STANDALONE)
716static void
717siginfo(int sig __unused)
718{
719
720 g_cp_info = 1;
721}
722#endif
723
724
725static int
726usage(PKMKBUILTINCTX pCtx, int fIsErr)
727{
728 kmk_builtin_ctx_printf(pCtx, fIsErr,
729"usage: %s [options] src target\n"
730" or: %s [options] src1 ... srcN directory\n"
731" or: %s --help\n"
732" or: %s --version\n"
733"\n"
734"Options:\n"
735" -R Recursive copy.\n"
736" -H Follow symbolic links on the commandline. Only valid with -R.\n"
737" -L Follow all symbolic links. Only valid with -R.\n"
738" -P Do not follow symbolic links. Default. Only valid with -R\n"
739" -f Force. Overrides -i and -n.\n"
740" -i Iteractive. Overrides -n and -f.\n"
741" -n Don't overwrite any files. Overrides -i and -f.\n"
742" -v Verbose.\n"
743" --ignore-non-existing\n"
744" Don't fail if the specified source file doesn't exist.\n"
745" --changed\n"
746" Only copy if changed (i.e. compare first).\n"
747" --disable-protection\n"
748" Will disable the protection file protection applied with -R.\n"
749" --enable-protection\n"
750" Will enable the protection file protection applied with -R.\n"
751" --enable-full-protection\n"
752" Will enable the protection file protection for all operations.\n"
753" --disable-full-protection\n"
754" Will disable the protection file protection for all operations.\n"
755" --protection-depth\n"
756" Number or path indicating the file protection depth. Default: %d\n"
757"\n"
758"Environment:\n"
759" KMK_CP_DISABLE_PROTECTION\n"
760" Same as --disable-protection. Overrides command line.\n"
761" KMK_CP_ENABLE_PROTECTION\n"
762" Same as --enable-protection. Overrides everyone else.\n"
763" KMK_CP_ENABLE_FULL_PROTECTION\n"
764" Same as --enable-full-protection. Overrides everyone else.\n"
765" KMK_CP_DISABLE_FULL_PROTECTION\n"
766" Same as --disable-full-protection. Overrides command line.\n"
767" KMK_CP_PROTECTION_DEPTH\n"
768" Same as --protection-depth. Overrides command line.\n"
769"\n"
770"The file protection of the top %d layers of the file hierarchy is there\n"
771"to try prevent makefiles from doing bad things to your system. This\n"
772"protection is not bulletproof, but should help prevent you from shooting\n"
773"yourself in the foot.\n"
774 ,
775 pCtx->pszProgName, pCtx->pszProgName,
776 pCtx->pszProgName, pCtx->pszProgName,
777 kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
778 return 1;
779}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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