summaryrefslogtreecommitdiff
path: root/lib9p/srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r--lib9p/srv.c121
1 files changed, 84 insertions, 37 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 917b41e..05d7144 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -44,28 +44,66 @@ static_assert(CONFIG_9P_SRV_MAX_HOSTMSG_SIZE <= SSIZE_MAX);
/* context ********************************************************************/
-void lib9p_ctx_clear_error(struct lib9p_srv_ctx *ctx) {
+static void lib9p_ctx_clear_error(struct lib9p_srv_ctx *ctx) {
assert(ctx);
ctx->err_num = 0;
ctx->err_msg[0] = '\0';
}
-bool lib9p_ctx_has_error(struct lib9p_srv_ctx *ctx) {
+static bool lib9p_ctx_has_error(struct lib9p_srv_ctx *ctx) {
assert(ctx);
return ctx->err_msg[0];
}
+/** Write a <libmisc/fmt.h>-style error into ctx, return -1. */
+#define lib9p_error(ctx, libmisc_errno, ...) ({ \
+ if (!lib9p_ctx_has_error(ctx)) { \
+ (ctx)->err_num = libmisc_errno; \
+ struct fmt_buf _w = { \
+ .dat = (ctx)->err_msg, \
+ .cap = sizeof((ctx)->err_msg), \
+ }; \
+ lo_interface fmt_dest w = LO_BOX(fmt_dest, &_w); \
+ fmt_print(w, __VA_ARGS__); \
+ if (_w.len < _w.cap) \
+ memset(_w.dat + _w.len, 0, _w.cap - _w.len); \
+ } \
+ -1; \
+})
+
+#define CTX_ERR_OR(TYP, func, ctx, ...) \
+ ({ \
+ TYP##_or_error r = func(ctx __VA_OPT__(,) __VA_ARGS__); \
+ TYP v = {}; \
+ if (r.is_err && !lib9p_ctx_has_error(ctx)) { \
+ (ctx)->err_num = r.err.num; \
+ strncpy((ctx)->err_msg, error_msg(r.err), CONFIG_9P_SRV_MAX_ERR_SIZE); \
+ error_cleanup(&r.err); \
+ } \
+ if (!r.is_err) \
+ v = r.TYP; \
+ v; \
+ })
+
+#define CTX_LO_ERR_OR(TYP, obj, func, ctx, ...) \
+ ({ \
+ TYP##_or_error r = LO_CALL(obj, func, ctx __VA_OPT__(,) __VA_ARGS__); \
+ TYP v = {}; \
+ if (r.is_err && !lib9p_ctx_has_error(ctx)) { \
+ (ctx)->err_num = r.err.num; \
+ strncpy((ctx)->err_msg, error_msg(r.err), CONFIG_9P_SRV_MAX_ERR_SIZE); \
+ error_cleanup(&r.err); \
+ } \
+ if (!r.is_err) \
+ v = r.TYP; \
+ v; \
+ })
+
bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) {
assert(ctx);
return cr_chan_can_send(&ctx->flush_ch);
}
-void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) {
- assert(ctx);
- assert(cr_chan_can_send(&ctx->flush_ch));
- ctx->flush_acknowledged = true;
-}
-
#define req_debug(...) \
log_debugln( \
"cid=", cr_getcid(), ": ", \
@@ -707,10 +745,12 @@ void lib9p_srv_worker(struct srv_req *ctx) {
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)) {
- error:
- srv_respond_error(ctx);
- } else if (ctx->flush_acknowledged) {
- /* do nothing */
+ if (ctx->err_num == E_POSIX_ECANCELED && lib9p_srv_flush_requested(ctx)) {
+ /* do nothing */
+ } else {
+ error:
+ srv_respond_error(ctx);
+ }
} else {
assert(host_resp);
struct lib9p_Rmsg_send_buf net_resp;
@@ -893,7 +933,7 @@ static void handle_Tattach(struct srv_req *ctx,
}
/* 1. File object */
- lo_interface lib9p_srv_file root_file = srv->rootdir(ctx, req->aname);
+ lo_interface lib9p_srv_file root_file = CTX_ERR_OR(lib9p_srv_file, srv->rootdir, ctx, req->aname);
assert(LO_IS_NULL(root_file) == lib9p_ctx_has_error(ctx));
if (lib9p_ctx_has_error(ctx))
goto tattach_return;
@@ -929,12 +969,14 @@ static void handle_Tflush(struct srv_req *ctx,
CR_SELECT_SEND(&ctx->flush_ch, &res))) {
case 0: /* original request returned */
req_debug("original request (tag=", req->oldtag, ") returned");
- ctx->flush_acknowledged = (res == _LIB9P_SRV_FLUSH_SILENT);
+ if (res == _LIB9P_SRV_FLUSH_SILENT) {
+ ctx->responded = true;
+ return;
+ }
break;
case 1: /* flush itself got flushed */
- req_debug("flush itself flushed");
- ctx->flush_acknowledged = true;
- break;
+ ctx->responded = true;
+ return;
}
}
srv_respond(ctx, flush, &resp);
@@ -978,7 +1020,7 @@ static void handle_Twalk(struct srv_req *ctx,
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 = CTX_LO_ERR_OR(lib9p_srv_file, pathinfo->file, dwalk, ctx, req->wname[resp.nwqid]);
assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(ctx));
if (lib9p_ctx_has_error(ctx))
break;
@@ -987,7 +1029,7 @@ static void handle_Twalk(struct srv_req *ctx,
}
if (new_pathinfo->type == SRV_FILETYPE_DIR) {
- struct lib9p_srv_stat stat = LO_CALL(new_pathinfo->file, stat, ctx);
+ struct lib9p_srv_stat stat = CTX_LO_ERR_OR(lib9p_srv_stat, new_pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(ctx))
break;
lib9p_srv_stat_assert(stat);
@@ -1052,7 +1094,7 @@ 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_srv_stat parent_stat = LO_CALL(parent->file, stat, ctx);
+ struct lib9p_srv_stat parent_stat = CTX_LO_ERR_OR(lib9p_srv_stat, parent->file, stat, ctx);
if (lib9p_ctx_has_error(ctx))
goto topen_return;
lib9p_srv_stat_assert(parent_stat);
@@ -1062,7 +1104,7 @@ static void handle_Topen(struct srv_req *ctx,
}
fidflags |= FIDFLAG_RCLOSE;
}
- struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx);
+ struct lib9p_srv_stat stat = CTX_LO_ERR_OR(lib9p_srv_stat, pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(ctx))
goto topen_return;
lib9p_srv_stat_assert(stat);
@@ -1104,7 +1146,7 @@ static void handle_Topen(struct srv_req *ctx,
struct lib9p_qid qid;
switch (pathinfo->type) {
case SRV_FILETYPE_DIR:
- fidinfo->dir.io = LO_CALL(pathinfo->file, dopen, ctx);
+ fidinfo->dir.io = CTX_LO_ERR_OR(lib9p_srv_dio, pathinfo->file, dopen, ctx);
assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(ctx));
if (lib9p_ctx_has_error(ctx))
goto topen_return;
@@ -1114,9 +1156,9 @@ static void handle_Topen(struct srv_req *ctx,
iounit = 0;
break;
case SRV_FILETYPE_FILE:
- fidinfo->file.io = LO_CALL(pathinfo->file, fopen, ctx,
- rd, wr,
- reqmode & LIB9P_O_TRUNC);
+ fidinfo->file.io = CTX_LO_ERR_OR(lib9p_srv_fio, pathinfo->file, fopen, ctx,
+ rd, wr,
+ reqmode & LIB9P_O_TRUNC);
assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(ctx));
if (lib9p_ctx_has_error(ctx))
goto topen_return;
@@ -1220,7 +1262,7 @@ static void handle_Tread(struct srv_req *ctx,
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);
+ member_dirent = CTX_LO_ERR_OR(lib9p_srv_dirent, fidinfo->dir.io, dread, ctx, fidinfo->dir.idx);
if (lib9p_ctx_has_error(ctx)) {
if (!resp.count)
goto tread_return;
@@ -1233,17 +1275,23 @@ static void handle_Tread(struct srv_req *ctx,
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);
+ member_stat = CTX_LO_ERR_OR(lib9p_srv_stat, member_pathinfo->file, stat, ctx);
+ if (lib9p_ctx_has_error(ctx))
+ goto member_err;
} 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);
+ member_file = CTX_LO_ERR_OR(lib9p_srv_file, dir_pathinfo->file, dwalk, ctx, member_dirent.name);
assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(ctx));
- if (!lib9p_ctx_has_error(ctx))
- member_stat = LO_CALL(member_file, stat, ctx);
+ if (lib9p_ctx_has_error(ctx))
+ goto member_err;
+ member_stat = CTX_LO_ERR_OR(lib9p_srv_stat, member_file, stat, ctx);
+ if (lib9p_ctx_has_error(ctx))
+ goto member_err;
}
- if (lib9p_ctx_has_error(ctx)) {
+ if (false) {
+ member_err:
if (!LO_IS_NULL(member_file))
LO_CALL(member_file, free);
if (!resp.count)
@@ -1275,9 +1323,8 @@ static void handle_Tread(struct srv_req *ctx,
#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) && !ctx->flush_acknowledged) {
+ struct iovec iov = CTX_LO_ERR_OR(iovec, fidinfo->file.io, pread, ctx, req->count, req->offset);
+ if (!lib9p_ctx_has_error(ctx)) {
resp.count = iov.iov_len;
resp.data = iov.iov_base;
if (resp.count > req->count)
@@ -1317,7 +1364,7 @@ static void handle_Twrite(struct srv_req *ctx,
/* Do it. */
ctx->user = srv_userid_incref(fidinfo->user);
- resp.count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
+ resp.count = CTX_LO_ERR_OR(uint32_t, fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
twrite_return:
if (ctx->user)
ctx->user = srv_userid_decref(ctx->user);
@@ -1360,7 +1407,7 @@ static void handle_Tremove(struct srv_req *ctx,
}
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);
+ struct lib9p_srv_stat parent_stat = CTX_LO_ERR_OR(lib9p_srv_stat, parent->file, stat, ctx);
if (!lib9p_ctx_has_error(ctx) && !srv_check_perm(ctx, &parent_stat, 0b010)) {
lib9p_error(ctx, E_POSIX_EACCES, "you do not have write permission on the parent directory");
remove = false;
@@ -1386,7 +1433,7 @@ static void handle_Tstat(struct srv_req *ctx,
assert(pathinfo);
ctx->user = srv_userid_incref(fidinfo->user);
- struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx);
+ struct lib9p_srv_stat stat = CTX_LO_ERR_OR(lib9p_srv_stat, pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(ctx))
goto tstat_return;
lib9p_srv_stat_assert(stat);