diff options
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r-- | lib9p/srv.c | 96 |
1 files changed, 52 insertions, 44 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c index edb39ba..0196a0e 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -200,11 +200,9 @@ static struct lib9p_srv_userid *srv_userid_decref(struct lib9p_srv_userid *useri assert(userid); assert(userid->refcount); userid->refcount--; - if (!userid->refcount) { + if (!userid->refcount) free(userid); - return NULL; - } - return userid; + return NULL; } static struct lib9p_srv_userid *srv_userid_incref(struct lib9p_srv_userid *userid) { @@ -272,32 +270,21 @@ 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, bool remove) { - struct srv_fidinfo *fidinfo = map_load(&ctx->parent_sess->fids, fid); +static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, struct srv_fidinfo *fidinfo, bool remove) { + assert(ctx); + assert(!ctx->user); assert(fidinfo); + if (fidinfo->flags & FIDFLAG_RCLOSE) remove = true; + ctx->user = srv_userid_incref(fidinfo->user); + struct srv_pathinfo *pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path); assert(pathinfo); - if (remove) { - if (pathinfo->parent_dir == fidinfo->path) { - lib9p_error(&ctx->basectx, - LIB9P_ERRNO_L_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, - LIB9P_ERRNO_L_EACCES, "you do not have write permission on the parent directory"); - goto clunk; - } + if (remove) LO_CALL(pathinfo->file, remove, ctx); - } - clunk: if (fidinfo->flags & FIDFLAG_OPEN) { switch (fidinfo->type) { case SRV_FILETYPE_DIR: @@ -315,6 +302,8 @@ static inline void srv_fid_del(struct srv_req *ctx, lib9p_fid_t fid, bool remove fidinfo->user = srv_userid_decref(fidinfo->user); srv_path_decref(ctx, fidinfo->path); map_del(&ctx->parent_sess->fids, fid); + + ctx->user = srv_userid_decref(ctx->user); } /** @@ -543,17 +532,19 @@ void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn _conn) { assert(map_len(&sess.reqs) == 0); map_free(&sess.reqs); + struct srv_req pseudoreq = { + .basectx = { + .version = sess.version, + .max_msg_size = sess.max_msg_size, + }, + .parent_sess = &sess, + }; MAP_FOREACH(&sess.fids, fid, fidinfo) { - struct srv_req req = { - .basectx = { - .version = sess.version, - .max_msg_size = sess.max_msg_size, - }, - .parent_sess = &sess, - }; - 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); + srv_fid_del(&pseudoreq, fid, fidinfo, false); + if (lib9p_ctx_has_error(&pseudoreq.basectx)) { + srv_nonrespond_errorf("clunk: %.*s", CONFIG_9P_MAX_ERR_SIZE, pseudoreq.basectx.err_msg); + lib9p_ctx_clear_error(&pseudoreq.basectx); + } } map_free(&sess.fids); @@ -781,10 +772,12 @@ static void handle_Tversion(struct srv_req *ctx, cr_select_v(i, args); } } - if (map_len(&ctx->parent_sess->fids)) { - /* Close all FIDs. */ - MAP_FOREACH(&ctx->parent_sess->fids, fid, fidinfo) { - srv_fid_del(ctx, fid, false); + /* 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_errorf("clunk: %.*s", CONFIG_9P_MAX_ERR_SIZE, ctx->basectx.err_msg); + lib9p_ctx_clear_error(&ctx->basectx); } } @@ -1260,11 +1253,9 @@ static void handle_Tclunk(struct srv_req *ctx, goto tclunk_return; } - ctx->user = srv_userid_incref(fidinfo->user); - srv_fid_del(ctx, req->fid, false); + srv_fid_del(ctx, req->fid, fidinfo, false); + tclunk_return: - if (ctx->user) - ctx->user = srv_userid_decref(ctx->user); srv_respond(ctx, clunk, &resp); } @@ -1279,11 +1270,28 @@ static void handle_Tremove(struct srv_req *ctx, goto tremove_return; } - ctx->user = srv_userid_incref(fidinfo->user); - srv_fid_del(ctx, req->fid, true); + bool remove = true; + 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"); + remove = false; + goto tremove_main; + } + 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 (!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"); + remove = false; + goto tremove_main; + } + + tremove_main: + srv_fid_del(ctx, req->fid, fidinfo, remove); tremove_return: - if (ctx->user) - ctx->user = srv_userid_decref(ctx->user); srv_respond(ctx, remove, &resp); } |