Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F139445640
D12485.id33861.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D12485.id33861.diff
View Options
Index: sys/fs/fuse/fuse_ipc.c
===================================================================
--- sys/fs/fuse/fuse_ipc.c
+++ sys/fs/fuse/fuse_ipc.c
@@ -636,23 +636,20 @@
break;
case FUSE_SETXATTR:
- panic("FUSE_SETXATTR implementor has forgotten to define a"
- " response body format check");
+ err = (blen == 0) ? 0 : EINVAL;
break;
case FUSE_GETXATTR:
- panic("FUSE_GETXATTR implementor has forgotten to define a"
- " response body format check");
- break;
-
case FUSE_LISTXATTR:
- panic("FUSE_LISTXATTR implementor has forgotten to define a"
- " response body format check");
+ /*
+ * These can have varying response lengths, and 0 length
+ * isn't necessarily invalid.
+ */
+ err = 0;
break;
case FUSE_REMOVEXATTR:
- panic("FUSE_REMOVEXATTR implementor has forgotten to define a"
- " response body format check");
+ err = (blen == 0) ? 0 : EINVAL;
break;
case FUSE_FLUSH:
Index: sys/fs/fuse/fuse_vnops.c
===================================================================
--- sys/fs/fuse/fuse_vnops.c
+++ sys/fs/fuse/fuse_vnops.c
@@ -73,6 +73,7 @@
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/namei.h>
+#include <sys/extattr.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <sys/filedesc.h>
@@ -112,10 +113,13 @@
static vop_access_t fuse_vnop_access;
static vop_close_t fuse_vnop_close;
static vop_create_t fuse_vnop_create;
+static vop_deleteextattr_t fuse_vnop_deleteextattr;
static vop_fsync_t fuse_vnop_fsync;
static vop_getattr_t fuse_vnop_getattr;
+static vop_getextattr_t fuse_vnop_getextattr;
static vop_inactive_t fuse_vnop_inactive;
static vop_link_t fuse_vnop_link;
+static vop_listextattr_t fuse_vnop_listextattr;
static vop_lookup_t fuse_vnop_lookup;
static vop_mkdir_t fuse_vnop_mkdir;
static vop_mknod_t fuse_vnop_mknod;
@@ -128,6 +132,7 @@
static vop_rename_t fuse_vnop_rename;
static vop_rmdir_t fuse_vnop_rmdir;
static vop_setattr_t fuse_vnop_setattr;
+static vop_setextattr_t fuse_vnop_setextattr;
static vop_strategy_t fuse_vnop_strategy;
static vop_symlink_t fuse_vnop_symlink;
static vop_write_t fuse_vnop_write;
@@ -140,10 +145,13 @@
.vop_access = fuse_vnop_access,
.vop_close = fuse_vnop_close,
.vop_create = fuse_vnop_create,
+ .vop_deleteextattr = fuse_vnop_deleteextattr,
.vop_fsync = fuse_vnop_fsync,
.vop_getattr = fuse_vnop_getattr,
+ .vop_getextattr = fuse_vnop_getextattr,
.vop_inactive = fuse_vnop_inactive,
.vop_link = fuse_vnop_link,
+ .vop_listextattr = fuse_vnop_listextattr,
.vop_lookup = fuse_vnop_lookup,
.vop_mkdir = fuse_vnop_mkdir,
.vop_mknod = fuse_vnop_mknod,
@@ -157,6 +165,7 @@
.vop_rename = fuse_vnop_rename,
.vop_rmdir = fuse_vnop_rmdir,
.vop_setattr = fuse_vnop_setattr,
+ .vop_setextattr = fuse_vnop_setextattr,
.vop_strategy = fuse_vnop_strategy,
.vop_symlink = fuse_vnop_symlink,
.vop_write = fuse_vnop_write,
@@ -1959,6 +1968,380 @@
}
/*
+ struct vop_getextattr_args {
+ struct vop_generic_args a_gen;
+ struct vnode *a_vp;
+ int a_attrnamespace;
+ const char *a_name;
+ struct uio *a_uio;
+ size_t *a_size;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ };
+*/
+
+static const char extattr_namespace_separator = '.';
+
+static int
+fuse_vnop_getextattr(struct vop_getextattr_args *ap)
+{
+ 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 mount *mp = vnode_mount(vp);
+ char *prefix;
+ size_t len;
+ char *attr_str;
+ struct thread *td = ap->a_td;
+ struct ucred *cred = ap->a_cred;
+ int err = 0;
+
+ fuse_trace_printf_vnop();
+
+ if (fuse_isdeadfs(vp))
+ return ENXIO;
+
+ /* Default to looking for user attributes. */
+ if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
+ prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
+ else
+ prefix = EXTATTR_NAMESPACE_USER_STRING;
+
+ len = strlen(prefix) + sizeof(extattr_namespace_separator) +
+ strlen(ap->a_name) + 1;
+
+ fdisp_init(&fdi, len + sizeof(*get_xattr_in));
+ fdisp_make_vp(&fdi, FUSE_GETXATTR, vp, td, cred);
+
+ get_xattr_in = fdi.indata;
+ /*
+ * Check to see whether we're querying the available size or
+ * issuing the actual request. If we pass in 0, we get back struct
+ * 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)
+ get_xattr_in->size = 0;
+ else
+ get_xattr_in->size = uio->uio_resid;
+
+ attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
+ snprintf(attr_str, len, "%s.%s", prefix, ap->a_name);
+
+ err = fdisp_wait_answ(&fdi);
+
+ if (err != 0) {
+ if (err == ENOSYS)
+ fsess_set_notimpl(mp, FUSE_GETXATTR);
+ debug_printf("getxattr: got err=%d from daemon\n", err);
+ 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) {
+ *ap->a_size = get_xattr_out->size;
+ } else if (fdi.iosize > 0) {
+ err = uiomove(fdi.answ, fdi.iosize, uio);
+ } else {
+ err = EINVAL;
+ }
+
+out:
+ fdisp_destroy(&fdi);
+ return (err);
+}
+
+/*
+ struct vop_setextattr_args {
+ struct vop_generic_args a_gen;
+ struct vnode *a_vp;
+ int a_attrnamespace;
+ const char *a_name;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ };
+*/
+
+static int
+fuse_vnop_setextattr(struct vop_setextattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct fuse_dispatcher fdi = {0};
+ struct fuse_setxattr_in *set_xattr_in;
+ struct mount *mp = vnode_mount(vp);
+ char *prefix;
+ size_t len;
+ char *attr_str;
+ struct thread *td = ap->a_td;
+ struct ucred *cred = ap->a_cred;
+ int err = 0;
+
+ fuse_trace_printf_vnop();
+
+ if (fuse_isdeadfs(vp))
+ return ENXIO;
+
+ /* Default to looking for user attributes. */
+ if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
+ prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
+ else
+ prefix = EXTATTR_NAMESPACE_USER_STRING;
+
+ len = strlen(prefix) + sizeof(extattr_namespace_separator) +
+ strlen(ap->a_name) + 1;
+
+ fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
+ fdisp_make_vp(&fdi, FUSE_SETXATTR, vp, td, cred);
+
+ set_xattr_in = fdi.indata;
+ set_xattr_in->size = uio->uio_resid;
+
+ attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
+ snprintf(attr_str, len, "%s.%s", prefix, ap->a_name);
+
+ err = uiomove((char *)fdi.indata + sizeof(*set_xattr_in) + len,
+ uio->uio_resid, uio);
+ if (err != 0) {
+ debug_printf("setxattr: got error %d from uiomove\n", err);
+ goto out;
+ }
+
+ err = fdisp_wait_answ(&fdi);
+
+ if (err != 0) {
+ if (err == ENOSYS)
+ fsess_set_notimpl(mp, FUSE_SETXATTR);
+ debug_printf("setxattr: got err=%d from daemon\n", err);
+ goto out;
+ }
+
+out:
+ fdisp_destroy(&fdi);
+ return (err);
+}
+
+/*
+ * The Linux / FUSE extended attribute list is simply a collection of
+ * NUL-terminated strings. The FreeBSD extended attribute list is a single
+ * byte length followed by a non-NUL terminated string. So, this allows
+ * conversion of the Linux / FUSE format to the FreeBSD format in place.
+ * Linux attribute names are reported with the namespace as a prefix (e.g.
+ * "user.attribute_name"), but in FreeBSD they are reported without the
+ * namespace prefix (e.g. "attribute_name"). So, we're going from:
+ *
+ * user.attr_name1\0user.attr_name2\0
+ *
+ * to:
+ *
+ * <num>attr_name1<num>attr_name2
+ *
+ * Where "<num>" is a single byte number of characters in the attribute name.
+ */
+static int
+fuse_xattrlist_convert(char *prefix, /* exattr namespace prefix string */
+ const char *list, int list_len, /* input list with namespace prefixes */
+ char *bsd_list, int *bsd_list_len) /* output list compatible with bsd vfs */
+{
+ int len, pos, pos_next, prefix_len;
+
+ pos = 0;
+ *bsd_list_len = 0;
+ prefix_len = strlen(prefix);
+
+ while (pos < list_len && list[pos] != '\0') {
+ pos_next = strlen(&list[pos]) + 1;
+ if (bcmp(&list[pos], prefix, prefix_len) == 0 &&
+ list[pos + prefix_len] == extattr_namespace_separator) {
+ len = pos_next -
+ (prefix_len + sizeof(extattr_namespace_separator)) - 1;
+ bsd_list[*bsd_list_len] = len;
+ if (len < EXTATTR_MAXNAMELEN)
+ memcpy(&bsd_list[*bsd_list_len + 1],
+ &list[pos + prefix_len +
+ sizeof(extattr_namespace_separator)], len);
+ else
+ return (ENAMETOOLONG);
+
+ *bsd_list_len += len + 1;
+ }
+
+ pos += pos_next;
+ }
+
+ return (0);
+}
+
+/*
+ struct vop_listextattr_args {
+ struct vop_generic_args a_gen;
+ struct vnode *a_vp;
+ int a_attrnamespace;
+ struct uio *a_uio;
+ size_t *a_size;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ };
+*/
+
+static int
+fuse_vnop_listextattr(struct vop_listextattr_args *ap)
+{
+ 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 mount *mp = vnode_mount(vp);
+ size_t len;
+ char *prefix;
+ char *attr_str;
+ char *bsd_list = NULL;
+ int bsd_list_len;
+ struct thread *td = ap->a_td;
+ struct ucred *cred = ap->a_cred;
+ int err = 0;
+
+ fuse_trace_printf_vnop();
+
+ if (fuse_isdeadfs(vp))
+ return ENXIO;
+
+ /*
+ * Add space for a NUL and the period separator if enabled.
+ * Default to looking for user attributes.
+ */
+ if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
+ prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
+ else
+ prefix = EXTATTR_NAMESPACE_USER_STRING;
+
+ len = strlen(prefix) + sizeof(extattr_namespace_separator) + 1;
+
+ fdisp_init(&fdi, sizeof(*get_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);
+ snprintf(attr_str, len, "%s%c", prefix, extattr_namespace_separator);
+
+ err = fdisp_wait_answ(&fdi);
+ if (err != 0) {
+ if (err == ENOSYS)
+ fsess_set_notimpl(mp, FUSE_LISTXATTR);
+ debug_printf("listextattr: got err=%d from daemon\n", err);
+ goto out;
+ }
+
+ if ((fdi.answ == NULL) || (fdi.iosize == 0)) {
+ err = EINVAL;
+ 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;
+
+ 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);
+ fdisp_destroy(&fdi);
+ return (err);
+}
+
+/*
+ struct vop_deleteextattr_args {
+ struct vop_generic_args a_gen;
+ struct vnode *a_vp;
+ int a_attrnamespace;
+ const char *a_name;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ };
+*/
+
+static int
+fuse_vnop_deleteextattr(struct vop_deleteextattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct fuse_dispatcher fdi = {0};
+ struct mount *mp = vnode_mount(vp);
+ char *prefix;
+ size_t len;
+ char *attr_str;
+ struct thread *td = ap->a_td;
+ struct ucred *cred = ap->a_cred;
+ int err;
+
+ fuse_trace_printf_vnop();
+
+ if (fuse_isdeadfs(vp))
+ return ENXIO;
+
+ /* Default to looking for user attributes. */
+ if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM)
+ prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
+ else
+ prefix = EXTATTR_NAMESPACE_USER_STRING;
+
+ len = strlen(prefix) + sizeof(extattr_namespace_separator) +
+ strlen(ap->a_name) + 1;
+
+ fdisp_init(&fdi, len);
+ fdisp_make_vp(&fdi, FUSE_REMOVEXATTR, vp, td, cred);
+
+ attr_str = (char *)fdi.indata;
+ snprintf(attr_str, len, "%s.%s", prefix, ap->a_name);
+
+ err = fdisp_wait_answ(&fdi);
+ if (err != 0) {
+ if (err == ENOSYS)
+ fsess_set_notimpl(mp, FUSE_REMOVEXATTR);
+ debug_printf("removexattr: got err=%d from daemon\n", err);
+ }
+
+ fdisp_destroy(&fdi);
+ return (err);
+}
+
+/*
struct vnop_print_args {
struct vnode *a_vp;
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 13, 4:26 AM (1 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26921285
Default Alt Text
D12485.id33861.diff (12 KB)
Attached To
Mode
D12485: fuse.ko: Add extattrs support.
Attached
Detach File
Event Timeline
Log In to Comment