summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordzwdz2024-08-18 23:06:26 +0200
committerdzwdz2024-08-18 23:06:26 +0200
commit8b4a2d50de67b746bcc472bd46c55d83eff668fc (patch)
tree21bcf9814b07bc54e7705f4e9ae93528d627e838 /src
parent446acde84c7f244792bf412996678254ee296356 (diff)
kernel: basic _sys_setxattr implementationHEADmain
Diffstat (limited to 'src')
-rw-r--r--src/cmd/setxattr.c23
-rw-r--r--src/cmd/tmpfs.c107
-rw-r--r--src/kernel/syscalls.c36
-rw-r--r--src/kernel/vfs/request.c9
-rw-r--r--src/kernel/vfs/request.h2
-rw-r--r--src/libc/include/__errno.h1
-rw-r--r--src/libc/syscall.c4
-rw-r--r--src/libk/include/camellia/errno.h1
-rw-r--r--src/libk/include/camellia/syscalls.h2
-rw-r--r--src/libk/include/camellia/types.h1
10 files changed, 179 insertions, 7 deletions
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 {