summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/srv9p/static.c33
-rw-r--r--lib9p/include/lib9p/srv.h10
-rw-r--r--lib9p/srv.c83
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,