summaryrefslogtreecommitdiff
path: root/src/kernel/vfs
diff options
context:
space:
mode:
authordzwdz2024-08-18 19:51:22 +0200
committerdzwdz2024-08-18 19:51:22 +0200
commit446acde84c7f244792bf412996678254ee296356 (patch)
treeaac69ff6be5a77afdb1e7026e8ae42d81234e650 /src/kernel/vfs
parentc04e6c907efdbfa0a897c55530262f59ea1a5cef (diff)
kernel/req: support combined kernel and user inputs
prep work for setxattr
Diffstat (limited to 'src/kernel/vfs')
-rw-r--r--src/kernel/vfs/request.c53
1 files changed, 34 insertions, 19 deletions
diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c
index 4e8a162..9c5b327 100644
--- a/src/kernel/vfs/request.c
+++ b/src/kernel/vfs/request.c
@@ -144,36 +144,51 @@ vfsback_useraccept(VfsReq *req)
handler = backend->user.handler;
assert(handler->state == PS_WAITS4REQUEST);
+ res.capacity = req->outlen;
+ res.id = req->id;
+ res.id2 = req->id2;
+ res.offset = req->offset;
+ res.flags = req->flags;
+ res.op = req->type;
+
// the pcpy calls aren't present in all kernel backends
// it's a way to tell apart kernel and user backends apart
// TODO check validity of memory regions somewhere else
- assert(!(req->kin && req->uin));
- if (req->kin) {
+ if (req->kin || req->uin) {
void __user *buf = handler->awaited_req.buf;
- if (req->kinlen+1 <= handler->awaited_req.max_len) {
+ size_t space = handler->awaited_req.max_len;
+ len = 0;
+ if (req->kin) {
+ /* the +1 is for the NUL terminator, the length passed to userland
+ * doesn't include it. */
+ if (space < req->kinlen+1) {
+ /* no space to fit the string, fail instead of truncating */
+ // XXX this is an easy way to tell user fses apart from kernel fses
+ vfsreq_finish_short(req, -ENOENT);
+ return;
+ }
len = req->kinlen;
pcpy_to(handler, buf, req->kin, len+1); /* +1 for NUL */
- } else {
- // XXX this is an easy way to tell user fses apart from kernel fses
- vfsreq_finish_short(req, -ENOENT);
- return;
+ buf += len+1;
+ space -= len+1;
+ }
+ if (req->uin) {
+ if (req->kin) {
+ /* save the address of the "second buffer" in id2,
+ * which should be free */
+ assert(res.id2 == NULL);
+ res.id2 = buf;
+ }
+
+ len = min(req->uinlen, space);
+ len = pcpy_bi(handler, buf, req->caller, req->uin, len);
}
- } else if (req->uin) {
- void __user *buf = handler->awaited_req.buf;
- len = min(req->uinlen, handler->awaited_req.max_len);
- len = pcpy_bi(handler, buf, req->caller, req->uin, len);
} else {
+ /* this is stupid but a bunch of old code depends on it */
len = req->outlen;
}
-
- res.len = len;
- res.capacity = req->outlen;
- res.id = req->id;
- res.id2 = req->id2;
- res.offset = req->offset;
- res.flags = req->flags;
- res.op = req->type;
+ res.len = len;
if (pcpy_to(handler, handler->awaited_req.res, &res, sizeof res) < sizeof(res))
{