summaryrefslogtreecommitdiff
path: root/lib9p
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p')
-rw-r--r--lib9p/include/lib9p/srv.h10
-rw-r--r--lib9p/srv.c83
2 files changed, 81 insertions, 12 deletions
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,