Changeset View
Changeset View
Standalone View
Standalone View
head/sys/fs/fuse/fuse_vnops.c
Show First 20 Lines • Show All 2,219 Lines • ▼ Show 20 Lines | while (pos < list_len && list[pos] != '\0') { | ||||
pos += dist_to_next; | pos += dist_to_next; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* List extended attributes | |||||
* | |||||
* The FUSE_LISTXATTR operation is based on Linux's listxattr(2) syscall, which | |||||
* has a number of differences compared to its FreeBSD equivalent, | |||||
* extattr_list_file: | |||||
* | |||||
* - FUSE_LISTXATTR returns all extended attributes across all namespaces, | |||||
* whereas listxattr(2) only returns attributes for a single namespace | |||||
* - FUSE_LISTXATTR prepends each attribute name with "namespace." | |||||
* - If the provided buffer is not large enough to hold the result, | |||||
* FUSE_LISTXATTR should return ERANGE, whereas listxattr is expected to | |||||
* return as many results as will fit. | |||||
*/ | |||||
/* | |||||
struct vop_listextattr_args { | struct vop_listextattr_args { | ||||
struct vop_generic_args a_gen; | struct vop_generic_args a_gen; | ||||
struct vnode *a_vp; | struct vnode *a_vp; | ||||
int a_attrnamespace; | int a_attrnamespace; | ||||
struct uio *a_uio; | struct uio *a_uio; | ||||
size_t *a_size; | size_t *a_size; | ||||
struct ucred *a_cred; | struct ucred *a_cred; | ||||
struct thread *a_td; | struct thread *a_td; | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | if (linux_list_len == 0) { | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* Retrieve Linux / FUSE compatible list values. | * Retrieve Linux / FUSE compatible list values. | ||||
*/ | */ | ||||
fdisp_refresh_vp(&fdi, FUSE_LISTXATTR, vp, td, cred); | fdisp_refresh_vp(&fdi, FUSE_LISTXATTR, vp, td, cred); | ||||
list_xattr_in = fdi.indata; | list_xattr_in = fdi.indata; | ||||
list_xattr_in->size = linux_list_len + sizeof(*list_xattr_out); | list_xattr_in->size = linux_list_len; | ||||
err = fdisp_wait_answ(&fdi); | err = fdisp_wait_answ(&fdi); | ||||
if (err != 0) | if (err == ERANGE) { | ||||
/* | |||||
* Race detected. The attribute list must've grown since the | |||||
* first FUSE_LISTXATTR call. Start over. Go all the way back | |||||
* to userland so we can process signals, if necessary, before | |||||
* restarting. | |||||
*/ | |||||
err = ERESTART; | |||||
goto out; | goto out; | ||||
} else if (err != 0) | |||||
goto out; | |||||
linux_list = fdi.answ; | linux_list = fdi.answ; | ||||
/* FUSE doesn't allow the server to return more data than requested */ | |||||
if (fdi.iosize > linux_list_len) { | |||||
printf("WARNING: FUSE protocol violation. Server returned " | |||||
"more extended attribute data than requested; " | |||||
"should've returned ERANGE instead"); | |||||
} else { | |||||
/* But returning less data is fine */ | |||||
linux_list_len = fdi.iosize; | linux_list_len = fdi.iosize; | ||||
} | |||||
/* | /* | ||||
* Retrieve the BSD compatible list values. | * Retrieve the BSD compatible list values. | ||||
* The Linux / FUSE attribute list format isn't the same | * The Linux / FUSE attribute list format isn't the same | ||||
* as FreeBSD's format. So we need to transform it into | * as FreeBSD's format. So we need to transform it into | ||||
* FreeBSD's format before giving it to the user. | * FreeBSD's format before giving it to the user. | ||||
*/ | */ | ||||
bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK); | bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK); | ||||
▲ Show 20 Lines • Show All 142 Lines • Show Last 20 Lines |