aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro F. Giffuni <pfg@FreeBSD.org>2017-05-28 15:39:11 +0000
committerPedro F. Giffuni <pfg@FreeBSD.org>2017-05-28 15:39:11 +0000
commit39999a69986ca5e94457c1f27e70b12424f890ba (patch)
tree83063aacb2556798c3421b651ca0a8c2fcae3924
parent5a4380b5657fda4a93021acdaff6dfa4d2f59ab6 (diff)
Support for linux ext2fs posix-draft ACLs.
This is closely tied to the Extended Attribute implementation. Submitted by: Fedor Uporov Reviewed by: kevlo, pfg Differential Revision: https://reviews.freebsd.org/D10807
Notes
Notes: svn path=/head/; revision=319071
-rw-r--r--sys/conf/files1
-rw-r--r--sys/fs/ext2fs/ext2_acl.c521
-rw-r--r--sys/fs/ext2fs/ext2_acl.h55
-rw-r--r--sys/fs/ext2fs/ext2_extattr.c281
-rw-r--r--sys/fs/ext2fs/ext2_vnops.c179
-rw-r--r--sys/modules/ext2fs/Makefile6
6 files changed, 985 insertions, 58 deletions
diff --git a/sys/conf/files b/sys/conf/files
index f929ef142265..0257f9c5be6c 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3525,6 +3525,7 @@ geom/virstor/binstream.c optional geom_virstor
geom/virstor/g_virstor.c optional geom_virstor
geom/virstor/g_virstor_md.c optional geom_virstor
geom/zero/g_zero.c optional geom_zero
+fs/ext2fs/ext2_acl.c optional ext2fs
fs/ext2fs/ext2_alloc.c optional ext2fs
fs/ext2fs/ext2_balloc.c optional ext2fs
fs/ext2fs/ext2_bmap.c optional ext2fs
diff --git a/sys/fs/ext2fs/ext2_acl.c b/sys/fs/ext2fs/ext2_acl.c
new file mode 100644
index 000000000000..2a20d7359159
--- /dev/null
+++ b/sys/fs/ext2fs/ext2_acl.c
@@ -0,0 +1,521 @@
+/*-
+ * Copyright (c) 2017, Fedor Uporov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/endian.h>
+#include <sys/conf.h>
+#include <sys/mount.h>
+#include <sys/extattr.h>
+
+#include <fs/ext2fs/fs.h>
+#include <fs/ext2fs/ext2fs.h>
+#include <fs/ext2fs/inode.h>
+#include <fs/ext2fs/ext2_acl.h>
+#include <fs/ext2fs/ext2_extattr.h>
+#include <fs/ext2fs/ext2_extern.h>
+#include <fs/ext2fs/ext2_dinode.h>
+#include <fs/ext2fs/ext2_mount.h>
+
+void
+ext2_sync_acl_from_inode(struct inode *ip, struct acl *acl)
+{
+ struct acl_entry *acl_mask, *acl_group_obj;
+ int i;
+
+ /*
+ * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK
+ * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is
+ * present.
+ */
+ acl_mask = NULL;
+ acl_group_obj = NULL;
+ for (i = 0; i < acl->acl_cnt; i++) {
+ switch (acl->acl_entry[i].ae_tag) {
+ case ACL_USER_OBJ:
+ acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
+ ACL_USER_OBJ, ip->i_mode);
+ acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
+ break;
+
+ case ACL_GROUP_OBJ:
+ acl_group_obj = &acl->acl_entry[i];
+ acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
+ break;
+
+ case ACL_OTHER:
+ acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
+ ACL_OTHER, ip->i_mode);
+ acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
+ break;
+
+ case ACL_MASK:
+ acl_mask = &acl->acl_entry[i];
+ acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ break;
+
+ default:
+ panic("ext2_sync_acl_from_inode(): bad ae_tag");
+ }
+ }
+
+ if (acl_group_obj == NULL)
+ panic("ext2_sync_acl_from_inode(): no ACL_GROUP_OBJ");
+
+ if (acl_mask == NULL) {
+ /*
+ * There is no ACL_MASK, so update ACL_GROUP_OBJ.
+ */
+ acl_group_obj->ae_perm = acl_posix1e_mode_to_perm(
+ ACL_GROUP_OBJ, ip->i_mode);
+ } else {
+ /*
+ * Update the ACL_MASK entry instead of ACL_GROUP_OBJ.
+ */
+ acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ,
+ ip->i_mode);
+ }
+}
+
+static void
+ext2_sync_inode_from_acl(struct acl *acl, struct inode *ip)
+{
+
+ ip->i_mode &= ACL_PRESERVE_MASK;
+ ip->i_mode |= acl_posix1e_acl_to_mode(acl);
+}
+
+/*
+ * Convert from filesystem to in-memory representation.
+ */
+static int
+ext4_acl_from_disk(char *value, size_t size, struct acl *acl)
+{
+ const char *end = value + size;
+ int n, count, s;
+
+ if (((struct ext2_acl_header *)value)->a_version != EXT4_ACL_VERSION)
+ return (EINVAL);
+
+ if (!value || size < sizeof(struct ext2_acl_header))
+ return (EINVAL);
+
+ s = size - sizeof(struct ext2_acl_header);
+ s -= 4 * sizeof(struct ext2_acl_entry_short);
+ if (s < 0)
+ if ((size - sizeof(struct ext2_acl_header)) %
+ sizeof(struct ext2_acl_entry_short))
+ count = -1;
+ else
+ count = (size - sizeof(struct ext2_acl_header)) /
+ sizeof(struct ext2_acl_entry_short);
+ else
+ if (s % sizeof(struct ext2_acl_entry))
+ count = -1;
+ else
+ count = s / sizeof(struct ext2_acl_entry) + 4;
+
+ if (count <= 0 || count > acl->acl_maxcnt)
+ return (EINVAL);
+
+ value = value + sizeof(struct ext2_acl_header);
+
+ for (n = 0; n < count; n++) {
+ struct ext2_acl_entry *entry = (struct ext2_acl_entry *)value;
+ if ((char *)value + sizeof(struct ext2_acl_entry_short) > end)
+ return (EINVAL);
+
+ acl->acl_entry[n].ae_tag = entry->ae_tag;
+ acl->acl_entry[n].ae_perm = entry->ae_perm;
+
+ switch (acl->acl_entry[n].ae_tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ value = (char *)value + sizeof(struct ext2_acl_entry_short);
+ break;
+
+ case ACL_USER:
+ value = (char *)value + sizeof(struct ext2_acl_entry);
+ if ((char *)value > end)
+ return (EINVAL);
+
+ acl->acl_entry[n].ae_id = entry->ae_id;
+ break;
+
+ case ACL_GROUP:
+ value = (char *)value + sizeof(struct ext2_acl_entry);
+ if ((char *)value > end)
+ return (EINVAL);
+
+ acl->acl_entry[n].ae_id = entry->ae_id;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ }
+
+ if (value != end)
+ return (EINVAL);
+
+ acl->acl_cnt = count;
+
+ return (0);
+}
+
+static int
+ext2_getacl_posix1e(struct vop_getacl_args *ap)
+{
+ int attrnamespace;
+ const char *attrname;
+ char *value;
+ int len;
+ int error;
+
+ len = sizeof(*ap->a_aclp) + sizeof(struct ext2_acl_header);
+ value = malloc(len, M_ACL, M_WAITOK);
+ if (!value)
+ return (ENOMEM);
+
+ switch (ap->a_type) {
+ case ACL_TYPE_DEFAULT:
+ attrnamespace = POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE;
+ attrname = POSIX1E_ACL_DEFAULT_EXTATTR_NAME;
+ break;
+ case ACL_TYPE_ACCESS:
+ attrnamespace = POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE;
+ attrname = POSIX1E_ACL_ACCESS_EXTATTR_NAME;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ error = vn_extattr_get(ap->a_vp, IO_NODELOCKED, attrnamespace, attrname,
+ &len, value, ap->a_td);
+ switch (error) {
+ case ENOATTR:
+ switch (ap->a_type) {
+ case ACL_TYPE_ACCESS:
+ ap->a_aclp->acl_cnt = 3;
+ ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ;
+ ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
+ ap->a_aclp->acl_entry[0].ae_perm = ACL_PERM_NONE;
+ ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
+ ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
+ ap->a_aclp->acl_entry[1].ae_perm = ACL_PERM_NONE;
+ ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER;
+ ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
+ ap->a_aclp->acl_entry[2].ae_perm = ACL_PERM_NONE;
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ ap->a_aclp->acl_cnt = 0;
+ break;
+ }
+ case 0:
+ if (!error) {
+ error = ext4_acl_from_disk(value, len, ap->a_aclp);
+ if (error)
+ goto out;
+ }
+
+ if (error == ENOATTR)
+ error = 0;
+
+ if (ap->a_type == ACL_TYPE_ACCESS)
+ ext2_sync_acl_from_inode(VTOI(ap->a_vp), ap->a_aclp);
+ default:
+ break;
+ }
+
+out:
+ free(value, M_TEMP);
+ return (error);
+}
+
+int
+ext2_getacl(struct vop_getacl_args *ap)
+{
+
+ if (((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) ||
+ ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 1))
+ return (EOPNOTSUPP);
+
+ if (ap->a_type == ACL_TYPE_NFS4)
+ return (ENOTSUP);
+
+ return (ext2_getacl_posix1e(ap));
+}
+
+/*
+ * Convert from in-memory to filesystem representation.
+ */
+static int
+ext4_acl_to_disk(const struct acl *acl, size_t *size, char *value)
+{
+ struct ext2_acl_header *ext_acl;
+ int disk_size;
+ char *e;
+ size_t n;
+
+ if (acl->acl_cnt <= 4)
+ disk_size = sizeof(struct ext2_acl_header) +
+ acl->acl_cnt * sizeof(struct ext2_acl_entry_short);
+ else
+ disk_size = sizeof(struct ext2_acl_header) +
+ 4 * sizeof(struct ext2_acl_entry_short) +
+ (acl->acl_cnt - 4) * sizeof(struct ext2_acl_entry);
+
+ if (disk_size > *size)
+ return (EINVAL);
+
+ *size = disk_size;
+ ext_acl = (struct ext2_acl_header *)value;
+
+ ext_acl->a_version = EXT4_ACL_VERSION;
+ e = (char *)ext_acl + sizeof(struct ext2_acl_header);
+ for (n = 0; n < acl->acl_cnt; n++) {
+ const struct acl_entry *acl_e = &acl->acl_entry[n];
+ struct ext2_acl_entry *entry = (struct ext2_acl_entry *)e;
+ entry->ae_tag = acl_e->ae_tag;
+ entry->ae_perm = acl_e->ae_perm;
+ switch (acl_e->ae_tag) {
+ case ACL_USER:
+ entry->ae_id = acl_e->ae_id;
+ e += sizeof(struct ext2_acl_entry);
+ break;
+
+ case ACL_GROUP:
+ entry->ae_id = acl_e->ae_id;
+ e += sizeof(struct ext2_acl_entry);
+ break;
+
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ e += sizeof(struct ext2_acl_entry_short);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ }
+
+ return (0);
+}
+
+static int
+ext2_setacl_posix1e(struct vop_setacl_args *ap)
+{
+ struct inode *ip = VTOI(ap->a_vp);
+ char *value;
+ size_t len;
+ int error;
+
+ if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
+ return (EINVAL);
+
+ /*
+ * If this is a set operation rather than a delete operation,
+ * invoke VOP_ACLCHECK() on the passed ACL to determine if it is
+ * valid for the target. This will include a check on ap->a_type.
+ */
+ if (ap->a_aclp != NULL) {
+ /*
+ * Set operation.
+ */
+ error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp,
+ ap->a_cred, ap->a_td);
+ if (error)
+ return (error);
+ } else {
+ /*
+ * Delete operation.
+ * POSIX.1e allows only deletion of the default ACL on a
+ * directory (ACL_TYPE_DEFAULT).
+ */
+ if (ap->a_type != ACL_TYPE_DEFAULT)
+ return (EINVAL);
+ if (ap->a_vp->v_type != VDIR)
+ return (ENOTDIR);
+ }
+
+ if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+
+ /*
+ * Authorize the ACL operation.
+ */
+ if (ip->i_flags & (IMMUTABLE | APPEND))
+ return (EPERM);
+
+ /*
+ * Must hold VADMIN (be file owner) or have appropriate privilege.
+ */
+ if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td)))
+ return (error);
+
+ switch (ap->a_type) {
+ case ACL_TYPE_ACCESS:
+ len = sizeof(*ap->a_aclp) + sizeof(struct ext2_acl_header);
+ value = malloc(len, M_ACL, M_WAITOK | M_ZERO);
+ error = ext4_acl_to_disk(ap->a_aclp, &len, value);
+ if (error == 0)
+ error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAME, len,
+ value, ap->a_td);
+
+ free(value, M_ACL);
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ if (ap->a_aclp == NULL) {
+ error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td);
+
+ /*
+ * Attempting to delete a non-present default ACL
+ * will return success for portability purposes.
+ * (TRIX)
+ *
+ * XXX: Note that since we can't distinguish
+ * "that EA is not supported" from "that EA is not
+ * defined", the success case here overlaps the
+ * the ENOATTR->EOPNOTSUPP case below.
+ */
+ if (error == ENOATTR)
+ error = 0;
+ } else {
+ len = sizeof(*ap->a_aclp) + sizeof(struct ext2_acl_header);
+ value = malloc(len, M_ACL, M_WAITOK | M_ZERO);
+ error = ext4_acl_to_disk(ap->a_aclp, &len, value);
+ if (error == 0)
+ error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAME, len,
+ value, ap->a_td);
+
+ free(value, M_ACL);
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ }
+
+ /*
+ * Map lack of attribute definition in UFS_EXTATTR into lack of
+ * support for ACLs on the filesystem.
+ */
+ if (error == ENOATTR)
+ return (EOPNOTSUPP);
+
+ if (error != 0)
+ return (error);
+
+ if (ap->a_type == ACL_TYPE_ACCESS) {
+ /*
+ * Now that the EA is successfully updated, update the
+ * inode and mark it as changed.
+ */
+ ext2_sync_inode_from_acl(ap->a_aclp, ip);
+ ip->i_flag |= IN_CHANGE;
+ error = ext2_update(ip->i_vnode, 1);
+ }
+
+ VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB);
+
+ return (error);
+}
+
+int
+ext2_setacl(struct vop_setacl_args *ap)
+{
+ if (((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) ||
+ ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 1))
+ return (EOPNOTSUPP);
+
+ if (ap->a_type == ACL_TYPE_NFS4)
+ return (ENOTSUP);
+
+ return (ext2_setacl_posix1e(ap));
+}
+
+/*
+ * Check the validity of an ACL for a file.
+ */
+int
+ext2_aclcheck(struct vop_aclcheck_args *ap)
+{
+
+ if (((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) ||
+ ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 1))
+ return (EOPNOTSUPP);
+
+ if (ap->a_type == ACL_TYPE_NFS4)
+ return (ENOTSUP);
+
+ if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
+ return (EINVAL);
+
+ /*
+ * Verify we understand this type of ACL, and that it applies
+ * to this kind of object.
+ * Rely on the acl_posix1e_check() routine to verify the contents.
+ */
+ switch (ap->a_type) {
+ case ACL_TYPE_ACCESS:
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ if (ap->a_vp->v_type != VDIR)
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ return (acl_posix1e_check(ap->a_aclp));
+} \ No newline at end of file
diff --git a/sys/fs/ext2fs/ext2_acl.h b/sys/fs/ext2fs/ext2_acl.h
new file mode 100644
index 000000000000..abcb97d8517a
--- /dev/null
+++ b/sys/fs/ext2fs/ext2_acl.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2017, Fedor Uporov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FS_EXT2FS_EXT2_ACL_H_
+#define _FS_EXT2FS_EXT2_ACL_H_
+
+#define EXT4_ACL_VERSION 0x0001
+
+struct ext2_acl_entry {
+ int16_t ae_tag;
+ int16_t ae_perm;
+ int32_t ae_id;
+};
+
+struct ext2_acl_entry_short {
+ int16_t ae_tag;
+ int16_t ae_perm;
+};
+
+struct ext2_acl_header {
+ int32_t a_version;
+};
+
+void ext2_sync_acl_from_inode(struct inode *ip, struct acl *acl);
+
+int ext2_getacl(struct vop_getacl_args *);
+int ext2_setacl(struct vop_setacl_args *);
+int ext2_aclcheck(struct vop_aclcheck_args *);
+
+#endif /* !_FS_EXT2FS_EXT2_ACL_H_ */
diff --git a/sys/fs/ext2fs/ext2_extattr.c b/sys/fs/ext2fs/ext2_extattr.c
index 28ba8f9ad1a9..9c821949b550 100644
--- a/sys/fs/ext2fs/ext2_extattr.c
+++ b/sys/fs/ext2fs/ext2_extattr.c
@@ -46,35 +46,92 @@
#include <fs/ext2fs/ext2_extattr.h>
#include <fs/ext2fs/ext2_extern.h>
-
static int
-ext2_extattr_index_to_bsd(int index)
+ext2_extattr_attrnamespace_to_bsd(int attrnamespace)
{
- switch (index) {
- case EXT4_XATTR_INDEX_SYSTEM:
- return (EXTATTR_NAMESPACE_SYSTEM);
- case EXT4_XATTR_INDEX_USER:
- return (EXTATTR_NAMESPACE_USER);
+ switch (attrnamespace) {
+ case EXT4_XATTR_INDEX_SYSTEM:
+ return (EXTATTR_NAMESPACE_SYSTEM);
+
+ case EXT4_XATTR_INDEX_USER:
+ return (EXTATTR_NAMESPACE_USER);
+
+ case EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT:
+ return (POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE);
+
+ case EXT4_XATTR_INDEX_POSIX_ACL_ACCESS:
+ return (POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE);
}
return (EXTATTR_NAMESPACE_EMPTY);
}
+static const char *
+ext2_extattr_name_to_bsd(int attrnamespace, const char *name, int* name_len)
+{
+
+ if (attrnamespace == EXT4_XATTR_INDEX_SYSTEM)
+ return (name);
+ else if (attrnamespace == EXT4_XATTR_INDEX_USER)
+ return (name);
+ else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT) {
+ *name_len = strlen(POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
+ return (POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
+ } else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_ACCESS) {
+ *name_len = strlen(POSIX1E_ACL_ACCESS_EXTATTR_NAME);
+ return (POSIX1E_ACL_ACCESS_EXTATTR_NAME);
+ }
+
+ /*
+ * XXX: Not all linux namespaces are mapped to bsd for now,
+ * return NULL, which will be converted to ENOTSUP on upper layer.
+ */
+#ifdef EXT2FS_DEBUG
+ printf("can not convert ext2fs name to bsd: namespace=%d\n", attrnamespace);
+#endif /* DEBUG */
+
+ return (NULL);
+}
+
static int
-ext2_extattr_index_to_linux(int index)
+ext2_extattr_attrnamespace_to_linux(int attrnamespace, const char *name)
{
- switch (index) {
- case EXTATTR_NAMESPACE_SYSTEM:
- return (EXT4_XATTR_INDEX_SYSTEM);
- case EXTATTR_NAMESPACE_USER:
- return (EXT4_XATTR_INDEX_USER);
+ if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE &&
+ !strcmp(name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME))
+ return (EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT);
+
+ if (attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE &&
+ !strcmp(name, POSIX1E_ACL_ACCESS_EXTATTR_NAME))
+ return (EXT4_XATTR_INDEX_POSIX_ACL_ACCESS);
+
+ switch (attrnamespace) {
+ case EXTATTR_NAMESPACE_SYSTEM:
+ return (EXT4_XATTR_INDEX_SYSTEM);
+
+ case EXTATTR_NAMESPACE_USER:
+ return (EXT4_XATTR_INDEX_USER);
}
+ /*
+ * In this case namespace conversion should be unique,
+ * so this point is unreachable.
+ */
return (-1);
}
+static const char *
+ext2_extattr_name_to_linux(int attrnamespace, const char *name)
+{
+
+ if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE ||
+ attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE)
+ return ("");
+ else
+ return (name);
+}
+
int
ext2_extattr_valid_attrname(int attrnamespace, const char *attrname)
{
@@ -114,6 +171,8 @@ ext2_extattr_inode_list(struct inode *ip, int attrnamespace,
struct buf *bp;
struct ext2fs_extattr_dinode_header *header;
struct ext2fs_extattr_entry *entry;
+ const char *attr_name;
+ int name_len;
int error;
fs = ip->i_e2fs;
@@ -147,17 +206,26 @@ ext2_extattr_inode_list(struct inode *ip, int attrnamespace,
for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
entry = EXT2_EXTATTR_NEXT(entry)) {
- if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace)
+ if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
+ attrnamespace)
continue;
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
if (uio == NULL)
- *size += entry->e_name_len + 1;
+ *size += name_len + 1;
else {
- char *attr_name = malloc(entry->e_name_len + 1, M_TEMP, M_WAITOK);
- attr_name[0] = entry->e_name_len;
- memcpy(&attr_name[1], entry->e_name, entry->e_name_len);
- error = uiomove(attr_name, entry->e_name_len + 1, uio);
- free(attr_name, M_TEMP);
+ char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
+ name[0] = name_len;
+ memcpy(&name[1], attr_name, name_len);
+ error = uiomove(name, name_len + 1, uio);
+ free(name, M_TEMP);
if (error)
break;
}
@@ -176,6 +244,8 @@ ext2_extattr_block_list(struct inode *ip, int attrnamespace,
struct buf *bp;
struct ext2fs_extattr_header *header;
struct ext2fs_extattr_entry *entry;
+ const char *attr_name;
+ int name_len;
int error;
fs = ip->i_e2fs;
@@ -202,17 +272,26 @@ ext2_extattr_block_list(struct inode *ip, int attrnamespace,
for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
entry = EXT2_EXTATTR_NEXT(entry)) {
- if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace)
+ if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
+ attrnamespace)
continue;
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
if (uio == NULL)
- *size += entry->e_name_len + 1;
+ *size += name_len + 1;
else {
- char *attr_name = malloc(entry->e_name_len + 1, M_TEMP, M_WAITOK);
- attr_name[0] = entry->e_name_len;
- memcpy(&attr_name[1], entry->e_name, entry->e_name_len);
- error = uiomove(attr_name, entry->e_name_len + 1, uio);
- free(attr_name, M_TEMP);
+ char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
+ name[0] = name_len;
+ memcpy(&name[1], attr_name, name_len);
+ error = uiomove(name, name_len + 1, uio);
+ free(name, M_TEMP);
if (error)
break;
}
@@ -231,6 +310,8 @@ ext2_extattr_inode_get(struct inode *ip, int attrnamespace,
struct buf *bp;
struct ext2fs_extattr_dinode_header *header;
struct ext2fs_extattr_entry *entry;
+ const char *attr_name;
+ int name_len;
int error;
fs = ip->i_e2fs;
@@ -264,11 +345,20 @@ ext2_extattr_inode_get(struct inode *ip, int attrnamespace,
for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
entry = EXT2_EXTATTR_NEXT(entry)) {
- if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace)
+ if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
+ attrnamespace)
continue;
- if (strlen(name) == entry->e_name_len &&
- 0 == strncmp(entry->e_name, name, entry->e_name_len)) {
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
+ if (strlen(name) == name_len &&
+ 0 == strncmp(attr_name, name, name_len)) {
if (uio == NULL)
*size += entry->e_value_size;
else {
@@ -294,6 +384,8 @@ ext2_extattr_block_get(struct inode *ip, int attrnamespace,
struct buf *bp;
struct ext2fs_extattr_header *header;
struct ext2fs_extattr_entry *entry;
+ const char *attr_name;
+ int name_len;
int error;
fs = ip->i_e2fs;
@@ -320,11 +412,20 @@ ext2_extattr_block_get(struct inode *ip, int attrnamespace,
for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
entry = EXT2_EXTATTR_NEXT(entry)) {
- if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace)
+ if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
+ attrnamespace)
continue;
- if (strlen(name) == entry->e_name_len &&
- 0 == strncmp(entry->e_name, name, entry->e_name_len)) {
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
+ if (strlen(name) == name_len &&
+ 0 == strncmp(attr_name, name, name_len)) {
if (uio == NULL)
*size += entry->e_value_size;
else {
@@ -411,6 +512,8 @@ ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name)
struct buf *bp;
struct ext2fs_extattr_dinode_header *header;
struct ext2fs_extattr_entry *entry;
+ const char *attr_name;
+ int name_len;
int error;
fs = ip->i_e2fs;
@@ -444,9 +547,20 @@ ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name)
/* If I am last entry, just make magic zero */
entry = EXT2_IFIRST(header);
- if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) {
- if (strlen(name) == entry->e_name_len &&
- 0 == strncmp(entry->e_name, name, entry->e_name_len)) {
+ if ((EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) &&
+ (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
+ attrnamespace)) {
+
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
+ if (strlen(name) == name_len &&
+ 0 == strncmp(attr_name, name, name_len)) {
memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header));
return (bwrite(bp));
@@ -455,11 +569,20 @@ ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name)
for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
entry = EXT2_EXTATTR_NEXT(entry)) {
- if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace)
+ if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
+ attrnamespace)
continue;
- if (strlen(name) == entry->e_name_len &&
- 0 == strncmp(entry->e_name, name, entry->e_name_len)) {
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
+ if (strlen(name) == name_len &&
+ 0 == strncmp(attr_name, name, name_len)) {
ext2_extattr_delete_entry((char *)EXT2_IFIRST(header),
EXT2_IFIRST(header), entry,
(char *)dinode + EXT2_INODE_SIZE(fs));
@@ -521,6 +644,8 @@ ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
struct buf *bp;
struct ext2fs_extattr_header *header;
struct ext2fs_extattr_entry *entry;
+ const char *attr_name;
+ int name_len;
int error;
fs = ip->i_e2fs;
@@ -555,9 +680,20 @@ ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
/* If I am last entry, clean me and free the block */
entry = EXT2_FIRST_ENTRY(bp);
- if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) {
- if (strlen(name) == entry->e_name_len &&
- 0 == strncmp(entry->e_name, name, entry->e_name_len)) {
+ if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) &&
+ (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
+ attrnamespace)) {
+
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
+ if (strlen(name) == name_len &&
+ 0 == strncmp(attr_name, name, name_len)) {
ip->i_blocks -= btodb(fs->e2fs_bsize);
ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
ip->i_facl = 0;
@@ -570,11 +706,20 @@ ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
entry = EXT2_EXTATTR_NEXT(entry)) {
- if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace)
+ if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
+ attrnamespace)
continue;
- if (strlen(name) == entry->e_name_len &&
- 0 == strncmp(entry->e_name, name, entry->e_name_len)) {
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
+ if (strlen(name) == name_len &&
+ 0 == strncmp(attr_name, name, name_len)) {
ext2_extattr_delete_entry(bp->b_data,
EXT2_FIRST_ENTRY(bp), entry,
bp->b_data + bp->b_bufsize);
@@ -592,15 +737,18 @@ static struct ext2fs_extattr_entry *
allocate_entry(const char *name, int attrnamespace, uint16_t offs,
uint32_t size, uint32_t hash)
{
- size_t name_len;
+ const char *attr_name;
+ int name_len;
struct ext2fs_extattr_entry *entry;
- name_len = strlen(name);
+ attr_name = ext2_extattr_name_to_linux(attrnamespace, name);
+ name_len = strlen(attr_name);
+
entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len,
M_TEMP, M_WAITOK);
entry->e_name_len = name_len;
- entry->e_name_index = ext2_extattr_index_to_linux(attrnamespace);
+ entry->e_name_index = ext2_extattr_attrnamespace_to_linux(attrnamespace, name);
entry->e_value_offs = offs;
entry->e_value_block = 0;
entry->e_value_size = size;
@@ -727,6 +875,8 @@ ext2_extattr_inode_set(struct inode *ip, int attrnamespace,
struct buf *bp;
struct ext2fs_extattr_dinode_header *header;
struct ext2fs_extattr_entry *entry;
+ const char *attr_name;
+ int name_len;
size_t size = 0, max_size;
int error;
@@ -762,11 +912,20 @@ ext2_extattr_inode_set(struct inode *ip, int attrnamespace,
/* Find if entry exist */
for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
entry = EXT2_EXTATTR_NEXT(entry)) {
- if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace)
+ if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
+ attrnamespace)
continue;
- if (strlen(name) == entry->e_name_len &&
- 0 == strncmp(entry->e_name, name, entry->e_name_len))
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
+ if (strlen(name) == name_len &&
+ 0 == strncmp(attr_name, name, name_len))
break;
}
@@ -876,6 +1035,8 @@ ext2_extattr_block_set(struct inode *ip, int attrnamespace,
struct buf *bp;
struct ext2fs_extattr_header *header;
struct ext2fs_extattr_entry *entry;
+ const char *attr_name;
+ int name_len;
size_t size;
int error;
@@ -916,11 +1077,20 @@ ext2_extattr_block_set(struct inode *ip, int attrnamespace,
/* Find if entry exist */
for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
entry = EXT2_EXTATTR_NEXT(entry)) {
- if (ext2_extattr_index_to_bsd(entry->e_name_index) != attrnamespace)
+ if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
+ attrnamespace)
continue;
- if (strlen(name) == entry->e_name_len &&
- 0 == strncmp(entry->e_name, name, entry->e_name_len))
+ name_len = entry->e_name_len;
+ attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
+ entry->e_name, &name_len);
+ if (!attr_name) {
+ brelse(bp);
+ return (ENOTSUP);
+ }
+
+ if (strlen(name) == name_len &&
+ 0 == strncmp(attr_name, name, name_len))
break;
}
@@ -961,7 +1131,8 @@ ext2_extattr_block_set(struct inode *ip, int attrnamespace,
}
size = ext2_extattr_get_size(NULL, NULL,
- sizeof(struct ext2fs_extattr_header), strlen(name), uio->uio_resid);
+ sizeof(struct ext2fs_extattr_header),
+ strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid);
if (size > fs->e2fs_bsize)
return (ENOSPC);
diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c
index b507a6200886..68d49827b3f2 100644
--- a/sys/fs/ext2fs/ext2_vnops.c
+++ b/sys/fs/ext2fs/ext2_vnops.c
@@ -81,6 +81,7 @@
#include <fs/ext2fs/fs.h>
#include <fs/ext2fs/inode.h>
+#include <fs/ext2fs/ext2_acl.h>
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/ext2_dinode.h>
@@ -163,6 +164,9 @@ struct vop_vector ext2_vnodeops = {
.vop_getextattr = ext2_getextattr,
.vop_listextattr = ext2_listextattr,
.vop_setextattr = ext2_setextattr,
+ .vop_getacl = ext2_getacl,
+ .vop_setacl = ext2_setacl,
+ .vop_aclcheck = ext2_aclcheck,
.vop_vptofh = ext2_vptofh,
};
@@ -1083,6 +1087,150 @@ out:
return (error);
}
+static int
+ext2_do_posix1e_acl_inheritance_dir(struct vnode *dvp, struct vnode *tvp,
+ mode_t dmode, struct ucred *cred, struct thread *td)
+{
+ int error;
+ struct inode *ip = VTOI(tvp);
+ struct acl *dacl, *acl;
+
+ acl = acl_alloc(M_WAITOK);
+ dacl = acl_alloc(M_WAITOK);
+
+ /*
+ * Retrieve default ACL from parent, if any.
+ */
+ error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred, td);
+ switch (error) {
+ case 0:
+ /*
+ * Retrieved a default ACL, so merge mode and ACL if
+ * necessary. If the ACL is empty, fall through to
+ * the "not defined or available" case.
+ */
+ if (acl->acl_cnt != 0) {
+ dmode = acl_posix1e_newfilemode(dmode, acl);
+ ip->i_mode = dmode;
+ *dacl = *acl;
+ ext2_sync_acl_from_inode(ip, acl);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case EOPNOTSUPP:
+ /*
+ * Just use the mode as-is.
+ */
+ ip->i_mode = dmode;
+ error = 0;
+ goto out;
+
+ default:
+ goto out;
+ }
+
+ error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred, td);
+ if (error == 0)
+ error = VOP_SETACL(tvp, ACL_TYPE_DEFAULT, dacl, cred, td);
+ switch (error) {
+ case 0:
+ break;
+
+ case EOPNOTSUPP:
+ /*
+ * XXX: This should not happen, as EOPNOTSUPP above
+ * was supposed to free acl.
+ */
+#ifdef DEBUG
+ printf("ext2_mkdir: VOP_GETACL() but no VOP_SETACL()\n");
+#endif /* DEBUG */
+ break;
+
+ default:
+ goto out;
+ }
+
+out:
+ acl_free(acl);
+ acl_free(dacl);
+
+ return (error);
+}
+
+static int
+ext2_do_posix1e_acl_inheritance_file(struct vnode *dvp, struct vnode *tvp,
+ mode_t mode, struct ucred *cred, struct thread *td)
+{
+ int error;
+ struct inode *ip = VTOI(tvp);
+ struct acl *acl;
+
+ acl = acl_alloc(M_WAITOK);
+
+ /*
+ * Retrieve default ACL for parent, if any.
+ */
+ error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred, td);
+ switch (error) {
+ case 0:
+ /*
+ * Retrieved a default ACL, so merge mode and ACL if
+ * necessary.
+ */
+ if (acl->acl_cnt != 0) {
+ /*
+ * Two possible ways for default ACL to not
+ * be present. First, the EA can be
+ * undefined, or second, the default ACL can
+ * be blank. If it's blank, fall through to
+ * the it's not defined case.
+ */
+ mode = acl_posix1e_newfilemode(mode, acl);
+ ip->i_mode = mode;
+ ext2_sync_acl_from_inode(ip, acl);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case EOPNOTSUPP:
+ /*
+ * Just use the mode as-is.
+ */
+ ip->i_mode = mode;
+ error = 0;
+ goto out;
+
+ default:
+ goto out;
+ }
+
+ error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred, td);
+ switch (error) {
+ case 0:
+ break;
+
+ case EOPNOTSUPP:
+ /*
+ * XXX: This should not happen, as EOPNOTSUPP above was
+ * supposed to free acl.
+ */
+ printf("ufs_do_posix1e_acl_inheritance_file: VOP_GETACL() "
+ "but no VOP_SETACL()\n");
+ /* panic("ufs_do_posix1e_acl_inheritance_file: VOP_GETACL() "
+ "but no VOP_SETACL()"); */
+ break;
+
+ default:
+ goto out;
+ }
+
+out:
+ acl_free(acl);
+
+ return (error);
+}
+
/*
* Mkdir system call
*/
@@ -1192,6 +1340,13 @@ ext2_mkdir(struct vop_mkdir_args *ap)
ip->i_flag |= IN_CHANGE;
}
+ if (dvp->v_mount->mnt_flag & MNT_ACLS) {
+ error = ext2_do_posix1e_acl_inheritance_dir(dvp, tvp, dmode,
+ cnp->cn_cred, cnp->cn_thread);
+ if (error)
+ goto bad;
+ }
+
/* Directory set up, now install its entry in the parent directory. */
error = ext2_direnter(ip, dvp, cnp);
if (error) {
@@ -1446,6 +1601,18 @@ ext2_pathconf(struct vop_pathconf_args *ap)
case _PC_NO_TRUNC:
*ap->a_retval = 1;
break;
+ case _PC_ACL_EXTENDED:
+ if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS)
+ *ap->a_retval = 1;
+ else
+ *ap->a_retval = 0;
+ break;
+ case _PC_ACL_PATH_MAX:
+ if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS)
+ *ap->a_retval = ACL_MAX_ENTRIES;
+ else
+ *ap->a_retval = 3;
+ break;
case _PC_MIN_HOLE_SIZE:
*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
break;
@@ -1513,6 +1680,8 @@ ext2_deleteextattr(struct vop_deleteextattr_args *ap)
if (error)
return (error);
+ error = ENOATTR;
+
if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) {
error = ext2_extattr_inode_delete(ip, ap->a_attrnamespace, ap->a_name);
if (error != ENOATTR)
@@ -1552,6 +1721,8 @@ ext2_getextattr(struct vop_getextattr_args *ap)
if (ap->a_size != NULL)
*ap->a_size = 0;
+ error = ENOATTR;
+
if (EXT2_INODE_SIZE(fs) != E2FS_REV0_INODE_SIZE) {
error = ext2_extattr_inode_get(ip, ap->a_attrnamespace,
ap->a_name, ap->a_uio, ap->a_size);
@@ -1755,6 +1926,14 @@ ext2_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
error = ext2_update(tvp, !DOINGASYNC(tvp));
if (error)
goto bad;
+
+ if (dvp->v_mount->mnt_flag & MNT_ACLS) {
+ error = ext2_do_posix1e_acl_inheritance_file(dvp, tvp, mode,
+ cnp->cn_cred, cnp->cn_thread);
+ if (error)
+ goto bad;
+ }
+
error = ext2_direnter(ip, dvp, cnp);
if (error)
goto bad;
diff --git a/sys/modules/ext2fs/Makefile b/sys/modules/ext2fs/Makefile
index 03ba089f66f6..64164798e297 100644
--- a/sys/modules/ext2fs/Makefile
+++ b/sys/modules/ext2fs/Makefile
@@ -3,8 +3,8 @@
.PATH: ${SRCTOP}/sys/fs/ext2fs
KMOD= ext2fs
SRCS= opt_ddb.h opt_directio.h opt_quota.h opt_suiddir.h vnode_if.h \
- ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_extattr.c ext2_extents.c \
- ext2_hash.c ext2_htree.c ext2_inode.c ext2_inode_cnv.c ext2_lookup.c \
- ext2_subr.c ext2_vfsops.c ext2_vnops.c
+ ext2_acl.c ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_extattr.c \
+ ext2_extents.c ext2_hash.c ext2_htree.c ext2_inode.c ext2_inode_cnv.c \
+ ext2_lookup.c ext2_subr.c ext2_vfsops.c ext2_vnops.c
.include <bsd.kmod.mk>