summaryrefslogtreecommitdiff
path: root/liblogfs/srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'liblogfs/srv.c')
-rw-r--r--liblogfs/srv.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/liblogfs/srv.c b/liblogfs/srv.c
new file mode 100644
index 00000000..efb590d3
--- /dev/null
+++ b/liblogfs/srv.c
@@ -0,0 +1,308 @@
+#include "lib9.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+static char *unimp = "unimplemented";
+char *logfsbadfid = "invalid fid";
+
+char *
+logfsstrdup(char *p)
+{
+ int l;
+ char *q;
+ if(p == nil)
+ return nil;
+ l = strlen(p);
+ q = logfsrealloc(nil, l + 1);
+ if(q == nil)
+ return nil;
+ return strcpy(q, p);
+}
+
+static
+mkdirentry(LogfsServer *server, Entry *e, int inuse, ulong path, Entry *parent, char *name, char *uid, char *gid,
+ ulong mtime, char *muid, ulong perm)
+{
+//print("mkdirentry 0x%.8lux\n", e);
+ e->inuse = inuse;
+ e->qid.path = path;
+ e->qid.vers = 0;
+ e->qid.type = QTDIR;
+ e->parent = parent;
+ e->name = name;
+ e->uid = logfsisustadd(server->is, uid);
+ e->gid = logfsisustadd(server->is, gid);
+ e->mtime = mtime;
+ e->muid = logfsisustadd(server->is, muid);
+ e->perm = perm | DMDIR;
+ e->next = nil;
+ return e->uid != nil && e->muid != nil && e->name != nil;
+}
+
+void
+logfsentryfree(Entry *e)
+{
+ logfsfreemem(e->name);
+ if((e->qid.type & QTDIR) == 0)
+ logfsextentlistfree(&e->u.file.extent);
+ logfsfreemem(e);
+}
+
+char *
+logfsentrynew(LogfsServer *server, int inuse, u32int path, Entry *parent, char *name, char *uid, char *gid,
+u32int mtime, char *muid, u32int perm, ulong cvers, ulong length, Entry **ep)
+{
+ Entry *e;
+ char *errmsg;
+ e = logfsrealloc(nil, sizeof(*e));
+ if(e == nil)
+ return Enomem;
+ e->inuse = inuse;
+ e->qid.path = path;
+ e->qid.vers = 0;
+ e->qid.type = perm >> 24;
+ e->parent = parent;
+ e->name = logfsstrdup(name);
+ e->uid = logfsisustadd(server->is, uid);
+ e->gid = logfsisustadd(server->is, gid);
+ e->muid = logfsisustadd(server->is, muid);
+ if(e->uid == nil || e->gid == nil || e->muid == nil || e->name == nil) {
+ logfsentryfree(e);
+ return Enomem;
+ }
+ e->mtime = mtime;
+ if(perm & DMDIR)
+ e->perm = perm & (~0777 | (parent->perm & 0777));
+ else {
+ e->perm = perm & (~0666 | (parent->perm & 0666));
+ e->u.file.cvers = cvers;
+ e->u.file.length = length;
+ errmsg = logfsextentlistnew(&e->u.file.extent);
+ if(errmsg) {
+ logfsentryfree(e);
+ return errmsg;
+ }
+ }
+//print("e 0x%.8lux perm 0%.uo\n", e, e->perm);
+ *ep = e;
+ return nil;
+
+}
+
+void
+logfsentryclunk(Entry *e)
+{
+ e->inuse--;
+ if(e->inuse <= 0)
+ logfsentryfree(e);
+}
+
+char *
+logfsservernew(LogfsBoot *lb, LogfsLowLevel *ll, LogfsIdentityStore *is, ulong openflags, int trace, LogfsServer **srvp)
+{
+ LogfsServer *srv;
+ char *errmsg;
+ Path *p;
+
+ if(trace > 1)
+ print("logfsservernew()\n");
+ if(ll->l2pagesperblock > 5)
+ return "more than 32 pages per block";
+ if((1 << (ll->pathbits - L2LogSweeps - L2BlockCopies)) < ll->blocks)
+ return "too many blocks";
+ srv = logfsrealloc(nil, sizeof(*srv));
+ if(srv == nil) {
+ memerror:
+ errmsg = Enomem;
+ err:
+ logfsserverfree(&srv);
+ return errmsg;
+ }
+ errmsg = logfsfidmapnew(&srv->fidmap);
+ if(errmsg)
+ goto memerror;
+ errmsg = logfspathmapnew(&srv->pathmap);
+ if(errmsg)
+ goto memerror;
+ srv->is = is;
+ srv->ll = ll;
+ srv->trace = trace;
+ srv->lb = lb;
+ srv->openflags = openflags;
+ if(!mkdirentry(srv, &srv->root, 1, 0, &srv->root, "", "inferno", "sys", logfsnow(), "inferno", 0777))
+ goto memerror;
+ errmsg = logfspathmapnewentry(srv->pathmap, 0, &srv->root, &p);
+ /* p is guaranteed to be non null */
+ if(errmsg)
+ goto memerror;
+ errmsg = logfslogsegmentnew(srv, 0, &srv->activelog);
+ if(errmsg)
+ goto memerror;
+ srv->ndatablocks = 0;
+ srv->datablock = logfsrealloc(nil, sizeof(DataBlock) * ll->blocks);
+ if(srv->datablock == nil)
+ goto memerror;
+ errmsg = logfsscan(srv);
+ if(errmsg)
+ goto err;
+ errmsg = logfsreplay(srv, srv->sweptlog, 0);
+ if(errmsg)
+ goto err;
+ errmsg = logfsreplay(srv, srv->activelog, srv->sweptlog != nil);
+ if(errmsg)
+ goto err;
+ logfsreplayfinddata(srv);
+ *srvp = srv;
+ return nil;
+}
+
+static void
+freeentrylist(Entry *e)
+{
+ Entry *next;
+ while(e) {
+ next = e->next;
+ if(e->qid.type & QTDIR)
+ freeentrylist(e->u.dir.list);
+ logfsentryfree(e);
+ e = next;
+ }
+}
+
+void
+logfsserverfree(LogfsServer **serverp)
+{
+ LogfsServer *server = *serverp;
+ if(server) {
+ logfsfidmapfree(&server->fidmap);
+ logfslogsegmentfree(&server->activelog);
+ logfslogsegmentfree(&server->sweptlog);
+ logfspathmapfree(&server->pathmap);
+ logfsfreemem(server->datablock);
+ logfsfreemem(server);
+ freeentrylist(server->root.u.dir.list);
+ *serverp = nil;
+ }
+}
+
+char *
+logfsserverattach(LogfsServer *server, u32int fid, char *uname, Qid *qid)
+{
+ char *errmsg;
+ Fid *f;
+ if(server->trace > 1)
+ print("logfsserverattach(%ud, %s)\n", fid, uname);
+ errmsg = logfsfidmapnewentry(server->fidmap, fid, &f);
+ if(errmsg)
+ return errmsg;
+ f->uname = logfsisustadd(server->is, uname);
+ if(f->uname == nil) {
+ logfsfidmapclunk(server->fidmap, fid);
+ return Enomem;
+ }
+ f->entry = &server->root;
+ f->entry->inuse++;
+ *qid = f->entry->qid;
+ return nil;
+}
+
+static void
+id2name(LogfsIdentityStore *is, char *id, char **namep, int *badp, int *lenp)
+{
+ char *name;
+ if(id == logfsisgroupnonename)
+ name = id;
+ else {
+ name = logfsisfindnamefromid(is, id);
+ if(name == nil) {
+ *badp = 2;
+ name = id;
+ }
+ }
+ *lenp = strlen(name);
+ *namep = name;
+}
+
+u32int
+logfsflattenentry(LogfsIdentityStore *is, uchar *buf, u32int limit, Entry *e)
+{
+ int unamelen, gnamelen, munamelen, namelen;
+ uint len;
+ uchar *p;
+ int unamebad = 0, gnamebad = 0, munamebad = 0;
+ char *uname, *gname, *muname;
+
+ id2name(is, e->uid, &uname, &unamebad, &unamelen);
+ id2name(is, e->gid, &gname, &gnamebad, &gnamelen);
+ id2name(is, e->muid, &muname, &munamebad, &munamelen);
+ namelen = strlen(e->name);
+ len = 49 + unamelen + unamebad + gnamelen + gnamebad + munamelen + munamebad + namelen;
+ if(buf == nil)
+ return len;
+ if(len > limit)
+ return 0;
+ p = buf;
+ /* size */ PBIT16(p, len - BIT16SZ); p += BIT16SZ;
+ /* type */ p += BIT16SZ;
+ /* dev */ p += BIT32SZ;
+ /* qid.type */ *p++ = e->qid.type;
+ /* qid.vers */ PBIT32(p, e->qid.vers); p += BIT32SZ;
+ /* qid.path */ PBIT64(p, e->qid.path); p+= 8;
+ /* mode */ PBIT32(p, e->perm); p+= BIT32SZ;
+ /* atime */ PBIT32(p, e->mtime); p+= BIT32SZ;
+ /* mtime */ PBIT32(p, e->mtime); p+= BIT32SZ;
+ /* length */ if(e->qid.type & QTDIR) {
+ PBIT64(p, 0);
+ p += 8;
+ }
+ else {
+ PBIT32(p, e->u.file.length); p += BIT32SZ;
+ PBIT32(p, 0); p += BIT32SZ;
+ }
+ /* name */ PBIT16(p, namelen); p += BIT16SZ; memcpy(p, e->name, namelen); p+= namelen;
+ /* uid */ PBIT16(p, unamelen + unamebad); p += BIT16SZ;
+ if(unamebad)
+ *p++ = '(';
+ memcpy(p, uname, unamelen + unamebad); p+= unamelen;
+ if(unamebad)
+ *p++ = ')';
+ /* gid */ PBIT16(p, gnamelen + gnamebad); p += BIT16SZ;
+ if(gnamebad)
+ *p++ = '(';
+ memcpy(p, gname, gnamelen); p+= gnamelen;
+ if(gnamebad)
+ *p++ = ')';
+ /* muid */ PBIT16(p, munamelen + munamebad); p += BIT16SZ;
+ if(munamebad)
+ *p++ = '(';
+ memcpy(p, muname, munamelen); p+= munamelen;
+ if(munamebad)
+ *p = ')';
+//print("len %ud p - buf %ld\n", len, p - buf);
+ return len;
+}
+
+char *
+logfsserverstat(LogfsServer *server, u32int fid, uchar *buf, u32int bufsize, ushort *nstat)
+{
+ Fid *f;
+ if(server->trace > 1)
+ print("logfsserverstat(%ud)\n", fid);
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsbadfid;
+ if(f->entry->deadandgone)
+ return Eio;
+ *nstat = logfsflattenentry(server->is, buf, bufsize, f->entry);
+ if(*nstat == 0)
+ return Emsgsize;
+ return nil;
+}
+
+
+void
+logfsservertrace(LogfsServer *server, int level)
+{
+ server->trace = level;
+}