summaryrefslogtreecommitdiff
path: root/lib9p/srv.c
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-19 12:53:51 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-19 12:53:51 -0600
commit59e1fc370371c8da876d6c2ce68794bb7f89e525 (patch)
tree8037e1493bfebe72cb6023f5eccb62cff0c63349 /lib9p/srv.c
parent0cf05b66f94bfe02ecca37a4cbafba25b27c32ae (diff)
parent7f34046f5b27617b70c1d55f479c2a1abb8b8d8a (diff)
Merge branch 'lukeshu/9p-tidy'
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r--lib9p/srv.c626
1 files changed, 381 insertions, 245 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 6ab2ab2..08ccfc3 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -92,11 +92,12 @@ struct srv_pathinfo {
#define FIDFLAG_OPEN_R (1<<0)
#define FIDFLAG_OPEN_W (1<<1)
#define FIDFLAG_RCLOSE (1<<2)
+#define FIDFLAG_APPEND (1<<3)
#define FIDFLAG_OPEN (FIDFLAG_OPEN_R|FIDFLAG_OPEN_W)
struct srv_fidinfo {
srv_path_t path;
- struct lib9p_srv_authinfo *authinfo;
+ struct lib9p_srv_userid *user;
uint8_t flags;
enum srv_filetype type;
union {
@@ -107,6 +108,7 @@ struct srv_fidinfo {
lo_interface lib9p_srv_dio io;
size_t idx;
uint64_t off;
+ struct lib9p_srv_dirent buffered_dirent;
} dir;
struct {
struct lib9p_s aname;
@@ -163,44 +165,52 @@ static inline enum srv_filetype srv_qid_filetype(struct lib9p_qid qid) {
return SRV_FILETYPE_FILE;
}
-static inline bool srv_check_perm(struct srv_req *ctx, struct lib9p_stat *stat, uint8_t action) {
+static inline bool srv_check_perm(struct srv_req *ctx, struct lib9p_srv_stat *stat, uint8_t action) {
assert(ctx);
assert(stat);
assert(action);
/* TODO actually check user and group instead of just assuming "other". */
- uint8_t mode = (uint8_t)(stat->file_mode & 07);
+ uint8_t mode = (uint8_t)(stat->mode & 07);
return mode & action;
}
-struct lib9p_srv_authinfo *srv_authinfo_new(struct lib9p_s uname, lib9p_nuid_t uid) {
- struct lib9p_srv_authinfo *ret = malloc(sizeof(struct lib9p_srv_authinfo) + uname.len);
+[[gnu::unused]]
+static struct lib9p_srv_userid *srv_userid_new(struct lib9p_s name
+#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
+ , lib9p_nuid_t num
+#endif
+ ) {
+ struct lib9p_srv_userid *ret = malloc(sizeof(struct lib9p_srv_userid) + name.len);
if (!ret)
return NULL;
- ret->uid = uid;
- ret->uname.len = uname.len;
- ret->uname.utf8 = (void *)&ret[1];
- memcpy(ret->uname.utf8, uname.utf8, uname.len);
+#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
+ ret->num = num;
+#endif
+ ret->name.len = name.len;
+ ret->name.utf8 = (void *)&ret[1];
+ memcpy(ret->name.utf8, name.utf8, name.len);
ret->refcount = 1;
return ret;
}
+#if !(CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L)
+#define srv_userid_new(name, num) srv_userid_new(name)
+#endif
-struct lib9p_srv_authinfo *srv_authinfo_decref(struct lib9p_srv_authinfo *authinfo) {
- assert(authinfo);
- assert(authinfo->refcount);
- authinfo->refcount--;
- if (!authinfo->refcount) {
- free(authinfo);
- return NULL;
- }
- return authinfo;
+static struct lib9p_srv_userid *srv_userid_decref(struct lib9p_srv_userid *userid) {
+ assert(userid);
+ assert(userid->refcount);
+ userid->refcount--;
+ if (!userid->refcount)
+ free(userid);
+ return NULL;
}
-struct lib9p_srv_authinfo *srv_authinfo_incref(struct lib9p_srv_authinfo *authinfo) {
- assert(authinfo);
- authinfo->refcount++;
- return authinfo;
+static struct lib9p_srv_userid *srv_userid_incref(struct lib9p_srv_userid *userid) {
+ assert(userid);
+ userid->refcount++;
+ return userid;
}
/**
@@ -262,32 +272,21 @@ static inline void srv_path_decref(struct srv_req *ctx, srv_path_t path) {
}
}
-static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove) {
- struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, fid);
+static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_fidinfo *fidinfo, bool remove) {
+ assert(ctx);
+ assert(!ctx->user);
assert(fidinfo);
+
if (fidinfo->flags & FIDFLAG_RCLOSE)
remove = true;
+ ctx->user = srv_userid_incref(fidinfo->user);
+
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(pathinfo);
- if (remove) {
- if (pathinfo->parent_dir == fidinfo->path) {
- lib9p_errorf(&ctx->basectx,
- LIB9P_ERRNO_L_EBUSY, "cannot remove root");
- goto clunk;
- }
- struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
- assert(parent);
- struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, ctx);
- if (!srv_check_perm(ctx, &parent_stat, 0b010)) {
- lib9p_error(&ctx->basectx,
- LIB9P_ERRNO_L_EACCES, "you do not have write permission on the parent directory");
- goto clunk;
- }
+ if (remove)
LO_CALL(pathinfo->file, remove, ctx);
- }
- clunk:
if (fidinfo->flags & FIDFLAG_OPEN) {
switch (fidinfo->type) {
case SRV_FILETYPE_DIR:
@@ -302,9 +301,11 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove
}
pathinfo->io_refcount--;
}
- fidinfo->authinfo = srv_authinfo_decref(fidinfo->authinfo);
+ fidinfo->user = srv_userid_decref(fidinfo->user);
srv_path_decref(ctx, fidinfo->path);
map_del(&ctx->parent_sess->fids, fid);
+
+ ctx->user = srv_userid_decref(ctx->user);
}
/**
@@ -329,7 +330,7 @@ static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t
assert(old_fidinfo->type == SRV_FILETYPE_DIR);
assert(old_fidinfo->flags == 0);
- old_fidinfo->authinfo = srv_authinfo_decref(old_fidinfo->authinfo);
+ old_fidinfo->user = srv_userid_decref(old_fidinfo->user);
srv_path_decref(ctx, old_fidinfo->path);
map_del(&ctx->parent_sess->fids, fid);
} else {
@@ -339,9 +340,9 @@ static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t
}
}
struct srv_fidinfo *fidinfo = map_store(&ctx->parent_sess->fids, fid, (struct srv_fidinfo){
- .path = qid.path,
- .type = srv_qid_filetype(qid),
- .authinfo = srv_authinfo_incref(ctx->authinfo),
+ .path = qid.path,
+ .type = srv_qid_filetype(qid),
+ .user = srv_userid_incref(ctx->user),
});
assert(fidinfo);
return fidinfo;
@@ -375,7 +376,7 @@ static ssize_t srv_write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *r
#define srv_nonrespond_errorf errorf
static void srv_respond_error(struct srv_req *req) {
-#if CONFIG_9P_ENABLE_9P2000_u
+#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
assert(req->basectx.err_num);
#endif
assert(req->basectx.err_msg[0]);
@@ -533,17 +534,19 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) {
assert(map_len(&sess.reqs) == 0);
map_free(&sess.reqs);
+ struct srv_req pseudoreq = {
+ .basectx = {
+ .version = sess.version,
+ .max_msg_size = sess.max_msg_size,
+ },
+ .parent_sess = &sess,
+ };
MAP_FOREACH(&sess.fids, fid, fidinfo) {
- struct srv_req req = {
- .basectx = {
- .version = sess.version,
- .max_msg_size = sess.max_msg_size,
- },
- .parent_sess = &sess,
- };
- srv_fid_del(&req, fid, false);
- if (lib9p_ctx_has_error(&req.basectx))
- errorf("clunk: %.*s", CONFIG_9P_MAX_ERR_SIZE, req.basectx.err_msg);
+ srv_fid_del(&pseudoreq, fid, fidinfo, false);
+ if (lib9p_ctx_has_error(&pseudoreq.basectx)) {
+ srv_nonrespond_errorf("clunk: %.*s", CONFIG_9P_MAX_ERR_SIZE, pseudoreq.basectx.err_msg);
+ lib9p_ctx_clear_error(&pseudoreq.basectx);
+ }
}
map_free(&sess.fids);
@@ -587,9 +590,9 @@ void lib9p_srv_worker_loop(struct lib9p_srv *srv) {
#define _HANDLER_PROTO(typ) \
static void handle_T##typ(struct srv_req *, \
- struct lib9p_msg_T##typ *, \
- struct lib9p_msg_R##typ *)
+ struct lib9p_msg_T##typ *)
_HANDLER_PROTO(version);
+#if _LIB9P_ENABLE_stat
_HANDLER_PROTO(auth);
_HANDLER_PROTO(attach);
_HANDLER_PROTO(flush);
@@ -602,6 +605,7 @@ _HANDLER_PROTO(clunk);
_HANDLER_PROTO(remove);
_HANDLER_PROTO(stat);
_HANDLER_PROTO(wstat);
+#endif
#if CONFIG_9P_ENABLE_9P2000_p9p
_HANDLER_PROTO(openfd);
#endif
@@ -611,16 +615,17 @@ _HANDLER_PROTO(sread);
_HANDLER_PROTO(swrite);
#endif
-typedef void (*tmessage_handler)(struct srv_req *, void *, void *);
+typedef void (*tmessage_handler)(struct srv_req *, void *);
void lib9p_srv_worker(struct srv_req *ctx) {
uint8_t *host_req = NULL;
- uint8_t host_resp[CONFIG_9P_SRV_MAX_HOSTMSG_SIZE];
/* Unmarshal it. *****************************************************/
ssize_t host_size = lib9p_Tmsg_validate(&ctx->basectx, ctx->net_bytes);
- if (host_size < 0)
- goto write;
+ if (host_size < 0) {
+ srv_respond_error(ctx);
+ goto release;
+ }
host_req = calloc(1, host_size);
assert(host_req);
enum lib9p_msg_type typ;
@@ -634,6 +639,7 @@ void lib9p_srv_worker(struct srv_req *ctx) {
#pragma GCC diagnostic ignored "-Wswitch-enum"
switch (typ) {
case LIB9P_TYP_Tversion: handler = (tmessage_handler)handle_Tversion; break;
+#if _LIB9P_ENABLE_stat
case LIB9P_TYP_Tauth: handler = (tmessage_handler)handle_Tauth; break;
case LIB9P_TYP_Tattach: handler = (tmessage_handler)handle_Tattach; break;
case LIB9P_TYP_Tflush: handler = (tmessage_handler)handle_Tflush; break;
@@ -646,8 +652,9 @@ void lib9p_srv_worker(struct srv_req *ctx) {
case LIB9P_TYP_Tremove: handler = (tmessage_handler)handle_Tremove; break;
case LIB9P_TYP_Tstat: handler = (tmessage_handler)handle_Tstat; break;
case LIB9P_TYP_Twstat: handler = (tmessage_handler)handle_Twstat; break;
+#endif
#if CONFIG_9P_ENABLE_9P2000_p9p
- case LIB9P_TYP_Topenfd: handler = (tmessage_handler)handle_Topenfd; break
+ case LIB9P_TYP_Topenfd: handler = (tmessage_handler)handle_Topenfd; break;
#endif
#if CONFIG_9P_ENABLE_9P2000_e
case LIB9P_TYP_Tsession: handler = (tmessage_handler)handle_Tsession; break;
@@ -658,24 +665,11 @@ void lib9p_srv_worker(struct srv_req *ctx) {
assert_notreached("lib9p_Tmsg_validate() should have rejected unknown typ");
}
#pragma GCC diagnostic pop
- handler(ctx, (void *)host_req, (void *)host_resp);
+ handler(ctx, (void *)host_req);
+ assert(ctx->responded);
- /* Write the response. ***********************************************/
- write:
- if (lib9p_ctx_has_error(&ctx->basectx)) {
- srv_respond_error(ctx);
- } else if (ctx->flush_acknowledged) {
- /* do nothing */
- } else {
- struct lib9p_Rmsg_send_buf net_resp;
- if (lib9p_Rmsg_marshal(&ctx->basectx,
- typ+1, host_resp,
- &net_resp))
- goto write;
- srv_msglog(ctx, typ+1, &host_resp);
- srv_write_Rmsg(ctx, &net_resp);
- }
/* Release resources. ************************************************/
+ release:
map_del(&ctx->parent_sess->reqs, ctx->tag);
size_t nwaiters;
while ((nwaiters = cr_chan_num_waiters(&ctx->flush_ch))) {
@@ -690,19 +684,41 @@ void lib9p_srv_worker(struct srv_req *ctx) {
free(ctx->net_bytes);
}
+static inline void _srv_respond(struct srv_req *ctx, enum lib9p_msg_type resp_typ, void *host_resp) {
+ assert(!ctx->responded);
+ if (lib9p_ctx_has_error(&ctx->basectx)) {
+ error:
+ srv_respond_error(ctx);
+ } else if (ctx->flush_acknowledged) {
+ /* do nothing */
+ } else {
+ assert(host_resp);
+ struct lib9p_Rmsg_send_buf net_resp;
+ if (lib9p_Rmsg_marshal(&ctx->basectx,
+ resp_typ, host_resp,
+ &net_resp))
+ goto error;
+ srv_msglog(ctx, resp_typ, host_resp);
+ srv_write_Rmsg(ctx, &net_resp);
+ }
+ ctx->responded = true;
+}
+#define srv_respond(CTX, TYP, HOST_RESP) do { \
+ struct lib9p_msg_R##TYP *_host_resp = HOST_RESP; \
+ _srv_respond(CTX, LIB9P_TYP_R##TYP, _host_resp); \
+} while (0)
+
/* handle_T* ******************************************************************/
-#define srv_handler_common(ctx, req, resp) do { \
- assert(ctx); \
- assert(req); \
- assert(resp); \
- resp->tag = req->tag; \
- } while (0)
+#define srv_handler_common(ctx, typ, req) \
+ assert(ctx); \
+ assert(req); \
+ struct lib9p_msg_T##typ *_typecheck_req [[gnu::unused]] = req; \
+ struct lib9p_msg_R##typ resp = { .tag = ctx->tag }
static void handle_Tversion(struct srv_req *ctx,
- struct lib9p_msg_Tversion *req,
- struct lib9p_msg_Rversion *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tversion *req) {
+ srv_handler_common(ctx, version, req);
enum lib9p_version version = LIB9P_VER_unknown;
@@ -714,7 +730,9 @@ static void handle_Tversion(struct srv_req *ctx,
'0' <= req->version.utf8[4] && req->version.utf8[4] <= '9' &&
'0' <= req->version.utf8[5] && req->version.utf8[5] <= '9' &&
(req->version.len == 6 || req->version.utf8[6] == '.')) {
+#if CONFIG_9P_ENABLE_9P2000
version = LIB9P_VER_9P2000;
+#endif
#if CONFIG_9P_ENABLE_9P2000_p9p
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
if (srv->type_assert_unix && !LO_IS_NULL(srv->type_assert_unix(ctx->parent_sess->parent_conn->fd)))
@@ -735,15 +753,15 @@ static void handle_Tversion(struct srv_req *ctx,
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")",
lib9p_version_str(version), req->max_msg_size, min_msg_size);
- return;
+ goto tversion_return;
}
- resp->version = lib9p_str((char *)lib9p_version_str(version)); /* cast to discard "const" qualifier */
+ resp.version = lib9p_str((char *)lib9p_version_str(version)); /* cast to discard "const" qualifier */
#if CONFIG_9P_ENABLE_9P2000_p9p
if (version == LIB9P_VER_9P2000_p9p)
- resp->version = lib9p_str("9P2000");
+ resp.version = lib9p_str("9P2000");
#endif
- resp->max_msg_size = (CONFIG_9P_SRV_MAX_MSG_SIZE < req->max_msg_size)
+ resp.max_msg_size = (CONFIG_9P_SRV_MAX_MSG_SIZE < req->max_msg_size)
? CONFIG_9P_SRV_MAX_MSG_SIZE
: req->max_msg_size;
@@ -762,33 +780,36 @@ static void handle_Tversion(struct srv_req *ctx,
cr_select_v(i, args);
}
}
- if (map_len(&ctx->parent_sess->fids)) {
- /* Close all FIDs. */
- MAP_FOREACH(&ctx->parent_sess->fids, fid, fidinfo) {
- handle_Tclunk(ctx,
- &(struct lib9p_msg_Tclunk){.fid = fid},
- &(struct lib9p_msg_Rclunk){});
+ /* Close all FIDs. */
+ MAP_FOREACH(&ctx->parent_sess->fids, fid, fidinfo) {
+ srv_fid_del(ctx, fid, fidinfo, false);
+ if (lib9p_ctx_has_error(&ctx->basectx)) {
+ srv_nonrespond_errorf("clunk: %.*s", CONFIG_9P_MAX_ERR_SIZE, ctx->basectx.err_msg);
+ lib9p_ctx_clear_error(&ctx->basectx);
}
}
/* Replace the old session with the new session. */
ctx->parent_sess->version = version;
- ctx->parent_sess->max_msg_size = resp->max_msg_size;
+ ctx->parent_sess->max_msg_size = resp.max_msg_size;
+
+ tversion_return:
+ srv_respond(ctx, version, &resp);
}
+#if _LIB9P_ENABLE_stat
static void handle_Tauth(struct srv_req *ctx,
- struct lib9p_msg_Tauth *req,
- struct lib9p_msg_Rauth *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tauth *req) {
+ srv_handler_common(ctx, auth, req);
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
if (!srv->auth) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EOPNOTSUPP, "authentication not required");
- return;
+ goto tauth_return;
}
- ctx->authinfo = srv_authinfo_new(req->uname, req->n_uid);
+ ctx->user = srv_userid_new(req->uname, req->unum);
srv->auth(ctx, req->aname);
@@ -796,18 +817,20 @@ static void handle_Tauth(struct srv_req *ctx,
LIB9P_ERRNO_L_EOPNOTSUPP, "TODO: auth not implemented");
if (lib9p_ctx_has_error(&ctx->basectx))
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ ctx->user = srv_userid_decref(ctx->user);
+
+ tauth_return:
+ srv_respond(ctx, auth, &resp);
}
static void handle_Tattach(struct srv_req *ctx,
- struct lib9p_msg_Tattach *req,
- struct lib9p_msg_Rattach *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tattach *req) {
+ srv_handler_common(ctx, attach, req);
if (req->fid == LIB9P_FID_NOFID) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID");
- return;
+ goto tattach_return;
}
struct lib9p_srv *srv = ctx->parent_sess->parent_conn->parent_srv;
@@ -819,16 +842,16 @@ static void handle_Tattach(struct srv_req *ctx,
else if (afid->type != SRV_FILETYPE_AUTH)
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is not an auth-file");
- else if (!lib9p_str_eq(afid->authinfo->uname, req->uname))
+ else if (!lib9p_str_eq(afid->user->name, req->uname))
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for user=\"%.*s\" and cannot be used for user=\"%.*s\"",
- afid->authinfo->uname.len, afid->authinfo->uname.utf8,
+ afid->user->name.len, afid->user->name.utf8,
req->uname.len, req->uname.utf8);
-#if CONFIG_9P_ENABLE_9P2000_u
- else if (afid->authinfo->uid != req->n_uid)
+#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L
+ else if (afid->user->num != req->unum)
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for user=%"PRIu32" and cannot be used for user=%"PRIu32,
- afid->authinfo->uid, req->n_uid);
+ afid->user->num, req->unum);
#endif
else if (!lib9p_str_eq(afid->auth.aname, req->aname))
lib9p_errorf(&ctx->basectx,
@@ -839,24 +862,22 @@ static void handle_Tattach(struct srv_req *ctx,
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EACCES, "FID provided as auth-file has not completed authentication");
if (lib9p_ctx_has_error(&ctx->basectx))
- return;
- ctx->authinfo = srv_authinfo_incref(afid->authinfo);
+ goto tattach_return;
+ ctx->user = srv_userid_incref(afid->user);
} else {
if (req->afid != LIB9P_FID_NOFID) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EACCES, "FID provided as auth-file, but no auth-file is required");
- return;
+ goto tattach_return;
}
- ctx->authinfo = srv_authinfo_new(req->uname, req->n_uid);
+ ctx->user = srv_userid_new(req->uname, req->unum);
}
/* 1. File object */
lo_interface lib9p_srv_file root_file = srv->rootdir(ctx, req->aname);
assert(LO_IS_NULL(root_file) == lib9p_ctx_has_error(&ctx->basectx));
- if (lib9p_ctx_has_error(&ctx->basectx)) {
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
- return;
- }
+ if (lib9p_ctx_has_error(&ctx->basectx))
+ goto tattach_return;
struct lib9p_qid root_qid = LO_CALL(root_file, qid);
assert(srv_qid_filetype(root_qid) == SRV_FILETYPE_DIR);
@@ -867,19 +888,19 @@ static void handle_Tattach(struct srv_req *ctx,
/* 3. fidinfo */
if (!srv_fid_store(ctx, req->fid, root_pathinfo, false)) {
srv_path_decref(ctx, root_qid.path);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
- return;
+ goto tattach_return;
}
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
- resp->qid = root_qid;
- return;
+ resp.qid = root_qid;
+ tattach_return:
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, attach, &resp);
}
static void handle_Tflush(struct srv_req *ctx,
- struct lib9p_msg_Tflush *req,
- struct lib9p_msg_Rflush *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tflush *req) {
+ srv_handler_common(ctx, flush, req);
struct srv_req **oldreqp = map_load(&ctx->parent_sess->reqs, req->oldtag);
if (oldreqp) {
@@ -897,38 +918,39 @@ static void handle_Tflush(struct srv_req *ctx,
break;
}
}
+ srv_respond(ctx, flush, &resp);
}
static void handle_Twalk(struct srv_req *ctx,
- struct lib9p_msg_Twalk *req,
- struct lib9p_msg_Rwalk *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Twalk *req) {
+ srv_handler_common(ctx, walk, req);
if (req->newfid == LIB9P_FID_NOFID) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID");
- return;
+ goto twalk_return;
}
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ goto twalk_return;
}
if (fidinfo->flags & FIDFLAG_OPEN) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EALREADY, "cannot walk on FID open for I/O");
- return;
+ goto twalk_return;
}
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(pathinfo);
pathinfo->gc_refcount++;
- resp->wqid = (struct lib9p_qid *)(&resp[1]);
- for (resp->nwqid = 0; resp->nwqid < req->nwname; resp->nwqid++) {
+ struct lib9p_qid _resp_qid[16];
+ resp.wqid = _resp_qid;
+ for (resp.nwqid = 0; resp.nwqid < req->nwname; resp.nwqid++) {
if (pathinfo->type != SRV_FILETYPE_DIR) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_ENOTDIR, "not a directory");
@@ -936,12 +958,12 @@ static void handle_Twalk(struct srv_req *ctx,
}
struct srv_pathinfo *new_pathinfo;
- if (lib9p_str_eq(req->wname[resp->nwqid], lib9p_str(".."))) {
+ if (lib9p_str_eq(req->wname[resp.nwqid], lib9p_str(".."))) {
new_pathinfo = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
assert(new_pathinfo);
new_pathinfo->gc_refcount++;
} else {
- lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dwalk, ctx, req->wname[resp->nwqid]);
+ lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dwalk, ctx, req->wname[resp.nwqid]);
assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->basectx));
if (lib9p_ctx_has_error(&ctx->basectx))
break;
@@ -950,10 +972,10 @@ static void handle_Twalk(struct srv_req *ctx,
}
if (new_pathinfo->type == SRV_FILETYPE_DIR) {
- struct lib9p_stat stat = LO_CALL(new_pathinfo->file, stat, ctx);
+ struct lib9p_srv_stat stat = LO_CALL(new_pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(&ctx->basectx))
break;
- lib9p_stat_assert(stat);
+ lib9p_srv_stat_assert(stat);
if (!srv_check_perm(ctx, &stat, 0b001)) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EACCES, "you do not have execute permission on that directory");
@@ -962,39 +984,41 @@ static void handle_Twalk(struct srv_req *ctx,
}
}
- resp->wqid[resp->nwqid] = LO_CALL(new_pathinfo->file, qid);
+ resp.wqid[resp.nwqid] = LO_CALL(new_pathinfo->file, qid);
srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path);
pathinfo = new_pathinfo;
}
- if (resp->nwqid == req->nwname) {
+ if (resp.nwqid == req->nwname) {
if (!srv_fid_store(ctx, req->newfid, pathinfo, req->newfid == req->fid))
srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path);
} else {
assert(lib9p_ctx_has_error(&ctx->basectx));
srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path);
- if (resp->nwqid > 0)
+ if (resp.nwqid > 0)
lib9p_ctx_clear_error(&ctx->basectx);
}
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ twalk_return:
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, walk, &resp);
}
static void handle_Topen(struct srv_req *ctx,
- struct lib9p_msg_Topen *req,
- struct lib9p_msg_Ropen *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Topen *req) {
+ srv_handler_common(ctx, open, req);
/* Check that the FID is valid for this. */
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ goto topen_return;
}
if (fidinfo->flags & FIDFLAG_OPEN) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EALREADY, "FID is already open");
- return;
+ goto topen_return;
}
if (fidinfo->type == SRV_FILETYPE_DIR) {
if ( ((req->mode & LIB9P_O_MODE_MASK) != LIB9P_O_MODE_READ) ||
@@ -1002,10 +1026,10 @@ static void handle_Topen(struct srv_req *ctx,
(req->mode & LIB9P_O_RCLOSE) ) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close");
- return;
+ goto topen_return;
}
}
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
/* Variables. */
lib9p_o_t reqmode = req->mode;
@@ -1017,10 +1041,10 @@ static void handle_Topen(struct srv_req *ctx,
if (reqmode & LIB9P_O_RCLOSE) {
struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
assert(parent);
- struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, ctx);
+ struct lib9p_srv_stat parent_stat = LO_CALL(parent->file, stat, ctx);
if (lib9p_ctx_has_error(&ctx->basectx))
goto topen_return;
- lib9p_stat_assert(parent_stat);
+ lib9p_srv_stat_assert(parent_stat);
if (!srv_check_perm(ctx, &parent_stat, 0b010)) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EACCES, "permission denied to remove-on-close");
@@ -1028,17 +1052,19 @@ static void handle_Topen(struct srv_req *ctx,
}
fidflags |= FIDFLAG_RCLOSE;
}
- struct lib9p_stat stat = LO_CALL(pathinfo->file, stat, ctx);
+ struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(&ctx->basectx))
goto topen_return;
- lib9p_stat_assert(stat);
- if ((stat.file_mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) {
+ lib9p_srv_stat_assert(stat);
+ if ((stat.mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EEXIST, "exclusive file is already opened");
goto topen_return;
}
- if (stat.file_mode & LIB9P_DM_APPEND)
+ if (stat.mode & LIB9P_DM_APPEND) {
+ fidflags |= FIDFLAG_APPEND;
reqmode = reqmode & ~LIB9P_O_TRUNC;
+ }
uint8_t perm_bits = 0;
bool rd = false, wr = false;
switch (reqmode & LIB9P_O_MODE_MASK) {
@@ -1104,25 +1130,48 @@ static void handle_Topen(struct srv_req *ctx,
fidflags |= FIDFLAG_OPEN_W;
pathinfo->io_refcount++;
fidinfo->flags = fidflags;
- resp->qid = qid;
- resp->iounit = iounit;
+ resp.qid = qid;
+ resp.iounit = iounit;
topen_return:
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, open, &resp);
}
static void handle_Tcreate(struct srv_req *ctx,
- struct lib9p_msg_Tcreate *req,
- struct lib9p_msg_Rcreate *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tcreate *req) {
+ srv_handler_common(ctx, create, req);
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EOPNOTSUPP, "create not (yet?) implemented");
+
+ srv_respond(ctx, create, &resp);
+}
+
+static inline struct lib9p_stat srv_stat_to_net_stat(struct lib9p_srv_stat in) {
+ return (struct lib9p_stat){
+ .qid = in.qid,
+ .mode = in.mode,
+ .atime = in.atime_sec,
+ .mtime = in.mtime_sec,
+ .length = in.size,
+ .name = in.name,
+ .owner_uname = in.owner_uid.name,
+ .owner_gname = in.owner_gid.name,
+ .last_modifier_uname = in.last_modifier_uid.name,
+#if CONFIG_9P_ENABLE_9P2000_u
+ .owner_unum = in.owner_uid.num,
+ .owner_gnum = in.owner_gid.num,
+ .last_modifier_unum = in.last_modifier_uid.num,
+ .extension = in.extension,
+#endif
+ };
}
static void handle_Tread(struct srv_req *ctx,
- struct lib9p_msg_Tread *req,
- struct lib9p_msg_Rread *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tread *req) {
+ srv_handler_common(ctx, read, req);
+ char *heap = NULL;
/* TODO: serialize simultaneous reads to the same FID */
@@ -1131,67 +1180,120 @@ static void handle_Tread(struct srv_req *ctx,
if (!fidinfo) {
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ goto tread_return;
}
if (!(fidinfo->flags & FIDFLAG_OPEN_R)) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EINVAL, "FID not open for reading");
- return;
+ goto tread_return;
}
/* Do it. */
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
switch (fidinfo->type) {
case SRV_FILETYPE_DIR:
- /* Translate byte-offset to object-index. */
- size_t idx;
- if (req->offset == 0)
- idx = 0;
- else if (req->offset == fidinfo->dir.off)
- idx = fidinfo->dir.idx;
- else {
+#if _LIB9P_ENABLE_stat
+ /* Seek. */
+ if (req->offset == 0) {
+ fidinfo->dir.idx = 0;
+ fidinfo->dir.off = 0;
+ fidinfo->dir.buffered_dirent = (struct lib9p_srv_dirent){};
+ } else if (req->offset != fidinfo->dir.off) {
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64,
fidinfo->dir.off, req->offset);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
- return;
+ goto tread_return;
}
- /* Do it. */
- resp->data = (char *)(&resp[1]);
- size_t num = LO_CALL(fidinfo->dir.io, dread, ctx, (uint8_t *)resp->data, req->count, idx);
- /* Translate object-count back to byte-count. */
- uint32_t len = 0;
- for (size_t i = 0; i < num; i++) {
- uint32_t i_len;
- lib9p_stat_validate(&ctx->basectx, req->count, &((uint8_t *)resp->data)[len], &i_len, NULL);
- len += i_len;
+ /* Read. */
+ resp.data = heap = malloc(req->count); /* TODO: cap req->count */
+ resp.count = 0;
+ struct srv_pathinfo *dir_pathinfo = NULL;
+ for (;;) {
+ lo_interface lib9p_srv_file member_file = {};
+ struct lib9p_srv_dirent member_dirent;
+ if (fidinfo->dir.buffered_dirent.name.len) {
+ member_dirent = fidinfo->dir.buffered_dirent;
+ } else {
+ member_dirent = LO_CALL(fidinfo->dir.io, dread, ctx, fidinfo->dir.idx);
+ if (lib9p_ctx_has_error(&ctx->basectx)) {
+ if (!resp.count)
+ goto tread_return;
+ lib9p_ctx_clear_error(&ctx->basectx);
+ break;
+ }
+ }
+ if (!member_dirent.name.len)
+ break;
+ struct lib9p_srv_stat member_stat;
+ struct srv_pathinfo *member_pathinfo = map_load(&ctx->parent_sess->paths, member_dirent.qid.path);
+ if (member_pathinfo) {
+ member_stat = LO_CALL(member_pathinfo->file, stat, ctx);
+ } else {
+ if (!dir_pathinfo)
+ dir_pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(dir_pathinfo);
+ member_file = LO_CALL(dir_pathinfo->file, dwalk, ctx, member_dirent.name);
+ assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->basectx));
+ if (!lib9p_ctx_has_error(&ctx->basectx))
+ member_stat = LO_CALL(member_file, stat, ctx);
+ }
+ if (lib9p_ctx_has_error(&ctx->basectx)) {
+ if (!LO_IS_NULL(member_file))
+ LO_CALL(member_file, free);
+ if (!resp.count)
+ goto tread_return;
+ lib9p_ctx_clear_error(&ctx->basectx);
+ break;
+ }
+ lib9p_srv_stat_assert(member_stat);
+ struct lib9p_stat member_netstat = srv_stat_to_net_stat(member_stat);
+ uint32_t nbytes = lib9p_stat_marshal(&ctx->basectx, req->count-resp.count, &member_netstat,
+ (uint8_t *)&resp.data[resp.count]);
+ if (!LO_IS_NULL(member_file))
+ LO_CALL(member_file, free);
+ if (!nbytes) {
+ if (!resp.count) {
+ lib9p_error(&ctx->basectx,
+ LIB9P_ERRNO_L_ERANGE, "stat object does not fit into negotiated max message size");
+ goto tread_return;
+ }
+ fidinfo->dir.buffered_dirent = member_dirent;
+ break;
+ }
+ resp.count += nbytes;
+ fidinfo->dir.idx++;
+ fidinfo->dir.off += nbytes;
+ fidinfo->dir.buffered_dirent = (struct lib9p_srv_dirent){};
}
- resp->count = len;
- /* Remember. */
- fidinfo->dir.idx = idx+num;
- fidinfo->dir.off = req->offset + len;
+#else
+ assert_notreached("Tread for directory on protocol version without that");
+#endif
break;
case SRV_FILETYPE_FILE:
struct iovec iov;
LO_CALL(fidinfo->file.io, pread, ctx, req->count, req->offset, &iov);
if (!lib9p_ctx_has_error(&ctx->basectx) && !ctx->flush_acknowledged) {
- resp->count = iov.iov_len;
- resp->data = iov.iov_base;
- if (resp->count > req->count)
- resp->count = req->count;
+ resp.count = iov.iov_len;
+ resp.data = iov.iov_base;
+ if (resp.count > req->count)
+ resp.count = req->count;
}
break;
case SRV_FILETYPE_AUTH:
assert_notreached("TODO: auth not yet implemented");
break;
}
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ tread_return:
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, read, &resp);
+ if (heap)
+ free(heap);
}
static void handle_Twrite(struct srv_req *ctx,
- struct lib9p_msg_Twrite *req,
- struct lib9p_msg_Rwrite *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Twrite *req) {
+ srv_handler_common(ctx, write, req);
/* TODO: serialize simultaneous writes to the same FID */
@@ -1200,120 +1302,154 @@ static void handle_Twrite(struct srv_req *ctx,
if (!fidinfo) {
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ goto twrite_return;
}
if (!(fidinfo->flags & FIDFLAG_OPEN_W)) {
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EINVAL, "FID not open for writing");
- return;
+ goto twrite_return;
}
+ if (fidinfo->flags & FIDFLAG_APPEND)
+ req->offset = 0;
/* Do it. */
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
- resp->count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
+ resp.count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
+ twrite_return:
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, write, &resp);
}
static void handle_Tclunk(struct srv_req *ctx,
- struct lib9p_msg_Tclunk *req,
- struct lib9p_msg_Rclunk *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tclunk *req) {
+ srv_handler_common(ctx, clunk, req);
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ goto tclunk_return;
}
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
- srv_fid_del(ctx, req->fid, false);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ srv_fid_del(ctx, req->fid, fidinfo, false);
+
+ tclunk_return:
+ srv_respond(ctx, clunk, &resp);
}
static void handle_Tremove(struct srv_req *ctx,
- struct lib9p_msg_Tremove *req,
- struct lib9p_msg_Rremove *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tremove *req) {
+ srv_handler_common(ctx, remove, req);
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ goto tremove_return;
}
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
- srv_fid_del(ctx, req->fid, true);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ bool remove = true;
+ struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
+ assert(pathinfo);
+ if (pathinfo->parent_dir == fidinfo->path) {
+ lib9p_error(&ctx->basectx,
+ LIB9P_ERRNO_L_EBUSY, "cannot remove root");
+ remove = false;
+ goto tremove_main;
+ }
+ struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
+ assert(parent);
+ struct lib9p_srv_stat parent_stat = LO_CALL(parent->file, stat, ctx);
+ if (!lib9p_ctx_has_error(&ctx->basectx) && !srv_check_perm(ctx, &parent_stat, 0b010)) {
+ lib9p_error(&ctx->basectx,
+ LIB9P_ERRNO_L_EACCES, "you do not have write permission on the parent directory");
+ remove = false;
+ goto tremove_main;
+ }
+
+ tremove_main:
+ srv_fid_del(ctx, req->fid, fidinfo, remove);
+ tremove_return:
+ srv_respond(ctx, remove, &resp);
}
static void handle_Tstat(struct srv_req *ctx,
- struct lib9p_msg_Tstat *req,
- struct lib9p_msg_Rstat *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tstat *req) {
+ srv_handler_common(ctx, stat, req);
struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid);
if (!fidinfo) {
lib9p_errorf(&ctx->basectx,
LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid);
- return;
+ goto tstat_return;
}
struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(pathinfo);
- ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo);
- resp->stat = LO_CALL(pathinfo->file, stat, ctx);
- if (!lib9p_ctx_has_error(&ctx->basectx))
- lib9p_stat_assert(resp->stat);
- ctx->authinfo = srv_authinfo_decref(ctx->authinfo);
+ ctx->user = srv_userid_incref(fidinfo->user);
+ struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx);
+ if (lib9p_ctx_has_error(&ctx->basectx))
+ goto tstat_return;
+ lib9p_srv_stat_assert(stat);
+ resp.stat = srv_stat_to_net_stat(stat);
+ tstat_return:
+ if (ctx->user)
+ ctx->user = srv_userid_decref(ctx->user);
+ srv_respond(ctx, stat, &resp);
}
static void handle_Twstat(struct srv_req *ctx,
- struct lib9p_msg_Twstat *req,
- struct lib9p_msg_Rwstat *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Twstat *req) {
+ srv_handler_common(ctx, wstat, req);
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EOPNOTSUPP, "wstat not (yet?) implemented");
+
+ srv_respond(ctx, wstat, &resp);
}
+#endif
#if CONFIG_9P_ENABLE_9P2000_p9p
static void handle_Topenfd(struct srv_req *ctx,
- struct lib9p_msg_Topenfd *req,
- struct lib9p_msg_Ropenfd *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Topenfd *req) {
+ srv_handler_common(ctx, openfd, req);
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EOPNOTSUPP, "openfd not (yet?) implemented");
+
+ srv_respond(ctx, openfd, &resp);
}
#endif
#if CONFIG_9P_ENABLE_9P2000_e
static void handle_Tsession(struct srv_req *ctx,
- struct lib9p_msg_Tsession *req,
- struct lib9p_msg_Rsession *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tsession *req) {
+ srv_handler_common(ctx, session, req);
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EOPNOTSUPP, "session not (yet?) implemented");
+
+ srv_respond(ctx, session, &resp);
}
static void handle_Tsread(struct srv_req *ctx,
- struct lib9p_msg_Tsread *req,
- struct lib9p_msg_Rsread *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tsread *req) {
+ srv_handler_common(ctx, sread, req);
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EOPNOTSUPP, "sread not (yet?) implemented");
+
+ srv_respond(ctx, sread, &resp);
}
static void handle_Tswrite(struct srv_req *ctx,
- struct lib9p_msg_Tswrite *req,
- struct lib9p_msg_Rswrite *resp) {
- srv_handler_common(ctx, req, resp);
+ struct lib9p_msg_Tswrite *req) {
+ srv_handler_common(ctx, swrite, req);
lib9p_error(&ctx->basectx,
LIB9P_ERRNO_L_EOPNOTSUPP, "swrite not (yet?) implemented");
+
+ srv_respond(ctx, swrite, &resp);
}
#endif