diff options
author | dzwdz | 2024-08-18 23:06:26 +0200 |
---|---|---|
committer | dzwdz | 2024-08-18 23:06:26 +0200 |
commit | 8b4a2d50de67b746bcc472bd46c55d83eff668fc (patch) | |
tree | 21bcf9814b07bc54e7705f4e9ae93528d627e838 | |
parent | 446acde84c7f244792bf412996678254ee296356 (diff) |
-rw-r--r-- | man/getxattr.2 | 3 | ||||
-rw-r--r-- | man/setxattr.2 | 59 | ||||
-rw-r--r-- | src/cmd/setxattr.c | 23 | ||||
-rw-r--r-- | src/cmd/tmpfs.c | 107 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 36 | ||||
-rw-r--r-- | src/kernel/vfs/request.c | 9 | ||||
-rw-r--r-- | src/kernel/vfs/request.h | 2 | ||||
-rw-r--r-- | src/libc/include/__errno.h | 1 | ||||
-rw-r--r-- | src/libc/syscall.c | 4 | ||||
-rw-r--r-- | src/libk/include/camellia/errno.h | 1 | ||||
-rw-r--r-- | src/libk/include/camellia/syscalls.h | 2 | ||||
-rw-r--r-- | src/libk/include/camellia/types.h | 1 |
12 files changed, 240 insertions, 8 deletions
diff --git a/man/getxattr.2 b/man/getxattr.2 index d7a287e..c64ba5d 100644 --- a/man/getxattr.2 +++ b/man/getxattr.2 @@ -56,7 +56,8 @@ The filesystem probably doesn't support xattrs, and it wasn't written very well. Sorry. .El -.\" .Sh SEE ALSO +.Sh SEE ALSO +.Xr getxattr 2 . .Sh NOTES The maximum size of the xattr value might become limited in the future, as in Linux. diff --git a/man/setxattr.2 b/man/setxattr.2 new file mode 100644 index 0000000..0690d35 --- /dev/null +++ b/man/setxattr.2 @@ -0,0 +1,59 @@ +.Dd August 18, 2024 +.Dt SETXATTR 2 +.Os Camellia +.Sh NAME +.Nm setxattr +.Nd set file attribute +.Sh SYNOPSIS +.In camellia/syscalls.h +.Ft ssize_t +.Fo _sys_setxattr +.Fa "hid_t h" +.Fa "const char *name" +.Fa "const void *buf" +.Fa "size_t len" +.Fa "int flags" +.Fc +.Sh DESCRIPTION +.Nm +sets the attribute of +.Fa h +named by +.Fa name +to the contents of +.Fa buf . +.Fa flags +is reserved for future use, for now it has to be 0. +.Pp +For more details see +.Xr getxattr 2 . +.Sh RETURN VALUES +.Nm +returns +.Fa len +or a negative value on failure. +The most common errors are: +.Bl -tag -width EGENERIC +.It Er ENOSYS +The filesystem doesn't support xattrs. +.It Er EGENERIC +The filesystem probably doesn't support xattrs, +and it wasn't written very well. +Sorry. +.It Er EACCES +You lack the permission to write this xattr. +.El +.Pp +In theory filesystems can return a nonnegative value different from +.Fa len , +but that shouldn't ever happen. +.Sh SEE ALSO +.Xr getxattr 2 +.Sh BUGS +There's no way to delete attributes right now. +This will probably be done with some sort of +.Dv XATTR_DELETE +flag. +.Sh RATIONALE +See +.Xr getxattr 2 . diff --git a/src/cmd/setxattr.c b/src/cmd/setxattr.c new file mode 100644 index 0000000..c2e422e --- /dev/null +++ b/src/cmd/setxattr.c @@ -0,0 +1,23 @@ +#include <camellia.h> +#include <camellia/syscalls.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +int +main(int argc, char **argv) +{ + if (argc != 4) { + fprintf(stderr, "usage: setxattr file key value\n"); + return 1; + } + hid_t h = camellia_open(argv[1], OPEN_WRITE); + if (h < 0) err(1, "open"); + + ssize_t ret = _sys_setxattr(h, argv[2], argv[3], strlen(argv[3]), 0); + if (ret < 0) { + errno = -ret; + err(1, "setxattr"); + } +} diff --git a/src/cmd/tmpfs.c b/src/cmd/tmpfs.c index 5e4b4e8..352b2f1 100644 --- a/src/cmd/tmpfs.c +++ b/src/cmd/tmpfs.c @@ -12,6 +12,7 @@ #include <unistd.h> typedef struct Node Node; +typedef struct Xattr Xattr; struct Node { char *name; size_t namelen; @@ -26,9 +27,16 @@ struct Node { * files. */ Node **ref; + Xattr *xattr; + /* allocated by tmpfs_open * freed by node_close when (open == 0 && ref == NULL && self != node_root). */ }; +struct Xattr { + Xattr *next; + char *name, *buf; /* owned */ + size_t len; /* 0 means deleted. yeah, this isn't efficient, idc */ +}; static Node node_root = { .directory = true, @@ -44,6 +52,8 @@ static long node_move(Node *from, Node *to); /** Removes a file. It's kept in memory until all the open handles are closed. */ static long node_remove(Node *node); static void node_sanity(Node *node, Node **from); +static Xattr *node_getxattr(Node *node, const char *name); +static char *node_xattrindex(Node *node, int *plen); static Node * @@ -106,19 +116,28 @@ tmpfs_open(const char *path, struct ufs_request *req) } static void -node_close(Node *node) { +node_close(Node *node) +{ node->open--; if (node->ref == NULL && node != &node_root && node->open == 0) { if (node->name) { free(node->name); } + while (node->xattr) { + Xattr *x = node->xattr; + node->xattr = x->next; + free(x->name); + free(x->buf); + free(x); + } free(node->buf); free(node); } } static long -node_move(Node *from, Node *to) { +node_move(Node *from, Node *to) +{ if (from == &node_root || to == &node_root) { return -1; } @@ -161,7 +180,8 @@ node_move(Node *from, Node *to) { } static long -node_remove(Node *node) { +node_remove(Node *node) +{ if (node == &node_root) return -1; if (!node->ref) return -1; if (node->child) return -ENOTEMPTY; @@ -173,7 +193,8 @@ node_remove(Node *node) { } static void -node_sanity(Node *node, Node **from) { +node_sanity(Node *node, Node **from) +{ if (node == NULL) return; if (node != &node_root && node->ref != from) { assert(false); @@ -182,8 +203,41 @@ node_sanity(Node *node, Node **from) { node_sanity(node->child, &node->child); } +static Xattr * +node_getxattr(Node *node, const char *name) +{ + for (Xattr *x = node->xattr; x; x = x->next) { + if (strcmp(name, x->name) == 0) { + return x; + } + } + return NULL; +} + +static char * +node_xattrindex(Node *node, int *plen) +{ + char *buf, *it; + int len = 0; + for (Xattr *x = node->xattr; x; x = x->next) { + if (x->len == 0) continue; + len += strlen(x->name) + 1; + } + buf = it = malloc(len); + *plen = len; + for (Xattr *x = node->xattr; x; x = x->next) { + if (x->len == 0) continue; + int slen = strlen(x->name) + 1; + memcpy(it, x->name, slen); + it += slen; + } + assert(buf + len == it); + return buf; +} + int -main(void) { +main(void) +{ const size_t buflen = 4096; char *buf = malloc(buflen); if (!buf) return -1; @@ -266,8 +320,49 @@ main(void) { } break; + case VFSOP_GETXATTR: + if (strcmp(buf, "virt.index") == 0) { + int len; + char *res = node_xattrindex(req.id, &len); + _sys_fs_respond(reqh, res, len, 0); + free(res); + } else { + Xattr *x = node_getxattr(req.id, buf); + if (x == NULL || x->len == 0) { + _sys_fs_respond(reqh, NULL, -ENOENT, 0); + } else { + _sys_fs_respond(reqh, x->buf, x->len, 0); + } + } + break; + + case VFSOP_SETXATTR: + /* dirty but safe in this context */ + if (memcmp("user.", buf, 5) != 0) { + _sys_fs_respond(reqh, NULL, -EACCES, 0); + } else { + Xattr *x = node_getxattr(req.id, buf); + if (x == NULL) { + x = calloc(1, sizeof(Xattr)); + x->name = strdup(buf); + x->next = ptr->xattr; + ptr->xattr = x; + } + free(x->buf); + x->buf = malloc(req.len); + if (x->buf == NULL) { + x->len = 0; + _sys_fs_respond(reqh, NULL, -ENOSPC, 0); + break; + } + x->len = req.len; + memcpy(x->buf, req.id2, req.len); + _sys_fs_respond(reqh, 0, req.len, 0); + } + break; + default: - _sys_fs_respond(reqh, NULL, -1, 0); + _sys_fs_respond(reqh, NULL, -ENOSYS, 0); break; } node_sanity(&node_root, NULL); diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 436000c..50ff589 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -548,6 +548,41 @@ ssize_t _sys_getxattr(hid_t hid, const char __user *name, void __user *buf, size return 0; } +ssize_t _sys_setxattr(hid_t hid, const char __user *name, const void __user *buf, size_t len, int flags) { + Handle *h = hs_get(proc_cur->hs, hid); + if (!h) { + SYSCALL_RETURN(-EBADF); + } + if (h->type != HANDLE_FILE || flags != 0) { + SYSCALL_RETURN(-ENOSYS); + } + if (!h->writeable) { + SYSCALL_RETURN(-EACCES); + } + char tmpbuf[XATTRNAME_MAX]; + size_t namelen = pcpy_from_str(proc_cur, tmpbuf, name, XATTRNAME_MAX); + if (namelen == 0) { + SYSCALL_RETURN(-EFAULT); + } + assert(namelen <= XATTRNAME_MAX); + assert(tmpbuf[namelen-1] == '\0'); + + char *namebuf = kmalloc(namelen, TagXattrName); + memcpy(namebuf, tmpbuf, namelen); + + vfsreq_dispatchcopy((VfsReq) { + .type = VFSOP_SETXATTR, + .backend = h->backend, + .id = h->file_id, + .caller = proc_cur, + .kin = namebuf, + .kinlen = namelen-1, + .uin = buf, + .uinlen = len, + }); + return 0; +} + long _sys_execbuf(void __user *ubuf, size_t len) { if (len == 0) SYSCALL_RETURN(0); static_assert(EXECBUF_MAX_LEN <= KMALLOC_MAX); @@ -607,6 +642,7 @@ long _syscall(long num, long a, long b, long c, long d, long e) { break; case _SYS_DUPLEX: _sys_duplex(a, b, c); break; case _SYS_INTR_RETURN: _sys_intr_return((userptr_t)a, b); break; case _SYS_GETXATTR: _sys_getxattr(a, (userptr_t)b, (userptr_t)c, d, e); + break; case _SYS_SETXATTR: _sys_setxattr(a, (userptr_t)b, (userptr_t)c, d, e); break; case _SYS_EXECBUF: _sys_execbuf((userptr_t)a, b); break; case _SYS_DEBUG_KLOG: _sys_debug_klog((userptr_t)a, b); break; diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c index 9c5b327..194ee49 100644 --- a/src/kernel/vfs/request.c +++ b/src/kernel/vfs/request.c @@ -174,6 +174,12 @@ vfsback_useraccept(VfsReq *req) space -= len+1; } if (req->uin) { + if (space < req->uinlen && req->type == VFSOP_SETXATTR) { + /* don't truncate xattr values */ + // TODO test + vfsreq_finish_short(req, -ERANGE); + return; + } if (req->kin) { /* save the address of the "second buffer" in id2, * which should be free */ @@ -181,6 +187,9 @@ vfsback_useraccept(VfsReq *req) res.id2 = buf; } + /* intentionally overriding the prior len */ + assert(len == 0 || req->type == VFSOP_SETXATTR); + len = min(req->uinlen, space); len = pcpy_bi(handler, buf, req->caller, req->uin, len); } diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h index 484fdd7..fa62b35 100644 --- a/src/kernel/vfs/request.h +++ b/src/kernel/vfs/request.h @@ -45,7 +45,7 @@ struct VfsReq { size_t kinlen; /* user inputs and outputs - just point to some buffer in the caller */ - char __user *uin; + const char __user *uin; size_t uinlen; char __user *out; size_t outlen; diff --git a/src/libc/include/__errno.h b/src/libc/include/__errno.h index 56bd64a..6f971e1 100644 --- a/src/libc/include/__errno.h +++ b/src/libc/include/__errno.h @@ -32,4 +32,5 @@ E(214, "EADDRNOTAVAIL") E(215, "EADDRINUSE") E(216, "ENOSPC") E(217, "ECONNREFUSED") +E(218, "E2BIG") #endif diff --git a/src/libc/syscall.c b/src/libc/syscall.c index 6577141..2366a9f 100644 --- a/src/libc/syscall.c +++ b/src/libc/syscall.c @@ -110,6 +110,10 @@ ssize_t _sys_getxattr(hid_t h, const char __user *name, void __user *buf, size_t return (ssize_t)_syscall(_SYS_GETXATTR, (long)h, (long)name, (long)buf, (long)len, (long)flags); } +ssize_t _sys_setxattr(hid_t h, const char __user *name, const void __user *buf, size_t len, int flags) { + return (ssize_t)_syscall(_SYS_SETXATTR, (long)h, (long)name, (long)buf, (long)len, (long)flags); +} + long _sys_execbuf(void __user *buf, size_t len) { return _syscall(_SYS_EXECBUF, (long)buf, (long)len, 0, 0, 0); } diff --git a/src/libk/include/camellia/errno.h b/src/libk/include/camellia/errno.h index eaeae38..8a424f2 100644 --- a/src/libk/include/camellia/errno.h +++ b/src/libk/include/camellia/errno.h @@ -35,3 +35,4 @@ #define EADDRINUSE 215 #define ENOSPC 216 #define ECONNREFUSED 217 +#define E2BIG 218 diff --git a/src/libk/include/camellia/syscalls.h b/src/libk/include/camellia/syscalls.h index b8dd52e..887d084 100644 --- a/src/libk/include/camellia/syscalls.h +++ b/src/libk/include/camellia/syscalls.h @@ -26,6 +26,7 @@ #define _SYS_DUPLEX 25 #define _SYS_INTR_RETURN 26 #define _SYS_GETXATTR 27 +#define _SYS_SETXATTR 28 #define _SYS_EXECBUF 100 #define _SYS_DEBUG_KLOG 101 @@ -97,6 +98,7 @@ long _sys_duplex(hid_t from, hid_t to, int flags); void _sys_intr_return(struct intr_data __user *intr, int flags); ssize_t _sys_getxattr(hid_t h, const char __user *name, void __user *buf, size_t len, int flags); +ssize_t _sys_setxattr(hid_t h, const char __user *name, const void __user *buf, size_t len, int flags); /* see shared/execbuf.h */ long _sys_execbuf(void __user *buf, size_t len); diff --git a/src/libk/include/camellia/types.h b/src/libk/include/camellia/types.h index 6864d4c..70af409 100644 --- a/src/libk/include/camellia/types.h +++ b/src/libk/include/camellia/types.h @@ -25,6 +25,7 @@ enum vfs_op { VFSOP_CLOSE, VFSOP_DUPLEX, VFSOP_GETXATTR, + VFSOP_SETXATTR, }; struct ufs_request { |