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; acl_type_t acl_type; int acl_supported = 0, ret, trivial; ret = pathconf(source_dir, _PC_ACL_NFS4); 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); /* * 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; } 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 * 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); acl_free(acl); return (1); } acl_free(acl); } acl = aclgetf(source_dir, acl_type); if (acl == NULL) { warn("failed to get acl entries on %s", source_dir); return (1); } if (acl_is_trivial_np(acl, &trivial)) { warn("acl_is_trivial() failed on %s", source_dir); acl_free(acl); 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); }
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; acl_type_t acl_type; int acl_supported = 0, ret, trivial; ret = pathconf(source_dir, _PC_ACL_NFS4); 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); 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; } if (acl_type == ACL_TYPE_ACCESS) { 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); acl_free(acl); return (1); } acl_free(acl); } acl = aclgetf(source_dir, acl_type); if (acl == NULL) { warn("failed to get acl entries on %s", source_dir); return (1); } if (acl_is_trivial_np(acl, &trivial)) { warn("acl_is_trivial() failed on %s", source_dir); acl_free(acl); 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); }