Page MenuHomeFreeBSD

D12485.id33382.diff
No OneTemporary

D12485.id33382.diff

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,
@@ -180,6 +189,11 @@
SYSCTL_INT(_vfs_fuse, OID_AUTO, lookup_cache_enable, CTLFLAG_RW,
&fuse_lookup_cache_enable, 0, "");
+int fuse_extattr_namespace_prefix_enable = 1;
+
+SYSCTL_INT(_vfs_fuse, OID_AUTO, extattr_namespace_prefix_enable, CTLFLAG_RW,
+ &fuse_extattr_namespace_prefix_enable, 0, "");
+
/*
* XXX: This feature is highly experimental and can bring to instabilities,
* needs revisiting before to be enabled by default.
@@ -1959,6 +1973,449 @@
}
/*
+ 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 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;
+ 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, prefix_len;
+ char *attr_str;
+ uint64_t parentnid = VTOFUD(vp)->nid;
+ 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;
+
+ /* String plus terminating NUL */
+ len = strlen(ap->a_name) + 1;
+
+ if (fuse_extattr_namespace_prefix_enable) {
+ /* Default to looking for user attributes. */
+ if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
+ prefix_len = strlen(EXTATTR_NAMESPACE_SYSTEM_STRING) + 1;
+ prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
+ } else {
+ prefix_len = strlen(EXTATTR_NAMESPACE_USER_STRING) + 1;
+ prefix = EXTATTR_NAMESPACE_USER_STRING;
+ }
+
+ len += prefix_len;
+ }
+
+ bzero(&fdi, sizeof(fdi));
+ fdisp_init(&fdi, len + sizeof(*get_xattr_in));
+ fdisp_make(&fdi, FUSE_GETXATTR, vnode_mount(vp), parentnid, 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;
+
+ if (fuse_extattr_namespace_prefix_enable) {
+ attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
+ snprintf(attr_str, len, "%s.%s", prefix, ap->a_name);
+ attr_str[len - 1] = '\0';
+ } else {
+ attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
+ snprintf(attr_str, len, "%s", ap->a_name);
+ attr_str[len - 1] = '\0';
+ }
+
+ 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((uint8_t *)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;
+ struct fuse_setxattr_in *set_xattr_in;
+ struct mount *mp = vnode_mount(vp);
+ char *prefix;
+ size_t len, prefix_len;
+ char *attr_str;
+ uint64_t parentnid = VTOFUD(vp)->nid;
+ 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;
+
+ /* String plus terminating NUL */
+ len = strlen(ap->a_name) + 1;
+
+ if (fuse_extattr_namespace_prefix_enable) {
+ /* Default to looking for user attributes. */
+ if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
+ prefix_len = strlen(EXTATTR_NAMESPACE_SYSTEM_STRING) + 1;
+ prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
+ } else {
+ prefix_len = strlen(EXTATTR_NAMESPACE_USER_STRING) + 1;
+ prefix = EXTATTR_NAMESPACE_USER_STRING;
+ }
+
+ len += prefix_len;
+ }
+
+ bzero(&fdi, sizeof(fdi));
+ fdisp_init(&fdi, len + sizeof(*set_xattr_in) + uio->uio_resid);
+ fdisp_make(&fdi, FUSE_SETXATTR, vnode_mount(vp), parentnid, td, cred);
+
+ set_xattr_in = fdi.indata;
+ set_xattr_in->size = uio->uio_resid;
+
+ if (fuse_extattr_namespace_prefix_enable) {
+ attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
+ snprintf(attr_str, len, "%s.%s", prefix, ap->a_name);
+ attr_str[len - 1] = '\0';
+ } else {
+ attr_str = (char *)fdi.indata + sizeof(*set_xattr_in);
+ snprintf(attr_str, len, "%s", ap->a_name);
+ attr_str[len - 1] = '\0';
+ }
+
+ err = uiomove((uint8_t *)fdi.indata + sizeof(*set_xattr_in) + len,
+ uio->uio_resid, uio);
+ if (err != 0) {
+ printf("%s: got error %d from uiomove\n", __func__, 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 void
+fuse_xattrlist_convert(int fix_prefix, uint8_t *list, int list_len, int *new_list_len,
+ char *prefix, int prefix_len, char separator)
+{
+ int len, pos, pos_next, count;
+
+ if (fix_prefix) {
+ pos = 0;
+ *new_list_len = 0;
+
+ while (pos < list_len && list[pos] != '\0') {
+ pos_next = strlen(&list[pos]) + 1;
+ if (!bcmp(&list[pos], prefix, prefix_len) &&
+ list[pos + prefix_len] == separator) {
+ len = pos_next - (prefix_len + 1) - 1;
+ list[*new_list_len] = len;
+ memmove(&list[*new_list_len + 1],
+ &list[pos + prefix_len + 1], len);
+ *new_list_len += len + 1;
+ }
+
+ pos += pos_next;
+ }
+ } else {
+ pos = list_len - 1;
+ count = 0;
+
+ while (pos > 0) {
+ if (list[pos - 1] == '\0') {
+ list[pos] = count;
+ count = 0;
+ } else {
+ list[pos] = list[pos - 1];
+ count++;
+ }
+ pos--;
+ }
+
+ list[0] = count;
+ *new_list_len = list_len;
+ }
+}
+
+/*
+ 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;
+ 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;
+ size_t prefix_len;
+ char *attr_str;
+ char separator;
+ uint64_t parentnid = VTOFUD(vp)->nid;
+ 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.
+ */
+ if (fuse_extattr_namespace_prefix_enable) {
+ /* Default to looking for user attributes. */
+ if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
+ prefix_len = strlen(EXTATTR_NAMESPACE_SYSTEM_STRING);
+ prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
+ } else {
+ prefix_len = strlen(EXTATTR_NAMESPACE_USER_STRING);
+ prefix = EXTATTR_NAMESPACE_USER_STRING;
+ }
+ separator = '.';
+ len = prefix_len + 2;
+ } else
+ len = 0;
+
+ bzero(&fdi, sizeof(fdi));
+ fdisp_init(&fdi, sizeof(*get_xattr_in) + len);
+ fdisp_make(&fdi, FUSE_LISTXATTR, vnode_mount(vp), parentnid, td, cred);
+
+ get_xattr_in = fdi.indata;
+ get_xattr_out = fdi.answ;
+ if (ap->a_size != NULL)
+ get_xattr_in->size = 0;
+ else
+ get_xattr_in->size = uio->uio_resid + sizeof(*get_xattr_out);
+
+ if (fuse_extattr_namespace_prefix_enable) {
+ attr_str = (char *)fdi.indata + sizeof(*get_xattr_in);
+ snprintf(attr_str, len, "%s%c", prefix, separator);
+ attr_str[len - 1] = '\0';
+ }
+
+ err = fdisp_wait_answ(&fdi);
+ if (err) {
+ 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) {
+ int new_list_len;
+
+ new_list_len = fdi.iosize;
+
+ /*
+ * 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.
+ */
+ fuse_xattrlist_convert(fuse_extattr_namespace_prefix_enable,
+ (uint8_t *)fdi.answ, fdi.iosize, &new_list_len,
+ prefix, prefix_len, separator);
+
+ err = uiomove((uint8_t *)fdi.answ, new_list_len, uio);
+ } else {
+ printf("%s: returned iosize %zu for %s attribute list is "
+ "too small\n", __func__, fdi.iosize, prefix);
+ err = EINVAL;
+ }
+
+out:
+ 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;
+ struct mount *mp = vnode_mount(vp);
+ char *prefix;
+ size_t len, prefix_len;
+ char *attr_str;
+ uint64_t parentnid = VTOFUD(vp)->nid;
+ struct thread *td = ap->a_td;
+ struct ucred *cred = ap->a_cred;
+ int err;
+
+ fuse_trace_printf_vnop();
+
+ if (fuse_isdeadfs(vp))
+ return ENXIO;
+
+ len = strlen(ap->a_name) + 1;
+
+ if (fuse_extattr_namespace_prefix_enable) {
+ /* Default to looking for user attributes. */
+ if (ap->a_attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
+ prefix_len = strlen(EXTATTR_NAMESPACE_SYSTEM_STRING) + 1;
+ prefix = EXTATTR_NAMESPACE_SYSTEM_STRING;
+ } else {
+ prefix_len = strlen(EXTATTR_NAMESPACE_USER_STRING) + 1;
+ prefix = EXTATTR_NAMESPACE_USER_STRING;
+ }
+
+ len += prefix_len;
+ }
+
+ bzero(&fdi, sizeof(fdi));
+ fdisp_init(&fdi, len);
+ fdisp_make(&fdi, FUSE_REMOVEXATTR, vnode_mount(vp),parentnid, td, cred);
+
+ if (fuse_extattr_namespace_prefix_enable) {
+ attr_str = (char *)fdi.indata;
+ snprintf(attr_str, len, "%s.%s", prefix, ap->a_name);
+ attr_str[len - 1] = '\0';
+ } else {
+ attr_str = (char *)fdi.indata;
+ snprintf(attr_str, len, "%s", ap->a_name);
+ attr_str[len - 1] = '\0';
+ }
+
+ 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

Mime Type
text/plain
Expires
Sat, Apr 18, 8:10 AM (5 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31707771
Default Alt Text
D12485.id33382.diff (14 KB)

Event Timeline