diff options
-rw-r--r-- | sys/fs/pseudofs/pseudofs.h | 2 | ||||
-rw-r--r-- | sys/fs/pseudofs/pseudofs_vnops.c | 2 | ||||
-rw-r--r-- | sys/kern/syscalls.master | 15 | ||||
-rw-r--r-- | sys/kern/vfs_extattr.c | 141 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 141 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 3 | ||||
-rw-r--r-- | sys/kern/vnode_if.src | 1 | ||||
-rw-r--r-- | sys/security/lomac/lomacfs_vnops.c | 3 | ||||
-rw-r--r-- | sys/sys/extattr.h | 12 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_extattr.c | 51 |
10 files changed, 171 insertions, 200 deletions
diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h index ba0a93b..4017978 100644 --- a/sys/fs/pseudofs/pseudofs.h +++ b/sys/fs/pseudofs/pseudofs.h @@ -138,7 +138,7 @@ typedef int (*pfs_ioctl_t)(PFS_IOCTL_ARGS); #define PFS_GETEXTATTR_ARGS \ struct thread *td, struct proc *p, struct pfs_node *pn, \ int attrnamespace, const char *name, struct uio *uio, \ - struct ucred *cred + size_t *size, struct ucred *cred #define PFS_GETEXTATTR_PROTO(name) \ int name(PFS_GETEXTATTR_ARGS); struct ucred; diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c index 0c8bdc3..42662ea 100644 --- a/sys/fs/pseudofs/pseudofs_vnops.c +++ b/sys/fs/pseudofs/pseudofs_vnops.c @@ -283,7 +283,7 @@ pfs_getextattr(struct vop_getextattr_args *va) } error = (pn->pn_getextattr)(curthread, proc, pn, va->a_attrnamespace, - va->a_name, va->a_uio, va->a_cred); + va->a_name, va->a_uio, va->a_size, va->a_cred); if (proc != NULL) PRELE(proc); diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 92aecac..c534546 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -513,10 +513,10 @@ const char *attrname); } 356 STD BSD { int extattr_set_file(const char *path, \ int attrnamespace, const char *attrname, \ - struct iovec *iovp, unsigned iovcnt); } -357 STD BSD { int extattr_get_file(const char *path, \ + void *data, size_t nbytes); } +357 STD BSD { ssize_t extattr_get_file(const char *path, \ int attrnamespace, const char *attrname, \ - struct iovec *iovp, unsigned iovcnt); } + void *data, size_t nbytes); } 358 STD BSD { int extattr_delete_file(const char *path, \ int attrnamespace, const char *attrname); } 359 NOSTD BSD { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); } @@ -535,11 +535,10 @@ 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); } + const char *attrname, void *data, \ + size_t nbytes); } +372 STD BSD { ssize_t extattr_get_fd(int fd, int attrnamespace, \ + const char *attrname, void *data, size_t nbytes); } 373 STD BSD { int extattr_delete_fd(int fd, int attrnamespace, \ const char *attrname); } 374 MSTD BSD { int __setugid(int flag); } diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 0500dde..67cec3e 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -3993,67 +3993,52 @@ extattrctl(td, uap) return (error); } -/* - * extattr_set_vp(): Set a named extended attribute on a file or directory +/*- + * 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" + * 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, - struct iovec *iovp, unsigned iovcnt, struct thread *td) + const void *data, size_t nbytes, struct thread *td) { struct mount *mp; struct uio auio; - struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; - u_int iovlen, cnt; - int error, i; + struct iovec aiov; + ssize_t cnt; + int error; if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) return (error); VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - 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_WRITE; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_td = td; + aiov.iov_base = data; + aiov.iov_len = nbytes; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; auio.uio_offset = 0; - if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen))) + if (nbytes > INT_MAX) { + error = EINVAL; 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; + auio.uio_resid = nbytes; + auio.uio_rw = UIO_WRITE; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_td = td; + cnt = nbytes; + error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, td->td_proc->p_ucred, td); cnt -= auio.uio_resid; td->td_retval[0] = cnt; + done: - if (needfree) - FREE(needfree, M_IOV); VOP_UNLOCK(vp, 0, td); vn_finished_write(mp); return (error); @@ -4079,7 +4064,7 @@ extattr_set_file(td, uap) NDFREE(&nd, NDF_ONLY_PNBUF); error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, - SCARG(uap, iovp), SCARG(uap, iovcnt), td); + SCARG(uap, data), SCARG(uap, nbytes), td); vrele(nd.ni_vp); return (error); @@ -4103,71 +4088,65 @@ extattr_set_fd(td, uap) return (error); error = extattr_set_vp((struct vnode *)fp->f_data, - SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp), - SCARG(uap, iovcnt), td); + SCARG(uap, attrnamespace), attrname, SCARG(uap, data), + SCARG(uap, nbytes), td); fdrop(fp, td); return (error); } -/* - * extattr_get_vp(): Get a named extended attribute on a file or directory +/*- + * 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" + * 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, - struct iovec *iovp, unsigned iovcnt, struct thread *td) + void *data, size_t nbytes, struct thread *td) { struct uio auio; - struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; - u_int iovlen, cnt; - int error, i; + struct iovec aiov; + ssize_t cnt; + size_t size; + int error; VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_READ); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - 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_td = td; - 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) { + /* + * 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 += iov->iov_len; - iov++; + auio.uio_resid = nbytes; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_td = td; + cnt = nbytes; + error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, + NULL, td->td_proc->p_ucred, td); + cnt -= auio.uio_resid; + td->td_retval[0] = cnt; + } else { + error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, + &size, td->td_proc->p_ucred, td); + td->td_retval[0] = size; } - cnt = auio.uio_resid; - error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, - td->td_proc->p_ucred, td); - cnt -= auio.uio_resid; - td->td_retval[0] = cnt; done: - if (needfree) - FREE(needfree, M_IOV); VOP_UNLOCK(vp, 0, td); return (error); } @@ -4192,7 +4171,7 @@ extattr_get_file(td, uap) NDFREE(&nd, NDF_ONLY_PNBUF); error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, - SCARG(uap, iovp), SCARG(uap, iovcnt), td); + SCARG(uap, data), SCARG(uap, nbytes), td); vrele(nd.ni_vp); return (error); @@ -4216,8 +4195,8 @@ extattr_get_fd(td, uap) return (error); error = extattr_get_vp((struct vnode *)fp->f_data, - SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp), - SCARG(uap, iovcnt), td); + SCARG(uap, attrnamespace), attrname, SCARG(uap, data), + SCARG(uap, nbytes), td); fdrop(fp, td); return (error); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 0500dde..67cec3e 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -3993,67 +3993,52 @@ extattrctl(td, uap) return (error); } -/* - * extattr_set_vp(): Set a named extended attribute on a file or directory +/*- + * 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" + * 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, - struct iovec *iovp, unsigned iovcnt, struct thread *td) + const void *data, size_t nbytes, struct thread *td) { struct mount *mp; struct uio auio; - struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; - u_int iovlen, cnt; - int error, i; + struct iovec aiov; + ssize_t cnt; + int error; if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) return (error); VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - 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_WRITE; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_td = td; + aiov.iov_base = data; + aiov.iov_len = nbytes; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; auio.uio_offset = 0; - if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen))) + if (nbytes > INT_MAX) { + error = EINVAL; 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; + auio.uio_resid = nbytes; + auio.uio_rw = UIO_WRITE; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_td = td; + cnt = nbytes; + error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, td->td_proc->p_ucred, td); cnt -= auio.uio_resid; td->td_retval[0] = cnt; + done: - if (needfree) - FREE(needfree, M_IOV); VOP_UNLOCK(vp, 0, td); vn_finished_write(mp); return (error); @@ -4079,7 +4064,7 @@ extattr_set_file(td, uap) NDFREE(&nd, NDF_ONLY_PNBUF); error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, - SCARG(uap, iovp), SCARG(uap, iovcnt), td); + SCARG(uap, data), SCARG(uap, nbytes), td); vrele(nd.ni_vp); return (error); @@ -4103,71 +4088,65 @@ extattr_set_fd(td, uap) return (error); error = extattr_set_vp((struct vnode *)fp->f_data, - SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp), - SCARG(uap, iovcnt), td); + SCARG(uap, attrnamespace), attrname, SCARG(uap, data), + SCARG(uap, nbytes), td); fdrop(fp, td); return (error); } -/* - * extattr_get_vp(): Get a named extended attribute on a file or directory +/*- + * 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" + * 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, - struct iovec *iovp, unsigned iovcnt, struct thread *td) + void *data, size_t nbytes, struct thread *td) { struct uio auio; - struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; - u_int iovlen, cnt; - int error, i; + struct iovec aiov; + ssize_t cnt; + size_t size; + int error; VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_READ); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - 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_td = td; - 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) { + /* + * 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 += iov->iov_len; - iov++; + auio.uio_resid = nbytes; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_td = td; + cnt = nbytes; + error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, + NULL, td->td_proc->p_ucred, td); + cnt -= auio.uio_resid; + td->td_retval[0] = cnt; + } else { + error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, + &size, td->td_proc->p_ucred, td); + td->td_retval[0] = size; } - cnt = auio.uio_resid; - error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, - td->td_proc->p_ucred, td); - cnt -= auio.uio_resid; - td->td_retval[0] = cnt; done: - if (needfree) - FREE(needfree, M_IOV); VOP_UNLOCK(vp, 0, td); return (error); } @@ -4192,7 +4171,7 @@ extattr_get_file(td, uap) NDFREE(&nd, NDF_ONLY_PNBUF); error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, - SCARG(uap, iovp), SCARG(uap, iovcnt), td); + SCARG(uap, data), SCARG(uap, nbytes), td); vrele(nd.ni_vp); return (error); @@ -4216,8 +4195,8 @@ extattr_get_fd(td, uap) return (error); error = extattr_get_vp((struct vnode *)fp->f_data, - SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp), - SCARG(uap, iovcnt), td); + SCARG(uap, attrnamespace), attrname, SCARG(uap, data), + SCARG(uap, nbytes), td); fdrop(fp, td); return (error); diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index c411bfc..d7c4bc8 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -905,7 +905,8 @@ vn_extattr_get(struct vnode *vp, int ioflg, int attrnamespace, vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* authorize attribute retrieval as kernel */ - error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, NULL, td); + error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, NULL, NULL, + td); if ((ioflg & IO_NODELOCKED) == 0) VOP_UNLOCK(vp, 0, td); diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index 43ff6b5..460d5b8 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -512,6 +512,7 @@ vop_getextattr { IN int attrnamespace; IN const char *name; INOUT struct uio *uio; + OUT size_t *size; IN struct ucred *cred; IN struct thread *td; }; diff --git a/sys/security/lomac/lomacfs_vnops.c b/sys/security/lomac/lomacfs_vnops.c index ca4a188..fb1c3f4 100644 --- a/sys/security/lomac/lomacfs_vnops.c +++ b/sys/security/lomac/lomacfs_vnops.c @@ -1053,6 +1053,7 @@ lomacfs_getextattr( int a_attrnamespace; const char *a_name; struct uio *a_uio; + size_t *a_size; struct ucred *a_cred; struct thread *a_td; } */ *ap @@ -1065,7 +1066,7 @@ lomacfs_getextattr( return (EPERM); else return (VOP_GETEXTATTR(VTOLVP(ap->a_vp), ap->a_attrnamespace, - ap->a_name, ap->a_uio, ap->a_cred, ap->a_td)); + ap->a_name, ap->a_uio, ap->a_size, ap->a_cred, ap->a_td)); } static int diff --git a/sys/sys/extattr.h b/sys/sys/extattr.h index bca21bd..2d65624 100644 --- a/sys/sys/extattr.h +++ b/sys/sys/extattr.h @@ -55,14 +55,14 @@ int extattrctl(const char *_path, int _cmd, const char *_filename, 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); +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, - struct iovec *_iovp, unsigned _iovcnt); + const void *_data, size_t _nbytes); int extattr_set_file(const char *_path, int _attrnamespace, - const char *_attrname, struct iovec *_iovp, unsigned _iovcnt); + const char *_attrname, const void *_data, size_t _nbytes); __END_DECLS #endif /* !_KERNEL */ diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c index 71ed166..34e0bed 100644 --- a/sys/ufs/ufs/ufs_extattr.c +++ b/sys/ufs/ufs/ufs_extattr.c @@ -80,7 +80,8 @@ static int ufs_extattr_enable(struct ufsmount *ump, int attrnamespace, static int ufs_extattr_disable(struct ufsmount *ump, int attrnamespace, const char *attrname, struct thread *td); static int ufs_extattr_get(struct vnode *vp, int attrnamespace, - const char *name, struct uio *uio, struct ucred *cred, struct thread *td); + const char *name, struct uio *uio, size_t *size, struct ucred *cred, + struct thread *td); static int ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name, struct uio *uio, struct ucred *cred, struct thread *td); static int ufs_extattr_rm(struct vnode *vp, int attrnamespace, @@ -825,6 +826,7 @@ vop_getextattr { 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 thread *a_td; }; @@ -837,7 +839,7 @@ vop_getextattr { ufs_extattr_uepm_lock(ump, ap->a_td); error = ufs_extattr_get(ap->a_vp, ap->a_attrnamespace, ap->a_name, - ap->a_uio, ap->a_cred, ap->a_td); + ap->a_uio, ap->a_size, ap->a_cred, ap->a_td); ufs_extattr_uepm_unlock(ump, ap->a_td); @@ -850,7 +852,7 @@ vop_getextattr { */ static int ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name, - struct uio *uio, struct ucred *cred, struct thread *td) + struct uio *uio, size_t *size, struct ucred *cred, struct thread *td) { struct ufs_extattr_list_entry *attribute; struct ufs_extattr_header ueh; @@ -860,7 +862,7 @@ ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name, struct ufsmount *ump = VFSTOUFS(mp); struct inode *ip = VTOI(vp); off_t base_offset; - size_t size, old_size; + size_t len, old_len; int error = 0; if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) @@ -885,7 +887,7 @@ ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name, * extended attribute semantic. Otherwise we can't guarantee * atomicity, as we don't provide locks for extended attributes. */ - if (uio->uio_offset != 0) + if (uio != NULL && uio->uio_offset != 0) return (ENXIO); /* @@ -956,27 +958,36 @@ ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name, goto vopunlock_exit; } - /* Allow for offset into the attribute data. */ - uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header); + /* Return full data size if caller requested it. */ + if (size != NULL) + *size = ueh.ueh_len; - /* - * Figure out maximum to transfer -- use buffer size and local data - * limit. - */ - size = MIN(uio->uio_resid, ueh.ueh_len); - old_size = uio->uio_resid; - uio->uio_resid = size; + /* 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); - error = VOP_READ(attribute->uele_backing_vnode, uio, - IO_NODELOCKED, ump->um_extattr.uepm_ucred); - if (error) - goto vopunlock_exit; + /* + * 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; - uio->uio_resid = old_size - (size - uio->uio_resid); + 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: - uio->uio_offset = 0; + if (uio != NULL) + uio->uio_offset = 0; if (attribute->uele_backing_vnode != vp) VOP_UNLOCK(attribute->uele_backing_vnode, 0, td); |