summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/syscalls.master8
-rw-r--r--sys/kern/vfs_extattr.c287
-rw-r--r--sys/kern/vfs_syscalls.c287
-rw-r--r--sys/sys/extattr.h21
4 files changed, 447 insertions, 156 deletions
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 4130ff6..aec2ea6 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -533,3 +533,11 @@
368 STD BSD { int __cap_set_fd(int fd, struct cap *cap_p); }
369 STD BSD { int __cap_set_file(const char *path_p, struct cap *cap_p); }
370 NODEF NOHIDE lkmressys lkmressys nosys_args int
+371 STD BSD { int extattr_set_fd(int fd, int attrnamespace, \
+ const char *attrname, struct iovec *iovp, \
+ int iovcnt); }
+372 STD BSD { int extattr_get_fd(int fd, int attrnamespace, \
+ const char *attrname, struct iovec *iovp, \
+ int iovcnt); }
+373 STD BSD { int extattr_delete_fd(int fd, int attrnamespace, \
+ const char *attrname); }
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 407d685..6b73258 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -3745,38 +3745,34 @@ extattrctl(p, uap)
}
/*
- * Syscall to set a named extended attribute on a file or directory.
- * Accepts attribute name, and a uio structure pointing to the data to set.
- * The uio is consumed in the style of writev(). The real work happens
- * in VOP_SETEXTATTR().
+ * extattr_set_vp(): Set a named extended attribute on a file or directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname",
+ * userspace iovec array pointer "iovp", unsigned int iovcnt
+ * 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
*/
-int
-extattr_set_file(p, uap)
- struct proc *p;
- struct extattr_set_file_args *uap;
+static int
+extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ struct iovec *iovp, unsigned iovcnt, struct proc *p)
{
- struct nameidata nd;
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
- char attrname[EXTATTR_MAXNAMELEN];
u_int iovlen, cnt;
int error, i;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
- if (error)
- return (error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
- if ((error = namei(&nd)) != 0)
- return(error);
- if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
- NDFREE(&nd, 0);
+ if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
- }
- iovlen = uap->iovcnt * sizeof(struct iovec);
- if (uap->iovcnt > UIO_SMALLIOV) {
- if (uap->iovcnt > UIO_MAXIOV) {
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ iovlen = iovcnt * sizeof(struct iovec);
+ if (iovcnt > UIO_SMALLIOV) {
+ if (iovcnt > UIO_MAXIOV) {
error = EINVAL;
goto done;
}
@@ -3785,15 +3781,15 @@ extattr_set_file(p, uap)
} else
iov = aiov;
auio.uio_iov = iov;
- auio.uio_iovcnt = uap->iovcnt;
+ auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
- if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
+ if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
- for (i = 0; i < uap->iovcnt; i++) {
+ for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
@@ -3802,65 +3798,111 @@ extattr_set_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
- error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- &auio, p->p_cred->pc_ucred, p);
+ error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
+ p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
- NDFREE(&nd, 0);
+ VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
-/*
- * Syscall to get a named extended attribute on a file or directory.
- * Accepts attribute name, and a uio structure pointing to a buffer for the
- * data. The uio is consumed in the style of readv(). The real work
- * happens in VOP_GETEXTATTR();
- */
int
-extattr_get_file(p, uap)
+extattr_set_file(p, uap)
struct proc *p;
- struct extattr_get_file_args *uap;
+ struct extattr_set_file_args *uap;
{
struct nameidata nd;
- struct uio auio;
- struct iovec *iov, *needfree, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
- u_int iovlen, cnt;
- int error, i;
+ int error;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
if (error)
return (error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
- iovlen = uap->iovcnt * sizeof (struct iovec);
- if (uap->iovcnt > UIO_SMALLIOV) {
- if (uap->iovcnt > UIO_MAXIOV) {
- NDFREE(&nd, 0);
- return (EINVAL);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
+ SCARG(uap, iovp), SCARG(uap, iovcnt), p);
+
+ vrele(nd.ni_vp);
+ return (error);
+}
+
+int
+extattr_set_fd(p, uap)
+ struct proc *p;
+ struct extattr_set_fd_args *uap;
+{
+ 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);
+
+ error = extattr_set_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
+ SCARG(uap, iovcnt), p);
+
+ return (error);
+}
+
+/*
+ * extattr_get_vp(): Get a named extended attribute on a file or directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname",
+ * userspace iovec array pointer "iovp", unsigned int iovcnt,
+ * 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_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ struct iovec *iovp, unsigned iovcnt, struct proc *p)
+{
+ struct uio auio;
+ struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
+ u_int iovlen, cnt;
+ int error, i;
+
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ iovlen = iovcnt * sizeof (struct iovec);
+ if (iovcnt > UIO_SMALLIOV) {
+ if (iovcnt > UIO_MAXIOV) {
+ error = EINVAL;
+ goto done;
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
- } else {
+ } else
iov = aiov;
- needfree = NULL;
- }
auio.uio_iov = iov;
- auio.uio_iovcnt = uap->iovcnt;
+ auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
- if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
+ if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
- for (i = 0; i < uap->iovcnt; i++) {
+ for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
@@ -3869,45 +3911,142 @@ extattr_get_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
- error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- &auio, p->p_cred->pc_ucred, p);
+ error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
+ p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
- NDFREE(&nd, 0);
- return(error);
+ VOP_UNLOCK(vp, 0, p);
+ return (error);
+}
+
+int
+extattr_get_file(p, uap)
+ struct proc *p;
+ struct extattr_get_file_args *uap;
+{
+ 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);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
+ SCARG(uap, iovp), SCARG(uap, iovcnt), p);
+
+ vrele(nd.ni_vp);
+ return (error);
+}
+
+int
+extattr_get_fd(p, uap)
+ struct proc *p;
+ struct extattr_get_fd_args *uap;
+{
+ 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);
+
+ error = extattr_get_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
+ SCARG(uap, iovcnt), p);
+
+ return (error);
}
/*
- * Syscall to delete a named extended attribute from a file or directory.
- * Accepts attribute name. The real work happens in VOP_SETEXTATTR().
+ * 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)
+{
+ struct mount *mp;
+ int error;
+
+ if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
+ return (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_cred->pc_ucred, p);
+
+ VOP_UNLOCK(vp, 0, p);
+ vn_finished_write(mp);
+ return (error);
+}
+
int
extattr_delete_file(p, uap)
struct proc *p;
struct extattr_delete_file_args *uap;
{
- struct mount *mp;
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
- int error;
+ int error;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
if (error)
return(error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
- if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
- NDFREE(&nd, 0);
- return (error);
- }
- error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- NULL, p->p_cred->pc_ucred, p);
- NDFREE(&nd, 0);
- vn_finished_write(mp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
+ attrname, p);
+
+ vrele(nd.ni_vp);
return(error);
}
+
+int
+extattr_delete_fd(p, uap)
+ struct proc *p;
+ struct extattr_delete_fd_args *uap;
+{
+ 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);
+
+ error = extattr_delete_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, p);
+
+ return (error);
+}
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 407d685..6b73258 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -3745,38 +3745,34 @@ extattrctl(p, uap)
}
/*
- * Syscall to set a named extended attribute on a file or directory.
- * Accepts attribute name, and a uio structure pointing to the data to set.
- * The uio is consumed in the style of writev(). The real work happens
- * in VOP_SETEXTATTR().
+ * extattr_set_vp(): Set a named extended attribute on a file or directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname",
+ * userspace iovec array pointer "iovp", unsigned int iovcnt
+ * 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
*/
-int
-extattr_set_file(p, uap)
- struct proc *p;
- struct extattr_set_file_args *uap;
+static int
+extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ struct iovec *iovp, unsigned iovcnt, struct proc *p)
{
- struct nameidata nd;
struct mount *mp;
struct uio auio;
struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
- char attrname[EXTATTR_MAXNAMELEN];
u_int iovlen, cnt;
int error, i;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
- if (error)
- return (error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
- if ((error = namei(&nd)) != 0)
- return(error);
- if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
- NDFREE(&nd, 0);
+ if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
return (error);
- }
- iovlen = uap->iovcnt * sizeof(struct iovec);
- if (uap->iovcnt > UIO_SMALLIOV) {
- if (uap->iovcnt > UIO_MAXIOV) {
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ iovlen = iovcnt * sizeof(struct iovec);
+ if (iovcnt > UIO_SMALLIOV) {
+ if (iovcnt > UIO_MAXIOV) {
error = EINVAL;
goto done;
}
@@ -3785,15 +3781,15 @@ extattr_set_file(p, uap)
} else
iov = aiov;
auio.uio_iov = iov;
- auio.uio_iovcnt = uap->iovcnt;
+ auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
- if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
+ if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
- for (i = 0; i < uap->iovcnt; i++) {
+ for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
@@ -3802,65 +3798,111 @@ extattr_set_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
- error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- &auio, p->p_cred->pc_ucred, p);
+ error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
+ p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
- NDFREE(&nd, 0);
+ VOP_UNLOCK(vp, 0, p);
vn_finished_write(mp);
return (error);
}
-/*
- * Syscall to get a named extended attribute on a file or directory.
- * Accepts attribute name, and a uio structure pointing to a buffer for the
- * data. The uio is consumed in the style of readv(). The real work
- * happens in VOP_GETEXTATTR();
- */
int
-extattr_get_file(p, uap)
+extattr_set_file(p, uap)
struct proc *p;
- struct extattr_get_file_args *uap;
+ struct extattr_set_file_args *uap;
{
struct nameidata nd;
- struct uio auio;
- struct iovec *iov, *needfree, aiov[UIO_SMALLIOV];
char attrname[EXTATTR_MAXNAMELEN];
- u_int iovlen, cnt;
- int error, i;
+ int error;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
if (error)
return (error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return (error);
- iovlen = uap->iovcnt * sizeof (struct iovec);
- if (uap->iovcnt > UIO_SMALLIOV) {
- if (uap->iovcnt > UIO_MAXIOV) {
- NDFREE(&nd, 0);
- return (EINVAL);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
+ SCARG(uap, iovp), SCARG(uap, iovcnt), p);
+
+ vrele(nd.ni_vp);
+ return (error);
+}
+
+int
+extattr_set_fd(p, uap)
+ struct proc *p;
+ struct extattr_set_fd_args *uap;
+{
+ 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);
+
+ error = extattr_set_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
+ SCARG(uap, iovcnt), p);
+
+ return (error);
+}
+
+/*
+ * extattr_get_vp(): Get a named extended attribute on a file or directory
+ *
+ * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
+ * kernelspace string pointer "attrname",
+ * userspace iovec array pointer "iovp", unsigned int iovcnt,
+ * 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_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
+ struct iovec *iovp, unsigned iovcnt, struct proc *p)
+{
+ struct uio auio;
+ struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
+ u_int iovlen, cnt;
+ int error, i;
+
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ iovlen = iovcnt * sizeof (struct iovec);
+ if (iovcnt > UIO_SMALLIOV) {
+ if (iovcnt > UIO_MAXIOV) {
+ error = EINVAL;
+ goto done;
}
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
- } else {
+ } else
iov = aiov;
- needfree = NULL;
- }
auio.uio_iov = iov;
- auio.uio_iovcnt = uap->iovcnt;
+ auio.uio_iovcnt = iovcnt;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
auio.uio_offset = 0;
- if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
+ if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
goto done;
auio.uio_resid = 0;
- for (i = 0; i < uap->iovcnt; i++) {
+ for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - auio.uio_resid) {
error = EINVAL;
goto done;
@@ -3869,45 +3911,142 @@ extattr_get_file(p, uap)
iov++;
}
cnt = auio.uio_resid;
- error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- &auio, p->p_cred->pc_ucred, p);
+ error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
+ p->p_cred->pc_ucred, p);
cnt -= auio.uio_resid;
p->p_retval[0] = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
- NDFREE(&nd, 0);
- return(error);
+ VOP_UNLOCK(vp, 0, p);
+ return (error);
+}
+
+int
+extattr_get_file(p, uap)
+ struct proc *p;
+ struct extattr_get_file_args *uap;
+{
+ 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);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
+ SCARG(uap, iovp), SCARG(uap, iovcnt), p);
+
+ vrele(nd.ni_vp);
+ return (error);
+}
+
+int
+extattr_get_fd(p, uap)
+ struct proc *p;
+ struct extattr_get_fd_args *uap;
+{
+ 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);
+
+ error = extattr_get_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
+ SCARG(uap, iovcnt), p);
+
+ return (error);
}
/*
- * Syscall to delete a named extended attribute from a file or directory.
- * Accepts attribute name. The real work happens in VOP_SETEXTATTR().
+ * 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)
+{
+ struct mount *mp;
+ int error;
+
+ if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
+ return (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_cred->pc_ucred, p);
+
+ VOP_UNLOCK(vp, 0, p);
+ vn_finished_write(mp);
+ return (error);
+}
+
int
extattr_delete_file(p, uap)
struct proc *p;
struct extattr_delete_file_args *uap;
{
- struct mount *mp;
struct nameidata nd;
char attrname[EXTATTR_MAXNAMELEN];
- int error;
+ int error;
- error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
+ error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
+ NULL);
if (error)
return(error);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), p);
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
if ((error = namei(&nd)) != 0)
return(error);
- if ((error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH)) != 0) {
- NDFREE(&nd, 0);
- return (error);
- }
- error = VOP_SETEXTATTR(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
- NULL, p->p_cred->pc_ucred, p);
- NDFREE(&nd, 0);
- vn_finished_write(mp);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+
+ error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
+ attrname, p);
+
+ vrele(nd.ni_vp);
return(error);
}
+
+int
+extattr_delete_fd(p, uap)
+ struct proc *p;
+ struct extattr_delete_fd_args *uap;
+{
+ 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);
+
+ error = extattr_delete_vp((struct vnode *)fp->f_data,
+ SCARG(uap, attrnamespace), attrname, p);
+
+ return (error);
+}
diff --git a/sys/sys/extattr.h b/sys/sys/extattr.h
index dbde540..d53ab03 100644
--- a/sys/sys/extattr.h
+++ b/sys/sys/extattr.h
@@ -57,14 +57,19 @@
struct iovec;
__BEGIN_DECLS
-int extattrctl(const char *path, int cmd, const char *filename,
- int attrnamespace, const char *attrname);
-int extattr_delete_file(const char *path, int attrnamespace,
- const char *attrname);
-int extattr_get_file(const char *path, int attrnamespace,
- const char *attrname, struct iovec *iovp, unsigned iovcnt);
-int extattr_set_file(const char *path, int attrnamespace,
- const char *attrname, struct iovec *iovp, unsigned iovcnt);
+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);
+int extattr_get_fd(int _fd, int _attrnamespace, const char *_attrname,
+ struct iovec *_iovp, unsigned _iovcnt);
+int extattr_get_file(const char *_path, int _attrnamespace,
+ const char *_attrname, struct iovec *_iovp, unsigned _iovcnt);
+int extattr_set_fd(int _fd, int _attrnamespace, const char *_attrname,
+ struct iovec *_iovp, unsigned _iovcnt);
+int extattr_set_file(const char *_path, int _attrnamespace,
+ const char *_attrname, struct iovec *_iovp, unsigned _iovcnt);
__END_DECLS
#endif /* !_KERNEL */
OpenPOWER on IntegriCloud