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:
Edward Tomasz Napierala 2009-09-02 08:08:57 +00:00
parent f0246686c6
commit 2689ba2720
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=196754

View File

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