On Thu, May 23, 2019 at 02:35:10PM -0600, Tracey Emery wrote:
> Hello tech@,
> 
> Attached is a proposed diff for cp(1). It adds the -l (hard link) and -s
> (symlink) options. These options are available in GNU cp, FreeBSD cp,
> and the -l option is at least in NetBSD and Dragonfly.
> 
> I needed the -l option to use the system cp for rsnapshots, instead of
> their native_cl_al function. Hopefully, this will speed up my backups.
> 
> Thanks for your consideration,
> Tracey
> 
> 
> Index: bin/cp/cp.1
> ===================================================================
> RCS file: /cvs/src/bin/cp/cp.1,v
> retrieving revision 1.40
> diff -u -p -u -r1.40 cp.1
> --- bin/cp/cp.1       28 Jan 2019 18:58:42 -0000      1.40
> +++ bin/cp/cp.1       23 May 2019 20:28:29 -0000
> @@ -103,6 +103,8 @@ The
>  option overrides any previous
>  .Fl f
>  options.
> +.It Fl l
> +Create hard links to regular files in a hierarchy instead of copying.
>  .It Fl L
>  If the
>  .Fl R
> @@ -128,6 +130,8 @@ If the source file has both its set-user
>  and either the user ID or group ID cannot be preserved, neither
>  the set-user-ID nor set-group-ID bits are preserved in the copy's
>  permissions.
> +.It Fl s
> +Create symbolic links to regular files in a hirarcy instead of copying.
>  .It Fl R
>  If
>  .Ar source
> Index: bin/cp/cp.c
> ===================================================================
> RCS file: /cvs/src/bin/cp/cp.c,v
> retrieving revision 1.52
> diff -u -p -u -r1.52 cp.c
> --- bin/cp/cp.c       28 Jan 2019 18:58:42 -0000      1.52
> +++ bin/cp/cp.c       23 May 2019 20:28:30 -0000
> @@ -71,7 +71,7 @@
>  PATH_T to = { to.p_path, "" };
>  
>  uid_t myuid;
> -int Rflag, fflag, iflag, pflag, rflag, vflag;
> +int Rflag, fflag, iflag, lflag, pflag, rflag, sflag, vflag;
>  mode_t myumask;
>  
>  enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
> @@ -88,7 +88,7 @@ main(int argc, char *argv[])
>       char *target;
>  
>       Hflag = Lflag = Pflag = Rflag = 0;
> -     while ((ch = getopt(argc, argv, "HLPRafiprv")) != -1)
> +     while ((ch = getopt(argc, argv, "HLPRafiprvls")) != -1)
>               switch (ch) {
>               case 'H':
>                       Hflag = 1;
> @@ -119,12 +119,18 @@ main(int argc, char *argv[])
>                       iflag = 1;
>                       fflag = 0;
>                       break;
> +             case 'l':
> +                     lflag = 1;
> +                     break;
>               case 'p':
>                       pflag = 1;
>                       break;
>               case 'r':
>                       rflag = 1;
>                       break;
> +             case 's':
> +                     sflag = 1;
> +                     break;
>               case 'v':
>                       vflag = 1;
>                       break;
> @@ -157,6 +163,8 @@ main(int argc, char *argv[])
>               fts_options &= ~FTS_PHYSICAL;
>               fts_options |= FTS_LOGICAL;
>       }
> +     if (lflag && sflag)
> +             errx(1, "the -l and -s options may not be specified together.");
>       if (Rflag) {
>               if (Hflag)
>                       fts_options |= FTS_COMFOLLOW;
> @@ -319,7 +327,7 @@ copy(char *argv[], enum op type, int fts
>                               if (type != DIR_TO_DNE) {
>                                       p = find_last_component(curr->fts_path);
>                                       base = p - curr->fts_path;
> -                                     
> +
>                                       if (!strcmp(&curr->fts_path[base],
>                                           ".."))
>                                               base += 1;
> @@ -435,7 +443,7 @@ copy(char *argv[], enum op type, int fts
>                       break;
>               case S_IFBLK:
>               case S_IFCHR:
> -                     if (Rflag) {
> +                     if (Rflag && !sflag) {
>                               if ((cval = copy_special(curr->fts_statp,
>                                   !fts_dne(curr))) == 1)
>                                       rval = 1;
> @@ -448,7 +456,7 @@ copy(char *argv[], enum op type, int fts
>                       cval = 0;
>                       break;
>               case S_IFIFO:
> -                     if (Rflag) {
> +                     if (Rflag && !sflag) {
>                               if ((cval = copy_fifo(curr->fts_statp,
>                                   !fts_dne(curr))) == 1)
>                                       rval = 1;
> Index: bin/cp/extern.h
> ===================================================================
> RCS file: /cvs/src/bin/cp/extern.h,v
> retrieving revision 1.15
> diff -u -p -u -r1.15 extern.h
> --- bin/cp/extern.h   26 Dec 2015 18:11:43 -0000      1.15
> +++ bin/cp/extern.h   23 May 2019 20:28:30 -0000
> @@ -40,7 +40,7 @@ typedef struct {
>  
>  extern PATH_T to;
>  extern uid_t myuid;
> -extern int fflag, iflag, pflag;
> +extern int fflag, iflag, lflag, pflag, sflag;
>  extern mode_t myumask;
>  extern char *__progname;
>  
> Index: bin/cp/utils.c
> ===================================================================
> RCS file: /cvs/src/bin/cp/utils.c,v
> retrieving revision 1.47
> diff -u -p -u -r1.47 utils.c
> --- bin/cp/utils.c    28 Jan 2019 18:58:42 -0000      1.47
> +++ bin/cp/utils.c    23 May 2019 20:28:30 -0000
> @@ -71,7 +71,8 @@ copy_file(FTSENT *entp, int exists)
>                       err(1, "calloc");
>       }
>  
> -     if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
> +     if (!lflag && !sflag &&
> +         (from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
>               warn("%s", entp->fts_path);
>               return (1);
>       }
> @@ -97,12 +98,13 @@ copy_file(FTSENT *entp, int exists)
>                       (void)close(from_fd);
>                       return 2;
>               }
> -             to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
> -     } else
> +             if (!lflag && !sflag)
> +                     to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
> +     } else if (!lflag && !sflag)
>               to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
>                   fs->st_mode & ~(S_ISTXT | S_ISUID | S_ISGID));
>  
> -     if (to_fd == -1) {
> +     if (!lflag && !sflag && to_fd == -1) {
>               warn("%s", to.p_path);
>               (void)close(from_fd);
>               return (1);
> @@ -110,52 +112,69 @@ copy_file(FTSENT *entp, int exists)
>  
>       rval = 0;
>  
> -     /*
> -      * 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.
> -      */
> +     if (!lflag && !sflag) {
> +             /*
> +              * 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.
> +              */
>  #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
> -     /* XXX broken for 0-size mmap */
> -     if (fs->st_size <= 8 * 1048576) {
> -             if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
> -                 MAP_FILE|MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
> -                     warn("mmap: %s", entp->fts_path);
> -                     rval = 1;
> -             } else {
> -                     madvise(p, fs->st_size, MADV_SEQUENTIAL);
> -                     if (write(to_fd, p, fs->st_size) != fs->st_size) {
> -                             warn("%s", to.p_path);
> +             /* XXX broken for 0-size mmap */
> +             if (fs->st_size <= 8 * 1048576) {
> +                     if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
> +                         MAP_FILE|MAP_SHARED, from_fd,
> +                         (off_t)0)) == MAP_FAILED) {
> +                             warn("mmap: %s", entp->fts_path);
>                               rval = 1;
> +                     } else {
> +                             madvise(p, fs->st_size, MADV_SEQUENTIAL);
> +                             if (write(to_fd, p,
> +                                 fs->st_size) != fs->st_size) {
> +                                     warn("%s", to.p_path);
> +                                     rval = 1;
> +                             }
> +                             /* Some systems don't unmap on close(2). */
> +                             if (munmap(p, fs->st_size) < 0) {
> +                                     warn("%s", entp->fts_path);
> +                                     rval = 1;
> +                             }
>                       }
> -                     /* Some systems don't unmap on close(2). */
> -                     if (munmap(p, fs->st_size) < 0) {
> +             } else
> +#endif
> +             {
> +                     int skipholes = 0;
> +                     struct stat tosb;
> +                     if (!fstat(to_fd, &tosb) && S_ISREG(tosb.st_mode))
> +                             skipholes = 1;
> +                     while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
> +                             if (skipholes && memcmp(buf, zeroes,
> +                                 rcount) == 0)
> +                                     wcount = lseek(to_fd, rcount,
> +                                         SEEK_CUR) == -1 ? -1 : rcount;
> +                             else
> +                                     wcount = write(to_fd, buf, rcount);
> +                             if (rcount != wcount || wcount == -1) {
> +                                     warn("%s", to.p_path);
> +                                     rval = 1;
> +                                     break;
> +                             }
> +                     }
> +                     if (skipholes && rcount >= 0)
> +                             rcount = ftruncate(to_fd, lseek(to_fd, 0,
> +                                 SEEK_CUR));
> +                     if (rcount < 0) {
>                               warn("%s", entp->fts_path);
>                               rval = 1;
>                       }
>               }
> -     } else
> -#endif
> -     {
> -             int skipholes = 0;
> -             struct stat tosb;
> -             if (!fstat(to_fd, &tosb) && S_ISREG(tosb.st_mode))
> -                     skipholes = 1;
> -             while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
> -                     if (skipholes && memcmp(buf, zeroes, rcount) == 0)
> -                             wcount = lseek(to_fd, rcount, SEEK_CUR) == -1 ? 
> -1 : rcount;
> -                     else
> -                             wcount = write(to_fd, buf, rcount);
> -                     if (rcount != wcount || wcount == -1) {
> -                             warn("%s", to.p_path);
> -                             rval = 1;
> -                             break;
> -                     }
> +     } else if (lflag) {
> +             if (link(entp->fts_path, to.p_path) == -1) {
> +                     warn("%s", to.p_path);
> +                     rval = 1;
>               }
> -             if (skipholes && rcount >= 0)
> -                     rcount = ftruncate(to_fd, lseek(to_fd, 0, SEEK_CUR));
> -             if (rcount < 0) {
> -                     warn("%s", entp->fts_path);
> +     } else if (sflag) {
> +             if (symlink(entp->fts_path, to.p_path) == -1) {
> +                     warn("%s", to.p_path);
>                       rval = 1;
>               }
>       }
> @@ -166,30 +185,34 @@ copy_file(FTSENT *entp, int exists)
>               return (1);
>       }
>  
> -     if (pflag && setfile(fs, to_fd))
> -             rval = 1;
> -     /*
> -      * If the source was setuid or setgid, lose the bits unless the
> -      * copy is owned by the same user and group.
> -      */
> +     if (!lflag && !sflag) {
> +             if (pflag && setfile(fs, to_fd))
> +                     rval = 1;
> +             /*
> +              * If the source was setuid or setgid, lose the bits unless the
> +              * copy is owned by the same user and group.
> +              */
>  #define      RETAINBITS \
>       (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
> -     if (!pflag && !exists &&
> -         fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
> -             if (fstat(to_fd, &to_stat)) {
> -                     warn("%s", to.p_path);
> -                     rval = 1;
> -             } else if (fs->st_gid == to_stat.st_gid &&
> -                 fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) {
> +             if (!pflag && !exists &&
> +                 fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
> +                     if (fstat(to_fd, &to_stat)) {
> +                             warn("%s", to.p_path);
> +                             rval = 1;
> +                     } else if (fs->st_gid == to_stat.st_gid &&
> +                         fchmod(to_fd,
> +                             fs->st_mode & RETAINBITS & ~myumask)) {
> +                             warn("%s", to.p_path);
> +                             rval = 1;
> +                     }
> +             }
> +             if (close(to_fd)) {
>                       warn("%s", to.p_path);
>                       rval = 1;
>               }
>       }
> +
>       (void)close(from_fd);
> -     if (close(to_fd)) {
> -             warn("%s", to.p_path);
> -             rval = 1;
> -     }
>       return (rval);
>  }
>  
> @@ -326,9 +349,10 @@ void
>  usage(void)
>  {
>       (void)fprintf(stderr,
> -         "usage: %s [-afipv] [-R [-H | -L | -P]] source target\n", 
> __progname);
> +         "usage: %s [-afilpsv] [-R [-H | -L | -P]] source target\n",
> +         __progname);
>       (void)fprintf(stderr,
> -         "       %s [-afipv] [-R [-H | -L | -P]] source ... directory\n",
> +         "       %s [-afilpsv] [-R [-H | -L | -P]] source ... directory\n",
>           __progname);
>       exit(1);
>  }

Sorry, getopt not alphabetized.


Index: bin/cp/cp.1
===================================================================
RCS file: /cvs/src/bin/cp/cp.1,v
retrieving revision 1.40
diff -u -p -u -r1.40 cp.1
--- bin/cp/cp.1 28 Jan 2019 18:58:42 -0000      1.40
+++ bin/cp/cp.1 23 May 2019 20:39:48 -0000
@@ -103,6 +103,8 @@ The
 option overrides any previous
 .Fl f
 options.
+.It Fl l
+Create hard links to regular files in a hierarchy instead of copying.
 .It Fl L
 If the
 .Fl R
@@ -128,6 +130,8 @@ If the source file has both its set-user
 and either the user ID or group ID cannot be preserved, neither
 the set-user-ID nor set-group-ID bits are preserved in the copy's
 permissions.
+.It Fl s
+Create symbolic links to regular files in a hirarcy instead of copying.
 .It Fl R
 If
 .Ar source
Index: bin/cp/cp.c
===================================================================
RCS file: /cvs/src/bin/cp/cp.c,v
retrieving revision 1.52
diff -u -p -u -r1.52 cp.c
--- bin/cp/cp.c 28 Jan 2019 18:58:42 -0000      1.52
+++ bin/cp/cp.c 23 May 2019 20:39:48 -0000
@@ -71,7 +71,7 @@
 PATH_T to = { to.p_path, "" };
 
 uid_t myuid;
-int Rflag, fflag, iflag, pflag, rflag, vflag;
+int Rflag, fflag, iflag, lflag, pflag, rflag, sflag, vflag;
 mode_t myumask;
 
 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
@@ -88,7 +88,7 @@ main(int argc, char *argv[])
        char *target;
 
        Hflag = Lflag = Pflag = Rflag = 0;
-       while ((ch = getopt(argc, argv, "HLPRafiprv")) != -1)
+       while ((ch = getopt(argc, argv, "HLPRafilprsv")) != -1)
                switch (ch) {
                case 'H':
                        Hflag = 1;
@@ -119,12 +119,18 @@ main(int argc, char *argv[])
                        iflag = 1;
                        fflag = 0;
                        break;
+               case 'l':
+                       lflag = 1;
+                       break;
                case 'p':
                        pflag = 1;
                        break;
                case 'r':
                        rflag = 1;
                        break;
+               case 's':
+                       sflag = 1;
+                       break;
                case 'v':
                        vflag = 1;
                        break;
@@ -157,6 +163,8 @@ main(int argc, char *argv[])
                fts_options &= ~FTS_PHYSICAL;
                fts_options |= FTS_LOGICAL;
        }
+       if (lflag && sflag)
+               errx(1, "the -l and -s options may not be specified together.");
        if (Rflag) {
                if (Hflag)
                        fts_options |= FTS_COMFOLLOW;
@@ -319,7 +327,7 @@ copy(char *argv[], enum op type, int fts
                                if (type != DIR_TO_DNE) {
                                        p = find_last_component(curr->fts_path);
                                        base = p - curr->fts_path;
-                                       
+
                                        if (!strcmp(&curr->fts_path[base],
                                            ".."))
                                                base += 1;
@@ -435,7 +443,7 @@ copy(char *argv[], enum op type, int fts
                        break;
                case S_IFBLK:
                case S_IFCHR:
-                       if (Rflag) {
+                       if (Rflag && !sflag) {
                                if ((cval = copy_special(curr->fts_statp,
                                    !fts_dne(curr))) == 1)
                                        rval = 1;
@@ -448,7 +456,7 @@ copy(char *argv[], enum op type, int fts
                        cval = 0;
                        break;
                case S_IFIFO:
-                       if (Rflag) {
+                       if (Rflag && !sflag) {
                                if ((cval = copy_fifo(curr->fts_statp,
                                    !fts_dne(curr))) == 1)
                                        rval = 1;
Index: bin/cp/extern.h
===================================================================
RCS file: /cvs/src/bin/cp/extern.h,v
retrieving revision 1.15
diff -u -p -u -r1.15 extern.h
--- bin/cp/extern.h     26 Dec 2015 18:11:43 -0000      1.15
+++ bin/cp/extern.h     23 May 2019 20:39:48 -0000
@@ -40,7 +40,7 @@ typedef struct {
 
 extern PATH_T to;
 extern uid_t myuid;
-extern int fflag, iflag, pflag;
+extern int fflag, iflag, lflag, pflag, sflag;
 extern mode_t myumask;
 extern char *__progname;
 
Index: bin/cp/utils.c
===================================================================
RCS file: /cvs/src/bin/cp/utils.c,v
retrieving revision 1.47
diff -u -p -u -r1.47 utils.c
--- bin/cp/utils.c      28 Jan 2019 18:58:42 -0000      1.47
+++ bin/cp/utils.c      23 May 2019 20:39:48 -0000
@@ -71,7 +71,8 @@ copy_file(FTSENT *entp, int exists)
                        err(1, "calloc");
        }
 
-       if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
+       if (!lflag && !sflag &&
+           (from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
                warn("%s", entp->fts_path);
                return (1);
        }
@@ -97,12 +98,13 @@ copy_file(FTSENT *entp, int exists)
                        (void)close(from_fd);
                        return 2;
                }
-               to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
-       } else
+               if (!lflag && !sflag)
+                       to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+       } else if (!lflag && !sflag)
                to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
                    fs->st_mode & ~(S_ISTXT | S_ISUID | S_ISGID));
 
-       if (to_fd == -1) {
+       if (!lflag && !sflag && to_fd == -1) {
                warn("%s", to.p_path);
                (void)close(from_fd);
                return (1);
@@ -110,52 +112,69 @@ copy_file(FTSENT *entp, int exists)
 
        rval = 0;
 
-       /*
-        * 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.
-        */
+       if (!lflag && !sflag) {
+               /*
+                * 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.
+                */
 #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
-       /* XXX broken for 0-size mmap */
-       if (fs->st_size <= 8 * 1048576) {
-               if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
-                   MAP_FILE|MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
-                       warn("mmap: %s", entp->fts_path);
-                       rval = 1;
-               } else {
-                       madvise(p, fs->st_size, MADV_SEQUENTIAL);
-                       if (write(to_fd, p, fs->st_size) != fs->st_size) {
-                               warn("%s", to.p_path);
+               /* XXX broken for 0-size mmap */
+               if (fs->st_size <= 8 * 1048576) {
+                       if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
+                           MAP_FILE|MAP_SHARED, from_fd,
+                           (off_t)0)) == MAP_FAILED) {
+                               warn("mmap: %s", entp->fts_path);
                                rval = 1;
+                       } else {
+                               madvise(p, fs->st_size, MADV_SEQUENTIAL);
+                               if (write(to_fd, p,
+                                   fs->st_size) != fs->st_size) {
+                                       warn("%s", to.p_path);
+                                       rval = 1;
+                               }
+                               /* Some systems don't unmap on close(2). */
+                               if (munmap(p, fs->st_size) < 0) {
+                                       warn("%s", entp->fts_path);
+                                       rval = 1;
+                               }
                        }
-                       /* Some systems don't unmap on close(2). */
-                       if (munmap(p, fs->st_size) < 0) {
+               } else
+#endif
+               {
+                       int skipholes = 0;
+                       struct stat tosb;
+                       if (!fstat(to_fd, &tosb) && S_ISREG(tosb.st_mode))
+                               skipholes = 1;
+                       while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+                               if (skipholes && memcmp(buf, zeroes,
+                                   rcount) == 0)
+                                       wcount = lseek(to_fd, rcount,
+                                           SEEK_CUR) == -1 ? -1 : rcount;
+                               else
+                                       wcount = write(to_fd, buf, rcount);
+                               if (rcount != wcount || wcount == -1) {
+                                       warn("%s", to.p_path);
+                                       rval = 1;
+                                       break;
+                               }
+                       }
+                       if (skipholes && rcount >= 0)
+                               rcount = ftruncate(to_fd, lseek(to_fd, 0,
+                                   SEEK_CUR));
+                       if (rcount < 0) {
                                warn("%s", entp->fts_path);
                                rval = 1;
                        }
                }
-       } else
-#endif
-       {
-               int skipholes = 0;
-               struct stat tosb;
-               if (!fstat(to_fd, &tosb) && S_ISREG(tosb.st_mode))
-                       skipholes = 1;
-               while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
-                       if (skipholes && memcmp(buf, zeroes, rcount) == 0)
-                               wcount = lseek(to_fd, rcount, SEEK_CUR) == -1 ? 
-1 : rcount;
-                       else
-                               wcount = write(to_fd, buf, rcount);
-                       if (rcount != wcount || wcount == -1) {
-                               warn("%s", to.p_path);
-                               rval = 1;
-                               break;
-                       }
+       } else if (lflag) {
+               if (link(entp->fts_path, to.p_path) == -1) {
+                       warn("%s", to.p_path);
+                       rval = 1;
                }
-               if (skipholes && rcount >= 0)
-                       rcount = ftruncate(to_fd, lseek(to_fd, 0, SEEK_CUR));
-               if (rcount < 0) {
-                       warn("%s", entp->fts_path);
+       } else if (sflag) {
+               if (symlink(entp->fts_path, to.p_path) == -1) {
+                       warn("%s", to.p_path);
                        rval = 1;
                }
        }
@@ -166,30 +185,34 @@ copy_file(FTSENT *entp, int exists)
                return (1);
        }
 
-       if (pflag && setfile(fs, to_fd))
-               rval = 1;
-       /*
-        * If the source was setuid or setgid, lose the bits unless the
-        * copy is owned by the same user and group.
-        */
+       if (!lflag && !sflag) {
+               if (pflag && setfile(fs, to_fd))
+                       rval = 1;
+               /*
+                * If the source was setuid or setgid, lose the bits unless the
+                * copy is owned by the same user and group.
+                */
 #define        RETAINBITS \
        (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
-       if (!pflag && !exists &&
-           fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
-               if (fstat(to_fd, &to_stat)) {
-                       warn("%s", to.p_path);
-                       rval = 1;
-               } else if (fs->st_gid == to_stat.st_gid &&
-                   fchmod(to_fd, fs->st_mode & RETAINBITS & ~myumask)) {
+               if (!pflag && !exists &&
+                   fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == myuid) {
+                       if (fstat(to_fd, &to_stat)) {
+                               warn("%s", to.p_path);
+                               rval = 1;
+                       } else if (fs->st_gid == to_stat.st_gid &&
+                           fchmod(to_fd,
+                               fs->st_mode & RETAINBITS & ~myumask)) {
+                               warn("%s", to.p_path);
+                               rval = 1;
+                       }
+               }
+               if (close(to_fd)) {
                        warn("%s", to.p_path);
                        rval = 1;
                }
        }
+
        (void)close(from_fd);
-       if (close(to_fd)) {
-               warn("%s", to.p_path);
-               rval = 1;
-       }
        return (rval);
 }
 
@@ -326,9 +349,10 @@ void
 usage(void)
 {
        (void)fprintf(stderr,
-           "usage: %s [-afipv] [-R [-H | -L | -P]] source target\n", 
__progname);
+           "usage: %s [-afilpsv] [-R [-H | -L | -P]] source target\n",
+           __progname);
        (void)fprintf(stderr,
-           "       %s [-afipv] [-R [-H | -L | -P]] source ... directory\n",
+           "       %s [-afilpsv] [-R [-H | -L | -P]] source ... directory\n",
            __progname);
        exit(1);
 }

Reply via email to