Add NFSv4 ACL support to cp(1) and fix a few memory leaks.
Note that this changes error reporting behaviour somewhat - before, no error was reported if ACL couldn't be copied because the target filesystem doesn't support ACLs. Now, it will be reported - of course, only if there actually is an ACL to copy. Reviewed by: rwatson
This commit is contained in:
parent
f0246686c6
commit
2689ba2720
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=196754
127
bin/cp/utils.c
127
bin/cp/utils.c
@ -377,24 +377,52 @@ setfile(struct stat *fs, int fd)
|
|||||||
int
|
int
|
||||||
preserve_fd_acls(int source_fd, int dest_fd)
|
preserve_fd_acls(int source_fd, int dest_fd)
|
||||||
{
|
{
|
||||||
struct acl *aclp;
|
|
||||||
acl_t acl;
|
acl_t acl;
|
||||||
|
acl_type_t acl_type;
|
||||||
|
int acl_supported = 0, ret, trivial;
|
||||||
|
|
||||||
if (fpathconf(source_fd, _PC_ACL_EXTENDED) != 1 ||
|
ret = fpathconf(source_fd, _PC_ACL_NFS4);
|
||||||
fpathconf(dest_fd, _PC_ACL_EXTENDED) != 1)
|
if (ret > 0 ) {
|
||||||
|
acl_supported = 1;
|
||||||
|
acl_type = ACL_TYPE_NFS4;
|
||||||
|
} else if (ret < 0 && errno != EINVAL) {
|
||||||
|
warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", to.p_path);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (acl_supported == 0) {
|
||||||
|
ret = fpathconf(source_fd, _PC_ACL_EXTENDED);
|
||||||
|
if (ret > 0 ) {
|
||||||
|
acl_supported = 1;
|
||||||
|
acl_type = ACL_TYPE_ACCESS;
|
||||||
|
} else if (ret < 0 && errno != EINVAL) {
|
||||||
|
warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
|
||||||
|
to.p_path);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (acl_supported == 0)
|
||||||
return (0);
|
return (0);
|
||||||
acl = acl_get_fd(source_fd);
|
|
||||||
|
acl = acl_get_fd_np(source_fd, acl_type);
|
||||||
if (acl == NULL) {
|
if (acl == NULL) {
|
||||||
warn("failed to get acl entries while setting %s", to.p_path);
|
warn("failed to get acl entries while setting %s", to.p_path);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
aclp = &acl->ats_acl;
|
if (acl_is_trivial_np(acl, &trivial)) {
|
||||||
if (aclp->acl_cnt == 3)
|
warn("acl_is_trivial() failed for %s", to.p_path);
|
||||||
return (0);
|
acl_free(acl);
|
||||||
if (acl_set_fd(dest_fd, acl) < 0) {
|
|
||||||
warn("failed to set acl entries for %s", to.p_path);
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
if (trivial) {
|
||||||
|
acl_free(acl);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) {
|
||||||
|
warn("failed to set acl entries for %s", to.p_path);
|
||||||
|
acl_free(acl);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
acl_free(acl);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,10 +433,31 @@ preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir)
|
|||||||
int (*aclsetf)(const char *, acl_type_t, acl_t);
|
int (*aclsetf)(const char *, acl_type_t, acl_t);
|
||||||
struct acl *aclp;
|
struct acl *aclp;
|
||||||
acl_t acl;
|
acl_t acl;
|
||||||
|
acl_type_t acl_type;
|
||||||
|
int acl_supported = 0, ret, trivial;
|
||||||
|
|
||||||
if (pathconf(source_dir, _PC_ACL_EXTENDED) != 1 ||
|
ret = pathconf(source_dir, _PC_ACL_NFS4);
|
||||||
pathconf(dest_dir, _PC_ACL_EXTENDED) != 1)
|
if (ret > 0) {
|
||||||
|
acl_supported = 1;
|
||||||
|
acl_type = ACL_TYPE_NFS4;
|
||||||
|
} else if (ret < 0 && errno != EINVAL) {
|
||||||
|
warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", source_dir);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (acl_supported == 0) {
|
||||||
|
ret = pathconf(source_dir, _PC_ACL_EXTENDED);
|
||||||
|
if (ret > 0) {
|
||||||
|
acl_supported = 1;
|
||||||
|
acl_type = ACL_TYPE_ACCESS;
|
||||||
|
} else if (ret < 0 && errno != EINVAL) {
|
||||||
|
warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
|
||||||
|
source_dir);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (acl_supported == 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the file is a link we will not follow it
|
* If the file is a link we will not follow it
|
||||||
*/
|
*/
|
||||||
@ -419,34 +468,48 @@ preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir)
|
|||||||
aclgetf = acl_get_file;
|
aclgetf = acl_get_file;
|
||||||
aclsetf = acl_set_file;
|
aclsetf = acl_set_file;
|
||||||
}
|
}
|
||||||
/*
|
if (acl_type == ACL_TYPE_ACCESS) {
|
||||||
* Even if there is no ACL_TYPE_DEFAULT entry here, a zero
|
/*
|
||||||
* size ACL will be returned. So it is not safe to simply
|
* Even if there is no ACL_TYPE_DEFAULT entry here, a zero
|
||||||
* check the pointer to see if the default ACL is present.
|
* 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) {
|
acl = aclgetf(source_dir, ACL_TYPE_DEFAULT);
|
||||||
warn("failed to get default acl entries on %s",
|
if (acl == NULL) {
|
||||||
source_dir);
|
warn("failed to get default acl entries on %s",
|
||||||
return (1);
|
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);
|
||||||
|
acl_free(acl);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
acl_free(acl);
|
||||||
}
|
}
|
||||||
aclp = &acl->ats_acl;
|
acl = aclgetf(source_dir, acl_type);
|
||||||
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) {
|
if (acl == NULL) {
|
||||||
warn("failed to get acl entries on %s", source_dir);
|
warn("failed to get acl entries on %s", source_dir);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
aclp = &acl->ats_acl;
|
if (acl_is_trivial_np(acl, &trivial)) {
|
||||||
if (aclsetf(dest_dir, ACL_TYPE_ACCESS, acl) < 0) {
|
warn("acl_is_trivial() failed on %s", source_dir);
|
||||||
warn("failed to set acl entries on %s", dest_dir);
|
acl_free(acl);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
if (trivial) {
|
||||||
|
acl_free(acl);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
if (aclsetf(dest_dir, acl_type, acl) < 0) {
|
||||||
|
warn("failed to set acl entries on %s", dest_dir);
|
||||||
|
acl_free(acl);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
acl_free(acl);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user