bug 2443: bin/cp: sync with FreeBSD (bug fixes + new options)
authorJohn Marino <draco@marino.st>
Thu, 15 Nov 2012 20:57:01 +0000 (21:57 +0100)
committerJohn Marino <draco@marino.st>
Thu, 15 Nov 2012 23:06:56 +0000 (00:06 +0100)
* Fix FTS_NOCHDIR behavior on empty directory.
* Add -a option (archive mode, equivalent to -RpP)
* Add -l option (create hard links instead of copying)
* Add -x option (FS mount points are not traversed)
* Preserve file flags on symlinks on cp -Rp
* Don't copy socket anyway after "xxx is a socket (not copied)"
* Avoid division-by-zero situations
* make -r synonym for -R but maintain -r behavior with -L

Taken-from: FreeBSD (multiple commits)
https://bugs.dragonflybsd.org/issues/2443

bin/cp/cp.1
bin/cp/cp.c
bin/cp/extern.h
bin/cp/utils.c
lib/libc/gen/fts.c

index c59ca3e..c6303f3 100644 (file)
@@ -1,3 +1,4 @@
+.\"-
 .\" Copyright (c) 1989, 1990, 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.
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)cp.1        8.3 (Berkeley) 4/18/94
-.\" $FreeBSD: src/bin/cp/cp.1,v 1.33 2005/02/25 00:40:46 trhodes Exp $
-.\" $DragonFly: src/bin/cp/cp.1,v 1.6 2005/08/01 01:49:16 swildner Exp $
+.\" $FreeBSD$
 .\"
-.Dd February 23, 2005
+.Dd November 15, 2012
 .Dt CP 1
 .Os
 .Sh NAME
@@ -49,7 +45,7 @@
 .Op Fl H | Fl L | Fl P
 .Oc
 .Op Fl f | i | n
-.Op Fl pv
+.Op Fl alpvx
 .Ar source_file target_file
 .Nm
 .Oo
@@ -57,7 +53,7 @@
 .Op Fl H | Fl L | Fl P
 .Oc
 .Op Fl f | i | n
-.Op Fl pv
+.Op Fl alpvx
 .Ar source_file ... target_directory
 .Sh DESCRIPTION
 In the first synopsis form, the
@@ -120,6 +116,10 @@ If you need to preserve hard links, consider using
 or
 .Xr pax 1
 instead.
+.It Fl a
+Archive mode.
+Same as
+.Fl RpP .
 .It Fl f
 For each existing destination pathname, remove it and
 create a new file, without prompting for confirmation
@@ -148,6 +148,8 @@ option overrides any previous
 or
 .Fl n
 options.)
+.It Fl l
+Create hard links to regular files in a hierarchy instead of copying.
 .It Fl n
 Do not overwrite an existing file.
 (The
@@ -181,6 +183,8 @@ permissions.
 Cause
 .Nm
 to be verbose, showing files as they are copied.
+.It Fl x
+File system mount points are not traversed.
 .El
 .Pp
 For each destination file that already exists, its contents are
@@ -244,7 +248,7 @@ receives a
 argument for
 .Xr stty 1 )
 signal, the current input and output file and the percentage complete
-will be written to standard error.
+will be written to the standard output.
 .Sh EXIT STATUS
 .Ex -std
 .Sh COMPATIBILITY
@@ -253,9 +257,24 @@ Historic versions of the
 utility had a
 .Fl r
 option.
-This implementation supports that option, however, its use is strongly
-discouraged, as it does not correctly copy special files, symbolic links
-or fifo's.
+This implementation supports that option, however, its behavior
+is different from historical
+.Dx
+behavior.
+Use of this option
+is strongly discouraged as the behavior is
+implementation-dependent.
+In
+.Dx ,
+.Fl r
+is a synonym for
+.Fl RL
+and works the same unless modified by other flags.
+Historical implementations
+of
+.Fl r
+differ as they copy special files as normal
+files while recreating a hierarchy.
 .Pp
 The
 .Fl v
index d3e2fb5..86d8ae3 100644 (file)
@@ -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.
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * @(#) Copyright (c) 1988, 1993, 1994 The Regents of the University of California.  All rights reserved.
- * @(#)cp.c    8.2 (Berkeley) 4/1/94
- * $FreeBSD: src/bin/cp/cp.c,v 1.51 2005/01/10 08:39:21 imp Exp $ $
- * $DragonFly: src/bin/cp/cp.c,v 1.12 2006/06/19 12:07:50 corecode Exp $
  */
 
 /*
                 *--(p).p_end = 0;                                      \
 }
 
-PATH_T to = { to.p_path, to.p_path, "" };
+static char emptystring[] = "";
+
+PATH_T to = { to.p_path, emptystring, "" };
 
-int fflag, iflag, nflag, pflag, vflag;
+int fflag, iflag, lflag, nflag, pflag, vflag;
 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 copy(char *[], enum op, int);
 static int mastercmp (const FTSENT * const *, const FTSENT * const *);
 static void siginfo (int);
 
 int
-main(int argc, char **argv)
+main(int argc, char *argv[])
 {
        struct stat to_stat, tmp_stat;
        enum op type;
-       int Hflag, Lflag, Pflag, ch, has_trailing_slash, r, fts_options;
+       int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash;
        char *target;
 
+       fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
        Hflag = Lflag = Pflag = 0;
-       while ((ch = getopt(argc, argv, "HLPRfinprv")) != -1)
+       while ((ch = getopt(argc, argv, "HLPRafilnprvx")) != -1)
                switch (ch) {
                case 'H':
                        Hflag = 1;
@@ -112,6 +106,12 @@ main(int argc, char **argv)
                case 'R':
                        Rflag = 1;
                        break;
+               case 'a':
+                       Pflag = 1;
+                       pflag = 1;
+                       Rflag = 1;
+                       Hflag = Lflag = 0;
+                       break;
                case 'f':
                        fflag = 1;
                        iflag = nflag = 0;
@@ -120,6 +120,9 @@ main(int argc, char **argv)
                        iflag = 1;
                        fflag = nflag = 0;
                        break;
+               case 'l':
+                       lflag = 1;
+                       break;
                case 'n':
                        nflag = 1;
                        fflag = iflag = 0;
@@ -128,11 +131,15 @@ main(int argc, char **argv)
                        pflag = 1;
                        break;
                case 'r':
-                       rflag = 1;
+                       rflag = Lflag = 1;
+                       Hflag = Pflag = 0;
                        break;
                case 'v':
                        vflag = 1;
                        break;
+               case 'x':
+                       fts_options |= FTS_XDEV;
+                       break;
                default:
                        usage();
                        break;
@@ -143,17 +150,10 @@ main(int argc, char **argv)
        if (argc < 2)
                usage();
 
-       fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
-       if (rflag) {
-               if (Rflag)
-                       errx(1,
-                   "the -R and -r options may not be specified together.");
-               if (Hflag || Lflag || Pflag)
-                       errx(1,
-       "the -H, -L, and -P options may not be specified with the -r option.");
-               fts_options &= ~FTS_PHYSICAL;
-               fts_options |= FTS_LOGICAL;
-       }
+       if (Rflag && rflag)
+               errx(1, "the -R and -r options may not be specified together");
+       if (rflag)
+               Rflag = 1;
        if (Rflag) {
                if (Hflag)
                        fts_options |= FTS_COMFOLLOW;
@@ -165,19 +165,19 @@ main(int argc, char **argv)
                fts_options &= ~FTS_PHYSICAL;
                fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
        }
-       signal(SIGINFO, siginfo);
+       (void)signal(SIGINFO, siginfo);
 
        /* Save the target base in "to". */
        target = argv[--argc];
        if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path))
                errx(1, "%s: name too long", target);
        to.p_end = to.p_path + strlen(to.p_path);
-        if (to.p_path == to.p_end) {
+       if (to.p_path == to.p_end) {
                *to.p_end++ = '.';
                *to.p_end = 0;
        }
-       has_trailing_slash = (to.p_end[-1] == '/');
-       if (has_trailing_slash)
+       have_trailing_slash = (to.p_end[-1] == '/');
+       if (have_trailing_slash)
                STRIP_TRAILING_SLASH(to);
        to.target_end = to.p_end;
 
@@ -205,10 +205,9 @@ main(int argc, char **argv)
                /*
                 * Case (1).  Target is not a directory.
                 */
-               if (argc > 1) {
-                       usage();
-                       exit(1);
-               }
+               if (argc > 1)
+                       errx(1, "%s is not a directory", to.p_path);
+
                /*
                 * Need to detect the case:
                 *      cp -R dir foo
@@ -217,21 +216,22 @@ main(int argc, char **argv)
                 * the initial mkdir().
                 */
                if (r == -1) {
-                       if (rflag || (Rflag && (Lflag || Hflag)))
+                       if (Rflag && (Lflag || Hflag))
                                stat(*argv, &tmp_stat);
                        else
                                lstat(*argv, &tmp_stat);
 
-                       if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
+                       if (S_ISDIR(tmp_stat.st_mode) && Rflag)
                                type = DIR_TO_DNE;
                        else
                                type = FILE_TO_FILE;
                } else
                        type = FILE_TO_FILE;
                
-               if (has_trailing_slash && type == FILE_TO_FILE) {
+               if (have_trailing_slash && type == FILE_TO_FILE) {
                        if (r == -1)
-                               errx(1, "directory %s does not exist", to.p_path);
+                               errx(1, "directory %s does not exist",
+                                    to.p_path);
                        else
                                errx(1, "%s is not a directory", to.p_path);
                }
@@ -245,12 +245,13 @@ main(int argc, char **argv)
 }
 
 static int
-copy(char **argv, enum op type, int fts_options)
+copy(char *argv[], enum op type, int fts_options)
 {
        struct stat to_stat;
        FTS *ftsp;
        FTSENT *curr;
-       int base, dne, badcp, nlen, rval;
+       int base = 0, dne, badcp, rval;
+       size_t nlen;
        char *p, *target_mid;
        mode_t mask, mode;
 
@@ -260,10 +261,9 @@ copy(char **argv, enum op type, int fts_options)
         */
        mask = ~umask(0777);
        umask(~mask);
-       base = 0;
 
        if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
-               err(1, NULL);
+               err(1, "fts_open");
        for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
                switch (curr->fts_info) {
                case FTS_NS:
@@ -277,12 +277,14 @@ copy(char **argv, enum op type, int fts_options)
                        warnx("%s: directory causes a cycle", curr->fts_path);
                        rval = 1;
                        continue;
+               default:
+                       ;
                }
 
                /*
                 * If we are in case (2) or (3) above, we need to append the
-                 * source name to the target name.
-                 */
+                * source name to the target name.
+                */
                if (type != FILE_TO_FILE) {
                        /*
                         * Need to remember the roots of traversals to create
@@ -328,7 +330,7 @@ copy(char **argv, enum op type, int fts_options)
                                rval = 1;
                                continue;
                        }
-                       strncat(target_mid, p, nlen);
+                       (void)strncat(target_mid, p, nlen);
                        to.p_end = target_mid + nlen;
                        *to.p_end = 0;
                        STRIP_TRAILING_SLASH(to);
@@ -376,12 +378,13 @@ copy(char **argv, enum op type, int fts_options)
                                    to.p_path, curr->fts_path);
                                rval = 1;
                                if (S_ISDIR(curr->fts_statp->st_mode))
-                                       fts_set(ftsp, curr, FTS_SKIP);
+                                       (void)fts_set(ftsp, curr, FTS_SKIP);
                                continue;
                        }
                        if (!S_ISDIR(curr->fts_statp->st_mode) &&
                            S_ISDIR(to_stat.st_mode)) {
-               warnx("cannot overwrite directory %s with non-directory %s",
+                               warnx("cannot overwrite directory %s with "
+                                   "non-directory %s",
                                    to.p_path, curr->fts_path);
                                rval = 1;
                                continue;
@@ -403,10 +406,10 @@ copy(char **argv, enum op type, int fts_options)
                        }
                        break;
                case S_IFDIR:
-                       if (!Rflag && !rflag) {
+                       if (!Rflag) {
                                warnx("%s is a directory (not copied).",
                                    curr->fts_path);
-                               fts_set(ftsp, curr, FTS_SKIP);
+                               (void)fts_set(ftsp, curr, FTS_SKIP);
                                badcp = rval = 1;
                                break;
                        }
@@ -443,6 +446,10 @@ copy(char **argv, enum op type, int fts_options)
                                        badcp = rval = 1;
                        }
                        break;
+               case S_IFSOCK:
+                       warnx("%s is a socket (not copied).",
+                                   curr->fts_path);
+                       break;
                case S_IFIFO:
                        if (Rflag) {
                                if (copy_fifo(curr->fts_statp, !dne))
@@ -458,7 +465,7 @@ copy(char **argv, enum op type, int fts_options)
                        break;
                }
                if (vflag && !badcp)
-                       printf("%s -> %s\n", curr->fts_path, to.p_path);
+                       (void)printf("%s -> %s\n", curr->fts_path, to.p_path);
        }
        if (errno)
                err(1, "fts_read");
@@ -493,7 +500,7 @@ mastercmp(const FTSENT * const *a, const FTSENT * const *b)
 }
 
 static void
-siginfo(int notused __unused)
+siginfo(int sig __unused)
 {
 
        info = 1;
index e261e22..ad74008 100644 (file)
  * 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.
@@ -31,8 +27,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)extern.h    8.2 (Berkeley) 4/1/94
- * $FreeBSD: src/bin/cp/extern.h,v 1.19 2004/04/06 20:06:44 markm $
- * $DragonFly: src/bin/cp/extern.h,v 1.5 2005/02/28 23:15:35 corecode Exp $
+ * $FreeBSD$
  */
 
 typedef struct {
@@ -42,7 +37,7 @@ typedef struct {
 } PATH_T;
 
 extern PATH_T to;
-extern int fflag, iflag, nflag, pflag, vflag;
+extern int fflag, iflag, lflag, nflag, pflag, vflag;
 extern volatile sig_atomic_t info;
 
 __BEGIN_DECLS
index 6e8f18f..55356fb 100644 (file)
  * 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.
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * @(#)utils.c 8.3 (Berkeley) 4/1/94
- * $FreeBSD: src/bin/cp/utils.c,v 1.45 2005/02/09 17:37:37 ru Exp $
- * $DragonFly: src/bin/cp/utils.c,v 1.12 2008/09/05 03:16:55 y0netan1 Exp $
  */
 
 #include <sys/param.h>
 #include <unistd.h>
 
 #include "extern.h"
-#define        cp_pct(x,y)     (int)(100.0 * (double)(x) / (double)(y))
 
-#define YESNO "(y/n [n]) "
+#define        cp_pct(x, y)    ((y == 0) ? 0 : (int)(100.0 * (x) / (y)))
+
 
 int
 copy_file(const FTSENT *entp, int dne)
 {
        static char buf[MAXBSIZE];
        struct stat *fs;
-       int ch, checkch, from_fd, rval, to_fd;
-       size_t rcount, wcount, wresid;
+       ssize_t wcount, rcount;
+       size_t wresid;
        off_t wtotal;
+       int ch, checkch, from_fd = 0, rval, to_fd = 0;
        char *bufp;
 #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
        char *p;
@@ -86,20 +79,21 @@ copy_file(const FTSENT *entp, int dne)
         * modified by the umask.)
         */
        if (!dne) {
+#define YESNO "(y/n [n]) "
                if (nflag) {
                        if (vflag)
                                printf("%s not overwritten\n", to.p_path);
-                       close(from_fd);
+                       (void)close(from_fd);
                        return (0);
                } else if (iflag) {
-                       fprintf(stderr, "overwrite %s? %s", 
+                       (void)fprintf(stderr, "overwrite %s? %s",
                                        to.p_path, YESNO);
                        checkch = ch = getchar();
                        while (ch != '\n' && ch != EOF)
                                ch = getchar();
                        if (checkch != 'y' && checkch != 'Y') {
-                               close(from_fd);
-                               fprintf(stderr, "not overwritten\n");
+                               (void)close(from_fd);
+                               (void)fprintf(stderr, "not overwritten\n");
                                return (1);
                        }
                }
@@ -107,55 +101,60 @@ copy_file(const FTSENT *entp, int dne)
                if (fflag) {
                    /* remove existing destination file name, 
                     * create a new file  */
-                   unlink(to.p_path);
-                   to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
-                                fs->st_mode & ~(S_ISUID | S_ISGID));
-               } else 
-                   /* overwrite existing destination file name */
-                   to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
-       } else
-               to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
-                   fs->st_mode & ~(S_ISUID | S_ISGID));
+                   (void)unlink(to.p_path);
+                   if (!lflag)
+                       to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+                           fs->st_mode & ~(S_ISUID | S_ISGID));
+               } else {
+                   if (!lflag)
+                       /* overwrite existing destination file name */
+                           to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+               }
+       } else {
+               if (!lflag)
+                       to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+                           fs->st_mode & ~(S_ISUID | S_ISGID));
+       }
 
        if (to_fd == -1) {
                warn("%s", to.p_path);
-               close(from_fd);
+               (void)close(from_fd);
                return (1);
        }
 
        rval = 0;
 
+       if (!lflag) {
        /*
-        * Mmap and write if less than 8M (the limit is so we don't totally
-        * trash memory on big files.  This is really a minor hack, but it
-        * wins some CPU back.
+                * Mmap and write if less than 8M (the limit is so we don't totally
+                * trash memory on big files.  This is really a minor hack, but it
+                * wins some CPU back.
+                * Some filesystems, such as smbnetfs, don't support mmap,
+                * so this is a best-effort attempt.
         */
 #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
-       if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
-           fs->st_size <= 8 * 1048576) {
-               if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
-                   MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
-                       warn("%s", entp->fts_path);
-                       rval = 1;
-               } else {
+               if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
+                   fs->st_size <= 8 * 1024 * 1024 &&
+                   (p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
+                   MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) {
                        wtotal = 0;
                        for (bufp = p, wresid = fs->st_size; ;
-                           bufp += wcount, wresid -= wcount) {
+                           bufp += wcount, wresid -= (size_t)wcount) {
                                wcount = write(to_fd, bufp, wresid);
-                               if ((ssize_t)wcount == -1)
+                               if (wcount <= 0)
                                        break;
                                wtotal += wcount;
                                if (info) {
                                        info = 0;
-                                       fprintf(stderr,
+                                       (void)fprintf(stderr,
                                            "%s -> %s %3d%%\n",
                                            entp->fts_path, to.p_path,
                                            cp_pct(wtotal, fs->st_size));
                                }
-                               if (wcount >= wresid || wcount == 0)
+                               if (wcount >= (ssize_t)wresid)
                                        break;
                        }
-                       if (wcount != wresid) {
+                       if (wcount != (ssize_t)wresid) {
                                warn("%s", to.p_path);
                                rval = 1;
                        }
@@ -164,36 +163,41 @@ copy_file(const FTSENT *entp, int dne)
                                warn("%s", entp->fts_path);
                                rval = 1;
                        }
-               }
-       } else
+               } else
 #endif
-       {
-               wtotal = 0;
-               while ((ssize_t)(rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
-                       for (bufp = buf, wresid = rcount; ;
-                           bufp += wcount, wresid -= wcount) {
-                               wcount = write(to_fd, bufp, wresid);
-                               if ((ssize_t)wcount == -1)
-                                       break;
-                               wtotal += wcount;
-                               if (info) {
-                                       info = 0;
-                                       fprintf(stderr,
-                                           "%s -> %s %3d%%\n",
-                                           entp->fts_path, to.p_path,
-                                           cp_pct(wtotal, fs->st_size));
+               {
+                       wtotal = 0;
+                       while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+                               for (bufp = buf, wresid = rcount; ;
+                                   bufp += wcount, wresid -= wcount) {
+                                       wcount = write(to_fd, bufp, wresid);
+                                       if (wcount <= 0)
+                                               break;
+                                       wtotal += wcount;
+                                       if (info) {
+                                               info = 0;
+                                               (void)fprintf(stderr,
+                                                   "%s -> %s %3d%%\n",
+                                                   entp->fts_path, to.p_path,
+                                                   cp_pct(wtotal, fs->st_size));
+                                       }
+                                       if (wcount >= (ssize_t)wresid)
+                                               break;
                                }
-                               if (wcount >= wresid || wcount == 0)
+                               if (wcount != (ssize_t)wresid) {
+                                       warn("%s", to.p_path);
+                                       rval = 1;
                                        break;
+                               }
                        }
-                       if (wcount != wresid) {
-                               warn("%s", to.p_path);
+                       if (rcount < 0) {
+                               warn("%s", entp->fts_path);
                                rval = 1;
-                               break;
                        }
                }
-               if ((ssize_t)rcount == -1) {
-                       warn("%s", entp->fts_path);
+       } else {
+               if (link(entp->fts_path, to.p_path)) {
+                       warn("%s", to.p_path);
                        rval = 1;
                }
        }
@@ -205,13 +209,17 @@ copy_file(const FTSENT *entp, int dne)
         * to remove it if we created it and its length is 0.
         */
 
-       if (pflag && setfile(fs, to_fd))
-               rval = 1;
-       close(from_fd);
-       if (close(to_fd)) {
-               warn("%s", to.p_path);
-               rval = 1;
+       if (!lflag) {
+               if (pflag && setfile(fs, to_fd))
+                       rval = 1;
+               if (close(to_fd)) {
+                       warn("%s", to.p_path);
+                       rval = 1;
+               }
        }
+
+       (void)close(from_fd);
+
        return (rval);
 }
 
@@ -219,19 +227,19 @@ int
 copy_link(const FTSENT *p, int exists)
 {
        int len;
-       char linkname[PATH_MAX];
+       char llink[PATH_MAX];
 
-       if ((len = readlink(p->fts_path, linkname, sizeof(linkname) - 1)) == -1) {
+       if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) {
                warn("readlink: %s", p->fts_path);
                return (1);
        }
-       linkname[len] = '\0';
+       llink[len] = '\0';
        if (exists && unlink(to.p_path)) {
                warn("unlink: %s", to.p_path);
                return (1);
        }
-       if (symlink(linkname, to.p_path)) {
-               warn("symlink: %s", linkname);
+       if (symlink(llink, to.p_path)) {
+               warn("symlink: %s", llink);
                return (1);
        }
        return (pflag ? setfile(p->fts_statp, -1) : 0);
@@ -285,9 +293,9 @@ setfile(struct stat *fs, int fd)
                rval = 1;
        }
        if (fdval ? fstat(fd, &ts) :
-           (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) {
+           (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts)))
                gotstat = 0;
-       else {
+       else {
                gotstat = 1;
                ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
                              S_IRWXU | S_IRWXG | S_IRWXO;
@@ -320,7 +328,7 @@ setfile(struct stat *fs, int fd)
        if (!gotstat || fs->st_flags != ts.st_flags)
                if (fdval ?
                    fchflags(fd, fs->st_flags) :
-                   (islink ? (errno = 0) :
+                   (islink ? lchflags(to.p_path, fs->st_flags) :
                    chflags(to.p_path, fs->st_flags))) {
                        warn("chflags: %s", to.p_path);
                        rval = 1;
@@ -332,9 +340,10 @@ setfile(struct stat *fs, int fd)
 void
 usage(void)
 {
-       fprintf(stderr, "%s\n%s\n",
-"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-pv] source_file target_file",
-"       cp [-R [-H | -L | -P]] [-f | -i | -n] [-pv] source_file ... "
+
+       (void)fprintf(stderr, "%s\n%s\n",
+"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpvx] source_file target_file",
+"       cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpvx] source_file ... "
 "target_directory");
        exit(EX_USAGE);
 }
index a8e24b0..3af5487 100644 (file)
@@ -29,7 +29,6 @@
  * @(#)fts.c   8.6 (Berkeley) 8/14/94
  * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
  * $FreeBSD: src/lib/libc/gen/fts.c,v 1.30 2009/03/04 03:30:21 das Exp $
- * $DragonFly: src/lib/libc/gen/fts.c,v 1.7 2005/11/13 00:07:42 swildner Exp $
  */
 
 #include "namespace.h"
@@ -117,9 +116,8 @@ fts_open(char * const *argv, int options,
        }
 
        /* Allocate/initialize the stream. */
-       if ((priv = malloc(sizeof(*priv))) == NULL)
+       if ((priv = calloc(1, sizeof(*priv))) == NULL)
                return (NULL);
-       memset(priv, 0, sizeof(*priv));
        sp = &priv->ftsp_fts;
        sp->fts_compar = compar;
        sp->fts_options = options;
@@ -817,11 +815,8 @@ mem1:                              saved_errno = errno;
         * If not changing directories, reset the path back to original
         * state.
         */
-       if (ISSET(FTS_NOCHDIR)) {
-               if (len == sp->fts_pathlen || nitems == 0)
-                       --cp;
-               *cp = '\0';
-       }
+       if (ISSET(FTS_NOCHDIR))
+               sp->fts_path[cur->fts_pathlen] = '\0';
 
        /*
         * If descended after called from fts_children or after called from