Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_extattr.c
Show First 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", | * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", | ||||
* kernelspace string pointer "attrname", userspace buffer | * kernelspace string pointer "attrname", userspace buffer | ||||
* pointer "data", buffer length "nbytes", thread "td". | * pointer "data", buffer length "nbytes", thread "td". | ||||
* Returns: 0 on success, an error number otherwise | * Returns: 0 on success, an error number otherwise | ||||
* Locks: none | * Locks: none | ||||
* References: vp must be a valid reference for the duration of the call | * References: vp must be a valid reference for the duration of the call | ||||
*/ | */ | ||||
static int | int | ||||
extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, | extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, | ||||
void *data, size_t nbytes, struct thread *td) | void *data, size_t nbytes, enum uio_seg segflg, struct thread *td) | ||||
{ | { | ||||
struct mount *mp; | struct mount *mp; | ||||
struct uio auio; | struct uio auio; | ||||
struct iovec aiov; | struct iovec aiov; | ||||
ssize_t cnt; | ssize_t cnt; | ||||
int error; | int error; | ||||
error = vn_start_write(vp, &mp, V_WAIT | PCATCH); | error = vn_start_write(vp, &mp, V_WAIT | PCATCH); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | ||||
aiov.iov_base = data; | aiov.iov_base = data; | ||||
aiov.iov_len = nbytes; | aiov.iov_len = nbytes; | ||||
auio.uio_iov = &aiov; | auio.uio_iov = &aiov; | ||||
auio.uio_iovcnt = 1; | auio.uio_iovcnt = 1; | ||||
auio.uio_offset = 0; | auio.uio_offset = 0; | ||||
if (nbytes > IOSIZE_MAX) { | if (nbytes > IOSIZE_MAX) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto done; | goto done; | ||||
} | } | ||||
auio.uio_resid = nbytes; | auio.uio_resid = nbytes; | ||||
auio.uio_rw = UIO_WRITE; | auio.uio_rw = UIO_WRITE; | ||||
auio.uio_segflg = UIO_USERSPACE; | auio.uio_segflg = segflg; | ||||
auio.uio_td = td; | auio.uio_td = td; | ||||
cnt = nbytes; | cnt = nbytes; | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace, | error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace, | ||||
attrname); | attrname); | ||||
if (error) | if (error) | ||||
goto done; | goto done; | ||||
Show All 34 Lines | sys_extattr_set_fd(td, uap) | ||||
AUDIT_ARG_TEXT(attrname); | AUDIT_ARG_TEXT(attrname); | ||||
error = getvnode(td, uap->fd, | error = getvnode(td, uap->fd, | ||||
cap_rights_init(&rights, CAP_EXTATTR_SET), &fp); | cap_rights_init(&rights, CAP_EXTATTR_SET), &fp); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
error = extattr_set_vp(fp->f_vnode, uap->attrnamespace, | error = extattr_set_vp(fp->f_vnode, uap->attrnamespace, | ||||
attrname, uap->data, uap->nbytes, td); | attrname, uap->data, uap->nbytes, UIO_USERSPACE, td); | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_extattr_set_file(td, uap) | sys_extattr_set_file(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
Show All 18 Lines | sys_extattr_set_file(td, uap) | ||||
NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, | NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, | ||||
uap->path, td); | uap->path, td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, | error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, | ||||
uap->data, uap->nbytes, td); | uap->data, uap->nbytes, UIO_USERSPACE, td); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_extattr_set_link(td, uap) | sys_extattr_set_link(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
Show All 18 Lines | sys_extattr_set_link(td, uap) | ||||
NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, | NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, | ||||
uap->path, td); | uap->path, td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, | error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, | ||||
uap->data, uap->nbytes, td); | uap->data, uap->nbytes, UIO_USERSPACE, td); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
/*- | /*- | ||||
* 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", | * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", | ||||
* kernelspace string pointer "attrname", userspace buffer | * kernelspace string pointer "attrname", userspace buffer | ||||
* pointer "data", buffer length "nbytes", thread "td". | * pointer "data", buffer length "nbytes", thread "td". | ||||
* Returns: 0 on success, an error number otherwise | * Returns: 0 on success, an error number otherwise | ||||
* Locks: none | * Locks: none | ||||
* References: vp must be a valid reference for the duration of the call | * References: vp must be a valid reference for the duration of the call | ||||
*/ | */ | ||||
static int | int | ||||
extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, | extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, | ||||
void *data, size_t nbytes, struct thread *td) | void *data, size_t nbytes, enum uio_seg segflg, struct thread *td) | ||||
{ | { | ||||
struct uio auio, *auiop; | struct uio auio, *auiop; | ||||
struct iovec aiov; | struct iovec aiov; | ||||
ssize_t cnt; | ssize_t cnt; | ||||
size_t size, *sizep; | size_t size, *sizep; | ||||
int error; | int error; | ||||
vn_lock(vp, LK_SHARED | LK_RETRY); | vn_lock(vp, LK_SHARED | LK_RETRY); | ||||
Show All 13 Lines | if (data != NULL) { | ||||
auio.uio_iovcnt = 1; | auio.uio_iovcnt = 1; | ||||
auio.uio_offset = 0; | auio.uio_offset = 0; | ||||
if (nbytes > IOSIZE_MAX) { | if (nbytes > IOSIZE_MAX) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto done; | goto done; | ||||
} | } | ||||
auio.uio_resid = nbytes; | auio.uio_resid = nbytes; | ||||
auio.uio_rw = UIO_READ; | auio.uio_rw = UIO_READ; | ||||
auio.uio_segflg = UIO_USERSPACE; | auio.uio_segflg = segflg; | ||||
auio.uio_td = td; | auio.uio_td = td; | ||||
auiop = &auio; | auiop = &auio; | ||||
cnt = nbytes; | cnt = nbytes; | ||||
} else | } else | ||||
sizep = &size; | sizep = &size; | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace, | error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace, | ||||
Show All 40 Lines | sys_extattr_get_fd(td, uap) | ||||
AUDIT_ARG_TEXT(attrname); | AUDIT_ARG_TEXT(attrname); | ||||
error = getvnode(td, uap->fd, | error = getvnode(td, uap->fd, | ||||
cap_rights_init(&rights, CAP_EXTATTR_GET), &fp); | cap_rights_init(&rights, CAP_EXTATTR_GET), &fp); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
error = extattr_get_vp(fp->f_vnode, uap->attrnamespace, | error = extattr_get_vp(fp->f_vnode, uap->attrnamespace, | ||||
attrname, uap->data, uap->nbytes, td); | attrname, uap->data, uap->nbytes, UIO_USERSPACE, td); | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_extattr_get_file(td, uap) | sys_extattr_get_file(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
Show All 17 Lines | sys_extattr_get_file(td, uap) | ||||
NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td); | NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, | error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, | ||||
uap->data, uap->nbytes, td); | uap->data, uap->nbytes, UIO_USERSPACE, td); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_extattr_get_link(td, uap) | sys_extattr_get_link(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
Show All 18 Lines | sys_extattr_get_link(td, uap) | ||||
NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, | NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, | ||||
td); | td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, | error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, | ||||
uap->data, uap->nbytes, td); | uap->data, uap->nbytes, UIO_USERSPACE, td); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* extattr_delete_vp(): Delete a named extended attribute on a file or | * extattr_delete_vp(): Delete a named extended attribute on a file or | ||||
* directory | * directory | ||||
* | * | ||||
* Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", | * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", | ||||
* kernelspace string pointer "attrname", proc "p" | * kernelspace string pointer "attrname", proc "p" | ||||
* Returns: 0 on success, an error number otherwise | * Returns: 0 on success, an error number otherwise | ||||
* Locks: none | * Locks: none | ||||
* References: vp must be a valid reference for the duration of the call | * References: vp must be a valid reference for the duration of the call | ||||
*/ | */ | ||||
static int | int | ||||
extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, | extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, | ||||
struct thread *td) | struct thread *td) | ||||
{ | { | ||||
struct mount *mp; | struct mount *mp; | ||||
int error; | int error; | ||||
error = vn_start_write(vp, &mp, V_WAIT | PCATCH); | error = vn_start_write(vp, &mp, V_WAIT | PCATCH); | ||||
if (error) | if (error) | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace", | * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace", | ||||
* userspace buffer pointer "data", buffer length "nbytes", | * userspace buffer pointer "data", buffer length "nbytes", | ||||
* thread "td". | * thread "td". | ||||
* Returns: 0 on success, an error number otherwise | * Returns: 0 on success, an error number otherwise | ||||
* Locks: none | * Locks: none | ||||
* References: vp must be a valid reference for the duration of the call | * References: vp must be a valid reference for the duration of the call | ||||
*/ | */ | ||||
static int | int | ||||
extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, | extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, | ||||
size_t nbytes, struct thread *td) | size_t nbytes, enum uio_seg segflg, struct thread *td) | ||||
{ | { | ||||
struct uio auio, *auiop; | struct uio auio, *auiop; | ||||
size_t size, *sizep; | size_t size, *sizep; | ||||
struct iovec aiov; | struct iovec aiov; | ||||
ssize_t cnt; | ssize_t cnt; | ||||
int error; | int error; | ||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | ||||
auiop = NULL; | auiop = NULL; | ||||
sizep = NULL; | sizep = NULL; | ||||
cnt = 0; | cnt = 0; | ||||
if (data != NULL) { | if (data != NULL) { | ||||
aiov.iov_base = data; | aiov.iov_base = data; | ||||
aiov.iov_len = nbytes; | aiov.iov_len = nbytes; | ||||
auio.uio_iov = &aiov; | auio.uio_iov = &aiov; | ||||
auio.uio_iovcnt = 1; | auio.uio_iovcnt = 1; | ||||
auio.uio_offset = 0; | auio.uio_offset = 0; | ||||
if (nbytes > IOSIZE_MAX) { | if (nbytes > IOSIZE_MAX) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto done; | goto done; | ||||
} | } | ||||
auio.uio_resid = nbytes; | auio.uio_resid = nbytes; | ||||
auio.uio_rw = UIO_READ; | auio.uio_rw = UIO_READ; | ||||
auio.uio_segflg = UIO_USERSPACE; | auio.uio_segflg = segflg; | ||||
auio.uio_td = td; | auio.uio_td = td; | ||||
auiop = &auio; | auiop = &auio; | ||||
cnt = nbytes; | cnt = nbytes; | ||||
} else | } else | ||||
sizep = &size; | sizep = &size; | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace); | error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace); | ||||
Show All 10 Lines | #endif | ||||
} else | } else | ||||
td->td_retval[0] = size; | td->td_retval[0] = size; | ||||
done: | done: | ||||
VOP_UNLOCK(vp, 0); | VOP_UNLOCK(vp, 0); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_extattr_list_fd(td, uap) | sys_extattr_list_fd(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
struct extattr_list_fd_args /* { | struct extattr_list_fd_args /* { | ||||
int fd; | int fd; | ||||
int attrnamespace; | int attrnamespace; | ||||
void *data; | void *data; | ||||
size_t nbytes; | size_t nbytes; | ||||
} */ *uap; | } */ *uap; | ||||
{ | { | ||||
struct file *fp; | struct file *fp; | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
int error; | int error; | ||||
AUDIT_ARG_FD(uap->fd); | AUDIT_ARG_FD(uap->fd); | ||||
AUDIT_ARG_VALUE(uap->attrnamespace); | AUDIT_ARG_VALUE(uap->attrnamespace); | ||||
error = getvnode(td, uap->fd, | error = getvnode(td, uap->fd, | ||||
cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp); | cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data, | error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data, | ||||
uap->nbytes, td); | uap->nbytes, UIO_USERSPACE, td); | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_extattr_list_file(td, uap) | sys_extattr_list_file(td, uap) | ||||
struct thread*td; | struct thread*td; | ||||
Show All 10 Lines | sys_extattr_list_file(td, uap) | ||||
AUDIT_ARG_VALUE(uap->attrnamespace); | AUDIT_ARG_VALUE(uap->attrnamespace); | ||||
NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td); | NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, | error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, | ||||
uap->nbytes, td); | uap->nbytes, UIO_USERSPACE, td); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
sys_extattr_list_link(td, uap) | sys_extattr_list_link(td, uap) | ||||
struct thread*td; | struct thread*td; | ||||
Show All 11 Lines | sys_extattr_list_link(td, uap) | ||||
NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, | NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, | ||||
td); | td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, | error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, | ||||
uap->nbytes, td); | uap->nbytes, UIO_USERSPACE, td); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
} | } |