diff options
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r-- | lib9p/srv.c | 286 |
1 files changed, 163 insertions, 123 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c index 0a33e03..6ab2ab2 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#include <alloca.h> #include <inttypes.h> /* for PRI* */ #include <limits.h> /* for SSIZE_MAX, not set by newlib */ #include <stddef.h> /* for size_t */ @@ -17,6 +16,7 @@ #include <libcr/coroutine.h> #include <libcr_ipc/chan.h> #include <libcr_ipc/mutex.h> +#include <libmisc/alloc.h> #include <libmisc/assert.h> #include <libmisc/endian.h> #include <libmisc/map.h> @@ -32,16 +32,6 @@ #include "config.h" -#ifndef CONFIG_9P_SRV_MAX_FIDS - #error config.h must define CONFIG_9P_SRV_MAX_FIDS -#endif -#ifndef CONFIG_9P_SRV_MAX_REQS - #error config.h must define CONFIG_9P_SRV_MAX_REQS -#endif -#ifndef CONFIG_9P_SRV_MAX_DEPTH - /* 1=just the root dir, 2=just files in the root dir, 3=1 subdir, ... */ - #error config.h must define CONFIG_9P_SRV_MAX_DEPTH -#endif #ifndef CONFIG_9P_SRV_MAX_MSG_SIZE #error config.h must define CONFIG_9P_SRV_MAX_MSG_SIZE #endif @@ -55,16 +45,22 @@ static_assert(CONFIG_9P_SRV_MAX_HOSTMSG_SIZE <= SSIZE_MAX); bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) { assert(ctx); - return _lib9p_srv_flushch_can_send(&ctx->flushch); + return cr_chan_can_send(&ctx->flush_ch); } void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) { assert(ctx); - assert(_lib9p_srv_flushch_can_send(&ctx->flushch)); - lib9p_error(&ctx->basectx, LINUX_ECANCELED, "request canceled by flush"); - _lib9p_srv_flushch_send(&ctx->flushch, true); + assert(cr_chan_can_send(&ctx->flush_ch)); + ctx->flush_acknowledged = true; } +#define req_debugf(fmt, ...) \ + debugf("cid=%zu: %s(tag=%"PRIu16"): " fmt, \ + cr_getcid(), \ + lib9p_msgtype_str(ctx->basectx.version, ctx->net_bytes[4]), \ + ctx->tag \ + __VA_OPT__(,) __VA_ARGS__) + /* structs ********************************************************************/ enum srv_filetype { @@ -80,6 +76,8 @@ typedef typeof( ((struct lib9p_qid){}).path ) srv_path_t; struct srv_pathinfo { lo_interface lib9p_srv_file file; enum srv_filetype type; + /* .parent_dir is used for (1) Twalk(".."), and (2) for checking + * permissions on the parent directory for remove(). */ srv_path_t parent_dir; /* References from other srv_pathinfos (via .parent_dir) or @@ -249,14 +247,18 @@ static inline struct srv_pathinfo *srv_path_save(struct srv_req *ctx, static inline void srv_path_decref(struct srv_req *ctx, srv_path_t path) { assert(ctx); - struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, path); - assert(pathinfo); - pathinfo->gc_refcount--; - if (pathinfo->gc_refcount == 0) { - if (pathinfo->parent_dir != path) - srv_path_decref(ctx, pathinfo->parent_dir); + for (;;) { + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, path); + assert(pathinfo); + pathinfo->gc_refcount--; + if (pathinfo->gc_refcount) + break; + srv_path_t parent_path = pathinfo->parent_dir; LO_CALL(pathinfo->file, free); map_del(&ctx->parent_sess->paths, path); + if (parent_path == path) + break; + path = parent_path; } } @@ -271,7 +273,7 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove if (remove) { if (pathinfo->parent_dir == fidinfo->path) { lib9p_errorf(&ctx->basectx, - LINUX_EBUSY, "cannot remove root"); + LIB9P_ERRNO_L_EBUSY, "cannot remove root"); goto clunk; } struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir); @@ -279,7 +281,7 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove struct lib9p_stat parent_stat = LO_CALL(parent->file, stat, ctx); if (!srv_check_perm(ctx, &parent_stat, 0b010)) { lib9p_error(&ctx->basectx, - LINUX_EACCES, "remove: you do not have write permission on the parent directory"); + LIB9P_ERRNO_L_EACCES, "you do not have write permission on the parent directory"); goto clunk; } LO_CALL(pathinfo->file, remove, ctx); @@ -310,19 +312,29 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove * pathinfo->gc_refcount has already been incremented; does *not* * decrement it on failure. */ -static struct srv_fidinfo *srv_fid_store(struct srv_req *ctx, lib9p_fid_t fid, struct srv_pathinfo *pathinfo, bool overwrite) { +static inline struct srv_fidinfo *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); struct lib9p_qid qid = LO_CALL(pathinfo->file, qid); - if (map_load(&ctx->parent_sess->fids, fid)) { + struct srv_fidinfo *old_fidinfo = map_load(&ctx->parent_sess->fids, fid); + if (old_fidinfo) { if (overwrite) { - srv_fid_del(ctx, fid, false); + /* This should only happen from Twalk; because + * directories cannot be RCLOSE and Twalk cannot walk on + * FIDs open for I/O, we can skip most of + * srv_fid_del(). */ + assert(old_fidinfo->type == SRV_FILETYPE_DIR); + assert(old_fidinfo->flags == 0); + + old_fidinfo->authinfo = srv_authinfo_decref(old_fidinfo->authinfo); + srv_path_decref(ctx, old_fidinfo->path); + map_del(&ctx->parent_sess->fids, fid); } else { lib9p_error(&ctx->basectx, - LINUX_EBADF, "FID already in use"); + LIB9P_ERRNO_L_EBADF, "FID already in use"); return NULL; } } @@ -382,11 +394,11 @@ static void srv_respond_error(struct srv_req *req) { /* XXX: This assumes that a version's min_msg_size is the * Rerror overhead. That's true for the current - * implementation of protogen, but is a sneaky assumption. */ + * implementation of core_gen, but is a sneaky assumption. */ uint32_t overhead = lib9p_version_min_msg_size(sess->version); /* Truncate the error-string if necessary to avoid needing to - * return LINUX_ERANGE. */ + * return LIB9P_ERRNO_L_ERANGE. */ if (((uint32_t)host.errstr.len) + overhead > sess->max_msg_size) host.errstr.len = sess->max_msg_size - overhead; @@ -437,15 +449,13 @@ void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stre srv->readers--; if (srv->readers == 0) while (srv->writers > 0) - _lib9p_srv_reqch_send_req(&srv->_reqch, NULL); + cr_rpc_send_req(&srv->_reqch, NULL); return; } lib9p_srv_read(srv, conn); } } -static void handle_message(struct srv_req *ctx); - void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { assert(srv); assert(srv->rootdir); @@ -487,7 +497,7 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { }; if (goal > sess.max_msg_size) { lib9p_errorf(&req.basectx, - LINUX_EMSGSIZE, "T-message larger than %s limit (%zu > %"PRIu32")", + LIB9P_ERRNO_L_EMSGSIZE, "T-message larger than %s limit (%zu > %"PRIu32")", sess.initialized ? "negotiated" : "server", goal, sess.max_msg_size); @@ -505,10 +515,10 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { /* Handle the message... */ if (req.net_bytes[4] == LIB9P_TYP_Tversion) /* ...in this coroutine for Tversion, */ - handle_message(&req); + lib9p_srv_worker(&req); else /* ...but usually in another coroutine. */ - _lib9p_srv_reqch_send_req(&srv->_reqch, &req); + cr_rpc_send_req(&srv->_reqch, &req); } if (map_len(&sess.reqs) == 0) io_close(conn.fd); @@ -554,10 +564,10 @@ void lib9p_srv_worker_loop(struct lib9p_srv *srv) { for (;;) { /* Receive the request from the reader coroutine. ************/ - rpc_handle = _lib9p_srv_reqch_recv_req(&srv->_reqch); + rpc_handle = cr_rpc_recv_req(&srv->_reqch); if (!rpc_handle.req) { srv->writers--; - _lib9p_srv_reqch_send_resp(rpc_handle, 0); + cr_rpc_send_resp(rpc_handle, 0); return; } /* Copy the request from the reader coroutine's @@ -568,17 +578,10 @@ void lib9p_srv_worker_loop(struct lib9p_srv *srv) { assert(reqpp && *reqpp == &req); /* Notify the reader coroutine that we're done with * its data. */ - _lib9p_srv_reqch_send_resp(rpc_handle, 0); + cr_rpc_send_resp(rpc_handle, 0); /* Process the request. **************************************/ - handle_message(&req); - - /* Release resources. ****************************************/ - while (_lib9p_srv_flushch_can_send(&req.flushch)) - _lib9p_srv_flushch_send(&req.flushch, false); - map_del(&req.parent_sess->reqs, req.tag); - if (req.parent_sess->closing && !map_len(&req.parent_sess->reqs)) - cr_unpause(req.parent_sess->parent_conn->reader); + lib9p_srv_worker(&req); } } @@ -610,35 +613,11 @@ _HANDLER_PROTO(swrite); typedef void (*tmessage_handler)(struct srv_req *, void *, void *); -static tmessage_handler tmessage_handlers[0x100] = { - [LIB9P_TYP_Tversion] = (tmessage_handler)handle_Tversion, - [LIB9P_TYP_Tauth] = (tmessage_handler)handle_Tauth, - [LIB9P_TYP_Tattach] = (tmessage_handler)handle_Tattach, - [LIB9P_TYP_Tflush] = (tmessage_handler)handle_Tflush, - [LIB9P_TYP_Twalk] = (tmessage_handler)handle_Twalk, - [LIB9P_TYP_Topen] = (tmessage_handler)handle_Topen, - [LIB9P_TYP_Tcreate] = (tmessage_handler)handle_Tcreate, - [LIB9P_TYP_Tread] = (tmessage_handler)handle_Tread, - [LIB9P_TYP_Twrite] = (tmessage_handler)handle_Twrite, - [LIB9P_TYP_Tclunk] = (tmessage_handler)handle_Tclunk, - [LIB9P_TYP_Tremove] = (tmessage_handler)handle_Tremove, - [LIB9P_TYP_Tstat] = (tmessage_handler)handle_Tstat, - [LIB9P_TYP_Twstat] = (tmessage_handler)handle_Twstat, -#if CONFIG_9P_ENABLE_9P2000_p9p - [LIB9P_TYP_Topenfd] = (tmessage_handler)handle_Topenfd, -#endif -#if CONFIG_9P_ENABLE_9P2000_e - [LIB9P_TYP_Tsession] = (tmessage_handler)handle_Tsession, - [LIB9P_TYP_Tsread] = (tmessage_handler)handle_Tsread, - [LIB9P_TYP_Tswrite] = (tmessage_handler)handle_Tswrite, -#endif -}; - -static void handle_message(struct srv_req *ctx) { +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. */ + /* Unmarshal it. *****************************************************/ ssize_t host_size = lib9p_Tmsg_validate(&ctx->basectx, ctx->net_bytes); if (host_size < 0) goto write; @@ -649,13 +628,45 @@ static void handle_message(struct srv_req *ctx) { &typ, host_req); srv_msglog(ctx, typ, host_req); - /* Handle it. */ - tmessage_handlers[typ](ctx, (void *)host_req, (void *)host_resp); + /* Handle it. ********************************************************/ + tmessage_handler handler; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch-enum" + switch (typ) { + case LIB9P_TYP_Tversion: handler = (tmessage_handler)handle_Tversion; break; + 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; + case LIB9P_TYP_Twalk: handler = (tmessage_handler)handle_Twalk; break; + case LIB9P_TYP_Topen: handler = (tmessage_handler)handle_Topen; break; + case LIB9P_TYP_Tcreate: handler = (tmessage_handler)handle_Tcreate; break; + case LIB9P_TYP_Tread: handler = (tmessage_handler)handle_Tread; break; + case LIB9P_TYP_Twrite: handler = (tmessage_handler)handle_Twrite; break; + case LIB9P_TYP_Tclunk: handler = (tmessage_handler)handle_Tclunk; break; + 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; +#if CONFIG_9P_ENABLE_9P2000_p9p + 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; + case LIB9P_TYP_Tsread: handler = (tmessage_handler)handle_Tsread; break; + case LIB9P_TYP_Tswrite: handler = (tmessage_handler)handle_Tswrite; break; +#endif + default: + assert_notreached("lib9p_Tmsg_validate() should have rejected unknown typ"); + } +#pragma GCC diagnostic pop + handler(ctx, (void *)host_req, (void *)host_resp); + /* Write the response. ***********************************************/ write: - if (lib9p_ctx_has_error(&ctx->basectx)) + if (lib9p_ctx_has_error(&ctx->basectx)) { srv_respond_error(ctx); - else { + } 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, @@ -664,6 +675,16 @@ static void handle_message(struct srv_req *ctx) { srv_msglog(ctx, typ+1, &host_resp); srv_write_Rmsg(ctx, &net_resp); } + /* Release resources. ************************************************/ + map_del(&ctx->parent_sess->reqs, ctx->tag); + size_t nwaiters; + while ((nwaiters = cr_chan_num_waiters(&ctx->flush_ch))) { + cr_chan_send(&ctx->flush_ch, (nwaiters == 1) + ? _LIB9P_SRV_FLUSH_RFLUSH + : _LIB9P_SRV_FLUSH_SILENT); + } + if (ctx->parent_sess->closing && !map_len(&ctx->parent_sess->reqs)) + cr_unpause(ctx->parent_sess->parent_conn->reader); if (host_req) free(host_req); free(ctx->net_bytes); @@ -712,7 +733,7 @@ static void handle_Tversion(struct srv_req *ctx, uint32_t min_msg_size = lib9p_version_min_msg_size(version); if (req->max_msg_size < min_msg_size) { lib9p_errorf(&ctx->basectx, - LINUX_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")", + 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; } @@ -730,15 +751,15 @@ static void handle_Tversion(struct srv_req *ctx, if (map_len(&ctx->parent_sess->reqs)) { /* Flush all in-progress requests, and wait for them * to finish. */ - struct cr_select_arg *list = alloca(sizeof(struct cr_select_arg) * map_len(&ctx->parent_sess->reqs)); + struct cr_select_arg *args = stack_alloc(map_len(&ctx->parent_sess->reqs), struct cr_select_arg); while (map_len(&ctx->parent_sess->reqs)) { size_t i = 0; - bool flushed; MAP_FOREACH(&ctx->parent_sess->reqs, tag, reqpp) { - list[i] = CR_SELECT_RECV(&((*reqpp)->flushch), &flushed); + enum _lib9p_srv_flush_result flushed; + args[i++] = CR_SELECT_RECV(&((*reqpp)->flush_ch), &flushed); } assert(i == map_len(&ctx->parent_sess->reqs)); - cr_select_v(i, list); + cr_select_v(i, args); } } if (map_len(&ctx->parent_sess->fids)) { @@ -763,7 +784,7 @@ 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, - LINUX_EOPNOTSUPP, "authentication not required"); + LIB9P_ERRNO_L_EOPNOTSUPP, "authentication not required"); return; } @@ -772,7 +793,7 @@ static void handle_Tauth(struct srv_req *ctx, srv->auth(ctx, req->aname); lib9p_error(&ctx->basectx, - LINUX_EOPNOTSUPP, "TODO: auth not implemented"); + LIB9P_ERRNO_L_EOPNOTSUPP, "TODO: auth not implemented"); if (lib9p_ctx_has_error(&ctx->basectx)) ctx->authinfo = srv_authinfo_decref(ctx->authinfo); @@ -785,7 +806,7 @@ static void handle_Tattach(struct srv_req *ctx, if (req->fid == LIB9P_FID_NOFID) { lib9p_error(&ctx->basectx, - LINUX_EBADF, "cannot assign to NOFID"); + LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID"); return; } @@ -794,36 +815,36 @@ static void handle_Tattach(struct srv_req *ctx, struct srv_fidinfo *afid = map_load(&ctx->parent_sess->fids, req->afid); if (!afid) lib9p_error(&ctx->basectx, - LINUX_EACCES, "FID provided as auth-file is not a valid FID"); + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is not a valid FID"); else if (afid->type != SRV_FILETYPE_AUTH) lib9p_error(&ctx->basectx, - LINUX_EACCES, "FID provided as auth-file is not an auth-file"); + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is not an auth-file"); else if (!lib9p_str_eq(afid->authinfo->uname, req->uname)) lib9p_errorf(&ctx->basectx, - LINUX_EACCES, "FID provided as auth-file is for user=\"%.*s\" and cannot be used for user=\"%.*s\"", + 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, req->uname.len, req->uname.utf8); #if CONFIG_9P_ENABLE_9P2000_u else if (afid->authinfo->uid != req->n_uid) lib9p_errorf(&ctx->basectx, - LINUX_EACCES, "FID provided as auth-file is for user=%"PRIu32" and cannot be used for user=%"PRIu32, + 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); #endif else if (!lib9p_str_eq(afid->auth.aname, req->aname)) lib9p_errorf(&ctx->basectx, - LINUX_EACCES, "FID provided as auth-file is for tree=\"%.*s\" and cannot be used for tree=\"%.*s\"", + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file is for tree=\"%.*s\" and cannot be used for tree=\"%.*s\"", afid->auth.aname.len, afid->auth.aname.utf8, req->aname.len, req->aname.utf8); else if (!afid->auth.completed) lib9p_error(&ctx->basectx, - LINUX_EACCES, "FID provided as auth-file has not completed authentication"); + 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); } else { if (req->afid != LIB9P_FID_NOFID) { lib9p_error(&ctx->basectx, - LINUX_EACCES, "FID provided as auth-file, but no auth-file is required"); + LIB9P_ERRNO_L_EACCES, "FID provided as auth-file, but no auth-file is required"); return; } ctx->authinfo = srv_authinfo_new(req->uname, req->n_uid); @@ -861,8 +882,21 @@ static void handle_Tflush(struct srv_req *ctx, srv_handler_common(ctx, req, resp); struct srv_req **oldreqp = map_load(&ctx->parent_sess->reqs, req->oldtag); - if (oldreqp) - _lib9p_srv_flushch_recv(&((*oldreqp)->flushch)); + if (oldreqp) { + struct srv_req *oldreq = *oldreqp; + enum _lib9p_srv_flush_result res = _LIB9P_SRV_FLUSH_RFLUSH; + switch (cr_select_l(CR_SELECT_RECV(&oldreq->flush_ch, &res), + CR_SELECT_SEND(&ctx->flush_ch, &res))) { + case 0: /* original request returned */ + req_debugf("original request (tag=%"PRIu16") returned", req->oldtag); + ctx->flush_acknowledged = (res == _LIB9P_SRV_FLUSH_SILENT); + break; + case 1: /* flush itself got flushed */ + req_debugf("flush itself flushed"); + ctx->flush_acknowledged = true; + break; + } + } } static void handle_Twalk(struct srv_req *ctx, @@ -872,14 +906,19 @@ static void handle_Twalk(struct srv_req *ctx, if (req->newfid == LIB9P_FID_NOFID) { lib9p_error(&ctx->basectx, - LINUX_EBADF, "cannot assign to NOFID"); + LIB9P_ERRNO_L_EBADF, "cannot assign to NOFID"); return; } struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { lib9p_errorf(&ctx->basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); + return; + } + if (fidinfo->flags & FIDFLAG_OPEN) { + lib9p_error(&ctx->basectx, + LIB9P_ERRNO_L_EALREADY, "cannot walk on FID open for I/O"); return; } ctx->authinfo = srv_authinfo_incref(fidinfo->authinfo); @@ -890,23 +929,24 @@ static void handle_Twalk(struct srv_req *ctx, resp->wqid = (struct lib9p_qid *)(&resp[1]); 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"); + break; + } + struct srv_pathinfo *new_pathinfo; 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 { - if (pathinfo->type != SRV_FILETYPE_DIR) { - lib9p_error(&ctx->basectx, - LINUX_ENOTDIR, "not a directory"); - break; - } - 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; new_pathinfo = srv_path_save(ctx, member_file, LO_CALL(pathinfo->file, qid).path); + assert(new_pathinfo); } if (new_pathinfo->type == SRV_FILETYPE_DIR) { @@ -916,7 +956,7 @@ static void handle_Twalk(struct srv_req *ctx, lib9p_stat_assert(stat); if (!srv_check_perm(ctx, &stat, 0b001)) { lib9p_error(&ctx->basectx, - LINUX_EACCES, "you do not have execute permission on that directory"); + LIB9P_ERRNO_L_EACCES, "you do not have execute permission on that directory"); srv_path_decref(ctx, LO_CALL(new_pathinfo->file, qid).path); break; } @@ -948,12 +988,12 @@ static void handle_Topen(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { lib9p_errorf(&ctx->basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); return; } if (fidinfo->flags & FIDFLAG_OPEN) { lib9p_error(&ctx->basectx, - LINUX_EALREADY, "FID is already open"); + LIB9P_ERRNO_L_EALREADY, "FID is already open"); return; } if (fidinfo->type == SRV_FILETYPE_DIR) { @@ -961,7 +1001,7 @@ static void handle_Topen(struct srv_req *ctx, (req->mode & LIB9P_O_TRUNC) || (req->mode & LIB9P_O_RCLOSE) ) { lib9p_error(&ctx->basectx, - LINUX_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close"); + LIB9P_ERRNO_L_EISDIR, "directories cannot be written, executed, truncated, or removed-on-close"); return; } } @@ -983,7 +1023,7 @@ static void handle_Topen(struct srv_req *ctx, lib9p_stat_assert(parent_stat); if (!srv_check_perm(ctx, &parent_stat, 0b010)) { lib9p_error(&ctx->basectx, - LINUX_EACCES, "permission denied to remove-on-close"); + LIB9P_ERRNO_L_EACCES, "permission denied to remove-on-close"); goto topen_return; } fidflags |= FIDFLAG_RCLOSE; @@ -994,7 +1034,7 @@ static void handle_Topen(struct srv_req *ctx, lib9p_stat_assert(stat); if ((stat.file_mode & LIB9P_DM_EXCL) && pathinfo->io_refcount) { lib9p_error(&ctx->basectx, - LINUX_EEXIST, "exclusive file is already opened"); + LIB9P_ERRNO_L_EEXIST, "exclusive file is already opened"); goto topen_return; } if (stat.file_mode & LIB9P_DM_APPEND) @@ -1021,7 +1061,7 @@ static void handle_Topen(struct srv_req *ctx, } if (!srv_check_perm(ctx, &stat, perm_bits)) { lib9p_error(&ctx->basectx, - LINUX_EACCES, "permission denied"); + LIB9P_ERRNO_L_EACCES, "permission denied"); goto topen_return; } @@ -1076,7 +1116,7 @@ static void handle_Tcreate(struct srv_req *ctx, srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, - LINUX_EOPNOTSUPP, "create not (yet?) implemented"); + LIB9P_ERRNO_L_EOPNOTSUPP, "create not (yet?) implemented"); } static void handle_Tread(struct srv_req *ctx, @@ -1090,12 +1130,12 @@ static void handle_Tread(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { lib9p_errorf(&ctx->basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); return; } if (!(fidinfo->flags & FIDFLAG_OPEN_R)) { lib9p_error(&ctx->basectx, - LINUX_EINVAL, "FID not open for reading"); + LIB9P_ERRNO_L_EINVAL, "FID not open for reading"); return; } @@ -1111,7 +1151,7 @@ static void handle_Tread(struct srv_req *ctx, idx = fidinfo->dir.idx; else { lib9p_errorf(&ctx->basectx, - LINUX_EINVAL, "invalid offset (must be 0 or %"PRIu64"): %"PRIu64, + 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; @@ -1134,7 +1174,7 @@ static void handle_Tread(struct srv_req *ctx, 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)) { + 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) @@ -1159,12 +1199,12 @@ static void handle_Twrite(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { lib9p_errorf(&ctx->basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); return; } if (!(fidinfo->flags & FIDFLAG_OPEN_W)) { lib9p_error(&ctx->basectx, - LINUX_EINVAL, "FID not open for writing"); + LIB9P_ERRNO_L_EINVAL, "FID not open for writing"); return; } @@ -1182,7 +1222,7 @@ static void handle_Tclunk(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { lib9p_errorf(&ctx->basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); return; } @@ -1199,7 +1239,7 @@ static void handle_Tremove(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { lib9p_errorf(&ctx->basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); return; } @@ -1216,7 +1256,7 @@ static void handle_Tstat(struct srv_req *ctx, struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { lib9p_errorf(&ctx->basectx, - LINUX_EBADF, "bad file number %"PRIu32, req->fid); + LIB9P_ERRNO_L_EBADF, "bad file number %"PRIu32, req->fid); return; } struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); @@ -1235,7 +1275,7 @@ static void handle_Twstat(struct srv_req *ctx, srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, - LINUX_EOPNOTSUPP, "wstat not (yet?) implemented"); + LIB9P_ERRNO_L_EOPNOTSUPP, "wstat not (yet?) implemented"); } #if CONFIG_9P_ENABLE_9P2000_p9p @@ -1245,7 +1285,7 @@ static void handle_Topenfd(struct srv_req *ctx, srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, - LINUX_EOPNOTSUPP, "openfd not (yet?) implemented"); + LIB9P_ERRNO_L_EOPNOTSUPP, "openfd not (yet?) implemented"); } #endif @@ -1256,7 +1296,7 @@ static void handle_Tsession(struct srv_req *ctx, srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, - LINUX_EOPNOTSUPP, "session not (yet?) implemented"); + LIB9P_ERRNO_L_EOPNOTSUPP, "session not (yet?) implemented"); } static void handle_Tsread(struct srv_req *ctx, @@ -1265,7 +1305,7 @@ static void handle_Tsread(struct srv_req *ctx, srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, - LINUX_EOPNOTSUPP, "sread not (yet?) implemented"); + LIB9P_ERRNO_L_EOPNOTSUPP, "sread not (yet?) implemented"); } static void handle_Tswrite(struct srv_req *ctx, @@ -1274,6 +1314,6 @@ static void handle_Tswrite(struct srv_req *ctx, srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, - LINUX_EOPNOTSUPP, "swrite not (yet?) implemented"); + LIB9P_ERRNO_L_EOPNOTSUPP, "swrite not (yet?) implemented"); } #endif |