ref: 94443daf8e248e65afc8d3f17f26efea22748b51
dir: /liblogfs/srv.c/
#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;
}