#include "logfsos.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);} staticmkdirentry(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;} voidlogfsentryfree(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; } voidlogfsentryclunk(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 voidfreeentrylist(Entry *e){ Entry *next; while(e) { next = e->next; if(e->qid.type & QTDIR) freeentrylist(e->u.dir.list); logfsentryfree(e); e = next; }} voidlogfsserverfree(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 voidid2name(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;} u32intlogfsflattenentry(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; memmove(p, e->name, namelen); p+= namelen; /* uid */ PBIT16(p, unamelen + unamebad); p += BIT16SZ; if(unamebad) *p++ = '('; memmove(p, uname, unamelen + unamebad); p+= unamelen; if(unamebad) *p++ = ')'; /* gid */ PBIT16(p, gnamelen + gnamebad); p += BIT16SZ; if(gnamebad) *p++ = '('; memmove(p, gname, gnamelen); p+= gnamelen; if(gnamebad) *p++ = ')'; /* muid */ PBIT16(p, munamelen + munamebad); p += BIT16SZ; if(munamebad) *p++ = '('; memmove(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 Eshortstat; return nil;} voidlogfsservertrace(LogfsServer *server, int level){ server->trace = level;}
#include "logfsos.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; memmove(p, e->name, namelen); p+= namelen;
/* uid */ PBIT16(p, unamelen + unamebad); p += BIT16SZ;
if(unamebad)
*p++ = '(';
memmove(p, uname, unamelen + unamebad); p+= unamelen;
if(unamebad)
*p++ = ')';
/* gid */ PBIT16(p, gnamelen + gnamebad); p += BIT16SZ;
if(gnamebad)
*p++ = '(';
memmove(p, gname, gnamelen); p+= gnamelen;
if(gnamebad)
*p++ = ')';
/* muid */ PBIT16(p, munamelen + munamebad); p += BIT16SZ;
if(munamebad)
*p++ = '(';
memmove(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 Eshortstat;
return nil;
}
void
logfsservertrace(LogfsServer *server, int level)
{
server->trace = level;
}