diff --git a/doc/bookmarkfs.texi b/doc/bookmarkfs.texi index 66d7e9e..8ff30d4 100644 --- a/doc/bookmarkfs.texi +++ b/doc/bookmarkfs.texi @@ -1755,7 +1755,7 @@ struct bookmarkfs_backend_create_resp @{ void *backend_ctx; uint64_t bookmarks_root_id; uint64_t tags_root_id; - char const *bookmark_attrs; + char const *xattr_names; uint32_t flags; @}; @end example @@ -1796,7 +1796,7 @@ before entering sandbox. @xref{Tags}. @end itemize -@item bookmark_attrs +@item xattr_names Names of extended attributes (@pxref{Extended Attributes}) supported for this backend context. diff --git a/src/backend.h b/src/backend.h index e990584..18e0c1c 100644 --- a/src/backend.h +++ b/src/backend.h @@ -261,7 +261,7 @@ struct bookmarkfs_backend_create_resp { void *backend_ctx; uint64_t bookmarks_root_id; uint64_t tags_root_id; - char const *bookmark_attrs; + char const *xattr_names; uint32_t flags; }; diff --git a/src/backend_chromium.c b/src/backend_chromium.c index 2fd0f9f..7335d48 100644 --- a/src/backend_chromium.c +++ b/src/backend_chromium.c @@ -1745,16 +1745,16 @@ backend_create ( resp_flags |= BOOKMARKFS_BACKEND_EXCLUSIVE; } - char const *bookmark_attrs = "guid\0date_added\0"; + char const *xattr_names = "guid\0date_added\0"; if (opts.other_flags & BACKEND_FILENAME_GUID) { - bookmark_attrs = "title\0date_added\0"; + xattr_names = "title\0date_added\0"; } resp->name = "chromium"; resp->backend_ctx = ctx; resp->bookmarks_root_id = BOOKMARKS_ROOT_ID; resp->flags = resp_flags; - resp->bookmark_attrs = bookmark_attrs; + resp->xattr_names = xattr_names; return 0; } diff --git a/src/backend_firefox.c b/src/backend_firefox.c index f111501..21a7d14 100644 --- a/src/backend_firefox.c +++ b/src/backend_firefox.c @@ -2880,16 +2880,16 @@ backend_create ( resp_flags |= BOOKMARKFS_BACKEND_EXCLUSIVE; } - char const *bookmark_attrs = "guid\0date_added\0description\0"; + char const *xattr_names = "guid\0date_added\0description\0"; if (opts.flags & BACKEND_FILENAME_GUID) { - bookmark_attrs = "title\0date_added\0description\0"; + xattr_names = "title\0date_added\0description\0"; } resp->name = "firefox"; resp->backend_ctx = ctx; resp->bookmarks_root_id = bookmarks_root_id; resp->tags_root_id = tags_root_id; - resp->bookmark_attrs = bookmark_attrs; + resp->xattr_names = xattr_names; resp->flags = resp_flags; return 0; diff --git a/src/defs.h b/src/defs.h index c5a2052..983bb7b 100644 --- a/src/defs.h +++ b/src/defs.h @@ -120,5 +120,6 @@ #endif #define BOOKMARKFS_HOMEPAGE_URL "https://www.nongnu.org/bookmarkfs/" +#define BOOKMARKFS_XATTR_PREFIX "user.bookmarkfs." #endif /* !defined(BOOKMARKFS_DEFS_H_) */ diff --git a/src/fs_ops.c b/src/fs_ops.c index 0fb1723..cb0c437 100644 --- a/src/fs_ops.c +++ b/src/fs_ops.c @@ -33,6 +33,9 @@ #include #include +#ifdef __linux__ +# include +#endif #include #include @@ -66,8 +69,6 @@ #define FH_FLAG_DIRTY ( 1u << 0 ) #define FH_FLAG_FSCK ( 1u << 1 ) -#define XATTR_PREFIX "user.bookmarkfs." - #define SUBSYS_ID_BITS ( 64 - BOOKMARKFS_BOOKMARK_TYPE_BITS ) #define SUBSYS_ID_MASK ( ((fuse_ino_t)1 << SUBSYS_ID_BITS) - 1 ) #define INODE_SUBSYS_TYPE(ino) ( (ino) >> SUBSYS_ID_BITS ) @@ -87,6 +88,16 @@ #define BACKEND_CALL(name, ...) \ ctx.backend_impl->name(ctx.backend_ctx, __VA_ARGS__) +#define BM_XATTR_FOREACH(name, name_len) \ + for (char const *name = ctx.xattr_names, *next_; ; name = next_) { \ + size_t name_len = strlen(name); \ + if (name_len == 0) { \ + break; \ + } \ + next_ = name + name_len + 1; +#define BM_XATTR_FOREACH_END \ + } + #define backend_has_tags() ( TAGS_ROOT_ID != UINT64_MAX ) #define backend_has_keywords() ( ctx.flags.has_keyword ) #define send_reply(name, ...) \ @@ -139,7 +150,7 @@ struct fs_ctx { uint64_t bookmarks_root_id; uint64_t tags_root_id; size_t file_max; - char const *bookmark_attrs; + char const *xattr_names; char *buf; size_t buf_len; @@ -219,7 +230,7 @@ static int bm_set_keyword (uint64_t, char const *, struct stat *); static int bm_set_tag (uint64_t, uint64_t, char const *, struct stat *); static int bm_setattr (uint64_t, int, bool, struct fuse_file_info const *, struct stat *); -static int bm_setxattr (uint64_t, char const *, void const *, size_t); +static int bm_setxattr (uint64_t, char const *, void const *, size_t, int); static int bm_write (fuse_req_t, int, char const *, size_t, off_t, struct fs_file_handle *); static int current_time (struct timespec *); @@ -243,10 +254,10 @@ static int intfs_mkdir (unsigned, char const *, struct stat *); static int intfs_opendir (unsigned, fuse_ino_t, struct fuse_file_info *); static int intfs_readdir (fuse_req_t, unsigned, size_t, off_t, uint32_t, void *); +static bool is_xattr_name (char const *); static int reply_errcheck (int, char const *, int); static int subsys_type (fuse_ino_t, uint64_t *); static int timespec_cmp (struct timespec const *, struct timespec const *); -static int xattr_name (char const *, char const **); // Forward declaration end static struct fs_ctx ctx = { @@ -586,10 +597,11 @@ bm_getxattr ( char const *name, size_t buf_max ) { - if (0 != xattr_name(name, &name)) { + if (!is_xattr_name(name)) { return -ENOATTR; } + name += strlen(BOOKMARKFS_XATTR_PREFIX); struct bm_getxattr_ctx gctx = { .req = req, .buf_max = buf_max, @@ -603,7 +615,7 @@ bm_getxattr_cb ( void const *xattr_val, size_t xattr_len ) { - struct bm_getxattr_ctx *gctx = user_data; + struct bm_getxattr_ctx const *gctx = user_data; size_t buf_max = gctx->buf_max; if (buf_max == 0) { @@ -729,15 +741,11 @@ bm_lsxattr ( size_t buf_max, size_t *buf_len_ptr ) { - size_t buf_len = 0; - for (char const *xattrs = ctx.bookmark_attrs, *next; ; xattrs = next) { - size_t xattr_len = strlen(xattrs) + 1; - if (xattr_len == 1) { - break; - } - next = xattrs + xattr_len; + size_t buf_len = 0; + size_t prefix_len = strlen(BOOKMARKFS_XATTR_PREFIX); - xattr_len += strlen(XATTR_PREFIX); + BM_XATTR_FOREACH(xattr, xattr_len) + xattr_len += prefix_len + 1; buf_len += xattr_len; if (buf_max == 0) { continue; @@ -746,10 +754,9 @@ bm_lsxattr ( return -ERANGE; } char *dest = buf + buf_len - xattr_len; - memcpy(dest, XATTR_PREFIX, strlen(XATTR_PREFIX)); - dest += strlen(XATTR_PREFIX); - memcpy(dest, xattrs, xattr_len - strlen(XATTR_PREFIX)); - } + memcpy(dest, BOOKMARKFS_XATTR_PREFIX, prefix_len); + memcpy(dest + prefix_len, xattr, xattr_len - prefix_len); + BM_XATTR_FOREACH_END *buf_len_ptr = buf_len; return 0; @@ -1005,7 +1012,7 @@ bm_rmxattr ( uint64_t UNUSED_VAR(id), char const *name ) { - if (0 != xattr_name(name, NULL)) { + if (!is_xattr_name(name)) { return -ENOATTR; } return -EPERM; @@ -1132,12 +1139,21 @@ bm_setxattr ( uint64_t id, char const *name, void const *val, - size_t val_len + size_t val_len, + int flags ) { - if (0 != xattr_name(name, &name)) { + if (!is_xattr_name(name)) { return -ENOATTR; } +#ifdef __linux__ + if (flags == XATTR_CREATE) { + return -EEXIST; + } +#else + debug_assert(flags == 0); +#endif + name += strlen(BOOKMARKFS_XATTR_PREFIX); return BACKEND_CALL(bookmark_set, id, name, 0, val, val_len); } @@ -1621,6 +1637,29 @@ intfs_readdir ( return send_reply(buf, req, reply_buf - reply_size, reply_size); } +static bool +is_xattr_name ( + char const *name +) { + size_t name_len = strlen(name); + size_t prefix_len = strlen(BOOKMARKFS_XATTR_PREFIX); + if (name_len <= prefix_len) { + return false; + } + if (0 != memcmp(name, BOOKMARKFS_XATTR_PREFIX, prefix_len)) { + return false; + } + name += prefix_len; + name_len -= prefix_len; + + BM_XATTR_FOREACH(xattr, xattr_len) + if (name_len == xattr_len && 0 == memcmp(name, xattr, name_len)) { + return true; + } + BM_XATTR_FOREACH_END + return false; +} + static int reply_errcheck ( int err, @@ -1679,43 +1718,6 @@ timespec_cmp ( return 0; } -static int -xattr_name ( - char const *name, - char const **name_ptr -) { - size_t name_len = strlen(name); - size_t prefix_len = strlen(XATTR_PREFIX); - if (name_len <= prefix_len) { - return -1; - } - if (0 != memcmp(name, XATTR_PREFIX, prefix_len)) { - return -1; - } - name += prefix_len; - name_len -= prefix_len; - - for (char const *xattrs = ctx.bookmark_attrs, *next; ; xattrs = next) { - size_t xattr_len = strlen(xattrs); - if (xattr_len == 0) { - break; - } - next = xattrs + xattr_len + 1; - - if (name_len != xattr_len) { - continue; - } - if (0 != memcmp(name, xattrs, name_len)) { - continue; - } - if (name_ptr != NULL) { - *name_ptr = name; - } - return 0; - } - return -1; -} - void fs_init_backend ( struct bookmarkfs_backend const *backend_impl, @@ -1736,7 +1738,7 @@ void fs_init_metadata ( uint64_t bookmarks_root_id, uint64_t tags_root_id, - char const *bookmark_attrs + char const *xattr_names ) { if (bookmarks_root_id != UINT64_MAX) { ctx.bookmarks_root_id = bookmarks_root_id; @@ -1744,8 +1746,8 @@ fs_init_metadata ( if (tags_root_id != UINT64_MAX) { ctx.tags_root_id = tags_root_id; } - if (bookmark_attrs != NULL) { - ctx.bookmark_attrs = bookmark_attrs; + if (xattr_names != NULL) { + ctx.xattr_names = xattr_names; } } @@ -2352,7 +2354,7 @@ fs_op_setxattr ( char const *name, char const *val, size_t val_len, - int UNUSED_VAR(flags) + int flags ) { int status = -ERANGE; if (val_len > ctx.file_max) { @@ -2362,7 +2364,7 @@ fs_op_setxattr ( switch (INODE_SUBSYS_TYPE(ino)) { case SUBSYS_TYPE_BOOKMARK: - status = bm_setxattr(INODE_SUBSYS_ID(ino), name, val, val_len); + status = bm_setxattr(INODE_SUBSYS_ID(ino), name, val, val_len, flags); break; } diff --git a/src/fs_ops.h b/src/fs_ops.h index 5d8b680..9048f42 100644 --- a/src/fs_ops.h +++ b/src/fs_ops.h @@ -52,7 +52,7 @@ void fs_init_metadata ( uint64_t bookmarks_root_id, uint64_t tags_root_id, - char const *bookmark_attrs + char const *xattr_names ); void diff --git a/src/mount.c b/src/mount.c index 33758b2..f1b1f4a 100644 --- a/src/mount.c +++ b/src/mount.c @@ -212,7 +212,7 @@ init_backend ( struct bookmarkfs_backend_create_resp resp = { .bookmarks_root_id = UINT64_MAX, .tags_root_id = UINT64_MAX, - .bookmark_attrs = "", + .xattr_names = "", }; if (0 != impl->backend_create(&info->backend_conf, &resp)) { debug_puts("backend_create() failed"); @@ -227,7 +227,7 @@ init_backend ( fs_init_backend(impl, resp.backend_ctx); fs_init_metadata(resp.bookmarks_root_id, resp.tags_root_id, - resp.bookmark_attrs); + resp.xattr_names); fs_init_opts(info->fs_flags, info->file_max); return 0; }