diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-13 01:04:59 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-13 02:33:42 -0600 |
commit | b267e241f0545b68864fb2bcf593c02f3bc2cf19 (patch) | |
tree | 5fb86e8ce4033a9b2c30546ee39d768fcac39b11 | |
parent | 06cc1184f375ce5929010254781483277d9447d2 (diff) |
lib9p: srv: Try to go for consistent naming
-rw-r--r-- | build-aux/measurestack/app_plugins.py | 10 | ||||
-rw-r--r-- | lib9p/srv.c | 502 |
2 files changed, 265 insertions, 247 deletions
diff --git a/build-aux/measurestack/app_plugins.py b/build-aux/measurestack/app_plugins.py index 6eeb35b..16ac297 100644 --- a/build-aux/measurestack/app_plugins.py +++ b/build-aux/measurestack/app_plugins.py @@ -406,9 +406,9 @@ class Lib9PPlugin: ), } if isinstance(self.CONFIG_9P_SRV_MAX_DEPTH, int): - ret[BaseName("srv_util_pathfree")] = analyze.SkipModel( + ret[BaseName("srv_path_decref")] = analyze.SkipModel( self.CONFIG_9P_SRV_MAX_DEPTH, - self._skipmodel_srv_util_pathfree, + self._skipmodel_srv_path_decref, ) return ret @@ -423,13 +423,13 @@ class Lib9PPlugin: return False return m_caller.group("grp") != m_callee.group("grp") - def _skipmodel_srv_util_pathfree( + def _skipmodel_srv_path_decref( self, chain: typing.Sequence[QName], call: QName ) -> bool: assert isinstance(self.CONFIG_9P_SRV_MAX_DEPTH, int) - if call.base() == BaseName("srv_util_pathfree"): + if call.base() == BaseName("srv_path_decref"): return len(chain) >= self.CONFIG_9P_SRV_MAX_DEPTH and all( - c.base() == BaseName("srv_util_pathfree") + c.base() == BaseName("srv_path_decref") for c in chain[-self.CONFIG_9P_SRV_MAX_DEPTH :] ) return False diff --git a/lib9p/srv.c b/lib9p/srv.c index b8b6683..ac65699 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -67,10 +67,19 @@ void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) { /* structs ********************************************************************/ +enum srv_filetype { + SRV_FILETYPE_FILE, + SRV_FILETYPE_DIR, + SRV_FILETYPE_AUTH, +}; + +/* path *****************************************/ + typedef typeof( ((struct lib9p_qid){}).path ) srv_path_t; struct srv_pathinfo { lo_interface lib9p_srv_file file; + enum srv_filetype type; srv_path_t parent_dir; /* References from other srv_pathinfos (via .parent_dir) or @@ -80,7 +89,7 @@ struct srv_pathinfo { unsigned int io_refcount; }; -MAP_DECLARE(pathmap, srv_path_t, struct srv_pathinfo); +/* fid ******************************************/ #define FIDFLAG_OPEN_R (1<<0) #define FIDFLAG_OPEN_W (1<<1) @@ -90,6 +99,7 @@ MAP_DECLARE(pathmap, srv_path_t, struct srv_pathinfo); struct srv_fidinfo { srv_path_t path; uint8_t flags; + enum srv_filetype type; union { struct { lo_interface lib9p_srv_fio io; @@ -102,10 +112,9 @@ struct srv_fidinfo { }; }; -MAP_DECLARE(fidmap, lib9p_fid_t, struct srv_fidinfo); -MAP_DECLARE(reqmap, lib9p_tag_t, struct lib9p_srv_ctx *); - -/* The hierarchy of concepts is: +/* contexts ************************************** + * + * The hierarchy of contexts is: * * server -> connection -> session -> request * @@ -123,6 +132,9 @@ struct srv_conn { }; #define srv_sess _lib9p_srv_sess +MAP_DECLARE(srv_pathmap, srv_path_t, struct srv_pathinfo); +MAP_DECLARE(srv_fidmap, lib9p_fid_t, struct srv_fidinfo); +MAP_DECLARE(srv_reqmap, lib9p_tag_t, struct lib9p_srv_ctx *); struct srv_sess { /* immutable */ struct srv_conn *parent_conn; @@ -131,16 +143,169 @@ struct srv_sess { /* mutable */ bool initialized; bool closing; - struct pathmap paths; /* srv_path_t => `lib9p_srv_file` + metadata */ - struct fidmap fids; /* lib9p_fid_t => `lib9p_srv_{fio,dio}` + metadata */ - struct reqmap reqs; /* lib9p_tag_t => `struct srv_req *` */ + struct srv_pathmap paths; /* srv_path_t => `lib9p_srv_file` + metadata */ + struct srv_fidmap fids; /* lib9p_fid_t => `lib9p_srv_{fio,dio}` + metadata */ + struct srv_reqmap reqs; /* lib9p_tag_t => `struct srv_req *` */ }; #define srv_req lib9p_srv_ctx /* struct lib9p_srv_ctx {} is defined in <lib9p/srv.h> */ +/* utilities for the above types **********************************************/ + +static inline enum srv_filetype srv_qid_filetype(struct lib9p_qid qid) { + if (qid.type & LIB9P_QT_AUTH) + return SRV_FILETYPE_AUTH; + if (qid.type & LIB9P_QT_DIR) + return SRV_FILETYPE_DIR; + return SRV_FILETYPE_FILE; +} + +static inline bool srv_check_perm(struct srv_req *ctx, struct lib9p_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); + + return mode & action; +} + +/** + * Ensures that `file` is saved into the pathmap, and increments the + * gc_refcount by 1 (for presumptive insertion into the fidmap). + * parent_path's gc_refcount is also incremented as appropriate. + * + * Returns a pointer to the stored pathinfo. + */ +static inline struct srv_pathinfo *srv_path_save(struct srv_req *ctx, + lo_interface lib9p_srv_file file, + srv_path_t parent_path) { + assert(ctx); + assert(!LO_IS_NULL(file)); + + struct lib9p_qid qid = LO_CALL(file, qid); + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, qid.path); + if (pathinfo) + assert(LO_EQ(pathinfo->file, file)); + else { + pathinfo = map_store(&ctx->parent_sess->paths, qid.path, + (struct srv_pathinfo){ + .file = file, + .type = srv_qid_filetype(qid), + .parent_dir = parent_path, + .gc_refcount = 0, + .io_refcount = 0, + }); + assert(pathinfo); + if (parent_path != qid.path) { + struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, parent_path); + assert(parent); + parent->gc_refcount++; + } + } + pathinfo->gc_refcount++; + return pathinfo; +} + +/** + * Decrement the path's gc_refcount, and trigger garbage collection as + * appropriate. + */ +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); + LO_CALL(pathinfo->file, free); + map_del(&ctx->parent_sess->paths, 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); + if (!fidinfo) { + lib9p_errorf(&ctx->basectx, + LINUX_EBADF, "bad file number %"PRIu32, fid); + return; + } + if (fidinfo->flags & FIDFLAG_RCLOSE) + remove = true; + 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, + LINUX_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, + LINUX_EACCES, "remove: you do not have write permission on the parent directory"); + goto clunk; + } + LO_CALL(pathinfo->file, remove, ctx); + } + + clunk: + if (fidinfo->flags & FIDFLAG_OPEN) { + switch (fidinfo->type) { + case SRV_FILETYPE_DIR: + LO_CALL(fidinfo->dir.io, iofree); + break; + case SRV_FILETYPE_FILE: + LO_CALL(fidinfo->file.io, iofree); + break; + case SRV_FILETYPE_AUTH: + assert_notreached("TODO: auth not yet implemented"); + break; + } + pathinfo->io_refcount--; + } + srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path); + map_del(&ctx->parent_sess->fids, fid); +} + +/** + * Store fid as pointing to pathinfo. Assumes that + * 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) { + 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)) { + if (overwrite) { + srv_fid_del(ctx, fid, false); + } else { + lib9p_error(&ctx->basectx, + LINUX_EBADF, "FID already in use"); + return NULL; + } + } + struct srv_fidinfo *fidinfo = map_store(&ctx->parent_sess->fids, fid, (struct srv_fidinfo){ + .path = qid.path, + .type = srv_qid_filetype(qid), + }); + assert(fidinfo); + return fidinfo; +} + /* base utilities *************************************************************/ -static void msglog(struct srv_req *req, enum lib9p_msg_type typ, void *hostmsg) { +static void srv_msglog(struct srv_req *req, enum lib9p_msg_type typ, void *hostmsg) { struct lib9p_srv *srv = req->parent_sess->parent_conn->parent_srv; if (srv->msglog) { srv->msglog(req, typ, hostmsg); @@ -155,9 +320,7 @@ static void msglog(struct srv_req *req, enum lib9p_msg_type typ, void *hostmsg) #pragma GCC diagnostic pop } -#define nonrespond_errorf errorf - -static ssize_t write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) { +static ssize_t srv_write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) { ssize_t r; cr_mutex_lock(&req->parent_sess->parent_conn->writelock); r = io_writev(req->parent_sess->parent_conn->fd, resp->iov, resp->iov_cnt); @@ -165,7 +328,9 @@ static ssize_t write_Rmsg(struct srv_req *req, struct lib9p_Rmsg_send_buf *resp) return r; } -static void respond_error(struct srv_req *req) { +#define srv_nonrespond_errorf errorf + +static void srv_respond_error(struct srv_req *req) { #if CONFIG_9P_ENABLE_9P2000_u assert(req->basectx.err_num); #endif @@ -199,26 +364,26 @@ static void respond_error(struct srv_req *req) { LIB9P_TYP_Rerror, &host, &net); - msglog(req, LIB9P_TYP_Rerror, &host); - r = write_Rmsg(req, &net); + srv_msglog(req, LIB9P_TYP_Rerror, &host); + r = srv_write_Rmsg(req, &net); if (r < 0) - nonrespond_errorf("write: %s", net_strerror(-r)); + srv_nonrespond_errorf("write: %s", net_strerror(-r)); } /* read coroutine *************************************************************/ -static bool read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) { +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) { - nonrespond_errorf("read: %s", net_strerror(-r)); + srv_nonrespond_errorf("read: %s", net_strerror(-r)); return true; } else if (r == 0) { if (*done != 0) - nonrespond_errorf("read: unexpected EOF"); + srv_nonrespond_errorf("read: unexpected EOF"); return true; } *done += r; @@ -226,8 +391,6 @@ static bool read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t g return false; } -static void handle_message(struct srv_req *ctx); - void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stream_listener listener) { assert(srv); assert(srv->rootdir); @@ -238,7 +401,7 @@ void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stre for (;;) { lo_interface net_stream_conn conn = LO_CALL(listener, accept); if (LO_IS_NULL(conn)) { - nonrespond_errorf("accept: error"); + srv_nonrespond_errorf("accept: error"); srv->readers--; if (srv->readers == 0) while (srv->writers > 0) @@ -249,7 +412,7 @@ void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stre } } -static void clunkremove(struct srv_req *ctx, lib9p_fid_t fid, bool remove); +static void handle_message(struct srv_req *ctx); void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { assert(srv); @@ -271,14 +434,14 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { /* Read the message. */ size_t done = 0; uint8_t buf[7]; - if (read_exactly(conn.fd, buf, 4, &done)) + if (srv_read_exactly(conn.fd, buf, 4, &done)) break; size_t goal = uint32le_decode(buf); if (goal < 7) { - nonrespond_errorf("T-message is impossibly small"); + srv_nonrespond_errorf("T-message is impossibly small"); break; } - if (read_exactly(conn.fd, buf, 7, &done)) + if (srv_read_exactly(conn.fd, buf, 7, &done)) break; struct lib9p_srv_authinfo authinfo = {}; struct srv_req req = { @@ -298,13 +461,13 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { sess.initialized ? "negotiated" : "server", goal, sess.max_msg_size); - respond_error(&req); + srv_respond_error(&req); continue; } req.net_bytes = malloc(goal); assert(req.net_bytes); memcpy(req.net_bytes, buf, done); - if (read_exactly(conn.fd, req.net_bytes, goal, &done)) { + if (srv_read_exactly(conn.fd, req.net_bytes, goal, &done)) { free(req.net_bytes); break; } @@ -338,7 +501,7 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { }, .parent_sess = &sess, }; - clunkremove(&req, fid, false); + 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); } @@ -448,151 +611,41 @@ static void handle_message(struct srv_req *ctx) { enum lib9p_msg_type typ; lib9p_Tmsg_unmarshal(&ctx->basectx, ctx->net_bytes, &typ, host_req); - msglog(ctx, typ, host_req); + srv_msglog(ctx, typ, host_req); /* Handle it. */ tmessage_handlers[typ](ctx, (void *)host_req, (void *)host_resp); write: if (lib9p_ctx_has_error(&ctx->basectx)) - respond_error(ctx); + srv_respond_error(ctx); else { struct lib9p_Rmsg_send_buf net_resp; if (lib9p_Rmsg_marshal(&ctx->basectx, typ+1, host_resp, &net_resp)) goto write; - msglog(ctx, typ+1, &host_resp); - write_Rmsg(ctx, &net_resp); + srv_msglog(ctx, typ+1, &host_resp); + srv_write_Rmsg(ctx, &net_resp); } if (host_req) free(host_req); free(ctx->net_bytes); } -#define util_handler_common(ctx, req, resp) do { \ - assert(ctx); \ - assert(req); \ - assert(resp); \ - resp->tag = req->tag; \ - } while (0) - -static inline bool srv_util_check_perm(struct srv_req *ctx, struct lib9p_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); - - return mode & action; -} - -/** - * Ensures that `file` is saved into the pathmap, and increments the - * gc_refcount by 1 (for presumptive insertion into the fidmap). - * parent_path's gc_refcount is also incremented as appropriate. - * - * Returns a pointer to the stored pathinfo. - */ -static inline struct srv_pathinfo *srv_util_pathsave(struct srv_req *ctx, - lo_interface lib9p_srv_file file, - srv_path_t parent_path) { - assert(ctx); - assert(!LO_IS_NULL(file)); - - struct lib9p_qid qid = LO_CALL(file, qid); - struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, qid.path); - if (pathinfo) - assert(LO_EQ(pathinfo->file, file)); - else { - pathinfo = map_store(&ctx->parent_sess->paths, qid.path, - (struct srv_pathinfo){ - .file = file, - .parent_dir = parent_path, - .gc_refcount = 0, - .io_refcount = 0, - }); - assert(pathinfo); - if (parent_path != qid.path) { - struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, parent_path); - assert(parent); - parent->gc_refcount++; - } - } - pathinfo->gc_refcount++; - return pathinfo; -} - -/** - * Decrement the path's gc_refcount, and trigger garbage collection as - * appropriate. - */ -static inline void srv_util_pathfree(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_util_pathfree(ctx, pathinfo->parent_dir); - LO_CALL(pathinfo->file, free); - map_del(&ctx->parent_sess->paths, path); - } -} - -static inline bool srv_util_pathisdir(struct srv_pathinfo *pathinfo) { - assert(pathinfo); - return LO_CALL(pathinfo->file, qid).type & LIB9P_QT_DIR; -} - -/** - * Store fid as pointing to pathinfo. Assumes that - * pathinfo->gc_refcount has already been incremented; does *not* - * decrement it on failure. - */ -static inline struct srv_fidinfo *srv_util_fidsave(struct srv_req *ctx, lib9p_fid_t fid, struct srv_pathinfo *pathinfo, bool overwrite) { - assert(ctx); - assert(fid != LIB9P_FID_NOFID); - assert(pathinfo); - infof("pathinfo=%p", pathinfo); - - struct lib9p_qid qid = LO_CALL(pathinfo->file, qid); - - struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, fid); - if (fidinfo) { - if (overwrite) { - struct srv_pathinfo *old_pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); - assert(old_pathinfo); - if (srv_util_pathisdir(old_pathinfo)) { - if (!LO_IS_NULL(fidinfo->dir.io)) - LO_CALL(fidinfo->dir.io, iofree); - } else { - if (!LO_IS_NULL(fidinfo->file.io)) - LO_CALL(fidinfo->file.io, iofree); - } - srv_util_pathfree(ctx, fidinfo->path); - } else { - lib9p_error(&ctx->basectx, - LINUX_EBADF, "FID already in use"); - return NULL; - } - } else { - fidinfo = map_store(&ctx->parent_sess->fids, fid, (struct srv_fidinfo){}); - assert(fidinfo); - } - *fidinfo = (struct srv_fidinfo){ - .path = qid.path, - }; - return fidinfo; -} +/* handle_T* ******************************************************************/ +#define srv_handler_common(ctx, req, resp) do { \ + assert(ctx); \ + assert(req); \ + assert(resp); \ + resp->tag = req->tag; \ + } while (0) static void handle_Tversion(struct srv_req *ctx, struct lib9p_msg_Tversion *req, struct lib9p_msg_Rversion *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); enum lib9p_version version = LIB9P_VER_unknown; @@ -660,7 +713,7 @@ static void handle_Tversion(struct srv_req *ctx, static void handle_Tauth(struct srv_req *ctx, struct lib9p_msg_Tauth *req, struct lib9p_msg_Rauth *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); ctx->authinfo->uid = req->n_uid; ctx->authinfo->uname = req->uname; @@ -680,7 +733,7 @@ static void handle_Tauth(struct srv_req *ctx, static void handle_Tattach(struct srv_req *ctx, struct lib9p_msg_Tattach *req, struct lib9p_msg_Rattach *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); ctx->authinfo->uid = req->n_uid; ctx->authinfo->uname = req->uname; @@ -736,14 +789,14 @@ static void handle_Tattach(struct srv_req *ctx, return; struct lib9p_qid root_qid = LO_CALL(root_file, qid); - assert(root_qid.type & LIB9P_QT_DIR); + assert(srv_qid_filetype(root_qid) == SRV_FILETYPE_DIR); /* 2. pathinfo */ - struct srv_pathinfo *root_pathinfo = srv_util_pathsave(ctx, root_file, root_qid.path); + struct srv_pathinfo *root_pathinfo = srv_path_save(ctx, root_file, root_qid.path); /* 3. fidinfo */ - if (!srv_util_fidsave(ctx, req->fid, root_pathinfo, false)) { - srv_util_pathfree(ctx, root_qid.path); + if (!srv_fid_store(ctx, req->fid, root_pathinfo, false)) { + srv_path_decref(ctx, root_qid.path); return; } @@ -754,7 +807,7 @@ static void handle_Tattach(struct srv_req *ctx, static void handle_Tflush(struct srv_req *ctx, struct lib9p_msg_Tflush *req, struct lib9p_msg_Rflush *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); struct srv_req **oldreqp = map_load(&ctx->parent_sess->reqs, req->oldtag); if (oldreqp) @@ -764,7 +817,7 @@ static void handle_Tflush(struct srv_req *ctx, static void handle_Twalk(struct srv_req *ctx, struct lib9p_msg_Twalk *req, struct lib9p_msg_Rwalk *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); if (req->newfid == LIB9P_FID_NOFID) { lib9p_error(&ctx->basectx, @@ -791,7 +844,7 @@ static void handle_Twalk(struct srv_req *ctx, assert(new_pathinfo); new_pathinfo->gc_refcount++; } else { - if (!srv_util_pathisdir(pathinfo)) { + if (pathinfo->type != SRV_FILETYPE_DIR) { lib9p_error(&ctx->basectx, LINUX_ENOTDIR, "not a directory"); break; @@ -801,33 +854,33 @@ static void handle_Twalk(struct srv_req *ctx, assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(&ctx->basectx)); if (lib9p_ctx_has_error(&ctx->basectx)) break; - new_pathinfo = srv_util_pathsave(ctx, member_file, LO_CALL(pathinfo->file, qid).path); + new_pathinfo = srv_path_save(ctx, member_file, LO_CALL(pathinfo->file, qid).path); } - if (srv_util_pathisdir(new_pathinfo)) { + if (new_pathinfo->type == SRV_FILETYPE_DIR) { struct lib9p_stat stat = LO_CALL(new_pathinfo->file, stat, ctx); if (lib9p_ctx_has_error(&ctx->basectx)) break; lib9p_stat_assert(stat); - if (!srv_util_check_perm(ctx, &stat, 0b001)) { + if (!srv_check_perm(ctx, &stat, 0b001)) { lib9p_error(&ctx->basectx, LINUX_EACCES, "you do not have execute permission on that directory"); - srv_util_pathfree(ctx, LO_CALL(new_pathinfo->file, qid).path); + srv_path_decref(ctx, LO_CALL(new_pathinfo->file, qid).path); break; } } resp->wqid[resp->nwqid] = LO_CALL(new_pathinfo->file, qid); - srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); + srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path); pathinfo = new_pathinfo; } if (resp->nwqid == req->nwname) { - if (!srv_util_fidsave(ctx, req->newfid, pathinfo, req->newfid == req->fid)) - srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); + 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_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); + srv_path_decref(ctx, LO_CALL(pathinfo->file, qid).path); if (resp->nwqid > 0) lib9p_ctx_clear_error(&ctx->basectx); } @@ -836,7 +889,7 @@ static void handle_Twalk(struct srv_req *ctx, static void handle_Topen(struct srv_req *ctx, struct lib9p_msg_Topen *req, struct lib9p_msg_Ropen *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); /* Check that the FID is valid for this. */ struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); @@ -850,9 +903,7 @@ static void handle_Topen(struct srv_req *ctx, LINUX_EALREADY, "FID is already open"); return; } - struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); - assert(pathinfo); - if (srv_util_pathisdir(pathinfo)) { + 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) ) { @@ -863,8 +914,10 @@ static void handle_Topen(struct srv_req *ctx, } /* Variables. */ - lib9p_o_t reqmode = req->mode; - uint8_t fidflags = fidinfo->flags; + lib9p_o_t reqmode = req->mode; + uint8_t fidflags = fidinfo->flags; + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); + assert(pathinfo); /* Check permissions. */ if (reqmode & LIB9P_O_RCLOSE) { @@ -874,7 +927,7 @@ static void handle_Topen(struct srv_req *ctx, if (lib9p_ctx_has_error(&ctx->basectx)) return; lib9p_stat_assert(parent_stat); - if (!srv_util_check_perm(ctx, &parent_stat, 0b010)) { + if (!srv_check_perm(ctx, &parent_stat, 0b010)) { lib9p_error(&ctx->basectx, LINUX_EACCES, "permission denied to remove-on-close"); return; @@ -912,7 +965,7 @@ static void handle_Topen(struct srv_req *ctx, rd = true; break; } - if (!srv_util_check_perm(ctx, &stat, perm_bits)) { + if (!srv_check_perm(ctx, &stat, perm_bits)) { lib9p_error(&ctx->basectx, LINUX_EACCES, "permission denied"); return; @@ -921,7 +974,8 @@ static void handle_Topen(struct srv_req *ctx, /* Actually make the call. */ uint32_t iounit; struct lib9p_qid qid; - if (srv_util_pathisdir(pathinfo)) { + 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)) @@ -930,7 +984,8 @@ static void handle_Topen(struct srv_req *ctx, fidinfo->dir.off = 0; qid = LO_CALL(fidinfo->dir.io, qid); iounit = 0; - } else { + break; + case SRV_FILETYPE_FILE: fidinfo->file.io = LO_CALL(pathinfo->file, fopen, ctx, rd, wr, reqmode & LIB9P_O_TRUNC); @@ -939,6 +994,13 @@ static void handle_Topen(struct srv_req *ctx, return; qid = LO_CALL(fidinfo->file.io, qid); iounit = LO_CALL(fidinfo->file.io, iounit); + break; + case SRV_FILETYPE_AUTH: + assert_notreached("TODO: auth not yet implemented"); + break; + default: + assert_notreached("invalid srv_filetype"); + break; } /* Success. */ @@ -955,7 +1017,7 @@ static void handle_Topen(struct srv_req *ctx, static void handle_Tcreate(struct srv_req *ctx, struct lib9p_msg_Tcreate *req, struct lib9p_msg_Rcreate *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, LINUX_EOPNOTSUPP, "create not (yet?) implemented"); @@ -964,7 +1026,7 @@ static void handle_Tcreate(struct srv_req *ctx, static void handle_Tread(struct srv_req *ctx, struct lib9p_msg_Tread *req, struct lib9p_msg_Rread *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); /* TODO: serialize simultaneous reads to the same FID */ @@ -981,12 +1043,9 @@ static void handle_Tread(struct srv_req *ctx, return; } - /* Variables. */ - struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); - assert(pathinfo); - /* Do it. */ - if (srv_util_pathisdir(pathinfo)) { + switch (fidinfo->type) { + case SRV_FILETYPE_DIR: /* Translate byte-offset to object-index. */ size_t idx; if (req->offset == 0) @@ -1013,7 +1072,8 @@ static void handle_Tread(struct srv_req *ctx, /* Remember. */ fidinfo->dir.idx = idx+num; fidinfo->dir.off = req->offset + len; - } else { + 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)) { @@ -1022,13 +1082,17 @@ static void handle_Tread(struct srv_req *ctx, if (resp->count > req->count) resp->count = req->count; } + break; + case SRV_FILETYPE_AUTH: + assert_notreached("TODO: auth not yet implemented"); + break; } } static void handle_Twrite(struct srv_req *ctx, struct lib9p_msg_Twrite *req, struct lib9p_msg_Rwrite *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); /* TODO: serialize simultaneous writes to the same FID */ @@ -1045,76 +1109,30 @@ static void handle_Twrite(struct srv_req *ctx, return; } - /* Variables. */ - struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); - assert(pathinfo); - /* Do it. */ resp->count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset); } -static void clunkremove(struct srv_req *ctx, lib9p_fid_t fid, bool remove) { - struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, fid); - if (!fidinfo) { - lib9p_errorf(&ctx->basectx, - LINUX_EBADF, "bad file number %"PRIu32, fid); - return; - } - if (fidinfo->flags & FIDFLAG_RCLOSE) - remove = true; - 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, - LINUX_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_util_check_perm(ctx, &parent_stat, 0b010)) { - lib9p_error(&ctx->basectx, - LINUX_EACCES, "you do not have write permission on the parent directory"); - goto clunk; - } - LO_CALL(pathinfo->file, remove, ctx); - } - - clunk: - if (fidinfo->flags & FIDFLAG_OPEN) { - if (srv_util_pathisdir(pathinfo)) - LO_CALL(fidinfo->dir.io, iofree); - else - LO_CALL(fidinfo->file.io, iofree); - pathinfo->io_refcount--; - } - srv_util_pathfree(ctx, LO_CALL(pathinfo->file, qid).path); - map_del(&ctx->parent_sess->fids, fid); -} - static void handle_Tclunk(struct srv_req *ctx, struct lib9p_msg_Tclunk *req, struct lib9p_msg_Rclunk *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); - clunkremove(ctx, req->fid, false); + srv_fid_del(ctx, req->fid, false); } - static void handle_Tremove(struct srv_req *ctx, struct lib9p_msg_Tremove *req, struct lib9p_msg_Rremove *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); - clunkremove(ctx, req->fid, true); + srv_fid_del(ctx, req->fid, true); } static void handle_Tstat(struct srv_req *ctx, struct lib9p_msg_Tstat *req, struct lib9p_msg_Rstat *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, req->fid); if (!fidinfo) { @@ -1133,7 +1151,7 @@ static void handle_Tstat(struct srv_req *ctx, static void handle_Twstat(struct srv_req *ctx, struct lib9p_msg_Twstat *req, struct lib9p_msg_Rwstat *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, LINUX_EOPNOTSUPP, "wstat not (yet?) implemented"); @@ -1143,7 +1161,7 @@ static void handle_Twstat(struct srv_req *ctx, static void handle_Tsession(struct srv_req *ctx, struct lib9p_msg_Tsession *req, struct lib9p_msg_Rsession *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, LINUX_EOPNOTSUPP, "session not (yet?) implemented"); @@ -1152,7 +1170,7 @@ static void handle_Tsession(struct srv_req *ctx, static void handle_Tsread(struct srv_req *ctx, struct lib9p_msg_Tsread *req, struct lib9p_msg_Rsread *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, LINUX_EOPNOTSUPP, "sread not (yet?) implemented"); @@ -1161,7 +1179,7 @@ static void handle_Tsread(struct srv_req *ctx, static void handle_Tswrite(struct srv_req *ctx, struct lib9p_msg_Tswrite *req, struct lib9p_msg_Rswrite *resp) { - util_handler_common(ctx, req, resp); + srv_handler_common(ctx, req, resp); lib9p_error(&ctx->basectx, LINUX_EOPNOTSUPP, "swrite not (yet?) implemented"); |