diff options
author | csjp <csjp@FreeBSD.org> | 2005-09-05 04:36:08 +0000 |
---|---|---|
committer | csjp <csjp@FreeBSD.org> | 2005-09-05 04:36:08 +0000 |
commit | 549c6812a94339302b34e899ce15d452ed69ef23 (patch) | |
tree | 4d654ae429b6264f02e5490e9c9b223e74cd7b60 /bin | |
parent | 57d500e0a77c3bb556a8303725a9195b630c5771 (diff) | |
download | FreeBSD-src-549c6812a94339302b34e899ce15d452ed69ef23.zip FreeBSD-src-549c6812a94339302b34e899ce15d452ed69ef23.tar.gz |
Attempt to complete the userspace integration of POSIX.1e extended ACLs.
This includes adding support for ACLs into cp(1) and mv(1) userspace
utilities.
For mv(1), if _PC_ACL_EXTENDED is in effect for the source AND destination
operands, the destination file's ACLs shall reflect the source.
For cp(1), if _PC_ACL_EXTENDED is in effect for both source and destination
operands, and -p has been specified, the ACLs from the source shall be
preserved on the destination.
MFC after: 1 month
Diffstat (limited to 'bin')
-rw-r--r-- | bin/cp/cp.c | 5 | ||||
-rw-r--r-- | bin/cp/extern.h | 2 | ||||
-rw-r--r-- | bin/cp/utils.c | 80 | ||||
-rw-r--r-- | bin/mv/mv.c | 19 |
4 files changed, 104 insertions, 2 deletions
diff --git a/bin/cp/cp.c b/bin/cp/cp.c index bbf73cd..0d0040a 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -363,7 +363,10 @@ copy(char *argv[], enum op type, int fts_options) */ if (pflag) { if (setfile(curr->fts_statp, -1)) - rval = 1; + rval = 1; + if (preserve_dir_acls(curr->fts_statp, + curr->fts_accpath, to.p_path) != 0) + rval = 1; } else { mode = curr->fts_statp->st_mode; if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) || diff --git a/bin/cp/extern.h b/bin/cp/extern.h index a6b53c2..25077f8 100644 --- a/bin/cp/extern.h +++ b/bin/cp/extern.h @@ -46,5 +46,7 @@ int copy_file(const FTSENT *, int); int copy_link(const FTSENT *, int); int copy_special(struct stat *, int); int setfile(struct stat *, int); +int preserve_dir_acls(struct stat *, char *, char *); +int preserve_fd_acls(int, int); void usage(void); __END_DECLS diff --git a/bin/cp/utils.c b/bin/cp/utils.c index 3505225..5b29e6a 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -35,6 +35,8 @@ static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <sys/types.h> +#include <sys/acl.h> #include <sys/param.h> #include <sys/stat.h> #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED @@ -204,6 +206,8 @@ copy_file(const FTSENT *entp, int dne) if (pflag && setfile(fs, to_fd)) rval = 1; + if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) + rval = 1; (void)close(from_fd); if (close(to_fd)) { warn("%s", to.p_path); @@ -326,6 +330,82 @@ setfile(struct stat *fs, int fd) return (rval); } +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); +} + void usage(void) { diff --git a/bin/mv/mv.c b/bin/mv/mv.c index e400729..54c035d 100644 --- a/bin/mv/mv.c +++ b/bin/mv/mv.c @@ -44,6 +44,8 @@ static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94"; #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <sys/types.h> +#include <sys/acl.h> #include <sys/param.h> #include <sys/time.h> #include <sys/wait.h> @@ -252,6 +254,7 @@ fastcopy(char *from, char *to, struct stat *sbp) static char *bp; mode_t oldmode; int nread, from_fd, to_fd; + acl_t acl; if ((from_fd = open(from, O_RDONLY, 0)) < 0) { warn("%s", from); @@ -288,7 +291,6 @@ err: if (unlink(to)) (void)close(to_fd); return (1); } - (void)close(from_fd); oldmode = sbp->st_mode & ALLPERMS; if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) { @@ -301,6 +303,21 @@ err: if (unlink(to)) sbp->st_mode &= ~(S_ISUID | S_ISGID); } } + /* + * POSIX 1003.2c states that if _POSIX_ACL_EXTENDED is in effect + * for dest_file, then it's ACLs shall reflect the ACLs of the + * source_file. + */ + if (fpathconf(to_fd, _PC_ACL_EXTENDED) == 1 && + fpathconf(from_fd, _PC_ACL_EXTENDED) == 1) { + acl = acl_get_fd(from_fd); + if (acl == NULL) + warn("failed to get acl entries while setting %s", + from); + else if (acl_set_fd(to_fd, acl) < 0) + warn("failed to set acl entries for %s", to); + } + (void)close(from_fd); if (fchmod(to_fd, sbp->st_mode)) warn("%s: set mode (was: 0%03o)", to, oldmode); /* |