]> git.saurik.com Git - apple/file_cmds.git/blobdiff - cp/cp.c
file_cmds-242.tar.gz
[apple/file_cmds.git] / cp / cp.c
diff --git a/cp/cp.c b/cp/cp.c
index 43e094b8dbc5df13c655c6099ec4385ddc8dfed5..7af6bbcf945fb524d48dd0fe406c40d7546214f9 100644 (file)
--- a/cp/cp.c
+++ b/cp/cp.c
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 1988, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
@@ -34,6 +30,7 @@
  * SUCH DAMAGE.
  */
 
+#if 0
 #ifndef lint
 static char const copyright[] =
 "@(#) Copyright (c) 1988, 1993, 1994\n\
@@ -41,12 +38,11 @@ static char const copyright[] =
 #endif /* not lint */
 
 #ifndef lint
-#if 0
 static char sccsid[] = "@(#)cp.c       8.2 (Berkeley) 4/1/94";
-#endif
 #endif /* not lint */
+#endif
 #include <sys/cdefs.h>
-__RCSID("$FreeBSD: src/bin/cp/cp.c,v 1.42 2002/09/22 11:15:56 mckay Exp $");
+__FBSDID("$FreeBSD: src/bin/cp/cp.c,v 1.52 2005/09/05 04:36:08 csjp Exp $");
 
 /*
  * Cp copies source files to target files.
@@ -63,18 +59,26 @@ __RCSID("$FreeBSD: src/bin/cp/cp.c,v 1.42 2002/09/22 11:15:56 mckay Exp $");
  * in "to") to form the final target path.
  */
 
-#include <sys/param.h>
+#include <sys/types.h>
 #include <sys/stat.h>
 
 #include <err.h>
 #include <errno.h>
 #include <fts.h>
 #include <limits.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+#ifdef __APPLE__
+#include <copyfile.h>
+#include <get_compat.h>
+#else /* !__APPLE__ */
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
 #include "extern.h"
 
 #define        STRIP_TRAILING_SLASH(p) {                                       \
@@ -87,12 +91,16 @@ static char emptystring[] = "";
 PATH_T to = { to.p_path, emptystring, "" };
 
 int fflag, iflag, nflag, pflag, vflag;
+#ifdef __APPLE__
+int Xflag;
+#endif /* __APPLE__ */
 static int Rflag, rflag;
+volatile sig_atomic_t info;
 
 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
 
 static int copy(char *[], enum op, int);
-static int mastercmp(const FTSENT * const *, const FTSENT * const *);
+static void siginfo(int __unused);
 
 int
 main(int argc, char *argv[])
@@ -103,7 +111,7 @@ main(int argc, char *argv[])
        char *target;
 
        Hflag = Lflag = Pflag = 0;
-       while ((ch = getopt(argc, argv, "HLPRfinprv")) != -1)
+       while ((ch = getopt(argc, argv, "HLPRXafinprv")) != -1)
                switch (ch) {
                case 'H':
                        Hflag = 1;
@@ -120,13 +128,23 @@ main(int argc, char *argv[])
                case 'R':
                        Rflag = 1;
                        break;
+               case 'X':
+                       Xflag = 1;
+                       break;
                case 'f':
                        fflag = 1;
-                       iflag = nflag = 0;
+                       /* Determine if the STD is SUSv3 or Legacy */
+                       if (COMPAT_MODE("bin/cp", "unix2003"))
+                               nflag = 0;      /* reset nflag, but not iflag */
+                       else
+                               iflag = nflag = 0;      /* reset both */
                        break;
                case 'i':
                        iflag = 1;
-                       fflag = nflag = 0;
+                       if (COMPAT_MODE("bin/cp", "unix2003"))
+                               nflag = 0;      /* reset nflag, but not fflag */
+                       else
+                               fflag = nflag = 0;
                        break;
                case 'n':
                        nflag = 1;
@@ -141,6 +159,11 @@ main(int argc, char *argv[])
                case 'v':
                        vflag = 1;
                        break;
+               case 'a':
+                       pflag = 1;
+                       Pflag = 1;
+                       Rflag = 1;
+                       break;
                default:
                        usage();
                        break;
@@ -173,6 +196,7 @@ main(int argc, char *argv[])
                fts_options &= ~FTS_PHYSICAL;
                fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
        }
+       (void)signal(SIGINFO, siginfo);
 
        /* Save the target base in "to". */
        target = argv[--argc];
@@ -252,7 +276,7 @@ main(int argc, char *argv[])
        exit (copy(argv, type, fts_options));
 }
 
-int
+static int
 copy(char *argv[], enum op type, int fts_options)
 {
        struct stat to_stat;
@@ -270,7 +294,7 @@ copy(char *argv[], enum op type, int fts_options)
        mask = ~umask(0777);
        umask(~mask);
 
-       if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
+       if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
                err(1, "fts_open");
        for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
                switch (curr->fts_info) {
@@ -279,16 +303,45 @@ copy(char *argv[], enum op type, int fts_options)
                case FTS_ERR:
                        warnx("%s: %s",
                            curr->fts_path, strerror(curr->fts_errno));
-                       badcp = rval = 1;
+                       rval = 1;
                        continue;
                case FTS_DC:                    /* Warn, continue. */
                        warnx("%s: directory causes a cycle", curr->fts_path);
-                       badcp = rval = 1;
+                       rval = 1;
                        continue;
                default:
                        ;
                }
+#ifdef __APPLE__
 
+#ifdef __clang__
+#pragma clang diagnostic push
+/* clang doesn't like fts_name[1], but we know better... */
+#pragma clang diagnostic ignored "-Warray-bounds"
+#endif
+               /* Skip ._<file> when using copyfile and <file> exists */
+               if ((pflag || !Xflag) && (curr->fts_level != FTS_ROOTLEVEL) &&
+                   (curr->fts_namelen > 2) && /* ._\0 is not AppleDouble */
+                   (curr->fts_name[0] == '.') && (curr->fts_name[1] == '_')) {
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+                       struct stat statbuf;
+                       char path[PATH_MAX];
+                       char *p = strrchr(curr->fts_path, '/');
+                       if (p) {
+                               size_t s = p + 2 - curr->fts_path;
+                               if (s > sizeof(path)) s = sizeof(path);
+                               strlcpy(path, curr->fts_path, s);
+                               strlcat(path, curr->fts_name+2, sizeof(path));
+                       } else {
+                               strlcpy(path, curr->fts_name+2, sizeof(path));
+                       }
+                       if (!lstat(path, &statbuf)) {
+                               continue;
+                       }
+               }
+#endif /* __APPLE__ */
                /*
                 * If we are in case (2) or (3) above, we need to append the
                  * source name to the target name.
@@ -335,7 +388,7 @@ copy(char *argv[], enum op type, int fts_options)
                        if (target_mid - to.p_path + nlen >= PATH_MAX) {
                                warnx("%s%s: name too long (not copied)",
                                    to.p_path, p);
-                               badcp = rval = 1;
+                               rval = 1;
                                continue;
                        }
                        (void)strncat(target_mid, p, nlen);
@@ -362,8 +415,17 @@ copy(char *argv[], enum op type, int fts_options)
                         * normally want to preserve them on directories.
                         */
                        if (pflag) {
-                               if (setfile(curr->fts_statp, 0))
-                                   rval = 1;
+                               if (setfile(curr->fts_statp, -1))
+                                       rval = 1;
+#ifdef __APPLE__
+                               /* setfile will fail if writeattr is denied */
+                               if (copyfile(curr->fts_path, to.p_path, NULL, COPYFILE_ACL)<0)
+                                       warn("%s: unable to copy ACL to %s", curr->fts_path, to.p_path);
+#else  /* !__APPLE__ */
+                               if (preserve_dir_acls(curr->fts_statp,
+                                   curr->fts_accpath, to.p_path) != 0)
+                                       rval = 1;
+#endif /* __APPLE__ */
                        } else {
                                mode = curr->fts_statp->st_mode;
                                if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) ||
@@ -384,7 +446,7 @@ copy(char *argv[], enum op type, int fts_options)
                            to_stat.st_ino == curr->fts_statp->st_ino) {
                                warnx("%s and %s are identical (not copied).",
                                    to.p_path, curr->fts_path);
-                               badcp = rval = 1;
+                               rval = 1;
                                if (S_ISDIR(curr->fts_statp->st_mode))
                                        (void)fts_set(ftsp, curr, FTS_SKIP);
                                continue;
@@ -394,7 +456,7 @@ copy(char *argv[], enum op type, int fts_options)
                                warnx("cannot overwrite directory %s with "
                                    "non-directory %s",
                                    to.p_path, curr->fts_path);
-                               badcp = rval = 1;
+                               rval = 1;
                                continue;
                        }
                        dne = 0;
@@ -416,7 +478,7 @@ copy(char *argv[], enum op type, int fts_options)
                case S_IFDIR:
                        if (!Rflag && !rflag) {
                                warnx("%s is a directory (not copied).",
-                                        curr->fts_path);
+                                   curr->fts_path);
                                (void)fts_set(ftsp, curr, FTS_SKIP);
                                badcp = rval = 1;
                                break;
@@ -431,11 +493,20 @@ copy(char *argv[], enum op type, int fts_options)
                         */
                        if (dne) {
                                if (mkdir(to.p_path,
-                                   curr->fts_statp->st_mode | S_IRWXU) < 0)
-                                       err(1, "%s", to.p_path);
+                                         curr->fts_statp->st_mode | S_IRWXU) < 0) {
+                                       if (COMPAT_MODE("bin/cp", "unix2003")) {
+                                               warn("%s", to.p_path);
+                                       } else {
+                                               err(1, "%s", to.p_path);
+                                       }
+                               }
                        } else if (!S_ISDIR(to_stat.st_mode)) {
                                errno = ENOTDIR;
-                               err(1, "%s", to.p_path);
+                               if (COMPAT_MODE("bin/cp", "unix2003")) {
+                                       warn("%s", to.p_path);
+                               } else {
+                                       err(1, "%s", to.p_path);
+                               }
                        }
                        /*
                         * Arrange to correct directory attributes later
@@ -443,6 +514,13 @@ copy(char *argv[], enum op type, int fts_options)
                         * directory, or if the -p flag is in effect.
                         */
                        curr->fts_number = pflag || dne;
+#ifdef __APPLE__
+                       if (!Xflag) {
+                               if (copyfile(curr->fts_path, to.p_path, NULL, COPYFILE_XATTR) < 0)
+                                       warn("%s: unable to copy extended attributes to %s", curr->fts_path, to.p_path);
+                               /* ACL and mtime set in postorder traversal */
+                       }
+#endif /* __APPLE__ */
                        break;
                case S_IFBLK:
                case S_IFCHR:
@@ -473,31 +551,13 @@ copy(char *argv[], enum op type, int fts_options)
        }
        if (errno)
                err(1, "fts_read");
+       fts_close(ftsp);
        return (rval);
 }
 
-/*
- * mastercmp --
- *     The comparison function for the copy order.  The order is to copy
- *     non-directory files before directory files.  The reason for this
- *     is because files tend to be in the same cylinder group as their
- *     parent directory, whereas directories tend not to be.  Copying the
- *     files first reduces seeking.
- */
-int
-mastercmp(const FTSENT * const *a, const FTSENT * const *b)
+static void
+siginfo(int sig __unused)
 {
-       int a_info, b_info;
-
-       a_info = (*a)->fts_info;
-       if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR)
-               return (0);
-       b_info = (*b)->fts_info;
-       if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR)
-               return (0);
-       if (a_info == FTS_D)
-               return (-1);
-       if (b_info == FTS_D)
-               return (1);
-       return (0);
+
+       info = 1;
 }