mirror of
https://git.sr.ht/~cismonx/bookmarkfs
synced 2025-06-07 19:58:50 +00:00
bookmarkctl: add sub-commands for xattr
Provides platform-agnostic command-line interface for managing extended attributes on a BookmarkFS filesystem.
This commit is contained in:
parent
402cc1a304
commit
7ae2b283c3
4 changed files with 572 additions and 9 deletions
|
@ -9,7 +9,8 @@
|
||||||
bin_PROGRAMS =
|
bin_PROGRAMS =
|
||||||
pkginclude_HEADERS = backend.h common.h ioctl.h fsck_handler.h version.h
|
pkginclude_HEADERS = backend.h common.h ioctl.h fsck_handler.h version.h
|
||||||
noinst_HEADERS = backend_util.h db.h defs.h frontend_util.h fs_ops.h \
|
noinst_HEADERS = backend_util.h db.h defs.h frontend_util.h fs_ops.h \
|
||||||
fsck_ops.h fsck_util.h json.h lib.h macros.h uuid.h xstd.h
|
fsck_ops.h fsck_util.h json.h lib.h macros.h uuid.h \
|
||||||
|
xattr.h xstd.h
|
||||||
lib_LTLIBRARIES =
|
lib_LTLIBRARIES =
|
||||||
pkglib_LTLIBRARIES =
|
pkglib_LTLIBRARIES =
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ if BOOKMARKCTL
|
||||||
bin_PROGRAMS += bookmarkctl
|
bin_PROGRAMS += bookmarkctl
|
||||||
|
|
||||||
bookmarkctl_CPPFLAGS = $(BASE_CPPFLAGS_)
|
bookmarkctl_CPPFLAGS = $(BASE_CPPFLAGS_)
|
||||||
bookmarkctl_SOURCES = bookmarkctl.c fsck_util.c
|
bookmarkctl_SOURCES = bookmarkctl.c fsck_util.c xattr.c xstd.c
|
||||||
endif # BOOKMARKCTL
|
endif # BOOKMARKCTL
|
||||||
|
|
||||||
if BOOKMARKFS_FSCK
|
if BOOKMARKFS_FSCK
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -37,14 +38,34 @@
|
||||||
#include "ioctl.h"
|
#include "ioctl.h"
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "xattr.h"
|
||||||
#include "xstd.h"
|
#include "xstd.h"
|
||||||
|
|
||||||
|
#define BMCTL_XATTR_GET_NOEOL (1u << 0)
|
||||||
|
#define BMCTL_XATTR_GET_BINARY (1u << 1)
|
||||||
|
#define BMCTL_XATTR_GET_MULTI (1u << 2)
|
||||||
|
#define BMCTL_XATTR_GET_QUIET (1u << 3)
|
||||||
|
|
||||||
|
struct xattr_get_ctx {
|
||||||
|
char const *prefix;
|
||||||
|
char sep;
|
||||||
|
char eol;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
// Forward declaration start
|
// Forward declaration start
|
||||||
static int dispatch_subcmds (int, char *[]);
|
static int dispatch_subcmds (int, char *[]);
|
||||||
static void print_help (void);
|
static void print_help (void);
|
||||||
static void print_version (void);
|
static void print_version (void);
|
||||||
static int subcmd_fsck (int, char *[]);
|
static int subcmd_fsck (int, char *[]);
|
||||||
static int subcmd_permd (int, char *[]);
|
static int subcmd_permd (int, char *[]);
|
||||||
|
static int subcmd_xattr_get (int, char *[]);
|
||||||
|
static int subcmd_xattr_list (int, char *[]);
|
||||||
|
static int subcmd_xattr_set (int, char *[]);
|
||||||
|
static int xattr_get_cb (void *, void *, size_t);
|
||||||
|
static int xattr_get_one (char const *, char *[], int,
|
||||||
|
struct xattr_get_ctx *);
|
||||||
|
static int xattr_list_cb (void *, void *, size_t);
|
||||||
// Forward declaration end
|
// Forward declaration end
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -61,6 +82,12 @@ dispatch_subcmds (
|
||||||
int status = 0;
|
int status = 0;
|
||||||
if (0 == strcmp("permd", cmd)) {
|
if (0 == strcmp("permd", cmd)) {
|
||||||
status = subcmd_permd(argc, argv);
|
status = subcmd_permd(argc, argv);
|
||||||
|
} else if (0 == strcmp("xattr-get", cmd)) {
|
||||||
|
status = subcmd_xattr_get(argc, argv);
|
||||||
|
} else if (0 == strcmp("xattr-set", cmd)) {
|
||||||
|
status = subcmd_xattr_set(argc, argv);
|
||||||
|
} else if (0 == strcmp("xattr-list", cmd)) {
|
||||||
|
status = subcmd_xattr_list(argc, argv);
|
||||||
} else if (0 == strcmp("fsck", cmd)) {
|
} else if (0 == strcmp("fsck", cmd)) {
|
||||||
status = subcmd_fsck(argc, argv);
|
status = subcmd_fsck(argc, argv);
|
||||||
} else if (0 == strcmp("help", cmd)) {
|
} else if (0 == strcmp("help", cmd)) {
|
||||||
|
@ -80,8 +107,11 @@ print_help (void)
|
||||||
puts("Usage: bookmarkctl <cmd> [args]\n"
|
puts("Usage: bookmarkctl <cmd> [args]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Main commands:\n"
|
"Main commands:\n"
|
||||||
" permd Permute directory entries\n"
|
" permd Permute directory entries\n"
|
||||||
" fsck Check filesystem\n"
|
" fsck Check filesystem\n"
|
||||||
|
" xattr-list List extended attribute names\n"
|
||||||
|
" xattr-get Get extended attribute value\n"
|
||||||
|
" xattr-set Set extended attribute value\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Other commands:\n"
|
"Other commands:\n"
|
||||||
" help Print help message\n"
|
" help Print help message\n"
|
||||||
|
@ -202,6 +232,222 @@ subcmd_permd (
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
subcmd_xattr_get (
|
||||||
|
int argc,
|
||||||
|
char *argv[]
|
||||||
|
) {
|
||||||
|
struct xattr_get_ctx ctx = {
|
||||||
|
.sep = '\t',
|
||||||
|
.eol = '\n',
|
||||||
|
};
|
||||||
|
|
||||||
|
OPT_START(argc, argv, "n:Nbmqs:")
|
||||||
|
OPT_OPT('n') {
|
||||||
|
ctx.eol = optarg[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OPT_OPT('N') {
|
||||||
|
ctx.flags |= BMCTL_XATTR_GET_NOEOL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OPT_OPT('b') {
|
||||||
|
ctx.flags |= BMCTL_XATTR_GET_BINARY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OPT_OPT('m') {
|
||||||
|
ctx.flags |= BMCTL_XATTR_GET_MULTI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OPT_OPT('q') {
|
||||||
|
ctx.flags |= BMCTL_XATTR_GET_QUIET;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OPT_OPT('s') {
|
||||||
|
ctx.sep = optarg[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OPT_NOVAL
|
||||||
|
OPT_END
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
log_puts("xattr-get: xattr name and file path must be specified");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.flags & BMCTL_XATTR_GET_MULTI) {
|
||||||
|
return xattr_get_one(argv[argc - 1], argv, argc - 1, &ctx);
|
||||||
|
}
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
char const *path = argv[i];
|
||||||
|
if (0 != xattr_get_one(path, argv, 1, &ctx)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
subcmd_xattr_list (
|
||||||
|
int argc,
|
||||||
|
char *argv[]
|
||||||
|
) {
|
||||||
|
if (--argc != 1) {
|
||||||
|
if (argc < 1) {
|
||||||
|
log_puts("xattr-set: file path must be provided");
|
||||||
|
} else {
|
||||||
|
log_puts("xattr-set: too many arguments");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char const *path = *(++argv);
|
||||||
|
|
||||||
|
int fd = bookmarkfs_xattr_open(path);
|
||||||
|
if (fd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int status = bookmarkfs_xattr_list(fd, xattr_list_cb, NULL);
|
||||||
|
close(fd);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
subcmd_xattr_set (
|
||||||
|
int argc,
|
||||||
|
char *argv[]
|
||||||
|
) {
|
||||||
|
char *val = NULL;
|
||||||
|
|
||||||
|
OPT_START(argc, argv, "v:")
|
||||||
|
OPT_OPT('v') {
|
||||||
|
val = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OPT_NOVAL
|
||||||
|
OPT_END
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
if (argc < 2) {
|
||||||
|
log_puts("xattr-set: xattr name and file path must be specified");
|
||||||
|
} else {
|
||||||
|
log_puts("xattr-set: too many arguments");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char const *name = argv[0];
|
||||||
|
char const *path = argv[1];
|
||||||
|
|
||||||
|
int fd = bookmarkfs_xattr_open(path);
|
||||||
|
if (fd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int status = -1;
|
||||||
|
|
||||||
|
size_t val_size = 0;
|
||||||
|
char *buf = val;
|
||||||
|
if (buf == NULL) {
|
||||||
|
size_t buf_size = 4096;
|
||||||
|
buf = xmalloc(buf_size);
|
||||||
|
do {
|
||||||
|
if (val_size == buf_size) {
|
||||||
|
buf_size += buf_size >> 1;
|
||||||
|
buf = xrealloc(buf, buf_size);
|
||||||
|
}
|
||||||
|
val_size += fread(buf + val_size, 1, buf_size - val_size, stdin);
|
||||||
|
if (ferror(stdin)) {
|
||||||
|
log_printf("fread(): %s", strerror(errno));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} while (!feof(stdin));
|
||||||
|
} else {
|
||||||
|
val_size = strlen(buf);
|
||||||
|
}
|
||||||
|
status = bookmarkfs_xattr_set(fd, name, buf, val_size);
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (val == NULL) {
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xattr_get_cb (
|
||||||
|
void *user_data,
|
||||||
|
void *buf,
|
||||||
|
size_t buf_len
|
||||||
|
) {
|
||||||
|
struct xattr_get_ctx const *ctx = user_data;
|
||||||
|
|
||||||
|
uint32_t flags = ctx->flags;
|
||||||
|
if (!(flags & BMCTL_XATTR_GET_QUIET)) {
|
||||||
|
if (0 > printf("%s%c", ctx->prefix, ctx->sep)) {
|
||||||
|
log_printf("printf(): %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(flags & BMCTL_XATTR_GET_BINARY)) {
|
||||||
|
for (unsigned char *s = buf, *end = s; s < end; ++s) {
|
||||||
|
if (iscntrl(*s)) {
|
||||||
|
*s = '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf_len != fwrite(buf, 1, buf_len, stdout)) {
|
||||||
|
log_printf("fwrite(): %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!(flags & BMCTL_XATTR_GET_NOEOL)) {
|
||||||
|
if (EOF == fputc(ctx->eol, stdout)) {
|
||||||
|
log_printf("fputc(): %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xattr_get_one (
|
||||||
|
char const *path,
|
||||||
|
char *names[],
|
||||||
|
int names_cnt,
|
||||||
|
struct xattr_get_ctx *ctx
|
||||||
|
) {
|
||||||
|
int fd = bookmarkfs_xattr_open(path);
|
||||||
|
if (fd < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status;
|
||||||
|
for (int i = 0; i < names_cnt; ++i) {
|
||||||
|
char const *name = names[i];
|
||||||
|
|
||||||
|
ctx->prefix = (ctx->flags & BMCTL_XATTR_GET_MULTI) ? name : path;
|
||||||
|
status = bookmarkfs_xattr_get(fd, name, xattr_get_cb, ctx);
|
||||||
|
if (status < 0) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
close(fd);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xattr_list_cb (
|
||||||
|
void *UNUSED_VAR(user_data),
|
||||||
|
void *buf,
|
||||||
|
size_t buf_len
|
||||||
|
) {
|
||||||
|
if (0 > printf("%.*s\n", (int)buf_len, (char *)buf)) {
|
||||||
|
log_printf("printf(): %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (
|
main (
|
||||||
int argc,
|
int argc,
|
||||||
|
|
254
src/xattr.c
Normal file
254
src/xattr.c
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/**
|
||||||
|
* bookmarkfs/src/xattr.c
|
||||||
|
* ----
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 CismonX <admin@cismon.net>
|
||||||
|
*
|
||||||
|
* This file is part of BookmarkFS.
|
||||||
|
*
|
||||||
|
* BookmarkFS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* BookmarkFS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with BookmarkFS. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "xattr.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#if defined(__linux__)
|
||||||
|
# include <sys/xattr.h>
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
# include <sys/extattr.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "xstd.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
# define XATTR_NAME_PREFIX BOOKMARKFS_XATTR_PREFIX
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
# define XATTR_NAME_PREFIX ( &BOOKMARKFS_XATTR_PREFIX[strlen("user.")] )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Forward declaration start
|
||||||
|
static ssize_t xattr_do_get (int, char const *, void *, size_t);
|
||||||
|
static ssize_t xattr_do_list (int, void *, size_t);
|
||||||
|
static int xattr_do_set (int, char const *, void const *, size_t);
|
||||||
|
static char * xattr_normalize_name (char const *);
|
||||||
|
// Forward declaration end
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
xattr_do_get (
|
||||||
|
int fd,
|
||||||
|
char const *name,
|
||||||
|
void *buf,
|
||||||
|
size_t buf_len
|
||||||
|
) {
|
||||||
|
ssize_t result;
|
||||||
|
#if defined(__linux__)
|
||||||
|
result = fgetxattr(fd, name, buf, buf_len);
|
||||||
|
if (result < 0) {
|
||||||
|
log_printf("fgetxattr(): %s", strerror(errno));
|
||||||
|
}
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
result = extattr_get_fd(fd, EXTATTR_NAMESPACE_USER, name, buf, buf_len);
|
||||||
|
if (result < 0) {
|
||||||
|
log_printf("extattr_get_fd(): %s", strerror(errno));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error "not implemented"
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
xattr_do_list (
|
||||||
|
int fd,
|
||||||
|
void *buf,
|
||||||
|
size_t buf_len
|
||||||
|
) {
|
||||||
|
ssize_t result;
|
||||||
|
#if defined(__linux__)
|
||||||
|
result = flistxattr(fd, buf, buf_len);
|
||||||
|
if (result < 0) {
|
||||||
|
log_printf("flistxattr(): %s", strerror(errno));
|
||||||
|
}
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
result = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, buf, buf_len);
|
||||||
|
if (result < 0) {
|
||||||
|
log_printf("extattr_list_fd(): %s", strerror(errno));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error "not implemented"
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xattr_do_set (
|
||||||
|
int fd,
|
||||||
|
char const *name,
|
||||||
|
void const *buf,
|
||||||
|
size_t buf_len
|
||||||
|
) {
|
||||||
|
#if defined(__linux__)
|
||||||
|
if (0 != fsetxattr(fd, name, buf, buf_len, 0)) {
|
||||||
|
log_printf("fsetxattr(): %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
if (0 > extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, name, buf, buf_len)) {
|
||||||
|
log_printf("extattr_set_fd(): %s", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error "not implemented"
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
xattr_normalize_name (
|
||||||
|
char const *name
|
||||||
|
) {
|
||||||
|
char const *prefix = XATTR_NAME_PREFIX;
|
||||||
|
size_t prefix_len = strlen(prefix);
|
||||||
|
size_t name_len = strlen(name);
|
||||||
|
|
||||||
|
char *new_name = xmalloc(prefix_len + name_len + 1);
|
||||||
|
memcpy(new_name, prefix, prefix_len);
|
||||||
|
memcpy(new_name + prefix_len, name, name_len + 1);
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bookmarkfs_xattr_get (
|
||||||
|
int fd,
|
||||||
|
char const *name,
|
||||||
|
bookmarkfs_xattr_cb *callback,
|
||||||
|
void *user_data
|
||||||
|
) {
|
||||||
|
char *real_name = xattr_normalize_name(name);
|
||||||
|
void *buf = NULL;
|
||||||
|
ssize_t result;
|
||||||
|
do {
|
||||||
|
result = xattr_do_get(fd, real_name, NULL, 0);
|
||||||
|
if (result < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = xrealloc(buf, result);
|
||||||
|
result = xattr_do_get(fd, real_name, buf, result);
|
||||||
|
if (unlikely(result < 0)) {
|
||||||
|
if (result == -ERANGE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = callback(user_data, buf, result);
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
free(real_name);
|
||||||
|
free(buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bookmarkfs_xattr_list (
|
||||||
|
int fd,
|
||||||
|
bookmarkfs_xattr_cb *callback,
|
||||||
|
void *user_data
|
||||||
|
) {
|
||||||
|
char *buf = NULL;
|
||||||
|
ssize_t result;
|
||||||
|
do {
|
||||||
|
result = xattr_do_list(fd, NULL, 0);
|
||||||
|
if (result < 0) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = xrealloc(buf, result);
|
||||||
|
result = xattr_do_list(fd, buf, result);
|
||||||
|
if (unlikely(result < 0)) {
|
||||||
|
if (result == -ERANGE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
char const *prefix = XATTR_NAME_PREFIX;
|
||||||
|
size_t prefix_len = strlen(prefix);
|
||||||
|
for (char *curr = buf, *end = curr + result; curr < end; ) {
|
||||||
|
char *name;
|
||||||
|
size_t name_len;
|
||||||
|
#if defined(__linux__)
|
||||||
|
name = curr;
|
||||||
|
name_len = strlen(name);
|
||||||
|
curr += name_len + 1;
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
name_len = (unsigned char)(*(curr++));
|
||||||
|
name = curr;
|
||||||
|
curr += name_len;
|
||||||
|
#else
|
||||||
|
# error "not implemented"
|
||||||
|
#endif
|
||||||
|
if (name_len <= prefix_len || 0 != memcmp(prefix, name, prefix_len)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result = callback(user_data, name + prefix_len, name_len - prefix_len);
|
||||||
|
if (result != 0) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
free(buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bookmarkfs_xattr_open (
|
||||||
|
char const *path
|
||||||
|
) {
|
||||||
|
int flags = O_RDONLY;
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
// Linux does not accept O_PATH fd for f*xattr() calls.
|
||||||
|
flags |= O_PATH;
|
||||||
|
#endif
|
||||||
|
int fd = open(path, flags);
|
||||||
|
if (fd < 0) {
|
||||||
|
log_printf("open(): %s: %s", path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bookmarkfs_xattr_set (
|
||||||
|
int fd,
|
||||||
|
char const *name,
|
||||||
|
void const *buf,
|
||||||
|
size_t buf_len
|
||||||
|
) {
|
||||||
|
char *real_name = xattr_normalize_name(name);
|
||||||
|
int status = xattr_do_set(fd, real_name, buf, buf_len);
|
||||||
|
free(real_name);
|
||||||
|
return status;
|
||||||
|
}
|
62
src/xattr.h
Normal file
62
src/xattr.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* bookmarkfs/src/xattr.h
|
||||||
|
* ----
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 CismonX <admin@cismon.net>
|
||||||
|
*
|
||||||
|
* This file is part of BookmarkFS.
|
||||||
|
*
|
||||||
|
* BookmarkFS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* BookmarkFS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with BookmarkFS. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOKMARKFS_XATTR_H_
|
||||||
|
#define BOOKMARKFS_XATTR_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef int (bookmarkfs_xattr_cb) (
|
||||||
|
void *user_data,
|
||||||
|
void *buf,
|
||||||
|
size_t buf_len
|
||||||
|
);
|
||||||
|
|
||||||
|
int
|
||||||
|
bookmarkfs_xattr_get (
|
||||||
|
int fd,
|
||||||
|
char const *name,
|
||||||
|
bookmarkfs_xattr_cb *callback,
|
||||||
|
void *user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
int
|
||||||
|
bookmarkfs_xattr_list (
|
||||||
|
int fd,
|
||||||
|
bookmarkfs_xattr_cb *callback,
|
||||||
|
void *user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
int
|
||||||
|
bookmarkfs_xattr_open (
|
||||||
|
char const *path
|
||||||
|
);
|
||||||
|
|
||||||
|
int
|
||||||
|
bookmarkfs_xattr_set (
|
||||||
|
int fd,
|
||||||
|
char const *name,
|
||||||
|
void const *buf,
|
||||||
|
size_t buf_len
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* !defined(BOOKMARKFS_XATTR_H_) */
|
Loading…
Add table
Reference in a new issue