diff options
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r-- | lib9p/srv.c | 121 |
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); |