diff options
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r-- | lib9p/srv.c | 515 |
1 files changed, 272 insertions, 243 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c index 32e9a9a..085cc8b 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -27,6 +27,8 @@ #define IMPLEMENTATION_FOR_LIB9P_SRV_H YES #include <lib9p/srv.h> +#include "srv_errno.h" + /* config *********************************************************************/ #include "config.h" @@ -47,12 +49,6 @@ bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *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(), ": ", \ @@ -123,6 +119,8 @@ struct srv_fidinfo { } auth; }; }; +typedef struct srv_fidinfo *srv_fidinfop; +DECLARE_ERROR_OR(srv_fidinfop); /* contexts ************************************** * @@ -279,11 +277,13 @@ 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, struct srv_fidinfo *fidinfo, bool remove) { +static inline error srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_fidinfo *fidinfo, bool remove) { assert(ctx); assert(!ctx->user); assert(fidinfo); + error err = {}; + if (fidinfo->flags & FIDFLAG_RCLOSE) remove = true; ctx->user = srv_userid_incref(fidinfo->user); @@ -292,7 +292,7 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_ assert(pathinfo); if (remove) - LO_CALL(pathinfo->file, remove, ctx); + err = LO_CALL(pathinfo->file, remove, ctx); if (fidinfo->flags & FIDFLAG_OPEN) { switch (fidinfo->type) { @@ -313,6 +313,8 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_ map_del(&ctx->parent_sess->fids, fid); ctx->user = srv_userid_decref(ctx->user); + + return err; } /** @@ -320,7 +322,7 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_ * pathinfo->gc_refcount has already been incremented; does *not* * decrement it on failure. */ -static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t fid, struct srv_pathinfo *pathinfo, bool overwrite) { +static inline srv_fidinfop_or_error srv_fid_store(struct srv_req *ctx, lib9p_fid_t fid, struct srv_pathinfo *pathinfo, bool overwrite) { assert(ctx); assert(fid != LIB9P_FID_NOFID); assert(pathinfo); @@ -341,9 +343,7 @@ static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t srv_path_decref(ctx, old_fidinfo->path); map_del(&ctx->parent_sess->fids, fid); } else { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "FID already in use"); - return NULL; + return ERROR_NEW_ERR(srv_fidinfop, error_new(E_POSIX_EBADF, "FID already in use")); } } struct srv_fidinfo *fidinfo = map_store(&ctx->parent_sess->fids, fid, (struct srv_fidinfo){ @@ -352,7 +352,7 @@ static inline struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t .user = srv_userid_incref(ctx->user), }); assert(fidinfo); - return fidinfo; + return ERROR_NEW_VAL(srv_fidinfop, fidinfo); } /* base utilities *************************************************************/ @@ -366,29 +366,25 @@ static void srv_msglog(struct srv_req *req, enum lib9p_msg_type typ, void *hostm log_infoln(typ % 2 ? "< " : "> ", (lib9p_msg, &req->basectx, typ, hostmsg)); } -static ssize_t srv_write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) { - ssize_t r; +#define srv_nonrespond_error log_errorln + +static void srv_write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) { + size_t_and_error r; cr_mutex_lock(&req->parent_sess->parent_conn->writelock); r = io_writev(req->parent_sess->parent_conn->fd, resp->iov, resp->iov_cnt); cr_mutex_unlock(&req->parent_sess->parent_conn->writelock); - return r; + if (!ERROR_IS_NULL(r.err)) + srv_nonrespond_error("write: (", r.size_t, ", ", (error, r.err), ")"); } -#define srv_nonrespond_error log_errorln - -static void srv_respond_error(struct srv_req *req) { -#if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L - assert(req->basectx.err_num); -#endif - assert(req->basectx.err_msg[0]); +static void srv_respond_error(struct srv_req *req, error err) { + assert(!ERROR_IS_NULL(err)); - ssize_t r; struct lib9p_msg_Rerror host = { .tag = req->tag, - .errstr = lib9p_strn(req->basectx.err_msg, - CONFIG_9P_MAX_ERR_SIZE), + .errstr = lib9p_str((char *)error_msg(err)), /* cast to discard `const` */ #if CONFIG_9P_ENABLE_9P2000_u - .errnum = req->basectx.err_num, + .errnum = libmisc_to_linuxgeneric_errno(err.num), #endif }; @@ -397,7 +393,7 @@ static void srv_respond_error(struct srv_req *req) { uint32_t overhead = lib9p_version_min_Rerror_size(sess->version); /* Truncate the error-string if necessary to avoid needing to - * return LIB9P_ERRNO_L_ERANGE. */ + * return E_POSIX_ERANGE. */ if (((uint32_t)host.errstr.len) + overhead > sess->max_msg_size) host.errstr.len = sess->max_msg_size - overhead; @@ -408,28 +404,30 @@ static void srv_respond_error(struct srv_req *req) { &net); srv_msglog(req, LIB9P_TYP_Rerror, &host); - r = srv_write_Rmsg(req, &net); - if (r < 0) - srv_nonrespond_error("write: ", net_strerror(-r)); + srv_write_Rmsg(req, &net); + error_cleanup(&err); } /* read coroutine *************************************************************/ +/** Return whether to `break`. */ static inline bool srv_read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) { assert(buf); assert(goal); assert(done); while (*done < goal) { - ssize_t r = io_read(fd, &buf[*done], goal - *done); - if (r < 0) { - srv_nonrespond_error("read: ", net_strerror(-r)); - return true; - } else if (r == 0) { - if (*done != 0) - srv_nonrespond_error("read: unexpected EOF"); + size_t_or_error r = io_read(fd, &buf[*done], goal - *done); + if (r.is_err) { + if (r.err.num == E_EOF) { + if (*done != 0) + srv_nonrespond_error("read: unexpected EOF"); + } else { + srv_nonrespond_error("read: ", (error, r.err)); + } + error_cleanup(&r.err); return true; } - *done += r; + *done += r.size_t; } return false; } @@ -442,16 +440,17 @@ void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stre srv->readers++; for (;;) { - lo_interface net_stream_conn conn = LO_CALL(listener, accept); - if (LO_IS_NULL(conn)) { - srv_nonrespond_error("accept: error"); + net_stream_conn_or_error r = LO_CALL(listener, accept); + if (r.is_err) { + srv_nonrespond_error("accept: ", (error, r.err)); + error_cleanup(&r.err); srv->readers--; if (srv->readers == 0) while (srv->writers > 0) cr_rpc_send_req(&srv->_reqch, NULL); return; } - lib9p_srv_read(srv, conn); + lib9p_srv_read(srv, r.net_stream_conn); } } @@ -495,10 +494,9 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { .net_bytes = buf, }; if (goal > sess.max_msg_size) { - lib9p_error(&req.basectx, LIB9P_ERRNO_L_EMSGSIZE, - "T-message larger than ", sess.initialized ? "negotiated" : "server", " limit", - " (", goal, " > ", sess.max_msg_size, ")"); - srv_respond_error(&req); + srv_respond_error(&req, error_new(E_POSIX_EMSGSIZE, + "T-message larger than ", sess.initialized ? "negotiated" : "server", " limit", + " (", goal, " > ", sess.max_msg_size, ")")); continue; } req.net_bytes = malloc(goal); @@ -517,14 +515,26 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { /* ...but usually in another coroutine. */ cr_rpc_send_req(&srv->_reqch, &req); } - if (map_len(&sess.reqs) == 0) - io_close(conn.fd); - else { - io_close_read(conn.fd); + if (map_len(&sess.reqs) == 0) { + error err = io_close(conn.fd); + if (!ERROR_IS_NULL(err)) { + srv_nonrespond_error("conn close: ", (error, err)); + error_cleanup(&err); + } + } else { + error err = io_close_read(conn.fd); + if (!ERROR_IS_NULL(err)) { + srv_nonrespond_error("conn close: ", (error, err)); + error_cleanup(&err); + } sess.closing = true; cr_pause_and_yield(); assert(map_len(&sess.reqs) == 0); - io_close_write(conn.fd); + err = io_close_write(conn.fd); + if (!ERROR_IS_NULL(err)) { + srv_nonrespond_error("conn close: ", (error, err)); + error_cleanup(&err); + } } assert(map_len(&sess.reqs) == 0); @@ -538,10 +548,10 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { .parent_sess = &sess, }; MAP_FOREACH(&sess.fids, fid, fidinfo) { - srv_fid_del(&pseudoreq, fid, fidinfo, false); - if (lib9p_ctx_has_error(&pseudoreq.basectx)) { - srv_nonrespond_error("clunk: ", (strn, pseudoreq.basectx.err_msg, CONFIG_9P_MAX_ERR_SIZE)); - lib9p_ctx_clear_error(&pseudoreq.basectx); + error err = srv_fid_del(&pseudoreq, fid, fidinfo, false); + if (!ERROR_IS_NULL(err)) { + srv_nonrespond_error("clunk: ", (error, err)); + error_cleanup(&err); } } map_free(&sess.fids); @@ -615,11 +625,12 @@ void lib9p_srv_worker(struct srv_req *ctx) { uint8_t *host_req = NULL; /* Unmarshal it. *****************************************************/ - ssize_t host_size = lib9p_Tmsg_validate(&ctx->basectx, ctx->net_bytes); - if (host_size < 0) { - srv_respond_error(ctx); + size_t_or_error r = lib9p_Tmsg_validate(&ctx->basectx, ctx->net_bytes); + if (r.is_err) { + srv_respond_error(ctx, r.err); goto release; } + size_t host_size = r.size_t; host_req = calloc(1, host_size); assert(host_req); enum lib9p_msg_type typ; @@ -675,28 +686,31 @@ 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) { +static inline void _srv_respond(struct srv_req *ctx, enum lib9p_msg_type resp_typ, void *host_resp, error err) { assert(!ctx->responded); - if (lib9p_ctx_has_error(&ctx->basectx)) { - error: - srv_respond_error(ctx); - } else if (ctx->flush_acknowledged) { - /* do nothing */ + if (!ERROR_IS_NULL(err)) { + if (err.num == E_POSIX_ECANCELED && lib9p_srv_flush_requested(ctx)) { + error_cleanup(&err); + } else { + error: + srv_respond_error(ctx, err); + } } else { assert(host_resp); struct lib9p_Rmsg_send_buf net_resp; - if (lib9p_Rmsg_marshal(&ctx->basectx, - resp_typ, host_resp, - &net_resp)) + err = lib9p_Rmsg_marshal(&ctx->basectx, + resp_typ, host_resp, + &net_resp); + if (!ERROR_IS_NULL(err)) 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); \ +#define srv_respond(CTX, TYP, HOST_RESP, ERR) do { \ + struct lib9p_msg_R##TYP *_host_resp = HOST_RESP; \ + _srv_respond(CTX, LIB9P_TYP_R##TYP, _host_resp, ERR); \ } while (0) /* handle_T* ******************************************************************/ @@ -705,7 +719,8 @@ static inline void _srv_respond(struct srv_req *ctx, enum lib9p_msg_type resp_ty assert(ctx); \ assert(req); \ struct lib9p_msg_T##typ *_typecheck_req [[maybe_unused]] = req; \ - struct lib9p_msg_R##typ resp = { .tag = ctx->tag } + struct lib9p_msg_R##typ resp = { .tag = ctx->tag }; \ + error err = {} static void handle_Tversion(struct srv_req *ctx, struct lib9p_msg_Tversion *req) { @@ -745,9 +760,8 @@ static void handle_Tversion(struct srv_req *ctx, uint32_t min_msg_size = _LIB9P_MAX(lib9p_version_min_Rerror_size(ctx->basectx.version), lib9p_version_min_Rread_size(ctx->basectx.version)+1); if (req->max_msg_size < min_msg_size) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EDOM, "requested max_msg_size is less than minimum for ", lib9p_version_str(version), - " (", req->max_msg_size, " < ", min_msg_size, ")"); + err = error_new(E_POSIX_EDOM, "requested max_msg_size is less than minimum for ", lib9p_version_str(version), + " (", req->max_msg_size, " < ", min_msg_size, ")"); goto tversion_return; } @@ -777,10 +791,10 @@ static void handle_Tversion(struct srv_req *ctx, } /* 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_error("clunk: ", (strn, ctx->basectx.err_msg, CONFIG_9P_MAX_ERR_SIZE)); - lib9p_ctx_clear_error(&ctx->basectx); + error fiderr = srv_fid_del(ctx, fid, fidinfo, false); + if (!ERROR_IS_NULL(fiderr)) { + srv_nonrespond_error("clunk: ", (error, fiderr)); + error_cleanup(&fiderr); } } @@ -789,7 +803,7 @@ static void handle_Tversion(struct srv_req *ctx, ctx->parent_sess->max_msg_size = resp.max_msg_size; tversion_return: - srv_respond(ctx, version, &resp); + srv_respond(ctx, version, &resp, err); } #if _LIB9P_ENABLE_stat @@ -799,23 +813,22 @@ static void handle_Tauth(struct srv_req *ctx, 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"); + err = error_new(E_POSIX_EOPNOTSUPP, "authentication not required"); goto tauth_return; } ctx->user = srv_userid_new(req->uname, req->unum); - srv->auth(ctx, req->aname); - - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EOPNOTSUPP, "TODO: auth not implemented"); + err = srv->auth(ctx, req->aname); + if (!ERROR_IS_NULL(err)) + goto tauth_return; - if (lib9p_ctx_has_error(&ctx->basectx)) - ctx->user = srv_userid_decref(ctx->user); + err = error_new(E_POSIX_EOPNOTSUPP, "TODO: auth not implemented"); tauth_return: - srv_respond(ctx, auth, &resp); + if (!ERROR_IS_NULL(err) && ctx->user) + ctx->user = srv_userid_decref(ctx->user); + srv_respond(ctx, auth, &resp, err); } static void handle_Tattach(struct srv_req *ctx, @@ -823,8 +836,7 @@ static void handle_Tattach(struct srv_req *ctx, srv_handler_common(ctx, attach, req); if (req->fid == LIB9P_FID_NOFID) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID"); + err = error_new(E_POSIX_EBADF, "cannot assign to NOFID"); goto tattach_return; } @@ -832,48 +844,43 @@ static void handle_Tattach(struct srv_req *ctx, if (srv->auth) { struct srv_fidinfo *afid = map_load(&ctx->parent_sess->fids, req->afid); if (!afid) - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is not a valid FID"); + err = error_new(E_POSIX_EACCES, "FID provided as auth-file is not a valid FID"); 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"); + err = error_new(E_POSIX_EACCES, "FID provided as auth-file is not an auth-file"); else if (!lib9p_str_eq(afid->user->name, req->uname)) - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EACCES, - "FID provided as auth-file is for user=", (qmem, afid->user->name.utf8, afid->user->name.len), - " and cannot be used for user=", (qmem, req->uname.utf8, req->uname.len)); + err = error_new(E_POSIX_EACCES, + "FID provided as auth-file is for user=", (qmem, afid->user->name.utf8, afid->user->name.len), + " and cannot be used for user=", (qmem, req->uname.utf8, req->uname.len)); #if CONFIG_9P_ENABLE_9P2000_u || CONFIG_9P_ENABLE_9P2000_L else if (afid->user->num != req->unum) - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EACCES, - "FID provided as auth-file is for user=", afid->user->num, - " and cannot be used for user=", req->unum); + err = error_new(E_POSIX_EACCES, + "FID provided as auth-file is for user=", afid->user->num, + " and cannot be used for user=", req->unum); #endif else if (!lib9p_str_eq(afid->auth.aname, req->aname)) - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EACCES, - "FID provided as auth-file is for tree=", (qmem, afid->auth.aname.utf8, afid->auth.aname.len), - " and cannot be used for tree=", (qmem, req->aname.utf8, req->aname.len)); + err = error_new(E_POSIX_EACCES, + "FID provided as auth-file is for tree=", (qmem, afid->auth.aname.utf8, afid->auth.aname.len), + " and cannot be used for tree=", (qmem, req->aname.utf8, req->aname.len)); else if (!afid->auth.completed) - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EACCES, "FID provided as auth-file has not completed authentication"); - if (lib9p_ctx_has_error(&ctx->basectx)) + err = error_new(E_POSIX_EACCES, "FID provided as auth-file has not completed authentication"); + if (!ERROR_IS_NULL(err)) 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"); + err = error_new(E_POSIX_EACCES, "FID provided as auth-file, but no auth-file is required"); goto tattach_return; } 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)) + lib9p_srv_file_or_error root_file_r = srv->rootdir(ctx, req->aname); + if (root_file_r.is_err) { + err = root_file_r.err; goto tattach_return; + } + lo_interface lib9p_srv_file root_file = root_file_r.lib9p_srv_file; struct lib9p_qid root_qid = LO_CALL(root_file, qid); assert(srv_qid_filetype(root_qid) == SRV_FILETYPE_DIR); @@ -882,7 +889,9 @@ static void handle_Tattach(struct srv_req *ctx, struct srv_pathinfo *root_pathinfo = srv_path_save(ctx, root_file, root_qid.path); /* 3. fidinfo */ - if (!srv_fid_store(ctx, req->fid, root_pathinfo, false)) { + srv_fidinfop_or_error fidinfo = srv_fid_store(ctx, req->fid, root_pathinfo, false); + if (fidinfo.is_err) { + err = fidinfo.err; srv_path_decref(ctx, root_qid.path); goto tattach_return; } @@ -891,7 +900,7 @@ static void handle_Tattach(struct srv_req *ctx, tattach_return: if (ctx->user) ctx->user = srv_userid_decref(ctx->user); - srv_respond(ctx, attach, &resp); + srv_respond(ctx, attach, &resp, err); } static void handle_Tflush(struct srv_req *ctx, @@ -906,15 +915,17 @@ 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); + srv_respond(ctx, flush, &resp, err); } static void handle_Twalk(struct srv_req *ctx, @@ -922,20 +933,17 @@ static void handle_Twalk(struct srv_req *ctx, srv_handler_common(ctx, walk, req); if (req->newfid == LIB9P_FID_NOFID) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID"); + err = error_new(E_POSIX_EBADF, "cannot assign to NOFID"); goto twalk_return; } struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid); + err = error_new(E_POSIX_EBADF, "bad file number ", req->fid); goto twalk_return; } if (fidinfo->flags & FIDFLAG_OPEN) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EALREADY, "cannot walk on FID open for I/O"); + err = error_new(E_POSIX_EALREADY, "cannot walk on FID open for I/O"); goto twalk_return; } ctx->user = srv_userid_incref(fidinfo->user); @@ -948,8 +956,7 @@ static void handle_Twalk(struct srv_req *ctx, 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"); + err = error_new(E_POSIX_ENOTDIR, "not a directory"); break; } @@ -959,22 +966,24 @@ 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]); - assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->basectx)); - if (lib9p_ctx_has_error(&ctx->basectx)) + lib9p_srv_file_or_error member_file = LO_CALL(pathinfo->file, dwalk, ctx, req->wname[resp.nwqid]); + if (member_file.is_err) { + err = member_file.err; break; - new_pathinfo = srv_path_save(ctx, member_file, LO_CALL(pathinfo->file, qid).path); + } + new_pathinfo = srv_path_save(ctx, member_file.lib9p_srv_file, LO_CALL(pathinfo->file, qid).path); assert(new_pathinfo); } if (new_pathinfo->type == SRV_FILETYPE_DIR) { - struct lib9p_srv_stat stat = LO_CALL(new_pathinfo->file, stat, ctx); - if (lib9p_ctx_has_error(&ctx->basectx)) + lib9p_srv_stat_or_error stat = LO_CALL(new_pathinfo->file, stat, ctx); + if (stat.is_err) { + err = stat.err; break; - 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"); + } + lib9p_srv_stat_assert(stat.lib9p_srv_stat); + if (!srv_check_perm(ctx, &stat.lib9p_srv_stat, 0b001)) { + err = error_new(E_POSIX_EACCES, "you do not have execute permission on that directory"); srv_path_decref(ctx, LO_CALL(new_pathinfo->file, qid).path); break; } @@ -986,18 +995,21 @@ static void handle_Twalk(struct srv_req *ctx, pathinfo = new_pathinfo; } if (resp.nwqid == req->nwname) { - if (!srv_fid_store(ctx, req->newfid, pathinfo, req->newfid == req->fid)) + srv_fidinfop_or_error fidinfo = srv_fid_store(ctx, req->newfid, pathinfo, req->newfid == req->fid); + if (fidinfo.is_err) { + err = fidinfo.err; srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path); + } } else { - assert(lib9p_ctx_has_error(&ctx->basectx)); + assert(!ERROR_IS_NULL(err)); srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path); if (resp.nwqid > 0) - lib9p_ctx_clear_error(&ctx->basectx); + error_cleanup(&err); } twalk_return: if (ctx->user) ctx->user = srv_userid_decref(ctx->user); - srv_respond(ctx, walk, &resp); + srv_respond(ctx, walk, &resp, err); } static void handle_Topen(struct srv_req *ctx, @@ -1007,21 +1019,18 @@ static void handle_Topen(struct srv_req *ctx, /* Check that the FID is valid for this. */ struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid); + err = error_new(E_POSIX_EBADF, "bad file number ", req->fid); goto topen_return; } if (fidinfo->flags & FIDFLAG_OPEN) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EALREADY, "FID is already open"); + err = error_new(E_POSIX_EALREADY, "FID is already open"); goto topen_return; } if (fidinfo->type == SRV_FILETYPE_DIR) { if ( ((req->mode & LIB9P_O_MODE_MASK) != LIB9P_O_MODE_READ) || (req->mode & LIB9P_O_TRUNC) || (req->mode & LIB9P_O_RCLOSE) ) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close"); + err = error_new(E_POSIX_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close"); goto topen_return; } } @@ -1037,27 +1046,29 @@ 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); - if (lib9p_ctx_has_error(&ctx->basectx)) + lib9p_srv_stat_or_error parent_stat = LO_CALL(parent->file, stat, ctx); + if (parent_stat.is_err) { + err = parent_stat.err; goto topen_return; - 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"); + } + lib9p_srv_stat_assert(parent_stat.lib9p_srv_stat); + if (!srv_check_perm(ctx, &parent_stat.lib9p_srv_stat, 0b010)) { + err = error_new(E_POSIX_EACCES, "permission denied to remove-on-close"); goto topen_return; } fidflags |= FIDFLAG_RCLOSE; } - struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx); - if (lib9p_ctx_has_error(&ctx->basectx)) + lib9p_srv_stat_or_error stat = LO_CALL(pathinfo->file, stat, ctx); + if (stat.is_err) { + err = stat.err; goto topen_return; - 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"); + } + lib9p_srv_stat_assert(stat.lib9p_srv_stat); + if ((stat.lib9p_srv_stat.mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) { + err = error_new(E_POSIX_EEXIST, "exclusive file is already opened"); goto topen_return; } - if (stat.mode & LIB9P_DM_APPEND) { + if (stat.lib9p_srv_stat.mode & LIB9P_DM_APPEND) { fidflags |= FIDFLAG_APPEND; reqmode = reqmode & ~LIB9P_O_TRUNC; } @@ -1081,9 +1092,8 @@ static void handle_Topen(struct srv_req *ctx, rd = true; break; } - if (!srv_check_perm(ctx, &stat, perm_bits)) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EACCES, "permission denied"); + if (!srv_check_perm(ctx, &stat.lib9p_srv_stat, perm_bits)) { + err = error_new(E_POSIX_EACCES, "permission denied"); goto topen_return; } @@ -1092,22 +1102,28 @@ 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); - assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(&ctx->basectx)); - if (lib9p_ctx_has_error(&ctx->basectx)) + lib9p_srv_dio_or_error dio_r = + LO_CALL(pathinfo->file, dopen, ctx); + if (dio_r.is_err) { + err = dio_r.err; goto topen_return; + } + fidinfo->dir.io = dio_r.lib9p_srv_dio; fidinfo->dir.idx = 0; fidinfo->dir.off = 0; qid = LO_CALL(fidinfo->dir.io, qid); iounit = 0; break; case SRV_FILETYPE_FILE: - fidinfo->file.io = LO_CALL(pathinfo->file, fopen, ctx, - rd, wr, - reqmode & LIB9P_O_TRUNC); - assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(&ctx->basectx)); - if (lib9p_ctx_has_error(&ctx->basectx)) + lib9p_srv_fio_or_error fio_r = + LO_CALL(pathinfo->file, fopen, ctx, + rd, wr, + reqmode & LIB9P_O_TRUNC); + if (fio_r.is_err) { + err = fio_r.err; goto topen_return; + } + fidinfo->file.io = fio_r.lib9p_srv_fio; qid = LO_CALL(fidinfo->file.io, qid); iounit = LO_CALL(fidinfo->file.io, iounit); break; @@ -1131,17 +1147,16 @@ static void handle_Topen(struct srv_req *ctx, topen_return: if (ctx->user) ctx->user = srv_userid_decref(ctx->user); - srv_respond(ctx, open, &resp); + srv_respond(ctx, open, &resp, err); } static void handle_Tcreate(struct srv_req *ctx, struct lib9p_msg_Tcreate *req) { srv_handler_common(ctx, create, req); - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EOPNOTSUPP, "create not (yet?) implemented"); + err = error_new(E_POSIX_EOPNOTSUPP, "create not (yet?) implemented"); - srv_respond(ctx, create, &resp); + srv_respond(ctx, create, &resp, err); } static inline struct lib9p_stat srv_stat_to_net_stat(struct lib9p_srv_stat in) { @@ -1177,13 +1192,11 @@ static void handle_Tread(struct srv_req *ctx, /* Check that the FID is valid for this. */ struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid); + err = error_new(E_POSIX_EBADF, "bad file number ", req->fid); goto tread_return; } if (!(fidinfo->flags & FIDFLAG_OPEN_R)) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EINVAL, "FID not open for reading"); + err = error_new(E_POSIX_EINVAL, "FID not open for reading"); goto tread_return; } @@ -1198,8 +1211,7 @@ static void handle_Tread(struct srv_req *ctx, fidinfo->dir.off = 0; fidinfo->dir.buffered_dirent = (struct lib9p_srv_dirent){}; } else if (req->offset != fidinfo->dir.off) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EINVAL, "invalid offset (must be 0 or ", fidinfo->dir.off, "): ", req->offset); + err = error_new(E_POSIX_EINVAL, "invalid offset (must be 0 or ", fidinfo->dir.off, "): ", req->offset); goto tread_return; } /* Read. */ @@ -1212,35 +1224,53 @@ 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); - if (lib9p_ctx_has_error(&ctx->basectx)) { - if (!resp.count) + lib9p_srv_dirent_or_error member_dirent_r; + member_dirent_r = LO_CALL(fidinfo->dir.io, dread, ctx, fidinfo->dir.idx); + if (member_dirent_r.is_err) { + if (!resp.count) { + err = member_dirent_r.err; goto tread_return; - lib9p_ctx_clear_error(&ctx->basectx); + } + error_cleanup(&member_dirent_r.err); break; } + member_dirent = member_dirent_r.lib9p_srv_dirent; } 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); + lib9p_srv_stat_or_error r = LO_CALL(member_pathinfo->file, stat, ctx); + if (r.is_err) { + err = r.err; + goto member_err; + } + member_stat = r.lib9p_srv_stat; } 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); + lib9p_srv_file_or_error file_r = LO_CALL(dir_pathinfo->file, dwalk, ctx, member_dirent.name); + if (file_r.is_err) { + err = file_r.err; + goto member_err; + } + member_file = file_r.lib9p_srv_file; + lib9p_srv_stat_or_error stat_r = LO_CALL(member_file, stat, ctx); + if (stat_r.is_err) { + err = stat_r.err; + goto member_err; + } + member_stat = stat_r.lib9p_srv_stat; } - if (lib9p_ctx_has_error(&ctx->basectx)) { + if (false) { + member_err: if (!LO_IS_NULL(member_file)) LO_CALL(member_file, free); if (!resp.count) goto tread_return; - lib9p_ctx_clear_error(&ctx->basectx); + error_cleanup(&err); break; } lib9p_srv_stat_assert(member_stat); @@ -1251,8 +1281,7 @@ static void handle_Tread(struct srv_req *ctx, 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"); + err = error_new(E_POSIX_ERANGE, "stat object does not fit into negotiated max message size"); goto tread_return; } fidinfo->dir.buffered_dirent = member_dirent; @@ -1268,11 +1297,12 @@ 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->basectx) && !ctx->flush_acknowledged) { - resp.count = iov.iov_len; - resp.data = iov.iov_base; + iovec_or_error iov = LO_CALL(fidinfo->file.io, pread, ctx, req->count, req->offset); + if (iov.is_err) { + err = iov.err; + } else { + resp.count = iov.iovec.iov_len; + resp.data = iov.iovec.iov_base; if (resp.count > req->count) resp.count = req->count; } @@ -1284,7 +1314,7 @@ static void handle_Tread(struct srv_req *ctx, tread_return: if (ctx->user) ctx->user = srv_userid_decref(ctx->user); - srv_respond(ctx, read, &resp); + srv_respond(ctx, read, &resp, err); if (heap) free(heap); } @@ -1298,13 +1328,11 @@ static void handle_Twrite(struct srv_req *ctx, /* Check that the FID is valid for this. */ struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid); + err = error_new(E_POSIX_EBADF, "bad file number ", req->fid); goto twrite_return; } if (!(fidinfo->flags & FIDFLAG_OPEN_W)) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EINVAL, "FID not open for writing"); + err = error_new(E_POSIX_EINVAL, "FID not open for writing"); goto twrite_return; } if (fidinfo->flags & FIDFLAG_APPEND) @@ -1312,11 +1340,15 @@ 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); + uint32_t_or_error count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset); + if (count.is_err) + err = count.err; + else + resp.count = count.uint32_t; twrite_return: if (ctx->user) ctx->user = srv_userid_decref(ctx->user); - srv_respond(ctx, write, &resp); + srv_respond(ctx, write, &resp, err); } static void handle_Tclunk(struct srv_req *ctx, @@ -1325,15 +1357,14 @@ static void handle_Tclunk(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid); + err = error_new(E_POSIX_EBADF, "bad file number ", req->fid); goto tclunk_return; } srv_fid_del(ctx, req->fid, fidinfo, false); tclunk_return: - srv_respond(ctx, clunk, &resp); + srv_respond(ctx, clunk, &resp, err); } static void handle_Tremove(struct srv_req *ctx, @@ -1342,8 +1373,7 @@ static void handle_Tremove(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid); + err = error_new(E_POSIX_EBADF, "bad file number ", req->fid); goto tremove_return; } @@ -1351,17 +1381,20 @@ static void handle_Tremove(struct srv_req *ctx, 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"); + err = error_new(E_POSIX_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"); + lib9p_srv_stat_or_error r = LO_CALL(parent->file, stat, ctx); + if (r.is_err) { + err = r.err; + goto tremove_main; + } + struct lib9p_srv_stat parent_stat = r.lib9p_srv_stat; + if (!srv_check_perm(ctx, &parent_stat, 0b010)) { + err = error_new(E_POSIX_EACCES, "you do not have write permission on the parent directory"); remove = false; goto tremove_main; } @@ -1369,7 +1402,7 @@ static void handle_Tremove(struct srv_req *ctx, tremove_main: srv_fid_del(ctx, req->fid, fidinfo, remove); tremove_return: - srv_respond(ctx, remove, &resp); + srv_respond(ctx, remove, &resp, err); } static void handle_Tstat(struct srv_req *ctx, @@ -1378,33 +1411,33 @@ static void handle_Tstat(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EBADF, "bad file number ", req->fid); + err = error_new(E_POSIX_EBADF, "bad file number ", req->fid); goto tstat_return; } struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); assert(pathinfo); 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)) + lib9p_srv_stat_or_error r = LO_CALL(pathinfo->file, stat, ctx); + if (r.is_err) { + err = r.err; goto tstat_return; - lib9p_srv_stat_assert(stat); - resp.stat = srv_stat_to_net_stat(stat); + } + lib9p_srv_stat_assert(r.lib9p_srv_stat); + resp.stat = srv_stat_to_net_stat(r.lib9p_srv_stat); tstat_return: if (ctx->user) ctx->user = srv_userid_decref(ctx->user); - srv_respond(ctx, stat, &resp); + srv_respond(ctx, stat, &resp, err); } static void handle_Twstat(struct srv_req *ctx, struct lib9p_msg_Twstat *req) { srv_handler_common(ctx, wstat, req); - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EOPNOTSUPP, "wstat not (yet?) implemented"); + err = error_new(E_POSIX_EOPNOTSUPP, "wstat not (yet?) implemented"); - srv_respond(ctx, wstat, &resp); + srv_respond(ctx, wstat, &resp, err); } #endif @@ -1413,10 +1446,9 @@ static void handle_Topenfd(struct srv_req *ctx, struct lib9p_msg_Topenfd *req) { srv_handler_common(ctx, openfd, req); - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EOPNOTSUPP, "openfd not (yet?) implemented"); + err = error_new(E_POSIX_EOPNOTSUPP, "openfd not (yet?) implemented"); - srv_respond(ctx, openfd, &resp); + srv_respond(ctx, openfd, &resp, err); } #endif @@ -1425,29 +1457,26 @@ static void handle_Tsession(struct srv_req *ctx, struct lib9p_msg_Tsession *req) { srv_handler_common(ctx, session, req); - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EOPNOTSUPP, "session not (yet?) implemented"); + err = error_new(E_POSIX_EOPNOTSUPP, "session not (yet?) implemented"); - srv_respond(ctx, session, &resp); + srv_respond(ctx, session, &resp, err); } static void handle_Tsread(struct srv_req *ctx, struct lib9p_msg_Tsread *req) { srv_handler_common(ctx, sread, req); - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EOPNOTSUPP, "sread not (yet?) implemented"); + err = error_new(E_POSIX_EOPNOTSUPP, "sread not (yet?) implemented"); - srv_respond(ctx, sread, &resp); + srv_respond(ctx, sread, &resp, err); } static void handle_Tswrite(struct srv_req *ctx, struct lib9p_msg_Tswrite *req) { srv_handler_common(ctx, swrite, req); - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_EOPNOTSUPP, "swrite not (yet?) implemented"); + err = error_new(E_POSIX_EOPNOTSUPP, "swrite not (yet?) implemented"); - srv_respond(ctx, swrite, &resp); + srv_respond(ctx, swrite, &resp, err); } #endif |