Index: cp.1 =================================================================== RCS file: /home/dcvs/src/bin/cp/cp.1,v retrieving revision 1.6 diff -u -r1.6 cp.1 --- cp.1 1 Aug 2005 01:49:16 -0000 1.6 +++ cp.1 5 Jul 2008 14:19:31 -0000 @@ -1,3 +1,4 @@ +.\"- .\" Copyright (c) 1989, 1990, 1993, 1994 .\" The Regents of the University of California. All rights reserved. .\" @@ -12,10 +13,6 @@ .\" 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. @@ -33,10 +30,10 @@ .\" 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 $ +.\" $FreeBSD: src/bin/cp/cp.1,v 1.40 2008/03/10 19:58:41 jhb Exp $ .\" $DragonFly: src/bin/cp/cp.1,v 1.6 2005/08/01 01:49:16 swildner Exp $ .\" -.Dd February 23, 2005 +.Dd July 5, 2008 .Dt CP 1 .Os .Sh NAME @@ -49,7 +46,7 @@ .Op Fl H | Fl L | Fl P .Oc .Op Fl f | i | n -.Op Fl pv +.Op Fl alpv .Ar source_file target_file .Nm .Oo @@ -57,7 +54,7 @@ .Op Fl H | Fl L | Fl P .Oc .Op Fl f | i | n -.Op Fl pv +.Op Fl alpv .Ar source_file ... target_directory .Sh DESCRIPTION In the first synopsis form, the @@ -120,6 +117,10 @@ 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 +149,8 @@ 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 @@ -253,9 +256,23 @@ 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 +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: cp.c =================================================================== RCS file: /home/dcvs/src/bin/cp/cp.c,v retrieving revision 1.12 diff -u -r1.12 cp.c --- cp.c 19 Jun 2006 12:07:50 -0000 1.12 +++ cp.c 5 Jul 2008 14:13:26 -0000 @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -13,10 +13,6 @@ * 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. @@ -35,7 +31,7 @@ * * @(#) 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 $ $ + * $FreeBSD: src/bin/cp/cp.c,v 1.60 2008/03/10 19:58:41 jhb Exp $ * $DragonFly: src/bin/cp/cp.c,v 1.12 2006/06/19 12:07:50 corecode Exp $ */ @@ -74,17 +70,19 @@ *--(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 mastercmp (const FTSENT **, const FTSENT **); -static void siginfo (int); +static int copy(char **, enum op, int); +static int mastercmp(const FTSENT **, const FTSENT **); +static void siginfo(int __unused); int main(int argc, char **argv) @@ -95,7 +93,7 @@ char *target; Hflag = Lflag = Pflag = 0; - while ((ch = getopt(argc, argv, "HLPRfinprv")) != -1) + while ((ch = getopt(argc, argv, "HLPRafilnprv")) != -1) switch (ch) { case 'H': Hflag = 1; @@ -112,6 +110,12 @@ 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 +124,9 @@ iflag = 1; fflag = nflag = 0; break; + case 'l': + lflag = 1; + break; case 'n': nflag = 1; fflag = iflag = 0; @@ -128,7 +135,8 @@ pflag = 1; break; case 'r': - rflag = 1; + rflag = Lflag = 1; + Hflag = Pflag = 0; break; case 'v': vflag = 1; @@ -144,16 +152,10 @@ 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; @@ -205,10 +207,9 @@ /* * 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 +218,22 @@ * 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 (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); } @@ -250,7 +252,8 @@ struct stat to_stat; FTS *ftsp; FTSENT *curr; - int base, dne, badcp, nlen, rval; + int base, dne, badcp, rval; + size_t nlen; char *p, *target_mid; mode_t mask, mode; @@ -263,7 +266,7 @@ 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,6 +280,8 @@ warnx("%s: directory causes a cycle", curr->fts_path); badcp = rval = 1; continue; + default: + ; } /* @@ -353,7 +358,12 @@ */ if (pflag) { if (setfile(curr->fts_statp, -1)) - rval = 1; + rval = 1; +#if 0 + if (preserve_dir_acls(curr->fts_statp, + curr->fts_accpath, to.p_path) != 0) + rval = 1; +#endif } else { mode = curr->fts_statp->st_mode; if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) || @@ -381,7 +391,8 @@ } 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); badcp = rval = 1; continue; @@ -403,7 +414,7 @@ } 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); @@ -443,6 +454,9 @@ badcp = rval = 1; } break; + case S_IFSOCK: + warnx("%s is a socket (not copied).", + curr->fts_path); case S_IFIFO: if (Rflag) { if (copy_fifo(curr->fts_statp, !dne)) Index: extern.h =================================================================== RCS file: /home/dcvs/src/bin/cp/extern.h,v retrieving revision 1.5 diff -u -r1.5 extern.h --- extern.h 28 Feb 2005 23:15:35 -0000 1.5 +++ extern.h 5 Jul 2008 14:09:06 -0000 @@ -10,10 +10,6 @@ * 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,7 +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 $ + * $FreeBSD: src/bin/cp/extern.h,v 1.21 2006/08/24 20:45:38 julian Exp $ * $DragonFly: src/bin/cp/extern.h,v 1.5 2005/02/28 23:15:35 corecode Exp $ */ @@ -42,7 +38,7 @@ } 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 @@ -51,5 +47,9 @@ int copy_link(const FTSENT *, int); int copy_special(struct stat *, int); int setfile(struct stat *, int); +#if 0 +int preserve_dir_acls(struct stat *, char *, char *); +int preserve_fd_acls(int, int); +#endif void usage(void); __END_DECLS Index: utils.c =================================================================== RCS file: /home/dcvs/src/bin/cp/utils.c,v retrieving revision 1.11 diff -u -r1.11 utils.c --- utils.c 15 Jun 2007 07:02:51 -0000 1.11 +++ utils.c 5 Jul 2008 14:10:38 -0000 @@ -10,10 +10,6 @@ * 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,13 +27,16 @@ * 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 $ + * $FreeBSD: src/bin/cp/utils.c,v 1.53 2008/03/10 19:58:41 jhb Exp $ * $DragonFly: src/bin/cp/utils.c,v 1.11 2007/06/15 07:02:51 corecode Exp $ */ +#if 0 +#include +#include +#endif #include #include -#include #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED #include #endif @@ -53,7 +52,7 @@ #include #include "extern.h" -#define cp_pct(x,y) (int)(100.0 * (double)(x) / (double)(y)) +#define cp_pct(x, y) ((y == 0) ? 0 : (int)(100.0 * (x) / (y))) #define YESNO "(y/n [n]) " @@ -62,9 +61,10 @@ { static char buf[MAXBSIZE]; struct stat *fs; - int ch, checkch, from_fd, rval, to_fd; - size_t rcount, wcount, wresid; + ssize_t wcount; + size_t wresid; off_t wtotal; + int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0; char *bufp; #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED char *p; @@ -105,18 +105,29 @@ } 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)); - + /* + * Remove existing destination file name. + * Create a new file. + */ + 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); @@ -125,79 +136,87 @@ 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) { + /* + * 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 - 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 { - wtotal = 0; - for (bufp = p, wresid = fs->st_size; ; - 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)); - } - if (wcount >= wresid || wcount == 0) - break; - } - if (wcount != wresid) { - warn("%s", to.p_path); - rval = 1; - } - /* Some systems don't unmap on close(2). */ - if (munmap(p, fs->st_size) < 0) { + 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 { + wtotal = 0; + for (bufp = p, wresid = fs->st_size; ; + bufp += wcount, wresid -= (size_t)wcount) { + wcount = write(to_fd, bufp, wresid); + if (wcount <= 0) + 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)); + } + if (wcount >= (ssize_t)wresid) + break; + } + if (wcount != (ssize_t)wresid) { + 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; + } } - } - } 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; + 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; } } - + close(from_fd); + /* * Don't remove the target even after an error. The target might * not be a regular file, or its attributes might be important, @@ -205,12 +224,18 @@ * 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 0 + if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) + rval = 1; +#endif + close(from_fd); + if (close(to_fd)) { + warn("%s", to.p_path); + rval = 1; + } } return (rval); } @@ -329,12 +354,91 @@ return (rval); } +#if 0 +int +preserve_fd_acls(int source_fd, int dest_fd) +{ + struct acl *aclp; + acl_t acl; + + if (fpathconf(source_fd, _PC_ACL_EXTENDED) != 1 || + fpathconf(dest_fd, _PC_ACL_EXTENDED) != 1) + return (0); + acl = acl_get_fd(source_fd); + if (acl == NULL) { + warn("failed to get acl entries while setting %s", to.p_path); + return (1); + } + aclp = &acl->ats_acl; + if (aclp->acl_cnt == 3) + return (0); + if (acl_set_fd(dest_fd, acl) < 0) { + warn("failed to set acl entries for %s", to.p_path); + return (1); + } + return (0); +} + +int +preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir) +{ + acl_t (*aclgetf)(const char *, acl_type_t); + int (*aclsetf)(const char *, acl_type_t, acl_t); + struct acl *aclp; + acl_t acl; + + if (pathconf(source_dir, _PC_ACL_EXTENDED) != 1 || + pathconf(dest_dir, _PC_ACL_EXTENDED) != 1) + return (0); + /* + * If the file is a link we will not follow it + */ + if (S_ISLNK(fs->st_mode)) { + aclgetf = acl_get_link_np; + aclsetf = acl_set_link_np; + } else { + aclgetf = acl_get_file; + aclsetf = acl_set_file; + } + /* + * Even if there is no ACL_TYPE_DEFAULT entry here, a zero + * size ACL will be returned. So it is not safe to simply + * check the pointer to see if the default ACL is present. + */ + acl = aclgetf(source_dir, ACL_TYPE_DEFAULT); + if (acl == NULL) { + warn("failed to get default acl entries on %s", + source_dir); + return (1); + } + aclp = &acl->ats_acl; + if (aclp->acl_cnt != 0 && aclsetf(dest_dir, + ACL_TYPE_DEFAULT, acl) < 0) { + warn("failed to set default acl entries on %s", + dest_dir); + return (1); + } + acl = aclgetf(source_dir, ACL_TYPE_ACCESS); + if (acl == NULL) { + warn("failed to get acl entries on %s", source_dir); + return (1); + } + aclp = &acl->ats_acl; + if (aclsetf(dest_dir, ACL_TYPE_ACCESS, acl) < 0) { + warn("failed to set acl entries on %s", dest_dir); + return (1); + } + return (0); +} +#endif + 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 ... " +"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpv] source_file target_file", +" cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpv] source_file ... " "target_directory"); exit(EX_USAGE); }