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
This commit is contained in:
Christian S.J. Peron 2005-09-05 04:36:08 +00:00
parent 5340ff6caa
commit 9b4261c9b4
4 changed files with 104 additions and 2 deletions

View File

@ -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)) ||

View File

@ -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

View File

@ -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)
{

View File

@ -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);
/*