summaryrefslogtreecommitdiff
path: root/lib9p/srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/srv.c')
-rw-r--r--lib9p/srv.c144
1 files changed, 78 insertions, 66 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 0a33e03..7e2bab0 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -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
@@ -61,7 +51,7 @@ bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) {
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_error(&ctx->basectx, LIB9P_ERRNO_L_ECANCELED, "request canceled by flush");
_lib9p_srv_flushch_send(&ctx->flushch, true);
}
@@ -80,6 +70,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 +241,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 +267,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 +275,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 +306,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 +388,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;
@@ -487,7 +493,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);
@@ -712,7 +718,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;
}
@@ -763,7 +769,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 +778,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 +791,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 +800,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);
@@ -872,14 +878,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 +901,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 +928,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 +960,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 +973,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 +995,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 +1006,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 +1033,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 +1088,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 +1102,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 +1123,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;
@@ -1159,12 +1171,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 +1194,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 +1211,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 +1228,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 +1247,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 +1257,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 +1268,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 +1277,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 +1286,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