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:
parent
57d500e0a7
commit
549c6812a9
@ -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)) ||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
19
bin/mv/mv.c
19
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);
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user