Index: head/sys/fs/fuse/fuse_kernel.h =================================================================== --- head/sys/fs/fuse/fuse_kernel.h +++ head/sys/fs/fuse/fuse_kernel.h @@ -282,11 +282,16 @@ __u32 padding; }; -struct fuse_setxattr_in { +struct fuse_listxattr_in { __u32 size; __u32 flags; }; +struct fuse_listxattr_out { + __u32 size; + __u32 flags; +}; + struct fuse_getxattr_in { __u32 size; __u32 padding; @@ -295,6 +300,11 @@ struct fuse_getxattr_out { __u32 size; __u32 padding; +}; + +struct fuse_setxattr_in { + __u32 size; + __u32 flags; }; struct fuse_lk_in { Index: head/sys/fs/fuse/fuse_vnops.c =================================================================== --- head/sys/fs/fuse/fuse_vnops.c +++ head/sys/fs/fuse/fuse_vnops.c @@ -2047,7 +2047,7 @@ * fuse_getxattr_out. If we pass in a non-zero size, we get back * that much data, without the struct fuse_getxattr_out header. */ - if (ap->a_size != NULL) + if (uio == NULL) get_xattr_in->size = 0; else get_xattr_in->size = uio->uio_resid; @@ -2065,25 +2065,13 @@ goto out; } - /* - * If we get to this point (i.e. no error), we should have a valid - * answer of some sort. i.e. non-zero iosize and a valid pointer. - */ - if ((fdi.answ == NULL) || (fdi.iosize == 0)) { - debug_printf("getxattr: err = 0, but answ = %p, iosize = %zu\n", - fdi.answ, fdi.iosize); - err = EINVAL; - goto out; - } get_xattr_out = fdi.answ; - if (ap->a_size != NULL) { + if (ap->a_size != NULL) *ap->a_size = get_xattr_out->size; - } else if (fdi.iosize > 0) { + + if (uio != NULL) err = uiomove(fdi.answ, fdi.iosize, uio); - } else { - err = EINVAL; - } out: fdisp_destroy(&fdi); @@ -2233,14 +2221,16 @@ struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct fuse_dispatcher fdi = {0}; - struct fuse_getxattr_in *get_xattr_in; - struct fuse_getxattr_out *get_xattr_out; + struct fuse_listxattr_in *list_xattr_in; + struct fuse_listxattr_out *list_xattr_out; struct mount *mp = vnode_mount(vp); size_t len; char *prefix; char *attr_str; char *bsd_list = NULL; + char *linux_list; int bsd_list_len; + int linux_list_len; struct thread *td = ap->a_td; struct ucred *cred = ap->a_cred; int err = 0; @@ -2261,17 +2251,15 @@ len = strlen(prefix) + sizeof(extattr_namespace_separator) + 1; - fdisp_init(&fdi, sizeof(*get_xattr_in) + len); + fdisp_init(&fdi, sizeof(*list_xattr_in) + len); fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred); - get_xattr_in = fdi.indata; - if (ap->a_size != NULL) - get_xattr_in->size = 0; - else - get_xattr_in->size = uio->uio_resid + sizeof(*get_xattr_out); - - - attr_str = (char *)fdi.indata + sizeof(*get_xattr_in); + /* + * Retrieve Linux / FUSE compatible list size. + */ + list_xattr_in = fdi.indata; + list_xattr_in->size = 0; + attr_str = (char *)fdi.indata + sizeof(*list_xattr_in); snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator); err = fdisp_wait_answ(&fdi); @@ -2282,32 +2270,47 @@ goto out; } - if ((fdi.answ == NULL) || (fdi.iosize == 0)) { - err = EINVAL; + list_xattr_out = fdi.answ; + linux_list_len = list_xattr_out->size; + if (linux_list_len == 0) { + if (ap->a_size != NULL) + *ap->a_size = linux_list_len; goto out; } - get_xattr_out = fdi.answ; - if (ap->a_size != NULL) { - *ap->a_size = get_xattr_out->size; - } else if (fdi.iosize > 0) { - /* - * The Linux / FUSE attribute list format isn't the same - * as FreeBSD's format. So we need to transform it into - * FreeBSD's format before giving it to the user. - */ - bsd_list = malloc(fdi.iosize, M_TEMP, M_WAITOK); - err = fuse_xattrlist_convert(prefix, fdi.answ, fdi.iosize, - bsd_list, &bsd_list_len); - if (err != 0) - goto out; + /* + * Retrieve Linux / FUSE compatible list values. + */ + fdisp_make_vp(&fdi, FUSE_LISTXATTR, vp, td, cred); + list_xattr_in = fdi.indata; + list_xattr_in->size = linux_list_len + sizeof(*list_xattr_out); + attr_str = (char *)fdi.indata + sizeof(*list_xattr_in); + snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator); + err = fdisp_wait_answ(&fdi); + if (err != 0) + goto out; + + linux_list = fdi.answ; + linux_list_len = fdi.iosize; + + /* + * Retrieve the BSD compatible list values. + * The Linux / FUSE attribute list format isn't the same + * as FreeBSD's format. So we need to transform it into + * FreeBSD's format before giving it to the user. + */ + bsd_list = malloc(linux_list_len, M_TEMP, M_WAITOK); + err = fuse_xattrlist_convert(prefix, linux_list, linux_list_len, + bsd_list, &bsd_list_len); + if (err != 0) + goto out; + + if (ap->a_size != NULL) + *ap->a_size = bsd_list_len; + + if (uio != NULL) err = uiomove(bsd_list, bsd_list_len, uio); - } else { - debug_printf("listextattr: returned iosize %zu for %s attribute list is " - "too small\n", fdi.iosize, prefix); - err = EINVAL; - } out: free(bsd_list, M_TEMP);