diff options
-rw-r--r-- | cmd/srv9p/static.c | 33 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 10 | ||||
-rw-r--r-- | lib9p/srv.c | 83 |
3 files changed, 105 insertions, 21 deletions
diff --git a/cmd/srv9p/static.c b/cmd/srv9p/static.c index 920daf2..e89c478 100644 --- a/cmd/srv9p/static.c +++ b/cmd/srv9p/static.c @@ -3,6 +3,26 @@ #include "static.h" #define UNUSED(name) /* name __attribute__((unused)) */ +#define p9_str(cstr) ((struct lib9p_s){ .len = strlen(cstr), .utf8 = cstr }) +#define p9_nulstr ((struct lib9p_s){ .len = 0, .utf8 = NULL }) + +/******************************************************************************/ + +static struct lib9p_srv_file *static_dir_clone(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) { + assert(ctx); + struct static_dir *file = (struct static_dir *)_file; + assert(file); + + return &file->header; +} + +static void static_dir_free(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) { + assert(ctx); + struct static_dir *file = (struct static_dir *)_file; + assert(file); + + /* do nothing */ +} static struct lib9p_srv_io *static_dir_io(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file, lib9p_o_t UNUSED(flags)) { assert(ctx); @@ -13,9 +33,6 @@ static struct lib9p_srv_io *static_dir_io(struct lib9p_srv_ctx *ctx, struct lib9 return NULL; } -#define p9_str(cstr) ((struct lib9p_s){ .len = strlen(cstr), .utf8 = cstr }) -#define p9_nulstr ((struct lib9p_s){ .len = 0, .utf8 = NULL }) - static struct lib9p_stat static_dir_stat(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) { assert(ctx); struct static_dir *file = (struct static_dir *)_file; @@ -61,11 +78,6 @@ static void static_dir_remove(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file * lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem"); } -static void static_dir_free(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) { - assert(ctx); - struct static_dir *file = (struct static_dir *)_file; - assert(file); -} static struct lib9p_srv_file *static_dir_dopen(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_dir, char *UNUSED(childname)) { @@ -89,11 +101,14 @@ static struct lib9p_srv_file *static_dir_dcreate(struct lib9p_srv_ctx *ctx, stru } struct lib9p_srv_file_vtable static_dir_vtable = { + .clone = static_dir_clone, + .free = static_dir_free, + .io = static_dir_io, .stat = static_dir_stat, .wstat = static_dir_wstat, .remove = static_dir_remove, - .free = static_dir_free, + .dopen = static_dir_dopen, .dcreate = static_dir_dcreate, }; diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index 11c1fac..d79e7db 100644 --- a/lib9p/include/lib9p/srv.h +++ b/lib9p/include/lib9p/srv.h @@ -38,16 +38,19 @@ struct lib9p_srv_file; struct lib9p_srv_io; struct lib9p_srv_file_vtable { - /* all */ + /* all - resource management */ + struct lib9p_srv_file *(*clone )(struct lib9p_srv_ctx *, struct lib9p_srv_file *); + void (*free )(struct lib9p_srv_ctx *, struct lib9p_srv_file *); + + /* all - syscalls */ struct lib9p_srv_io *(*io )(struct lib9p_srv_ctx *, struct lib9p_srv_file *, lib9p_o_t flags); struct lib9p_stat (*stat )(struct lib9p_srv_ctx *, struct lib9p_srv_file *); void (*wstat )(struct lib9p_srv_ctx *, struct lib9p_srv_file *, struct lib9p_stat new); void (*remove )(struct lib9p_srv_ctx *, struct lib9p_srv_file *); - void (*free )(struct lib9p_srv_ctx *, struct lib9p_srv_file *); /* optional */ - /* dir */ + /* directories */ struct lib9p_srv_file *(*dopen )(struct lib9p_srv_ctx *, struct lib9p_srv_file *, char *childname); struct lib9p_srv_file *(*dcreate)(struct lib9p_srv_ctx *, struct lib9p_srv_file *, @@ -77,7 +80,6 @@ struct lib9p_srv_file { /* Managed by srv.c */ struct lib9p_srv_file *_parent_dir; - struct lib9p_srv_file *_refcount; /* This is where your implementation data goes. */ char data[0]; diff --git a/lib9p/srv.c b/lib9p/srv.c index 84b3ae8..5af0971 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -515,6 +515,7 @@ static void handle_Tattach(struct _lib9p_srv_req *ctx, } struct lib9p_srv_file *rootdir = srv->rootdir(&ctx->ctx, req->aname.utf8); + assert((rootdir == NULL) == lib9p_ctx_has_error(&ctx->ctx.basectx)); if (lib9p_ctx_has_error(&ctx->ctx.basectx)) return; rootdir->_parent_dir = rootdir; @@ -522,8 +523,7 @@ static void handle_Tattach(struct _lib9p_srv_req *ctx, if (!fidmap_store(&ctx->parent_sess->fids, req->fid, rootdir)) { lib9p_error(&ctx->ctx.basectx, LINUX_EMFILE, "too many open files"); - if (rootdir->vtable->free) - rootdir->vtable->free(&ctx->ctx, rootdir); + rootdir->vtable->free(&ctx->ctx, rootdir); return; } @@ -558,8 +558,70 @@ static void handle_Twalk(struct _lib9p_srv_req *ctx, assert(req); assert(resp); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "walk not yet implemented"); + struct lib9p_srv_file **dirpp = fidmap_load(&ctx->parent_sess->fids, req->fid); + if (!dirpp) { + lib9p_errorf(&ctx->ctx.basectx, + LINUX_EBADF, "bad file number %"PRIu32, req->fid); + return; + } + if (req->newfid != req->fid && fidmap_load(&ctx->parent_sess->fids, req->newfid)) { + lib9p_error(&ctx->ctx.basectx, + LINUX_EBADF, "FID already in use"); + return; + } + + struct lib9p_srv_file *dirp; + if (req->newfid == req->fid) + dirp = *dirpp; + else { + dirp = (*dirpp)->vtable->clone(&ctx->ctx, *dirpp); + assert((dirp == NULL) == lib9p_ctx_has_error(&ctx->ctx.basectx)); + if (lib9p_ctx_has_error(&ctx->ctx.basectx)) + return; + } + + resp->wqid = (struct lib9p_qid *)(&resp[1]); + for (resp->nwqid = 0; resp->nwqid < req->nwname; resp->nwqid++) { + struct lib9p_srv_file *memberp; + if (strcmp(req->wname[resp->nwqid].utf8, "..")) { + memberp = dirp->_parent_dir; + } else { + struct lib9p_stat stat = dirp->vtable->stat(&ctx->ctx, dirp); + if (lib9p_ctx_has_error(&ctx->ctx.basectx)) + break; + if (!(stat.file_qid.type & LIB9P_QT_DIR) || !(stat.file_mode & LIB9P_DM_DIR)) { + lib9p_error(&ctx->ctx.basectx, + LINUX_ENOTDIR, "not a directory"); + break; + } + + memberp = dirp->vtable->dopen(&ctx->ctx, dirp, req->wname[resp->nwqid].utf8); + assert((memberp == NULL) == lib9p_ctx_has_error(&ctx->ctx.basectx)); + if (lib9p_ctx_has_error(&ctx->ctx.basectx)) + break; + } + + struct lib9p_stat stat = memberp->vtable->stat(&ctx->ctx, memberp); + if (lib9p_ctx_has_error(&ctx->ctx.basectx)) + break; + resp->wqid[resp->nwqid] = stat.file_qid; + + dirp->vtable->free(&ctx->ctx, dirp); + dirp = memberp; + } + if (resp->nwqid == req->nwname) { + if (req->newfid == req->fid) + *dirpp = dirp; + else + if (!fidmap_store(&ctx->parent_sess->fids, req->newfid, dirp)) { + lib9p_error(&ctx->ctx.basectx, + LINUX_EMFILE, "too many open files"); + dirp->vtable->free(&ctx->ctx, dirp); + } + } else if (resp->nwqid > 0) { + ctx->ctx.basectx.err_num = 0; + ctx->ctx.basectx.err_msg[0] = '\0'; + } } static void handle_Topen(struct _lib9p_srv_req *ctx, @@ -620,8 +682,7 @@ static void handle_Tclunk(struct _lib9p_srv_req *ctx, return; } - if ((*filepp)->vtable->free) - (*filepp)->vtable->free(&ctx->ctx, *filepp); + (*filepp)->vtable->free(&ctx->ctx, *filepp); fidmap_del(&ctx->parent_sess->fids, req->fid); } @@ -643,8 +704,14 @@ static void handle_Tstat(struct _lib9p_srv_req *ctx, assert(req); assert(resp); - lib9p_error(&ctx->ctx.basectx, - LINUX_EOPNOTSUPP, "stat not yet implemented"); + struct lib9p_srv_file **filepp = fidmap_load(&ctx->parent_sess->fids, req->fid); + if (!filepp) { + lib9p_errorf(&ctx->ctx.basectx, + LINUX_EBADF, "bad file number %"PRIu32, req->fid); + return; + } + + resp->stat = (*filepp)->vtable->stat(&ctx->ctx, *filepp); } static void handle_Twstat(struct _lib9p_srv_req *ctx, |