summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordrahn <drahn@openbsd.org>2002-02-22 20:37:45 +0000
committerdrahn <drahn@openbsd.org>2002-02-22 20:37:45 +0000
commitcfa7519356b6013a38a223053872a2f5f28b8181 (patch)
tree2ad7643831d2b488c88c147354b66fcc564c5c65 /sys
parentCall ether_ioctl() the way [insert favorite diety] intended. (diff)
downloadwireguard-openbsd-cfa7519356b6013a38a223053872a2f5f28b8181.tar.xz
wireguard-openbsd-cfa7519356b6013a38a223053872a2f5f28b8181.zip
Extended Attribute support from FreeBSD/TrustedBSD ok art@, deraadt@
Diffstat (limited to 'sys')
-rw-r--r--sys/compat/osf1/osf1_mount.c3
-rw-r--r--sys/conf/files3
-rw-r--r--sys/kern/syscalls.master32
-rw-r--r--sys/kern/vfs_default.c18
-rw-r--r--sys/kern/vfs_syscalls.c408
-rw-r--r--sys/kern/vnode_if.src26
-rw-r--r--sys/sys/extattr.h69
-rw-r--r--sys/sys/malloc.h5
-rw-r--r--sys/sys/mount.h18
-rw-r--r--sys/ufs/ext2fs/ext2fs_bmap.c3
-rw-r--r--sys/ufs/ext2fs/ext2fs_inode.c3
-rw-r--r--sys/ufs/ext2fs/ext2fs_lookup.c3
-rw-r--r--sys/ufs/ext2fs/ext2fs_vfsops.c6
-rw-r--r--sys/ufs/ext2fs/ext2fs_vnops.c3
-rw-r--r--sys/ufs/ffs/ffs_alloc.c3
-rw-r--r--sys/ufs/ffs/ffs_inode.c3
-rw-r--r--sys/ufs/ffs/ffs_softdep.c3
-rw-r--r--sys/ufs/ffs/ffs_softdep_stub.c3
-rw-r--r--sys/ufs/ffs/ffs_subr.c3
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c38
-rw-r--r--sys/ufs/ffs/ffs_vnops.c17
-rw-r--r--sys/ufs/lfs/lfs_vfsops.c5
-rw-r--r--sys/ufs/mfs/mfs_vfsops.c6
-rw-r--r--sys/ufs/ufs/extattr.h109
-rw-r--r--sys/ufs/ufs/ufs_bmap.c3
-rw-r--r--sys/ufs/ufs/ufs_extattr.c1338
-rw-r--r--sys/ufs/ufs/ufs_inode.c3
-rw-r--r--sys/ufs/ufs/ufs_lookup.c3
-rw-r--r--sys/ufs/ufs/ufs_quota.c3
29 files changed, 2107 insertions, 33 deletions
diff --git a/sys/compat/osf1/osf1_mount.c b/sys/compat/osf1/osf1_mount.c
index 506d18bca6b..ec17ba7b2ef 100644
--- a/sys/compat/osf1/osf1_mount.c
+++ b/sys/compat/osf1/osf1_mount.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: osf1_mount.c,v 1.6 2002/02/12 18:41:20 art Exp $ */
+/* $OpenBSD: osf1_mount.c,v 1.7 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: osf1_mount.c,v 1.14 1999/05/05 01:51:34 cgd Exp $ */
/*
@@ -83,6 +83,7 @@
#include <nfs/nfsmount.h>
#include <ufs/ufs/quota.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/ufsmount.h>
#include <machine/vmparam.h>
diff --git a/sys/conf/files b/sys/conf/files
index 5fccc90a7a4..7fcc9c1dbcc 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.239 2002/02/18 01:55:30 krw Exp $
+# $OpenBSD: files,v 1.240 2002/02/22 20:37:45 drahn Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -771,6 +771,7 @@ file ufs/ffs/ffs_softdep.c ffs_softupdates
file ufs/mfs/mfs_vfsops.c mfs
file ufs/mfs/mfs_vnops.c mfs
file ufs/ufs/ufs_bmap.c ffs | mfs | ext2fs
+file ufs/ufs/ufs_extattr.c ffs | mfs
file ufs/ufs/ufs_ihash.c ffs | mfs | ext2fs
file ufs/ufs/ufs_inode.c ffs | mfs | ext2fs
file ufs/ufs/ufs_lookup.c ffs | mfs | ext2fs
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 1a6ead6a9ec..9a9a5e90afa 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
-; $OpenBSD: syscalls.master,v 1.47 2001/06/26 19:56:52 dugsong Exp $
+; $OpenBSD: syscalls.master,v 1.48 2002/02/22 20:37:45 drahn Exp $
; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@@ -534,4 +534,32 @@
271 STD { int sys_mlockall(int flags); }
272 STD { int sys_munlockall(void); }
273 STD { int sys_getpeereid(int fdes, uid_t *euid, gid_t *egid); }
-
+#ifdef UFS_EXTATTR
+274 STD { int sys_extattrctl(const char *path, int cmd, \
+ const char *filename, int attrnamespace, \
+ const char *attrname); }
+275 STD { int sys_extattr_set_file(const char *path, \
+ int attrnamespace, const char *attrname, \
+ void *data, size_t nbytes); }
+276 STD { ssize_t sys_extattr_get_file(const char *path, \
+ int attrnamespace, const char *attrname, \
+ void *data, size_t nbytes); }
+277 STD { int sys_extattr_delete_file(const char *path, \
+ int attrnamespace, const char *attrname); }
+278 STD { int sys_extattr_set_fd(int fd, int attrnamespace, \
+ const char *attrname, void *data, \
+ size_t nbytes); }
+279 STD { ssize_t sys_extattr_get_fd(int fd, \
+ int attrnamespace, const char *attrname, \
+ void *data, size_t nbytes); }
+280 STD { int sys_extattr_delete_fd(int fd, int attrnamespace, \
+ const char *attrname); }
+#else
+274 UNIMPL sys_extattrctl
+275 UNIMPL sys_extattr_set_file
+276 UNIMPL sys_extattr_get_file
+277 UNIMPL sys_extattr_delete_file
+278 UNIMPL sys_extattr_set_fd
+279 UNIMPL sys_extattr_get_fd
+280 UNIMPL sys_extattr_delete_fd
+#endif
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index d987b1a78ec..fc15c1619e7 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_default.c,v 1.16 2001/12/19 08:58:06 art Exp $ */
+/* $OpenBSD: vfs_default.c,v 1.17 2002/02/22 20:37:45 drahn Exp $ */
/*
@@ -310,3 +310,19 @@ lease_check(void *v)
{
return (0);
}
+/*
+ * vfs default ops
+ * used to fill the vfs fucntion table to get reasonable default return values.
+ */
+
+int
+vfs_stdextattrctl(mp, cmd, filename_vp, attrnamespace, attrname, td)
+ struct mount *mp;
+ int cmd;
+ struct vnode *filename_vp;
+ int attrnamespace;
+ const char *attrname;
+ struct proc *td;
+{
+ return(EOPNOTSUPP);
+}
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index b4aeb2e150c..7b92e02b0e6 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_syscalls.c,v 1.93 2002/02/12 18:41:21 art Exp $ */
+/* $OpenBSD: vfs_syscalls.c,v 1.94 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */
/*
@@ -54,6 +54,7 @@
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
+#include <sys/extattr.h>
#include <sys/syscallargs.h>
@@ -2804,3 +2805,408 @@ sys_pwritev(p, v, retval)
return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
&offset, retval));
}
+
+#ifdef UFS_EXTATTR
+/*
+ * Syscall to push extended attribute configuration information into the
+ * VFS. Accepts a path, which it converts to a mountpoint, as well as
+ * a command (int cmd), and attribute name and misc data. For now, the
+ * attribute name is left in userspace for consumption by the VFS_op.
+ * It will probably be changed to be copied into sysspace by the
+ * syscall in the future, once issues with various consumers of the
+ * attribute code have raised their hands.
+ *
+ * Currently this is used only by UFS Extended Attributes.
+ */
+int
+sys_extattrctl(struct proc *p, void *v, register_t *reval)
+{
+ struct sys_extattrctl_args /* {
+ syscallarg(const char *) path;
+ syscallarg(int) cmd;
+ syscallarg(const char *) filename;
+ syscallarg(int) attrnamespace;
+ syscallarg(const char *) attrname;
+ } */ *uap = v;
+ struct vnode *filename_vp;
+ struct nameidata nd;
+ struct mount *mp;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ /*
+ * SCARG(uap, attrname) not always defined. We check again later
+ * when we invoke the VFS call so as to pass in NULL there if needed.
+ */
+ if (SCARG(uap, attrname) != NULL) {
+ error = copyinstr(SCARG(uap, attrname), attrname,
+ EXTATTR_MAXNAMELEN, NULL);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * SCARG(uap, filename) not always defined. If it is, grab
+ * a vnode lock, which VFS_EXTATTRCTL() will later release.
+ */
+ filename_vp = NULL;
+ if (SCARG(uap, filename) != NULL) {
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
+ SCARG(uap, filename), p);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+ filename_vp = nd.ni_vp;
+ }
+
+ /* SCARG(uap, path) always defined. */
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ if ((error = namei(&nd)) != 0) {
+ if (filename_vp != NULL)
+ vput(filename_vp);
+ return (error);
+ }
+
+ mp = nd.ni_vp->v_mount;
+ if (error) {
+ if (filename_vp != NULL)
+ vput(filename_vp);
+ return (error);
+ }
+
+ if (SCARG(uap, attrname) != NULL) {
+ error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
+ SCARG(uap, attrnamespace), attrname, p);
+ } else {
+ error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
+ SCARG(uap, attrnamespace), NULL, p);
+ }
+
+ /*
+ * VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
+ * filename_vp, so vrele it if it is defined.
+ */
+ if (filename_vp != NULL)
+ vrele(filename_vp);
+
+ return (error);
+}
+
+/*-
+ * Set a named extended attribute on a file or directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname", userspace buffer
+ * pointer "data", buffer length "nbytes", thread "td".
+ * Returns: 0 on success, an error number otherwise
+ * Locks: none
+ * References: vp must be a valid reference for the duration of the call
+ */
+static int
+extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ void *data, size_t nbytes, struct proc *p, register_t *retval)
+{
+ struct uio auio;
+ struct iovec aiov;
+ ssize_t cnt;
+ int error;
+
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ aiov.iov_base = data;
+ aiov.iov_len = nbytes;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_offset = 0;
+ if (nbytes > INT_MAX) {
+ error = EINVAL;
+ goto done;
+ }
+ auio.uio_resid = nbytes;
+ auio.uio_rw = UIO_WRITE;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_procp = p;
+ cnt = nbytes;
+
+ error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
+ p->p_ucred, p);
+ cnt -= auio.uio_resid;
+ retval[0] = cnt;
+
+done:
+ VOP_UNLOCK(vp, 0, p);
+ return (error);
+}
+
+int
+sys_extattr_set_file(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_extattr_set_file_args /* {
+ syscallarg(const char *) path;
+ syscallarg(int) attrnamespace;
+ syscallarg(const char *) attrname;
+ syscallarg(void *) data;
+ syscallarg(size_t) nbytes;
+ } */ *uap = v;
+ struct nameidata nd;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+
+ error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
+ SCARG(uap, data), SCARG(uap, nbytes), p, retval);
+
+ vrele(nd.ni_vp);
+ return (error);
+}
+
+int
+sys_extattr_set_fd(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_extattr_set_fd_args /* {
+ syscallarg(int) fd;
+ syscallarg(int) attrnamespace;
+ syscallarg(const char *) attrname;
+ syscallarg(struct iovec *) iovp;
+ syscallarg(int) iovcnt;
+ } */ *uap = v;
+ struct file *fp;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ return (error);
+
+ FREF(fp);
+ error = extattr_set_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, SCARG(uap, data),
+ SCARG(uap, nbytes), p, retval);
+ FRELE(fp);
+
+ return (error);
+}
+
+/*-
+ * Get a named extended attribute on a file or directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname", userspace buffer
+ * pointer "data", buffer length "nbytes", thread "td".
+ * Returns: 0 on success, an error number otherwise
+ * Locks: none
+ * References: vp must be a valid reference for the duration of the call
+ */
+static int
+extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ void *data, size_t nbytes, struct proc *p, register_t *retval)
+{
+ struct uio auio;
+ struct iovec aiov;
+ ssize_t cnt;
+ size_t size;
+ int error;
+
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ /*
+ * Slightly unusual semantics: if the user provides a NULL data
+ * pointer, they don't want to receive the data, just the
+ * maximum read length.
+ */
+ if (data != NULL) {
+ aiov.iov_base = data;
+ aiov.iov_len = nbytes;
+ auio.uio_iov = &aiov;
+ auio.uio_offset = 0;
+ if (nbytes > INT_MAX) {
+ error = EINVAL;
+ goto done;
+ }
+ auio.uio_resid = nbytes;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_procp = p;
+ cnt = nbytes;
+ error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
+ NULL, p->p_ucred, p);
+ cnt -= auio.uio_resid;
+ retval[0] = cnt;
+ } else {
+ error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL,
+ &size, p->p_ucred, p);
+ retval[0] = size;
+ }
+done:
+ VOP_UNLOCK(vp, 0, p);
+ return (error);
+}
+
+int
+sys_extattr_get_file(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ struct sys_extattr_get_file_args /* {
+ syscallarg(const char *) path;
+ syscallarg(int) attrnamespace;
+ syscallarg(const char *) attrname;
+ syscallarg(void *) data;
+ syscallarg(size_t) nbytes;
+ } */ *uap = v;
+ struct nameidata nd;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+
+ error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
+ SCARG(uap, data), SCARG(uap, nbytes), p, retval);
+
+ vrele(nd.ni_vp);
+ return (error);
+}
+
+int
+sys_extattr_get_fd(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ struct sys_extattr_get_fd_args /* {
+ syscallarg(int) fd;
+ syscallarg(int) attrnamespace;
+ syscallarg(const char *) attrname;
+ syscallarg(void *) data;
+ syscallarg(size_t) nbytes;
+ } */ *uap = v;
+ struct file *fp;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ return (error);
+
+ FREF(fp);
+ error = extattr_get_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, SCARG(uap, data),
+ SCARG(uap, nbytes), p, retval);
+ FRELE(fp);
+
+ return (error);
+}
+
+/*
+ * extattr_delete_vp(): Delete a named extended attribute on a file or
+ * directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname", proc "p"
+ * Returns: 0 on success, an error number otherwise
+ * Locks: none
+ * References: vp must be a valid reference for the duration of the call
+ */
+static int
+extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ struct proc *p)
+{
+ int error;
+
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
+ p->p_ucred, p);
+
+ VOP_UNLOCK(vp, 0, p);
+ return (error);
+}
+
+int
+sys_extattr_delete_file(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ struct sys_extattr_delete_file_args /* {
+ syscallarg(int) fd;
+ syscallarg(int) attrnamespace;
+ syscallarg(const char *) attrname;
+ } */ *uap = v;
+ struct nameidata nd;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return(error);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
+ if ((error = namei(&nd)) != 0)
+ return(error);
+
+ error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
+ attrname, p);
+
+ vrele(nd.ni_vp);
+ return(error);
+}
+
+int
+sys_extattr_delete_fd(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ struct sys_extattr_delete_fd_args /* {
+ syscallarg(int) fd;
+ syscallarg(int) attrnamespace;
+ syscallarg(const char *) attrname;
+ } */ *uap = v;
+ struct file *fp;
+ char attrname[EXTATTR_MAXNAMELEN];
+ int error;
+
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
+ if (error)
+ return (error);
+
+ if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ return (error);
+
+ FREF(fp);
+ error = extattr_delete_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, p);
+ FRELE(fp);
+
+ return (error);
+}
+#endif
diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src
index a1cd5c5b9c5..4eb88e93191 100644
--- a/sys/kern/vnode_if.src
+++ b/sys/kern/vnode_if.src
@@ -1,4 +1,4 @@
-# $OpenBSD: vnode_if.src,v 1.18 2001/12/19 08:58:06 art Exp $
+# $OpenBSD: vnode_if.src,v 1.19 2002/02/22 20:37:45 drahn Exp $
# $NetBSD: vnode_if.src,v 1.10 1996/05/11 18:26:27 mycroft Exp $
#
# Copyright (c) 1992, 1993
@@ -467,3 +467,27 @@ vop_whiteout {
#vop_bwrite {
# IN struct buf *bp;
#};
+#
+#% getextattr vp L L L
+#
+vop_getextattr {
+ IN struct vnode *vp;
+ IN int attrnamespace;
+ IN const char *name;
+ INOUT struct uio *uio;
+ OUT size_t *size;
+ IN struct ucred *cred;
+ IN struct proc *p;
+};
+
+#
+#% setextattr vp L L L
+#
+vop_setextattr {
+ IN struct vnode *vp;
+ IN int attrnamespace;
+ IN const char *name;
+ INOUT struct uio *uio;
+ IN struct ucred *cred;
+ IN struct proc *p;
+};
diff --git a/sys/sys/extattr.h b/sys/sys/extattr.h
new file mode 100644
index 00000000000..90e9cfaac3a
--- /dev/null
+++ b/sys/sys/extattr.h
@@ -0,0 +1,69 @@
+/* $OpenBSD: extattr.h,v 1.1 2002/02/22 20:37:45 drahn Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * 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 AUTHOR 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 AUTHOR 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: extattr.h,v 1.6 2001/03/31 16:20:05 rwatson Exp $
+ */
+/*
+ * Userland/kernel interface for Extended File System Attributes
+ *
+ * The POSIX.1e implementation page may be reached at:
+ * http://www.watson.org/fbsd-hardening/posix1e/
+ */
+
+#ifndef _SYS_EXTATTR_H_
+#define _SYS_EXTATTR_H_
+
+#define EXTATTR_NAMESPACE_USER 0x00000001
+#define EXTATTR_NAMESPACE_USER_STRING "user"
+#define EXTATTR_NAMESPACE_SYSTEM 0x00000002
+#define EXTATTR_NAMESPACE_SYSTEM_STRING "system"
+
+#ifdef _KERNEL
+
+#define EXTATTR_MAXNAMELEN NAME_MAX
+
+#else
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int extattrctl(const char *_path, int _cmd, const char *_filename,
+ int _attrnamespace, const char *_attrname);
+int extattr_delete_fd(int _fd, int _attrnamespace, const char *_attrname);
+int extattr_delete_file(const char *_path, int _attrnamespace,
+ const char *_attrname);
+ssize_t extattr_get_fd(int _fd, int _attrnamespace, const char *_attrname,
+ void *_data, size_t _nbytes);
+ssize_t extattr_get_file(const char *_path, int _attrnamespace,
+ const char *_attrname, void *_data, size_t _nbytes);
+int extattr_set_fd(int _fd, int _attrnamespace, const char *_attrname,
+ const void *_data, size_t _nbytes);
+int extattr_set_file(const char *_path, int _attrnamespace,
+ const char *_attrname, const void *_data, size_t _nbytes);
+__END_DECLS
+
+#endif /* !_KERNEL */
+#endif /* !_SYS_EXTATTR_H_ */
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index 05e70a81a44..cb49740f3f6 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: malloc.h,v 1.54 2002/02/12 17:19:41 provos Exp $ */
+/* $OpenBSD: malloc.h,v 1.55 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: malloc.h,v 1.39 1998/07/12 19:52:01 augustss Exp $ */
/*
@@ -149,7 +149,8 @@
#define M_USBHC 103 /* USB host controller */
/* 104 - free */
#define M_MEMDESC 105 /* Memory range */
-/* 106-107 - free */
+#define M_UFS_EXTATTR 106 /* Extended Attributes */
+/* 107 - free */
#define M_CRYPTO_DATA 108 /* Crypto framework data buffers (keys etc.) */
/* 109 - free */
#define M_CREDENTIALS 110 /* IPsec-related credentials and ID info */
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index 551f22b76d7..76b52596ac5 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mount.h,v 1.43 2002/01/18 01:36:29 mickey Exp $ */
+/* $OpenBSD: mount.h,v 1.44 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: mount.h,v 1.48 1996/02/18 11:55:47 fvdl Exp $ */
/*
@@ -473,6 +473,10 @@ struct vfsops {
size_t, struct proc *));
int (*vfs_checkexp) __P((struct mount *mp, struct mbuf *nam,
int *extflagsp, struct ucred **credanonp));
+ int (*vfs_extattrctl) __P((struct mount *mp, int cmd,
+ struct vnode *filename_vp,
+ int attrnamespace, const char *attrname,
+ struct proc *p));
};
#define VFS_MOUNT(MP, PATH, DATA, NDP, P) \
@@ -489,6 +493,18 @@ struct vfsops {
#define VFS_VPTOFH(VP, FIDP) (*(VP)->v_mount->mnt_op->vfs_vptofh)(VP, FIDP)
#define VFS_CHECKEXP(MP, NAM, EXFLG, CRED) \
(*(MP)->mnt_op->vfs_checkexp)(MP, NAM, EXFLG, CRED)
+#define VFS_EXTATTRCTL(MP, C, FN, NS, N, P) \
+ (*(MP)->mnt_op->vfs_extattrctl)(MP, C, FN, NS, N, P)
+
+/*
+ * Declarations for these vfs default operations are located in
+ * kern/vfs_default.c, they should be used instead of making "dummy"
+ * functions or casting entries in the VFS op table to "enopnotsupp()".
+ */
+int vfs_stdextattrctl __P((struct mount *mp, int cmd,
+ struct vnode *filename_vp, int attrnamespace, const char *attrname,
+ struct proc *p));
+
#endif /* _KERNEL */
/*
diff --git a/sys/ufs/ext2fs/ext2fs_bmap.c b/sys/ufs/ext2fs/ext2fs_bmap.c
index 84a05ace5aa..8f247adf707 100644
--- a/sys/ufs/ext2fs/ext2fs_bmap.c
+++ b/sys/ufs/ext2fs/ext2fs_bmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ext2fs_bmap.c,v 1.6 2001/09/18 00:22:31 art Exp $ */
+/* $OpenBSD: ext2fs_bmap.c,v 1.7 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: ext2fs_bmap.c,v 1.5 2000/03/30 12:41:11 augustss Exp $ */
/*
@@ -53,6 +53,7 @@
#include <miscfs/specfs/specdev.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
diff --git a/sys/ufs/ext2fs/ext2fs_inode.c b/sys/ufs/ext2fs/ext2fs_inode.c
index 0e2a975e333..f7eac005b0d 100644
--- a/sys/ufs/ext2fs/ext2fs_inode.c
+++ b/sys/ufs/ext2fs/ext2fs_inode.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ext2fs_inode.c,v 1.19 2001/12/19 08:58:07 art Exp $ */
+/* $OpenBSD: ext2fs_inode.c,v 1.20 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: ext2fs_inode.c,v 1.24 2001/06/19 12:59:18 wiz Exp $ */
/*
@@ -51,6 +51,7 @@
#include <uvm/uvm_extern.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
diff --git a/sys/ufs/ext2fs/ext2fs_lookup.c b/sys/ufs/ext2fs/ext2fs_lookup.c
index 82bd81c7dbd..663d5ef8a83 100644
--- a/sys/ufs/ext2fs/ext2fs_lookup.c
+++ b/sys/ufs/ext2fs/ext2fs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ext2fs_lookup.c,v 1.11 2001/09/18 01:21:55 art Exp $ */
+/* $OpenBSD: ext2fs_lookup.c,v 1.12 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: ext2fs_lookup.c,v 1.16 2000/08/03 20:29:26 thorpej Exp $ */
/*
@@ -62,6 +62,7 @@
#include <sys/malloc.h>
#include <sys/dirent.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
diff --git a/sys/ufs/ext2fs/ext2fs_vfsops.c b/sys/ufs/ext2fs/ext2fs_vfsops.c
index 6f404d98157..09df6e06183 100644
--- a/sys/ufs/ext2fs/ext2fs_vfsops.c
+++ b/sys/ufs/ext2fs/ext2fs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ext2fs_vfsops.c,v 1.20 2001/12/19 08:58:07 art Exp $ */
+/* $OpenBSD: ext2fs_vfsops.c,v 1.21 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */
/*
@@ -59,6 +59,7 @@
#include <miscfs/specfs/specdev.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>
@@ -97,7 +98,8 @@ struct vfsops ext2fs_vfsops = {
ext2fs_vptofh,
ext2fs_init,
ext2fs_sysctl,
- ufs_check_export
+ ufs_check_export,
+ vfs_stdextattrctl
};
struct pool ext2fs_inode_pool;
diff --git a/sys/ufs/ext2fs/ext2fs_vnops.c b/sys/ufs/ext2fs/ext2fs_vnops.c
index d85d4eba5d9..43ef065c46f 100644
--- a/sys/ufs/ext2fs/ext2fs_vnops.c
+++ b/sys/ufs/ext2fs/ext2fs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ext2fs_vnops.c,v 1.21 2001/12/19 08:58:07 art Exp $ */
+/* $OpenBSD: ext2fs_vnops.c,v 1.22 2002/02/22 20:37:45 drahn Exp $ */
/* $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $ */
/*
@@ -65,6 +65,7 @@
#include <miscfs/fifofs/fifo.h>
#include <miscfs/specfs/specdev.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index c42897ac4d4..a8233c33036 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_alloc.c,v 1.38 2001/12/19 08:58:07 art Exp $ */
+/* $OpenBSD: ffs_alloc.c,v 1.39 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ffs_alloc.c,v 1.11 1996/05/11 18:27:09 mycroft Exp $ */
/*
@@ -49,6 +49,7 @@
#include <dev/rndvar.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
index cb6e60a956a..9ee61587054 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_inode.c,v 1.30 2002/01/04 03:53:23 nordin Exp $ */
+/* $OpenBSD: ffs_inode.c,v 1.31 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ffs_inode.c,v 1.10 1996/05/11 18:27:19 mycroft Exp $ */
/*
@@ -49,6 +49,7 @@
#include <uvm/uvm_extern.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 027a3f42693..2589c800a3c 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_softdep.c,v 1.35 2002/01/29 14:31:59 millert Exp $ */
+/* $OpenBSD: ffs_softdep.c,v 1.36 2002/02/22 20:37:46 drahn Exp $ */
/*
* Copyright 1998, 2000 Marshall Kirk McKusick. All Rights Reserved.
*
@@ -58,6 +58,7 @@
#include <sys/systm.h>
#include <sys/vnode.h>
#include <miscfs/specfs/specdev.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
diff --git a/sys/ufs/ffs/ffs_softdep_stub.c b/sys/ufs/ffs/ffs_softdep_stub.c
index 2eabe90e9b3..fb29626b96e 100644
--- a/sys/ufs/ffs/ffs_softdep_stub.c
+++ b/sys/ufs/ffs/ffs_softdep_stub.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_softdep_stub.c,v 1.3 2001/02/21 23:24:31 csapuntz Exp $ */
+/* $OpenBSD: ffs_softdep_stub.c,v 1.4 2002/02/22 20:37:46 drahn Exp $ */
/*
* Copyright 1998 Marshall Kirk McKusick. All Rights Reserved.
@@ -41,6 +41,7 @@
#include <sys/param.h>
#include <sys/vnode.h>
#include <sys/systm.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ffs/ffs_extern.h>
diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c
index 50916fca74a..b70795e06d3 100644
--- a/sys/ufs/ffs/ffs_subr.c
+++ b/sys/ufs/ffs/ffs_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_subr.c,v 1.10 2001/12/01 19:12:25 deraadt Exp $ */
+/* $OpenBSD: ffs_subr.c,v 1.11 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ffs_subr.c,v 1.6 1996/03/17 02:16:23 christos Exp $ */
/*
@@ -43,6 +43,7 @@
#include <sys/systm.h>
#include <sys/vnode.h>
#include <sys/buf.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ffs/ffs_extern.h>
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index f4374c79bec..03293113e61 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_vfsops.c,v 1.50 2002/01/25 02:30:27 millert Exp $ */
+/* $OpenBSD: ffs_vfsops.c,v 1.51 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ffs_vfsops.c,v 1.19 1996/02/09 22:22:26 christos Exp $ */
/*
@@ -58,6 +58,7 @@
#include <miscfs/specfs/specdev.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>
@@ -84,7 +85,12 @@ struct vfsops ffs_vfsops = {
ffs_vptofh,
ffs_init,
ffs_sysctl,
- ufs_check_export
+ ufs_check_export,
+#ifdef UFS_EXTATTR
+ ufs_extattrctl,
+#else
+ vfs_stdextattrctl,
+#endif
};
struct inode_vtbl ffs_vtbl = {
@@ -746,6 +752,10 @@ ffs_mountfs(devvp, mp, p)
ump->um_seqinc = fs->fs_frag;
for (i = 0; i < MAXQUOTAS; i++)
ump->um_quotas[i] = NULLVP;
+#ifdef UFS_EXTATTR
+ ufs_extattr_uepm_init(&ump->um_extattr);
+#endif
+
devvp->v_specmountpoint = mp;
ffs_oldfscompat(fs);
@@ -796,6 +806,21 @@ ffs_mountfs(devvp, mp, p)
fs->fs_flags &= ~FS_DOSOFTDEP;
(void) ffs_sbupdate(ump, MNT_WAIT);
}
+#ifdef UFS_EXTATTR
+#ifdef UFS_EXTATTR_AUTOSTART
+ /*
+ *
+ * Auto-starting does the following:
+ * - check for /.attribute in the fs, and extattr_start if so
+ * - for each file in .attribute, enable that file with
+ * an attribute of the same name.
+ * Not clear how to report errors -- probably eat them.
+ * This would all happen while the file system was busy/not
+ * available, so would effectively be "atomic".
+ */
+ (void) ufs_extattr_autostart(mp, p);
+#endif /* !UFS_EXTATTR_AUTOSTART */
+#endif /* !UFS_EXTATTR */
return (0);
out:
devvp->v_specmountpoint = NULL;
@@ -862,6 +887,15 @@ ffs_unmount(mp, mntflags, p)
ump = VFSTOUFS(mp);
fs = ump->um_fs;
+#ifdef UFS_EXTATTR
+ if ((error = ufs_extattr_stop(mp, p))) {
+ if (error != EOPNOTSUPP)
+ printf("ffs_unmount: ufs_extattr_stop returned %d\n",
+ error);
+ } else {
+ ufs_extattr_uepm_destroy(&ump->um_extattr);
+ }
+#endif
if (mp->mnt_flag & MNT_SOFTDEP)
error = softdep_flushfiles(mp, flags, p);
else
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 1020b14a2bb..8e9ce74b9ba 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_vnops.c,v 1.25 2001/12/19 08:58:07 art Exp $ */
+/* $OpenBSD: ffs_vnops.c,v 1.26 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ffs_vnops.c,v 1.7 1996/05/11 18:27:24 mycroft Exp $ */
/*
@@ -56,6 +56,7 @@
#include <miscfs/specfs/specdev.h>
#include <miscfs/fifofs/fifo.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
@@ -107,7 +108,11 @@ struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
{ &vop_advlock_desc, ufs_advlock }, /* advlock */
{ &vop_reallocblks_desc, ffs_reallocblks }, /* reallocblks */
{ &vop_bwrite_desc, vop_generic_bwrite },
- { (struct vnodeop_desc*)NULL, (int(*) __P((void*)))NULL }
+#ifdef UFS_EXTATTR
+ { &vop_getextattr_desc, ufs_vop_getextattr },
+ { &vop_setextattr_desc, ufs_vop_setextattr },
+#endif
+ { NULL, NULL }
};
struct vnodeopv_desc ffs_vnodeop_opv_desc =
{ &ffs_vnodeop_p, ffs_vnodeop_entries };
@@ -152,6 +157,10 @@ struct vnodeopv_entry_desc ffs_specop_entries[] = {
{ &vop_advlock_desc, spec_advlock }, /* advlock */
{ &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */
{ &vop_bwrite_desc, vop_generic_bwrite },
+#ifdef UFS_EXTATTR
+ { &vop_getextattr_desc, ufs_vop_getextattr },
+ { &vop_setextattr_desc, ufs_vop_setextattr },
+#endif
{ NULL, NULL }
};
struct vnodeopv_desc ffs_specop_opv_desc =
@@ -198,6 +207,10 @@ struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
{ &vop_advlock_desc, fifo_advlock }, /* advlock */
{ &vop_reallocblks_desc, fifo_reallocblks }, /* reallocblks */
{ &vop_bwrite_desc, vop_generic_bwrite },
+#ifdef UFS_EXTATTR
+ { &vop_getextattr_desc, ufs_vop_getextattr },
+ { &vop_setextattr_desc, ufs_vop_setextattr },
+#endif
{ NULL, NULL }
};
struct vnodeopv_desc ffs_fifoop_opv_desc =
diff --git a/sys/ufs/lfs/lfs_vfsops.c b/sys/ufs/lfs/lfs_vfsops.c
index 825129518c6..940918be139 100644
--- a/sys/ufs/lfs/lfs_vfsops.c
+++ b/sys/ufs/lfs/lfs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lfs_vfsops.c,v 1.13 2001/02/20 01:50:12 assar Exp $ */
+/* $OpenBSD: lfs_vfsops.c,v 1.14 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: lfs_vfsops.c,v 1.11 1996/03/25 12:53:35 pk Exp $ */
/*
@@ -77,7 +77,8 @@ struct vfsops lfs_vfsops = {
lfs_vptofh,
lfs_init,
lfs_sysctl,
- ufs_check_export
+ ufs_check_export,
+ vfs_stdextattrctl
};
int
diff --git a/sys/ufs/mfs/mfs_vfsops.c b/sys/ufs/mfs/mfs_vfsops.c
index 63259f5408e..134f3c6c2fa 100644
--- a/sys/ufs/mfs/mfs_vfsops.c
+++ b/sys/ufs/mfs/mfs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfs_vfsops.c,v 1.17 2002/02/18 09:23:26 ericj Exp $ */
+/* $OpenBSD: mfs_vfsops.c,v 1.18 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: mfs_vfsops.c,v 1.10 1996/02/09 22:31:28 christos Exp $ */
/*
@@ -48,6 +48,7 @@
#include <sys/malloc.h>
#include <sys/kthread.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
@@ -82,7 +83,8 @@ struct vfsops mfs_vfsops = {
ffs_vptofh,
mfs_init,
ffs_sysctl,
- mfs_checkexp
+ mfs_checkexp,
+ vfs_stdextattrctl
};
/*
diff --git a/sys/ufs/ufs/extattr.h b/sys/ufs/ufs/extattr.h
new file mode 100644
index 00000000000..da32ed3f57c
--- /dev/null
+++ b/sys/ufs/ufs/extattr.h
@@ -0,0 +1,109 @@
+/* $OpenBSD: extattr.h,v 1.1 2002/02/22 20:37:46 drahn Exp $ */
+/*-
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
+ * 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 AUTHOR 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 AUTHOR 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: extattr.h,v 1.14 2001/09/12 08:38:10 julian Exp $
+ */
+/*
+ * TrustedBSD Project - extended attribute support for UFS-like file systems
+ */
+
+#ifndef _UFS_UFS_EXTATTR_H_
+#define _UFS_UFS_EXTATTR_H_
+
+#define UFS_EXTATTR_MAGIC 0x00b5d5ec
+#define UFS_EXTATTR_VERSION 0x00000003
+#define UFS_EXTATTR_FSROOTSUBDIR ".attribute"
+#define UFS_EXTATTR_SUBDIR_SYSTEM "system"
+#define UFS_EXTATTR_SUBDIR_USER "user"
+#define UFS_EXTATTR_MAXEXTATTRNAME 65 /* including null */
+
+#define UFS_EXTATTR_ATTR_FLAG_INUSE 0x00000001 /* attr has been set */
+#define UFS_EXTATTR_PERM_KERNEL 0x00000000
+#define UFS_EXTATTR_PERM_ROOT 0x00000001
+#define UFS_EXTATTR_PERM_OWNER 0x00000002
+#define UFS_EXTATTR_PERM_ANYONE 0x00000003
+
+#define UFS_EXTATTR_UEPM_INITIALIZED 0x00000001
+#define UFS_EXTATTR_UEPM_STARTED 0x00000002
+
+#define UFS_EXTATTR_CMD_START 0x00000001
+#define UFS_EXTATTR_CMD_STOP 0x00000002
+#define UFS_EXTATTR_CMD_ENABLE 0x00000003
+#define UFS_EXTATTR_CMD_DISABLE 0x00000004
+
+struct ufs_extattr_fileheader {
+ u_int uef_magic; /* magic number for sanity checking */
+ u_int uef_version; /* version of attribute file */
+ u_int uef_size; /* size of attributes, w/o header */
+};
+
+struct ufs_extattr_header {
+ u_int ueh_flags; /* flags for attribute */
+ u_int ueh_len; /* local defined length; <= uef_size */
+ u_int32_t ueh_i_gen; /* generation number for sanity */
+ /* data follows the header */
+};
+
+#ifdef _KERNEL
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_EXTATTR);
+#endif
+
+struct vnode;
+LIST_HEAD(ufs_extattr_list_head, ufs_extattr_list_entry);
+struct ufs_extattr_list_entry {
+ LIST_ENTRY(ufs_extattr_list_entry) uele_entries;
+ struct ufs_extattr_fileheader uele_fileheader;
+ int uele_attrnamespace;
+ char uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME];
+ struct vnode *uele_backing_vnode;
+};
+
+struct lock;
+struct ucred;
+struct ufs_extattr_per_mount {
+ struct lock uepm_lock;
+ struct ufs_extattr_list_head uepm_list;
+ struct ucred *uepm_ucred;
+ int uepm_flags;
+};
+
+void ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm);
+void ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm);
+int ufs_extattr_start(struct mount *mp, struct proc *p);
+int ufs_extattr_autostart(struct mount *mp, struct proc *p);
+int ufs_extattr_stop(struct mount *mp, struct proc *p);
+int ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename,
+ int attrnamespace, const char *attrname, struct proc *p);
+void ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p);
+
+int ufs_vop_getextattr(void *);
+int ufs_vop_setextattr(void *);
+
+#endif /* !_KERNEL */
+
+#endif /* !_UFS_UFS_EXTATTR_H_ */
diff --git a/sys/ufs/ufs/ufs_bmap.c b/sys/ufs/ufs/ufs_bmap.c
index fa060e3c6b8..fd8b1c397b3 100644
--- a/sys/ufs/ufs/ufs_bmap.c
+++ b/sys/ufs/ufs/ufs_bmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_bmap.c,v 1.12 2001/12/19 08:58:07 art Exp $ */
+/* $OpenBSD: ufs_bmap.c,v 1.13 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ufs_bmap.c,v 1.3 1996/02/09 22:36:00 christos Exp $ */
/*
@@ -51,6 +51,7 @@
#include <miscfs/specfs/specdev.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c
new file mode 100644
index 00000000000..25f39aae254
--- /dev/null
+++ b/sys/ufs/ufs/ufs_extattr.c
@@ -0,0 +1,1338 @@
+/* $OpenBSD: ufs_extattr.c,v 1.1 2002/02/22 20:37:46 drahn Exp $ */
+/*-
+ * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
+ * Copyright (c) 2002 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by NAI Labs,
+ * the Security Research Division of Network Associates, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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: ufs_extattr.c,v 1.44 2002/02/10 04:57:08 rwatson Exp $
+ */
+/*
+ * Developed by the TrustedBSD Project.
+ * Support for file system extended attribute: UFS-specific support functions.
+ */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/fcntl.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/lock.h>
+#include <sys/dirent.h>
+#include <sys/extattr.h>
+#include <sys/sysctl.h>
+
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/ufs_extern.h>
+
+#ifdef UFS_EXTATTR
+#ifdef __OpenBSD__
+#define static
+#endif
+#ifndef LK_NOPAUSE
+#define LK_NOPAUSE 0
+#endif /* LK_NOPAUSE */
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+/* -XXX
+static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute");
+*/
+
+static int ufs_extattr_sync = 0;
+/* -XXX
+SYSCTL_INT(_debug, OID_AUTO, ufs_extattr_sync, CTLFLAG_RW, &ufs_extattr_sync,
+ 0, "");
+*/
+
+static int ufs_extattr_valid_attrname(int attrnamespace,
+ const char *attrname);
+static int ufs_extattr_credcheck(struct vnode *vp,
+ struct ufs_extattr_list_entry *uele, struct ucred *cred, struct proc *p,
+ int access);
+static int ufs_extattr_enable_with_open(struct ufsmount *ump,
+ struct vnode *vp, int attrnamespace, const char *attrname, struct proc *p);
+static int ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
+ const char *attrname, struct vnode *backing_vnode, struct proc *p);
+static int ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
+ const char *attrname, struct proc *p);
+static int ufs_extattr_get(struct vnode *vp, int attrnamespace,
+ const char *name, struct uio *uio, size_t *size, struct ucred *cred,
+ struct proc *p);
+static int ufs_extattr_set(struct vnode *vp, int attrnamespace,
+ const char *name, struct uio *uio, struct ucred *cred, struct proc *p);
+static int ufs_extattr_rm(struct vnode *vp, int attrnamespace,
+ const char *name, struct ucred *cred, struct proc *p);
+
+static void ufs_extattr_uepm_lock(struct ufsmount *ump, struct proc *p);
+static void ufs_extattr_uepm_unlock(struct ufsmount *ump, struct proc *p);
+static struct ufs_extattr_list_entry *
+ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace,
+ const char *attrname);
+/*
+ * Per-FS attribute lock protecting attribute operations.
+ * XXX Right now there is a lot of lock contention due to having a single
+ * lock per-FS; really, this should be far more fine-grained.
+ */
+static void
+ufs_extattr_uepm_lock(struct ufsmount *ump, struct proc *p)
+{
+
+ /* Ideally, LK_CANRECURSE would not be used, here. */
+ lockmgr(&ump->um_extattr.uepm_lock, LK_EXCLUSIVE | LK_RETRY |
+ LK_CANRECURSE, 0, p);
+}
+
+static void
+ufs_extattr_uepm_unlock(struct ufsmount *ump, struct proc *p)
+{
+
+ lockmgr(&ump->um_extattr.uepm_lock, LK_RELEASE, 0, p);
+}
+
+/*
+ * Determine whether the name passed is a valid name for an actual
+ * attribute.
+ *
+ * Invalid currently consists of:
+ * NULL pointer for attrname
+ * zero-length attrname (used to retrieve application attribute list)
+ */
+static int
+ufs_extattr_valid_attrname(int attrnamespace, const char *attrname)
+{
+
+ if (attrname == NULL)
+ return (0);
+ if (strlen(attrname) == 0)
+ return (0);
+ return (1);
+}
+
+/*
+ * Locate an attribute given a name and mountpoint.
+ * Must be holding uepm lock for the mount point.
+ */
+static struct ufs_extattr_list_entry *
+ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace,
+ const char *attrname)
+{
+ struct ufs_extattr_list_entry *search_attribute;
+
+ for (search_attribute = LIST_FIRST(&ump->um_extattr.uepm_list);
+ search_attribute;
+ search_attribute = LIST_NEXT(search_attribute, uele_entries)) {
+ if (!(strncmp(attrname, search_attribute->uele_attrname,
+ UFS_EXTATTR_MAXEXTATTRNAME)) &&
+ (attrnamespace == search_attribute->uele_attrnamespace)) {
+ return (search_attribute);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Initialize per-FS structures supporting extended attributes. Do not
+ * start extended attributes yet.
+ */
+void
+ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm)
+{
+
+ uepm->uepm_flags = 0;
+
+ LIST_INIT(&uepm->uepm_list);
+ /* XXX is PVFS right, here? */
+ lockinit(&uepm->uepm_lock, PVFS, "extattr", 0, 0);
+ uepm->uepm_flags |= UFS_EXTATTR_UEPM_INITIALIZED;
+}
+
+/*
+ * Destroy per-FS structures supporting extended attributes. Assumes
+ * that EAs have already been stopped, and will panic if not.
+ */
+void
+ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm)
+{
+
+ if (!(uepm->uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
+ panic("ufs_extattr_uepm_destroy: not initialized");
+
+ if ((uepm->uepm_flags & UFS_EXTATTR_UEPM_STARTED))
+ panic("ufs_extattr_uepm_destroy: called while still started");
+
+ /*
+ * It's not clear that either order for the next two lines is
+ * ideal, and it should never be a problem if this is only called
+ * during unmount, and with vfs_busy().
+ */
+ uepm->uepm_flags &= ~UFS_EXTATTR_UEPM_INITIALIZED;
+ /* - XXX
+ lockdestroy(&uepm->uepm_lock);
+ */
+}
+
+/*
+ * Start extended attribute support on an FS.
+ */
+int
+ufs_extattr_start(struct mount *mp, struct proc *p)
+{
+ struct ufsmount *ump;
+ int error = 0;
+
+ ump = VFSTOUFS(mp);
+
+ ufs_extattr_uepm_lock(ump, p);
+
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) {
+ error = EOPNOTSUPP;
+ goto unlock;
+ }
+ if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED) {
+ error = EBUSY;
+ goto unlock;
+ }
+
+ ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED;
+
+ crhold(p->p_ucred);
+ ump->um_extattr.uepm_ucred = p->p_ucred;
+
+unlock:
+ ufs_extattr_uepm_unlock(ump, p);
+
+ return (error);
+}
+
+#ifdef UFS_EXTATTR_AUTOSTART
+static int
+ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname,
+ struct vnode **vp, struct proc *p);
+/*
+ * Helper routine: given a locked parent directory and filename, return
+ * the locked vnode of the inode associated with the name. Will not
+ * follow symlinks, may return any type of vnode. Lock on parent will
+ * be released even in the event of a failure. In the event that the
+ * target is the parent (i.e., "."), there will be two references and
+ * one lock, requiring the caller to possibly special-case.
+ */
+#define UE_GETDIR_LOCKPARENT 1
+#define UE_GETDIR_LOCKPARENT_DONT 2
+static int
+ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname,
+ struct vnode **vp, struct proc *p)
+{
+ struct vop_lookup_args vargs;
+ struct componentname cnp;
+ struct vnode *target_vp;
+ int error;
+
+ bzero(&cnp, sizeof(cnp));
+ cnp.cn_nameiop = LOOKUP;
+ cnp.cn_flags = ISLASTCN;
+ if (lockparent == UE_GETDIR_LOCKPARENT)
+ cnp.cn_flags |= LOCKPARENT;
+ cnp.cn_proc = p;
+ cnp.cn_cred = p->p_ucred;
+ MALLOC(cnp.cn_pnbuf, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
+
+ cnp.cn_nameptr = cnp.cn_pnbuf;
+ error = copystr(dirname, cnp.cn_pnbuf, MAXPATHLEN,
+ (size_t *) &cnp.cn_namelen);
+ if (error) {
+ if (lockparent == UE_GETDIR_LOCKPARENT_DONT) {
+ VOP_UNLOCK(start_dvp, 0, p);
+ }
+ FREE(cnp.cn_pnbuf, M_NAMEI);
+ printf("ufs_extattr_lookup: copystr failed\n");
+ return (error);
+ }
+ cnp.cn_namelen--; /* trim nul termination */
+ vargs.a_desc = NULL;
+ vargs.a_dvp = start_dvp;
+ vargs.a_vpp = &target_vp;
+ vargs.a_cnp = &cnp;
+ error = ufs_lookup(&vargs);
+ FREE(cnp.cn_pnbuf, M_NAMEI);
+
+ if (error) {
+#if 0
+ /* -XXX does OpenBSD ufs_lookup always unlock on error? */
+ /*
+ * Error condition, may have to release the lock on the parent
+ * if ufs_lookup() didn't.
+ */
+ if (!(cnp.cn_flags & PDIRUNLOCK) &&
+ (lockparent == UE_GETDIR_LOCKPARENT_DONT))
+ VOP_UNLOCK(start_dvp, 0, p);
+
+ /*
+ * Check that ufs_lookup() didn't release the lock when we
+ * didn't want it to.
+ */
+ if ((cnp.cn_flags & PDIRUNLOCK) &&
+ (lockparent == UE_GETDIR_LOCKPARENT))
+ panic("ufs_extattr_lookup: lockparent but PDIRUNLOCK");
+#endif
+
+ return (error);
+ }
+/*
+ if (target_vp == start_dvp)
+ panic("ufs_extattr_lookup: target_vp == start_dvp");
+*/
+
+#if 0
+ /* PDIRUNLOCK does not exist on OpenBSD */
+ if (target_vp != start_dvp &&
+ !(cnp.cn_flags & PDIRUNLOCK) &&
+ (lockparent == UE_GETDIR_LOCKPARENT_DONT))
+ panic("ufs_extattr_lookup: !lockparent but !PDIRUNLOCK");
+
+ if ((cnp.cn_flags & PDIRUNLOCK) &&
+ (lockparent == UE_GETDIR_LOCKPARENT))
+ panic("ufs_extattr_lookup: lockparent but PDIRUNLOCK");
+#endif
+
+ /* printf("ufs_extattr_lookup: success\n"); */
+ *vp = target_vp;
+ return (0);
+}
+#endif /* !UFS_EXTATTR_AUTOSTART */
+
+/*
+ * Enable an EA using the passed file system, backing vnode, attribute name,
+ * namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp
+ * to be locked when passed in. The vnode will be returned unlocked,
+ * regardless of success/failure of the function. As a result, the caller
+ * will always need to vrele(), but not vput().
+ */
+static int
+ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
+ int attrnamespace, const char *attrname, struct proc *p)
+{
+ int error;
+
+ error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p);
+ if (error) {
+ printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed "
+ "with %d\n", error);
+ VOP_UNLOCK(vp, 0, p);
+ return (error);
+ }
+
+#if 0
+ /* - XXX */
+ /*
+ * XXX: Note, should VOP_CLOSE() if vfs_object_create() fails, but due
+ * to a similar piece of code in vn_open(), we don't.
+ */
+ if (vn_canvmio(vp) == TRUE)
+ if ((error = vfs_object_create(vp, p, p->p_ucred)) != 0) {
+ /*
+ * XXX: bug replicated from vn_open(): should
+ * VOP_CLOSE() here.
+ */
+ VOP_UNLOCK(vp, 0, p);
+ return (error);
+ }
+#endif
+
+ vp->v_writecount++;
+
+ vref(vp);
+
+ VOP_UNLOCK(vp, 0, p);
+
+ error = ufs_extattr_enable(ump, attrnamespace, attrname, vp, p);
+ if (error != 0)
+ vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
+ return (error);
+}
+
+#ifdef UFS_EXTATTR_AUTOSTART
+static int
+ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
+ int attrnamespace, struct proc *p);
+/*
+ * Given a locked directory vnode, iterate over the names in the directory
+ * and use ufs_extattr_lookup() to retrieve locked vnodes of potential
+ * attribute files. Then invoke ufs_extattr_enable_with_open() on each
+ * to attempt to start the attribute. Leaves the directory locked on
+ * exit.
+ */
+static int
+ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
+ int attrnamespace, struct proc *p)
+{
+ struct vop_readdir_args vargs;
+ struct dirent *dp, *edp;
+ struct vnode *attr_vp;
+ struct uio auio;
+ struct iovec aiov;
+ char *dirbuf;
+ int error, eofflag = 0;
+
+ if (dvp->v_type != VDIR)
+ return (ENOTDIR);
+
+ MALLOC(dirbuf, char *, DIRBLKSIZ, M_TEMP, M_WAITOK);
+
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_procp = p;
+ auio.uio_offset = 0;
+
+ vargs.a_desc = NULL;
+ vargs.a_vp = dvp;
+ vargs.a_uio = &auio;
+ vargs.a_cred = p->p_ucred;
+ vargs.a_eofflag = &eofflag;
+ vargs.a_ncookies = NULL;
+ vargs.a_cookies = NULL;
+
+ while (!eofflag) {
+ auio.uio_resid = DIRBLKSIZ;
+ aiov.iov_base = dirbuf;
+ aiov.iov_len = DIRBLKSIZ;
+ error = ufs_readdir(&vargs);
+ if (error) {
+ printf("ufs_extattr_iterate_directory: ufs_readdir "
+ "%d\n", error);
+ return (error);
+ }
+
+ edp = (struct dirent *)&dirbuf[DIRBLKSIZ];
+ for (dp = (struct dirent *)dirbuf; dp < edp; ) {
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+ dp->d_type = dp->d_namlen;
+ dp->d_namlen = 0;
+#else
+ dp->d_type = 0;
+#endif
+ if (dp->d_reclen == 0)
+ break;
+ error = ufs_extattr_lookup(dvp, UE_GETDIR_LOCKPARENT,
+ dp->d_name, &attr_vp, p);
+ if (error) {
+ printf("ufs_extattr_iterate_directory: lookup "
+ "%s %d\n", dp->d_name, error);
+ } else if (attr_vp == dvp) {
+ vrele(attr_vp);
+ } else if (attr_vp->v_type != VREG) {
+/*
+ * Eventually, this will be uncommented, but in the mean time, the ".."
+ * entry causes unnecessary console warnings.
+ printf("ufs_extattr_iterate_directory: "
+ "%s not VREG\n", dp->d_name);
+*/
+ vput(attr_vp);
+ } else {
+ error = ufs_extattr_enable_with_open(ump,
+ attr_vp, attrnamespace, dp->d_name, p);
+ vrele(attr_vp);
+ if (error) {
+ printf("ufs_extattr_iterate_directory: "
+ "enable %s %d\n", dp->d_name,
+ error);
+ } else {
+/*
+ * While it's nice to have some visual output here, skip for the time-being.
+ * Probably should be enabled by -v at boot.
+ printf("Autostarted %s\n", dp->d_name);
+ */
+printf("Autostarted %s\n", dp->d_name); /* XXX - debug*/
+ }
+ }
+ dp = (struct dirent *) ((char *)dp + dp->d_reclen);
+ if (dp >= edp)
+ break;
+ }
+ }
+ FREE(dirbuf, M_TEMP);
+
+ return (0);
+}
+
+/*
+ * Auto-start of extended attributes, to be executed (optionally) at
+ * mount-time.
+ */
+int
+ufs_extattr_autostart(struct mount *mp, struct proc *p)
+{
+ struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp;
+ int error;
+
+ /*
+ * Does UFS_EXTATTR_FSROOTSUBDIR exist off the file system root?
+ * If so, automatically start EA's.
+ */
+ error = VFS_ROOT(mp, &rvp);
+ if (error) {
+ printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n", error);
+ return (error);
+ }
+
+ error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT,
+ UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, p);
+ if (error) {
+ /* rvp ref'd but now unlocked */
+ vrele(rvp);
+ return (error);
+ }
+ if (rvp == attr_dvp) {
+ /* Should never happen. */
+ vrele(attr_dvp);
+ vput(rvp);
+ return (EINVAL);
+ }
+ vrele(rvp);
+
+ if (attr_dvp->v_type != VDIR) {
+ printf("ufs_extattr_autostart: %s != VDIR\n",
+ UFS_EXTATTR_FSROOTSUBDIR);
+ goto return_vput_attr_dvp;
+ }
+
+ error = ufs_extattr_start(mp, p);
+ if (error) {
+ printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n",
+ error);
+ goto return_vput_attr_dvp;
+ }
+
+ /*
+ * Look for two subdirectories: UFS_EXTATTR_SUBDIR_SYSTEM,
+ * UFS_EXTATTR_SUBDIR_USER. For each, iterate over the sub-directory,
+ * and start with appropriate type. Failures in either don't
+ * result in an over-all failure. attr_dvp is left locked to
+ * be cleaned up on exit.
+ */
+ error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT,
+ UFS_EXTATTR_SUBDIR_SYSTEM, &attr_system_dvp, p);
+ if (!error) {
+ error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
+ attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, p);
+ if (error)
+ printf("ufs_extattr_iterate_directory returned %d\n",
+ error);
+ vput(attr_system_dvp);
+ }
+
+ error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT,
+ UFS_EXTATTR_SUBDIR_USER, &attr_user_dvp, p);
+ if (!error) {
+ error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
+ attr_user_dvp, EXTATTR_NAMESPACE_USER, p);
+ if (error)
+ printf("ufs_extattr_iterate_directory returned %d\n",
+ error);
+ vput(attr_user_dvp);
+ }
+
+ /* Mask startup failures in sub-directories. */
+ error = 0;
+
+return_vput_attr_dvp:
+ vput(attr_dvp);
+
+ return (error);
+}
+#endif /* !UFS_EXTATTR_AUTOSTART */
+
+/*
+ * Stop extended attribute support on an FS.
+ */
+int
+ufs_extattr_stop(struct mount *mp, struct proc *p)
+{
+ struct ufs_extattr_list_entry *uele;
+ struct ufsmount *ump = VFSTOUFS(mp);
+ int error = 0;
+
+ ufs_extattr_uepm_lock(ump, p);
+
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
+ error = EOPNOTSUPP;
+ goto unlock;
+ }
+
+ while (LIST_FIRST(&ump->um_extattr.uepm_list) != NULL) {
+ uele = LIST_FIRST(&ump->um_extattr.uepm_list);
+ ufs_extattr_disable(ump, uele->uele_attrnamespace,
+ uele->uele_attrname, p);
+ }
+
+ ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED;
+
+ crfree(ump->um_extattr.uepm_ucred);
+ ump->um_extattr.uepm_ucred = NULL;
+
+unlock:
+ ufs_extattr_uepm_unlock(ump, p);
+
+ return (error);
+}
+
+/*
+ * Enable a named attribute on the specified file system; provide an
+ * unlocked backing vnode to hold the attribute data.
+ */
+static int
+ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
+ const char *attrname, struct vnode *backing_vnode, struct proc *p)
+{
+ struct ufs_extattr_list_entry *attribute;
+ struct iovec aiov;
+ struct uio auio;
+ int error = 0;
+
+ if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
+ return (EINVAL);
+ if (backing_vnode->v_type != VREG)
+ return (EINVAL);
+
+ MALLOC(attribute, struct ufs_extattr_list_entry *,
+ sizeof(struct ufs_extattr_list_entry), M_UFS_EXTATTR, M_WAITOK);
+ if (attribute == NULL)
+ return (ENOMEM);
+
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
+ error = EOPNOTSUPP;
+ goto free_exit;
+ }
+
+ if (ufs_extattr_find_attr(ump, attrnamespace, attrname)) {
+ error = EEXIST;
+ goto free_exit;
+ }
+
+ strncpy(attribute->uele_attrname, attrname, UFS_EXTATTR_MAXEXTATTRNAME);
+ attribute->uele_attrnamespace = attrnamespace;
+ bzero(&attribute->uele_fileheader,
+ sizeof(struct ufs_extattr_fileheader));
+
+ attribute->uele_backing_vnode = backing_vnode;
+
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ aiov.iov_base = (caddr_t) &attribute->uele_fileheader;
+ aiov.iov_len = sizeof(struct ufs_extattr_fileheader);
+ auio.uio_resid = sizeof(struct ufs_extattr_fileheader);
+ auio.uio_offset = (off_t) 0;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_rw = UIO_READ;
+ auio.uio_procp = p;
+
+ VOP_LEASE(backing_vnode, p, p->p_ucred, LEASE_WRITE);
+ vn_lock(backing_vnode, LK_SHARED | LK_NOPAUSE | LK_RETRY, p);
+ error = VOP_READ(backing_vnode, &auio, IO_NODELOCKED,
+ ump->um_extattr.uepm_ucred);
+ VOP_UNLOCK(backing_vnode, 0, p);
+
+ if (error)
+ goto free_exit;
+
+ if (auio.uio_resid != 0) {
+ printf("ufs_extattr_enable: malformed attribute header\n");
+ error = EINVAL;
+ goto free_exit;
+ }
+
+ if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) {
+ printf("ufs_extattr_enable: invalid attribute header magic\n");
+ error = EINVAL;
+ goto free_exit;
+ }
+
+ if (attribute->uele_fileheader.uef_version != UFS_EXTATTR_VERSION) {
+ printf("ufs_extattr_enable: incorrect attribute header "
+ "version\n");
+ error = EINVAL;
+ goto free_exit;
+ }
+
+ backing_vnode->v_flag |= VSYSTEM;
+ LIST_INSERT_HEAD(&ump->um_extattr.uepm_list, attribute, uele_entries);
+
+ return (0);
+
+free_exit:
+ FREE(attribute, M_UFS_EXTATTR);
+ return (error);
+}
+
+/*
+ * Disable extended attribute support on an FS.
+ */
+static int
+ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
+ const char *attrname, struct proc *p)
+{
+ struct ufs_extattr_list_entry *uele;
+ int error = 0;
+
+ if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
+ return (EINVAL);
+
+ uele = ufs_extattr_find_attr(ump, attrnamespace, attrname);
+ if (!uele)
+ return (ENOENT);
+
+ LIST_REMOVE(uele, uele_entries);
+
+ uele->uele_backing_vnode->v_flag &= ~VSYSTEM;
+ error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE, p->p_ucred, p);
+
+ FREE(uele, M_UFS_EXTATTR);
+
+ return (error);
+}
+
+/*
+ * VFS call to manage extended attributes in UFS. If filename_vp is
+ * non-NULL, it must be passed in locked, and regardless of errors in
+ * processing, will be unlocked.
+ */
+int
+ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
+ int attrnamespace, const char *attrname, struct proc *p)
+{
+ struct ufsmount *ump = VFSTOUFS(mp);
+ int error;
+
+#if 0
+ /* jail? -XXX */
+ /*
+ * Processes with privilege, but in jail, are not allowed to
+ * configure extended attributes.
+ */
+ if ((error = suser_xxx(p->p_ucred, p, 0))) {
+ if (filename_vp != NULL)
+ VOP_UNLOCK(filename_vp, 0, p);
+ return (error);
+ }
+#endif
+
+ switch(cmd) {
+ case UFS_EXTATTR_CMD_START:
+ if (filename_vp != NULL) {
+ VOP_UNLOCK(filename_vp, 0, p);
+ return (EINVAL);
+ }
+ if (attrname != NULL)
+ return (EINVAL);
+
+ error = ufs_extattr_start(mp, p);
+
+ return (error);
+
+ case UFS_EXTATTR_CMD_STOP:
+ if (filename_vp != NULL) {
+ VOP_UNLOCK(filename_vp, 0, p);
+ return (EINVAL);
+ }
+ if (attrname != NULL)
+ return (EINVAL);
+
+ error = ufs_extattr_stop(mp, p);
+
+ return (error);
+
+ case UFS_EXTATTR_CMD_ENABLE:
+
+ if (filename_vp == NULL)
+ return (EINVAL);
+ if (attrname == NULL) {
+ VOP_UNLOCK(filename_vp, 0, p);
+ return (EINVAL);
+ }
+
+ /*
+ * ufs_extattr_enable_with_open() will always unlock the
+ * vnode, regardless of failure.
+ */
+ ufs_extattr_uepm_lock(ump, p);
+ error = ufs_extattr_enable_with_open(ump, filename_vp,
+ attrnamespace, attrname, p);
+ ufs_extattr_uepm_unlock(ump, p);
+
+ return (error);
+
+ case UFS_EXTATTR_CMD_DISABLE:
+
+ if (filename_vp != NULL) {
+ VOP_UNLOCK(filename_vp, 0, p);
+ return (EINVAL);
+ }
+ if (attrname == NULL)
+ return (EINVAL);
+
+ ufs_extattr_uepm_lock(ump, p);
+ error = ufs_extattr_disable(ump, attrnamespace, attrname, p);
+ ufs_extattr_uepm_unlock(ump, p);
+
+ return (error);
+
+ default:
+ return (EINVAL);
+ }
+}
+
+/*
+ * Credential check based on process requesting service, and per-attribute
+ * permissions.
+ */
+static int
+ufs_extattr_credcheck(struct vnode *vp, struct ufs_extattr_list_entry *uele,
+ struct ucred *cred, struct proc *p, int access)
+{
+
+ /*
+ * Kernel-invoked always succeeds.
+ */
+ if (cred == NULL)
+ return (0);
+
+ /*
+ * Do not allow privileged processes in jail to directly
+ * manipulate system attributes.
+ *
+ * XXX What capability should apply here?
+ * Probably CAP_SYS_SETFFLAG.
+ */
+ switch (uele->uele_attrnamespace) {
+ case EXTATTR_NAMESPACE_SYSTEM:
+ return (suser(cred, &p->p_acflag));
+ case EXTATTR_NAMESPACE_USER:
+ return (VOP_ACCESS(vp, access, cred, p));
+ default:
+ return (EPERM);
+ }
+}
+
+/*
+ * Vnode operating to retrieve a named extended attribute.
+ */
+int
+ufs_vop_getextattr(void *v)
+{
+ struct vop_getextattr_args /* {
+ IN struct vnode *a_vp;
+ IN int a_attrnamespace;
+ IN const char *a_name;
+ INOUT struct uio *a_uio;
+ OUT struct size_t *a_size;
+ IN struct ucred *a_cred;
+ IN struct proc *a_p;
+ } */ *ap = v;
+ struct mount *mp = ap->a_vp->v_mount;
+ struct ufsmount *ump = VFSTOUFS(mp);
+ int error;
+
+ ufs_extattr_uepm_lock(ump, ap->a_p);
+
+ error = ufs_extattr_get(ap->a_vp, ap->a_attrnamespace, ap->a_name,
+ ap->a_uio, ap->a_size, ap->a_cred, ap->a_p);
+
+ ufs_extattr_uepm_unlock(ump, ap->a_p);
+
+ return (error);
+}
+
+/*
+ * Real work associated with retrieving a named attribute--assumes that
+ * the attribute lock has already been grabbed.
+ */
+static int
+ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
+ struct uio *uio, size_t *size, struct ucred *cred, struct proc *p)
+{
+ struct ufs_extattr_list_entry *attribute;
+ struct ufs_extattr_header ueh;
+ struct iovec local_aiov;
+ struct uio local_aio;
+ struct mount *mp = vp->v_mount;
+ struct ufsmount *ump = VFSTOUFS(mp);
+ struct inode *ip = VTOI(vp);
+ off_t base_offset;
+ size_t len, old_len;
+ int error = 0;
+
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
+ return (EOPNOTSUPP);
+
+ if (strlen(name) == 0) {
+ /* XXX retrieve attribute lists. */
+ /* XXX should probably be checking for name == NULL? */
+ return (EINVAL);
+ }
+
+ attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
+ if (!attribute)
+ /* XXX: ENOENT here will eventually be ENOATTR. */
+ return (ENOENT);
+
+ if ((error = ufs_extattr_credcheck(vp, attribute, cred, p, IREAD)))
+ return (error);
+
+ /*
+ * Allow only offsets of zero to encourage the read/replace
+ * extended attribute semantic. Otherwise we can't guarantee
+ * atomicity, as we don't provide locks for extended attributes.
+ */
+ if (uio != NULL && uio->uio_offset != 0)
+ return (ENXIO);
+
+ /*
+ * Find base offset of header in file based on file header size, and
+ * data header size + maximum data size, indexed by inode number.
+ */
+ base_offset = sizeof(struct ufs_extattr_fileheader) +
+ ip->i_number * (sizeof(struct ufs_extattr_header) +
+ attribute->uele_fileheader.uef_size);
+
+ /*
+ * Read in the data header to see if the data is defined, and if so
+ * how much.
+ */
+ bzero(&ueh, sizeof(struct ufs_extattr_header));
+ local_aiov.iov_base = (caddr_t) &ueh;
+ local_aiov.iov_len = sizeof(struct ufs_extattr_header);
+ local_aio.uio_iov = &local_aiov;
+ local_aio.uio_iovcnt = 1;
+ local_aio.uio_rw = UIO_READ;
+ local_aio.uio_segflg = UIO_SYSSPACE;
+ local_aio.uio_procp = p;
+ local_aio.uio_offset = base_offset;
+ local_aio.uio_resid = sizeof(struct ufs_extattr_header);
+
+ /*
+ * Acquire locks.
+ */
+ VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_READ);
+ /*
+ * Don't need to get a lock on the backing file if the getattr is
+ * being applied to the backing file, as the lock is already held.
+ */
+ if (attribute->uele_backing_vnode != vp)
+ vn_lock(attribute->uele_backing_vnode, LK_SHARED |
+ LK_NOPAUSE | LK_RETRY, p);
+
+ error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
+ IO_NODELOCKED, ump->um_extattr.uepm_ucred);
+ if (error)
+ goto vopunlock_exit;
+
+ /* Defined? */
+ if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
+ /* XXX: ENOENT here will eventually be ENOATTR. */
+ error = ENOENT;
+ goto vopunlock_exit;
+ }
+
+ /* Valid for the current inode generation? */
+ if (ueh.ueh_i_gen != ip->i_ffs_gen) {
+ /*
+ * The inode itself has a different generation number
+ * than the attribute data. For now, the best solution
+ * is to coerce this to undefined, and let it get cleaned
+ * up by the next write or extattrctl clean.
+ */
+ printf("ufs_extattr_get: inode number inconsistency (%d, %d)\n",
+ ueh.ueh_i_gen, ip->i_ffs_gen);
+ /* XXX: ENOENT here will eventually be ENOATTR. */
+ error = ENOENT;
+ goto vopunlock_exit;
+ }
+
+ /* Local size consistency check. */
+ if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
+ error = ENXIO;
+ goto vopunlock_exit;
+ }
+
+ /* Return full data size if caller requested it. */
+ if (size != NULL)
+ *size = ueh.ueh_len;
+
+ /* Return data if the caller requested it. */
+ if (uio != NULL) {
+ /* Allow for offset into the attribute data. */
+ uio->uio_offset = base_offset + sizeof(struct
+ ufs_extattr_header);
+
+ /*
+ * Figure out maximum to transfer -- use buffer size and
+ * local data limit.
+ */
+ len = MIN(uio->uio_resid, ueh.ueh_len);
+ old_len = uio->uio_resid;
+ uio->uio_resid = len;
+
+ error = VOP_READ(attribute->uele_backing_vnode, uio,
+ IO_NODELOCKED, ump->um_extattr.uepm_ucred);
+ if (error)
+ goto vopunlock_exit;
+
+ uio->uio_resid = old_len - (len - uio->uio_resid);
+ }
+
+vopunlock_exit:
+
+ if (uio != NULL)
+ uio->uio_offset = 0;
+
+ if (attribute->uele_backing_vnode != vp)
+ VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
+
+ return (error);
+}
+
+/*
+ * Vnode operation to set a named attribute.
+ */
+int
+ufs_vop_setextattr(void *v)
+{
+ struct vop_setextattr_args /* {
+ IN struct vnode *a_vp;
+ IN int a_attrnamespace;
+ IN const char *a_name;
+ INOUT struct uio *a_uio;
+ IN struct ucred *a_cred;
+ IN struct proc *a_p;
+ } */ *ap = v;
+ struct mount *mp = ap->a_vp->v_mount;
+ struct ufsmount *ump = VFSTOUFS(mp);
+
+ int error;
+
+ ufs_extattr_uepm_lock(ump, ap->a_p);
+
+ if (ap->a_uio != NULL)
+ error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace,
+ ap->a_name, ap->a_uio, ap->a_cred, ap->a_p);
+ else
+ error = ufs_extattr_rm(ap->a_vp, ap->a_attrnamespace,
+ ap->a_name, ap->a_cred, ap->a_p);
+
+ ufs_extattr_uepm_unlock(ump, ap->a_p);
+
+ return (error);
+}
+
+/*
+ * Real work associated with setting a vnode's extended attributes;
+ * assumes that the attribute lock has already been grabbed.
+ */
+static int
+ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
+ struct uio *uio, struct ucred *cred, struct proc *p)
+{
+ struct ufs_extattr_list_entry *attribute;
+ struct ufs_extattr_header ueh;
+ struct iovec local_aiov;
+ struct uio local_aio;
+ struct mount *mp = vp->v_mount;
+ struct ufsmount *ump = VFSTOUFS(mp);
+ struct inode *ip = VTOI(vp);
+ off_t base_offset;
+ int error = 0, ioflag;
+
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
+ return (EOPNOTSUPP);
+ if (!ufs_extattr_valid_attrname(attrnamespace, name))
+ return (EINVAL);
+
+ attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
+ if (!attribute)
+ /* XXX: ENOENT here will eventually be ENOATTR. */
+ return (ENOENT);
+
+ if ((error = ufs_extattr_credcheck(vp, attribute, cred, p, IWRITE)))
+ return (error);
+
+ /*
+ * Early rejection of invalid offsets/length.
+ * Reject: any offset but 0 (replace)
+ * Any size greater than attribute size limit
+ */
+ if (uio->uio_offset != 0 ||
+ uio->uio_resid > attribute->uele_fileheader.uef_size)
+ return (ENXIO);
+
+ /*
+ * Find base offset of header in file based on file header size, and
+ * data header size + maximum data size, indexed by inode number.
+ */
+ base_offset = sizeof(struct ufs_extattr_fileheader) +
+ ip->i_number * (sizeof(struct ufs_extattr_header) +
+ attribute->uele_fileheader.uef_size);
+
+ /*
+ * Write out a data header for the data.
+ */
+ ueh.ueh_len = uio->uio_resid;
+ ueh.ueh_flags = UFS_EXTATTR_ATTR_FLAG_INUSE;
+ ueh.ueh_i_gen = ip->i_ffs_gen;
+ local_aiov.iov_base = (caddr_t) &ueh;
+ local_aiov.iov_len = sizeof(struct ufs_extattr_header);
+ local_aio.uio_iov = &local_aiov;
+ local_aio.uio_iovcnt = 1;
+ local_aio.uio_rw = UIO_WRITE;
+ local_aio.uio_segflg = UIO_SYSSPACE;
+ local_aio.uio_procp = p;
+ local_aio.uio_offset = base_offset;
+ local_aio.uio_resid = sizeof(struct ufs_extattr_header);
+
+ /*
+ * Acquire locks.
+ */
+ VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_WRITE);
+
+ /*
+ * Don't need to get a lock on the backing file if the setattr is
+ * being applied to the backing file, as the lock is already held.
+ */
+ if (attribute->uele_backing_vnode != vp)
+ vn_lock(attribute->uele_backing_vnode,
+ LK_EXCLUSIVE | LK_NOPAUSE | LK_RETRY, p);
+
+ ioflag = IO_NODELOCKED;
+ if (ufs_extattr_sync)
+ ioflag |= IO_SYNC;
+ error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
+ ump->um_extattr.uepm_ucred);
+ if (error)
+ goto vopunlock_exit;
+
+ if (local_aio.uio_resid != 0) {
+ error = ENXIO;
+ goto vopunlock_exit;
+ }
+
+ /*
+ * Write out user data.
+ */
+ uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);
+
+ ioflag = IO_NODELOCKED;
+ if (ufs_extattr_sync)
+ ioflag |= IO_SYNC;
+ error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag,
+ ump->um_extattr.uepm_ucred);
+
+vopunlock_exit:
+ uio->uio_offset = 0;
+
+ if (attribute->uele_backing_vnode != vp)
+ VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
+
+ return (error);
+}
+
+/*
+ * Real work associated with removing an extended attribute from a vnode.
+ * Assumes the attribute lock has already been grabbed.
+ */
+static int
+ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name,
+ struct ucred *cred, struct proc *p)
+{
+ struct ufs_extattr_list_entry *attribute;
+ struct ufs_extattr_header ueh;
+ struct iovec local_aiov;
+ struct uio local_aio;
+ struct mount *mp = vp->v_mount;
+ struct ufsmount *ump = VFSTOUFS(mp);
+ struct inode *ip = VTOI(vp);
+ off_t base_offset;
+ int error = 0, ioflag;
+
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
+ return (EOPNOTSUPP);
+ if (!ufs_extattr_valid_attrname(attrnamespace, name))
+ return (EINVAL);
+
+ attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
+ if (!attribute)
+ /* XXX: ENOENT here will eventually be ENOATTR. */
+ return (ENOENT);
+
+ if ((error = ufs_extattr_credcheck(vp, attribute, cred, p, IWRITE)))
+ return (error);
+
+ /*
+ * Find base offset of header in file based on file header size, and
+ * data header size + maximum data size, indexed by inode number.
+ */
+ base_offset = sizeof(struct ufs_extattr_fileheader) +
+ ip->i_number * (sizeof(struct ufs_extattr_header) +
+ attribute->uele_fileheader.uef_size);
+
+ /*
+ * Check to see if currently defined.
+ */
+ bzero(&ueh, sizeof(struct ufs_extattr_header));
+
+ local_aiov.iov_base = (caddr_t) &ueh;
+ local_aiov.iov_len = sizeof(struct ufs_extattr_header);
+ local_aio.uio_iov = &local_aiov;
+ local_aio.uio_iovcnt = 1;
+ local_aio.uio_rw = UIO_READ;
+ local_aio.uio_segflg = UIO_SYSSPACE;
+ local_aio.uio_procp = p;
+ local_aio.uio_offset = base_offset;
+ local_aio.uio_resid = sizeof(struct ufs_extattr_header);
+
+ VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_WRITE);
+
+ /*
+ * Don't need to get the lock on the backing vnode if the vnode we're
+ * modifying is it, as we already hold the lock.
+ */
+ if (attribute->uele_backing_vnode != vp)
+ vn_lock(attribute->uele_backing_vnode,
+ LK_EXCLUSIVE | LK_NOPAUSE | LK_RETRY, p);
+
+ error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
+ IO_NODELOCKED, ump->um_extattr.uepm_ucred);
+ if (error)
+ goto vopunlock_exit;
+
+ /* Defined? */
+ if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
+ /* XXX: ENOENT here will eventually be ENOATTR. */
+ error = ENOENT;
+ goto vopunlock_exit;
+ }
+
+ /* Valid for the current inode generation? */
+ if (ueh.ueh_i_gen != ip->i_ffs_gen) {
+ /*
+ * The inode itself has a different generation number than
+ * the attribute data. For now, the best solution is to
+ * coerce this to undefined, and let it get cleaned up by
+ * the next write or extattrctl clean.
+ */
+ printf("ufs_extattr_rm: inode number inconsistency (%d, %d)\n",
+ ueh.ueh_i_gen, ip->i_ffs_gen);
+ /* XXX: ENOENT here will eventually be ENOATTR. */
+ error = ENOENT;
+ goto vopunlock_exit;
+ }
+
+ /* Flag it as not in use. */
+ ueh.ueh_flags = 0;
+ ueh.ueh_len = 0;
+
+ local_aiov.iov_base = (caddr_t) &ueh;
+ local_aiov.iov_len = sizeof(struct ufs_extattr_header);
+ local_aio.uio_iov = &local_aiov;
+ local_aio.uio_iovcnt = 1;
+ local_aio.uio_rw = UIO_WRITE;
+ local_aio.uio_segflg = UIO_SYSSPACE;
+ local_aio.uio_procp = p;
+ local_aio.uio_offset = base_offset;
+ local_aio.uio_resid = sizeof(struct ufs_extattr_header);
+
+ ioflag = IO_NODELOCKED;
+ if (ufs_extattr_sync)
+ ioflag |= IO_SYNC;
+ error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
+ ump->um_extattr.uepm_ucred);
+ if (error)
+ goto vopunlock_exit;
+
+ if (local_aio.uio_resid != 0)
+ error = ENXIO;
+
+vopunlock_exit:
+ VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
+
+ return (error);
+}
+
+/*
+ * Called by UFS when an inode is no longer active and should have its
+ * attributes stripped.
+ */
+void
+ufs_extattr_vnode_inactive(struct vnode *vp, struct proc *p)
+{
+ struct ufs_extattr_list_entry *uele;
+ struct mount *mp = vp->v_mount;
+ struct ufsmount *ump = VFSTOUFS(mp);
+
+ /*
+ * In that case, we cannot lock. We should not have any active vnodes
+ * on the fs if this is not yet initialized but is going to be, so
+ * this can go unlocked.
+ */
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
+ return;
+
+ ufs_extattr_uepm_lock(ump, p);
+
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
+ ufs_extattr_uepm_unlock(ump, p);
+ return;
+ }
+
+ LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries)
+ ufs_extattr_rm(vp, uele->uele_attrnamespace,
+ uele->uele_attrname, NULL, p);
+
+ ufs_extattr_uepm_unlock(ump, p);
+}
+
+#endif /* !UFS_EXTATTR */
diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c
index dd2c6574d30..cdcbd6ecb6f 100644
--- a/sys/ufs/ufs/ufs_inode.c
+++ b/sys/ufs/ufs/ufs_inode.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_inode.c,v 1.16 2001/12/19 08:58:07 art Exp $ */
+/* $OpenBSD: ufs_inode.c,v 1.17 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ufs_inode.c,v 1.7 1996/05/11 18:27:52 mycroft Exp $ */
/*
@@ -50,6 +50,7 @@
#include <sys/malloc.h>
#include <sys/namei.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index b7d5802ddc8..1d3f46edf38 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_lookup.c,v 1.18 2001/11/06 19:53:21 miod Exp $ */
+/* $OpenBSD: ufs_lookup.c,v 1.19 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ufs_lookup.c,v 1.7 1996/02/09 22:36:06 christos Exp $ */
/*
@@ -53,6 +53,7 @@
#include <uvm/uvm_extern.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c
index a2fe18d2753..ab7ff29b562 100644
--- a/sys/ufs/ufs/ufs_quota.c
+++ b/sys/ufs/ufs/ufs_quota.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_quota.c,v 1.10 2002/02/20 18:40:49 csapuntz Exp $ */
+/* $OpenBSD: ufs_quota.c,v 1.11 2002/02/22 20:37:46 drahn Exp $ */
/* $NetBSD: ufs_quota.c,v 1.8 1996/02/09 22:36:09 christos Exp $ */
/*
@@ -48,6 +48,7 @@
#include <sys/vnode.h>
#include <sys/mount.h>
+#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>