diff options
author | mckay <mckay@FreeBSD.org> | 2001-12-11 13:18:10 +0000 |
---|---|---|
committer | mckay <mckay@FreeBSD.org> | 2001-12-11 13:18:10 +0000 |
commit | a6a1f2b728695247ffe0ffb64f387726737e3894 (patch) | |
tree | b1d1f24b5d1e5e3e6a15c55735b04e9dc4b26478 | |
parent | 46e660813b1062946c620efd70dfa17841e3fc6a (diff) | |
download | FreeBSD-src-a6a1f2b728695247ffe0ffb64f387726737e3894.zip FreeBSD-src-a6a1f2b728695247ffe0ffb64f387726737e3894.tar.gz |
Preserve directory timestamps with -p. Allow non-empty read-only
directories to be copied. Apply umask to newly created directories
when -p is not specified.
PR: 27970
PR: 31633
MFC after: 4 days
-rw-r--r-- | bin/cp/cp.c | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/bin/cp/cp.c b/bin/cp/cp.c index 3fe4af4..e48830d 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -248,6 +248,14 @@ copy(argv, type, fts_options) FTSENT *curr; int base = 0, dne, badcp, nlen, rval; char *p, *target_mid; + mode_t mask; + + /* + * Keep an inverted copy of the umask, for use in correcting + * permissions on created directories when not using -p. + */ + mask = ~umask(0777); + umask(~mask); if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL) err(1, NULL); @@ -264,8 +272,6 @@ copy(argv, type, fts_options) warnx("%s: directory causes a cycle", curr->fts_path); badcp = rval = 1; continue; - case FTS_DP: /* Ignore, continue. */ - continue; } /* @@ -323,6 +329,25 @@ copy(argv, type, fts_options) STRIP_TRAILING_SLASH(to); } + if (curr->fts_info == FTS_DP) { + /* + * We are finished copying to this directory. If + * -p is in effect, set permissions and timestamps. + * Otherwise, if we created this directory, set the + * correct permissions, limited by the umask. + */ + if (pflag) + rval = setfile(curr->fts_statp, 0); + else if (curr->fts_number) { + mode_t perm = curr->fts_statp->st_mode & mask; + if (chmod(to.p_path, perm)) { + warn("chmod: %s", to.p_path); + rval = 1; + } + } + continue; + } + /* Not an error but need to remember it happened */ if (stat(to.p_path, &to_stat) == -1) dne = 1; @@ -376,16 +401,19 @@ copy(argv, type, fts_options) err(1, "%s", to.p_path); } /* - * If not -p and directory didn't exist, set it to be - * the same as the from directory, umodified by the - * umask; arguably wrong, but it's been that way - * forever. + * Arrange to correct directory permissions later + * (in the post-order phase) if this is a new + * directory and the permissions aren't the final + * ones we want yet. Note that mkdir() does not + * honour setuid, setgid nor sticky bits, but we + * normally want to preserve them on directories. */ - if (pflag && setfile(curr->fts_statp, 0)) - badcp = rval = 1; - else if (dne) - (void)chmod(to.p_path, - curr->fts_statp->st_mode); + { + mode_t mode = curr->fts_statp->st_mode; + curr->fts_number = dne && + ((mode & (S_ISUID|S_ISGID|S_ISTXT)) || + ((mode | S_IRWXU) & mask) != (mode & mask)); + } break; case S_IFBLK: case S_IFCHR: |