diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 4130ff635fd1..aec2ea6706ba 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 407d6851449b..6b73258f0684 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) + if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 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); - 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,112 +3798,255 @@ 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); } +int +extattr_set_file(p, uap) + struct proc *p; + struct extattr_set_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_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); +} + /* - * 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(); + * 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 + iov = aiov; + auio.uio_iov = iov; + 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)iovp, (caddr_t)iov, iovlen))) + goto done; + auio.uio_resid = 0; + for (i = 0; i < iovcnt; i++) { + if (iov->iov_len > INT_MAX - auio.uio_resid) { + error = EINVAL; + goto done; + } + auio.uio_resid += iov->iov_len; + iov++; + } + cnt = auio.uio_resid; + 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); + 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; - 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); - } - MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); - needfree = iov; - } else { - iov = aiov; - needfree = NULL; - } - auio.uio_iov = iov; - auio.uio_iovcnt = uap->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))) - goto done; - auio.uio_resid = 0; - for (i = 0; i < uap->iovcnt; i++) { - if (iov->iov_len > INT_MAX - auio.uio_resid) { - error = EINVAL; - goto done; - } - auio.uio_resid += iov->iov_len; - iov++; - } - cnt = auio.uio_resid; - error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, 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); + 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 407d6851449b..6b73258f0684 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) + if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 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); - 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,112 +3798,255 @@ 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); } +int +extattr_set_file(p, uap) + struct proc *p; + struct extattr_set_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_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); +} + /* - * 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(); + * 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 + iov = aiov; + auio.uio_iov = iov; + 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)iovp, (caddr_t)iov, iovlen))) + goto done; + auio.uio_resid = 0; + for (i = 0; i < iovcnt; i++) { + if (iov->iov_len > INT_MAX - auio.uio_resid) { + error = EINVAL; + goto done; + } + auio.uio_resid += iov->iov_len; + iov++; + } + cnt = auio.uio_resid; + 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); + 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; - 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); - } - MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); - needfree = iov; - } else { - iov = aiov; - needfree = NULL; - } - auio.uio_iov = iov; - auio.uio_iovcnt = uap->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))) - goto done; - auio.uio_resid = 0; - for (i = 0; i < uap->iovcnt; i++) { - if (iov->iov_len > INT_MAX - auio.uio_resid) { - error = EINVAL; - goto done; - } - auio.uio_resid += iov->iov_len; - iov++; - } - cnt = auio.uio_resid; - error = VOP_GETEXTATTR(nd.ni_vp, SCARG(uap, 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); + 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 dbde54082539..d53ab0302f81 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 */