diff options
-rw-r--r-- | sys/kern/syscalls.master | 8 | ||||
-rw-r--r-- | sys/kern/vfs_extattr.c | 287 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 287 | ||||
-rw-r--r-- | sys/sys/extattr.h | 21 |
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 */ |