diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-04-18 06:35:33 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-04-18 06:35:33 +0000 |
commit | ad5522be0fbfcad7b47bb9baca9a44dadb4b6461 (patch) | |
tree | 4e5622e0b5d1d0037406ac345d2a91e2c11e1bfc | |
parent | a455c61024cab80bfc50c898d8686068cd8ea06a (diff) | |
download | plan9front-ad5522be0fbfcad7b47bb9baca9a44dadb4b6461.tar.xz |
remove fossil
57 files changed, 0 insertions, 21120 deletions
diff --git a/sys/src/cmd/fossil/9.h b/sys/src/cmd/fossil/9.h deleted file mode 100644 index b7bdec264..000000000 --- a/sys/src/cmd/fossil/9.h +++ /dev/null @@ -1,258 +0,0 @@ -#include <auth.h> -#include <fcall.h> - -enum { - NFidHash = 503, -}; - -typedef struct Con Con; -typedef struct DirBuf DirBuf; -typedef struct Excl Excl; -typedef struct Fid Fid; -typedef struct Fsys Fsys; -typedef struct Msg Msg; - -#pragma incomplete DirBuf -#pragma incomplete Excl -#pragma incomplete Fsys - -struct Msg { - uchar* data; - u32int msize; /* actual size of data */ - Fcall t; - Fcall r; - Con* con; - - Msg* anext; /* allocation free list */ - - Msg* mnext; /* all active messsages on this Con */ - Msg* mprev; - - int state; /* */ - - Msg* flush; /* flushes waiting for this Msg */ - - Msg* rwnext; /* read/write queue */ - int nowq; /* do not place on write queue */ -}; - -enum { - MsgN = 0, - MsgR = 1, - Msg9 = 2, - MsgW = 3, - MsgF = 4, -}; - -enum { - ConNoneAllow = 1<<0, - ConNoAuthCheck = 1<<1, - ConNoPermCheck = 1<<2, - ConWstatAllow = 1<<3, - ConIPCheck = 1<<4, -}; -struct Con { - char* name; - uchar* data; /* max, not negotiated */ - int isconsole; /* immutable */ - int flags; /* immutable */ - char remote[128]; /* immutable */ - VtLock* lock; - int state; - int fd; - Msg* version; - u32int msize; /* negotiated with Tversion */ - VtRendez* rendez; - - Con* anext; /* alloc */ - Con* cnext; /* in use */ - Con* cprev; - - VtLock* alock; - int aok; /* authentication done */ - - VtLock* mlock; - Msg* mhead; /* all Msgs on this connection */ - Msg* mtail; - VtRendez* mrendez; - - VtLock* wlock; - Msg* whead; /* write queue */ - Msg* wtail; - VtRendez* wrendez; - - VtLock* fidlock; /* */ - Fid* fidhash[NFidHash]; - Fid* fhead; - Fid* ftail; - int nfid; -}; - -enum { - ConDead = 0, - ConNew = 1, - ConDown = 2, - ConInit = 3, - ConUp = 4, - ConMoribund = 5, -}; - -struct Fid { - VtLock* lock; - Con* con; - u32int fidno; - int ref; /* inc/dec under Con.fidlock */ - int flags; - - int open; - Fsys* fsys; - File* file; - Qid qid; - char* uid; - char* uname; - DirBuf* db; - Excl* excl; - - VtLock* alock; /* Tauth/Tattach */ - AuthRpc* rpc; - char* cuname; - - Fid* sort; /* sorted by uname in cmdWho */ - Fid* hash; /* lookup by fidno */ - Fid* next; /* clunk session with Tversion */ - Fid* prev; -}; - -enum { /* Fid.flags and fidGet(..., flags) */ - FidFCreate = 0x01, - FidFWlock = 0x02, -}; - -enum { /* Fid.open */ - FidOCreate = 0x01, - FidORead = 0x02, - FidOWrite = 0x04, - FidORclose = 0x08, -}; - -/* - * 9p.c - */ -extern int (*rFcall[Tmax])(Msg*); -extern int validFileName(char*); - -/* - * 9auth.c - */ -extern int authCheck(Fcall*, Fid*, Fsys*); -extern int authRead(Fid*, void*, int); -extern int authWrite(Fid*, void*, int); - -/* - * 9dir.c - */ -extern void dirBufFree(DirBuf*); -extern int dirDe2M(DirEntry*, uchar*, int); -extern int dirRead(Fid*, uchar*, int, vlong); - -/* - * 9excl.c - */ -extern int exclAlloc(Fid*); -extern void exclFree(Fid*); -extern void exclInit(void); -extern int exclUpdate(Fid*); - -/* - * 9fid.c - */ -extern void fidClunk(Fid*); -extern void fidClunkAll(Con*); -extern Fid* fidGet(Con*, u32int, int); -extern void fidInit(void); -extern void fidPut(Fid*); - -/* - * 9fsys.c - */ -extern void fsysFsRlock(Fsys*); -extern void fsysFsRUnlock(Fsys*); -extern Fs* fsysGetFs(Fsys*); -extern Fsys* fsysGet(char*); -extern char* fsysGetName(Fsys*); -extern File* fsysGetRoot(Fsys*, char*); -extern Fsys* fsysIncRef(Fsys*); -extern int fsysInit(void); -extern int fsysNoAuthCheck(Fsys*); -extern int fsysNoPermCheck(Fsys*); -extern void fsysPut(Fsys*); -extern int fsysWstatAllow(Fsys*); - -/* - * 9lstn.c - */ -extern int lstnInit(void); - -/* - * 9proc.c - */ -extern Con* conAlloc(int, char*, int); -extern void conInit(void); -extern void msgFlush(Msg*); -extern void msgInit(void); - -/* - * 9srv.c - */ -extern int srvInit(void); - -/* - * 9user.c - */ -extern int groupLeader(char*, char*); -extern int groupMember(char*, char*); -extern int groupWriteMember(char*); -extern char* unameByUid(char*); -extern char* uidByUname(char*); -extern int usersInit(void); -extern int usersFileRead(char*); -extern int validUserName(char*); - -extern char* uidadm; -extern char* unamenone; -extern char* uidnoworld; - -/* - * Ccli.c - */ -extern int cliAddCmd(char*, int (*)(int, char*[])); -extern int cliError(char*, ...); -extern int cliInit(void); -extern int cliExec(char*); -#pragma varargck argpos cliError 1 - -/* - * Ccmd.c - */ -extern int cmdInit(void); - -/* - * Ccons.c - */ -extern int consPrompt(char*); -extern int consInit(void); -extern int consOpen(int, int, int); -extern int consTTY(void); -extern int consWrite(char*, int); - -/* - * Clog.c - */ -extern int consPrint(char*, ...); -extern int consVPrint(char*, va_list); -#pragma varargck argpos consPrint 1 - -/* - * fossil.c - */ -extern int Dflag; diff --git a/sys/src/cmd/fossil/9auth.c b/sys/src/cmd/fossil/9auth.c deleted file mode 100644 index 72b1f016e..000000000 --- a/sys/src/cmd/fossil/9auth.c +++ /dev/null @@ -1,175 +0,0 @@ -#include "stdinc.h" -#include "9.h" - -int -authRead(Fid* afid, void* data, int count) -{ - AuthInfo *ai; - AuthRpc *rpc; - - if((rpc = afid->rpc) == nil){ - vtSetError("not an auth fid"); - return -1; - } - - switch(auth_rpc(rpc, "read", nil, 0)){ - default: - vtSetError("fossil authRead: auth protocol not finished"); - return -1; - case ARdone: - if((ai = auth_getinfo(rpc)) == nil){ - vtSetError("%r"); - break; - } - if(ai->cuid == nil || *ai->cuid == '\0'){ - vtSetError("auth with no cuid"); - auth_freeAI(ai); - break; - } - assert(afid->cuname == nil); - afid->cuname = vtStrDup(ai->cuid); - auth_freeAI(ai); - if(Dflag) - fprint(2, "authRead cuname %s\n", afid->cuname); - assert(afid->uid == nil); - if((afid->uid = uidByUname(afid->cuname)) == nil){ - vtSetError("unknown user %#q", afid->cuname); - break; - } - return 0; - case ARok: - if(count < rpc->narg){ - vtSetError("not enough data in auth read"); - break; - } - memmove(data, rpc->arg, rpc->narg); - return rpc->narg; - case ARphase: - vtSetError("%r"); - break; - } - return -1; -} - -int -authWrite(Fid* afid, void* data, int count) -{ - assert(afid->rpc != nil); - if(auth_rpc(afid->rpc, "write", data, count) != ARok) - return -1; - return count; -} - -int -authCheck(Fcall* t, Fid* fid, Fsys* fsys) -{ - Con *con; - Fid *afid; - uchar buf[1]; - - /* - * Can't lookup with FidWlock here as there may be - * protocol to do. Use a separate lock to protect altering - * the auth information inside afid. - */ - con = fid->con; - if(t->afid == NOFID){ - /* - * If no authentication is asked for, allow - * "none" provided the connection has already - * been authenticatated. - * - * The console is allowed to attach without - * authentication. - */ - vtRLock(con->alock); - if(con->isconsole){ - /* anything goes */ - }else if((con->flags&ConNoneAllow) || con->aok){ - static int noneprint; - - if(noneprint++ < 10) - consPrint("attach %s as %s: allowing as none\n", - fsysGetName(fsys), fid->uname); - vtMemFree(fid->uname); - fid->uname = vtStrDup(unamenone); - }else{ - vtRUnlock(con->alock); - consPrint("attach %s as %s: connection not authenticated, not console\n", - fsysGetName(fsys), fid->uname); - vtSetError("cannot attach as none before authentication"); - return 0; - } - vtRUnlock(con->alock); - - if((fid->uid = uidByUname(fid->uname)) == nil){ - consPrint("attach %s as %s: unknown uname\n", - fsysGetName(fsys), fid->uname); - vtSetError("unknown user"); - return 0; - } - return 1; - } - - if((afid = fidGet(con, t->afid, 0)) == nil){ - consPrint("attach %s as %s: bad afid\n", - fsysGetName(fsys), fid->uname); - vtSetError("bad authentication fid"); - return 0; - } - - /* - * Check valid afid; - * check uname and aname match. - */ - if(!(afid->qid.type & QTAUTH)){ - consPrint("attach %s as %s: afid not an auth file\n", - fsysGetName(fsys), fid->uname); - fidPut(afid); - vtSetError("bad authentication fid"); - return 0; - } - if(strcmp(afid->uname, fid->uname) != 0 || afid->fsys != fsys){ - consPrint("attach %s as %s: afid is for %s as %s\n", - fsysGetName(fsys), fid->uname, - fsysGetName(afid->fsys), afid->uname); - fidPut(afid); - vtSetError("attach/auth mismatch"); - return 0; - } - - vtLock(afid->alock); - if(afid->cuname == nil){ - if(authRead(afid, buf, 0) != 0 || afid->cuname == nil){ - vtUnlock(afid->alock); - consPrint("attach %s as %s: %R\n", - fsysGetName(fsys), fid->uname); - fidPut(afid); - vtSetError("fossil authCheck: auth protocol not finished"); - return 0; - } - } - vtUnlock(afid->alock); - - assert(fid->uid == nil); - if((fid->uid = uidByUname(afid->cuname)) == nil){ - consPrint("attach %s as %s: unknown cuname %s\n", - fsysGetName(fsys), fid->uname, afid->cuname); - fidPut(afid); - vtSetError("unknown user"); - return 0; - } - - vtMemFree(fid->uname); - fid->uname = vtStrDup(afid->cuname); - fidPut(afid); - - /* - * Allow "none" once the connection has been authenticated. - */ - vtLock(con->alock); - con->aok = 1; - vtUnlock(con->alock); - - return 1; -} diff --git a/sys/src/cmd/fossil/9dir.c b/sys/src/cmd/fossil/9dir.c deleted file mode 100644 index 09b483bd1..000000000 --- a/sys/src/cmd/fossil/9dir.c +++ /dev/null @@ -1,132 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -/* one entry buffer for reading directories */ -struct DirBuf { - DirEntryEnum* dee; - int valid; - DirEntry de; -}; - -static DirBuf* -dirBufAlloc(File* file) -{ - DirBuf *db; - - db = vtMemAllocZ(sizeof(DirBuf)); - db->dee = deeOpen(file); - if(db->dee == nil){ - /* can happen if dir is removed from under us */ - vtMemFree(db); - return nil; - } - return db; -} - -void -dirBufFree(DirBuf* db) -{ - if(db == nil) - return; - - if(db->valid) - deCleanup(&db->de); - deeClose(db->dee); - vtMemFree(db); -} - -int -dirDe2M(DirEntry* de, uchar* p, int np) -{ - int n; - Dir dir; - - memset(&dir, 0, sizeof(Dir)); - - dir.qid.path = de->qid; - dir.qid.vers = de->mcount; - dir.mode = de->mode & 0777; - if(de->mode & ModeAppend){ - dir.qid.type |= QTAPPEND; - dir.mode |= DMAPPEND; - } - if(de->mode & ModeExclusive){ - dir.qid.type |= QTEXCL; - dir.mode |= DMEXCL; - } - if(de->mode & ModeDir){ - dir.qid.type |= QTDIR; - dir.mode |= DMDIR; - } - if(de->mode & ModeSnapshot){ - dir.qid.type |= QTMOUNT; /* just for debugging */ - dir.mode |= DMMOUNT; - } - if(de->mode & ModeTemporary){ - dir.qid.type |= QTTMP; - dir.mode |= DMTMP; - } - - dir.atime = de->atime; - dir.mtime = de->mtime; - dir.length = de->size; - - dir.name = de->elem; - if((dir.uid = unameByUid(de->uid)) == nil) - dir.uid = smprint("(%s)", de->uid); - if((dir.gid = unameByUid(de->gid)) == nil) - dir.gid = smprint("(%s)", de->gid); - if((dir.muid = unameByUid(de->mid)) == nil) - dir.muid = smprint("(%s)", de->mid); - - n = convD2M(&dir, p, np); - - vtMemFree(dir.muid); - vtMemFree(dir.gid); - vtMemFree(dir.uid); - - return n; -} - -int -dirRead(Fid* fid, uchar* p, int count, vlong offset) -{ - int n, nb; - DirBuf *db; - - /* - * special case of rewinding a directory - * otherwise ignore the offset - */ - if(offset == 0 && fid->db){ - dirBufFree(fid->db); - fid->db = nil; - } - - if(fid->db == nil){ - fid->db = dirBufAlloc(fid->file); - if(fid->db == nil) - return -1; - } - - db = fid->db; - - for(nb = 0; nb < count; nb += n){ - if(!db->valid){ - n = deeRead(db->dee, &db->de); - if(n < 0) - return -1; - if(n == 0) - break; - db->valid = 1; - } - n = dirDe2M(&db->de, p+nb, count-nb); - if(n <= BIT16SZ) - break; - db->valid = 0; - deCleanup(&db->de); - } - - return nb; -} diff --git a/sys/src/cmd/fossil/9excl.c b/sys/src/cmd/fossil/9excl.c deleted file mode 100644 index b9a0371e7..000000000 --- a/sys/src/cmd/fossil/9excl.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -static struct { - VtLock* lock; - - Excl* head; - Excl* tail; -} ebox; - -typedef struct Excl { - Fsys* fsys; - uvlong path; - ulong time; - - Excl* next; - Excl* prev; -} Excl; - -enum { - LifeTime = (5*60), -}; - -int -exclAlloc(Fid* fid) -{ - ulong t; - Excl *excl; - - assert(fid->excl == nil); - - t = time(0L); - vtLock(ebox.lock); - for(excl = ebox.head; excl != nil; excl = excl->next){ - if(excl->fsys != fid->fsys || excl->path != fid->qid.path) - continue; - /* - * Found it. - * Now, check if it's timed out. - * If not, return error, it's locked. - * If it has timed out, zap the old - * one and continue on to allocate a - * a new one. - */ - if(excl->time >= t){ - vtUnlock(ebox.lock); - vtSetError("exclusive lock"); - return 0; - } - excl->fsys = nil; - } - - /* - * Not found or timed-out. - * Alloc a new one and initialise. - */ - excl = vtMemAllocZ(sizeof(Excl)); - excl->fsys = fid->fsys; - excl->path = fid->qid.path; - excl->time = t+LifeTime; - if(ebox.tail != nil){ - excl->prev = ebox.tail; - ebox.tail->next = excl; - } - else{ - ebox.head = excl; - excl->prev = nil; - } - ebox.tail = excl; - excl->next = nil; - vtUnlock(ebox.lock); - - fid->excl = excl; - return 1; -} - -int -exclUpdate(Fid* fid) -{ - ulong t; - Excl *excl; - - excl = fid->excl; - - t = time(0L); - vtLock(ebox.lock); - if(excl->time < t || excl->fsys != fid->fsys){ - vtUnlock(ebox.lock); - vtSetError("exclusive lock broken"); - return 0; - } - excl->time = t+LifeTime; - vtUnlock(ebox.lock); - - return 1; -} - -void -exclFree(Fid* fid) -{ - Excl *excl; - - if((excl = fid->excl) == nil) - return; - fid->excl = nil; - - vtLock(ebox.lock); - if(excl->prev != nil) - excl->prev->next = excl->next; - else - ebox.head = excl->next; - if(excl->next != nil) - excl->next->prev = excl->prev; - else - ebox.tail = excl->prev; - vtUnlock(ebox.lock); - - vtMemFree(excl); -} - -void -exclInit(void) -{ - ebox.lock = vtLockAlloc(); -} diff --git a/sys/src/cmd/fossil/9fid.c b/sys/src/cmd/fossil/9fid.c deleted file mode 100644 index ea7de5abc..000000000 --- a/sys/src/cmd/fossil/9fid.c +++ /dev/null @@ -1,304 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -static struct { - VtLock* lock; - - Fid* free; - int nfree; - int inuse; -} fbox; - -static void -fidLock(Fid* fid, int flags) -{ - if(flags & FidFWlock){ - vtLock(fid->lock); - fid->flags = flags; - } - else - vtRLock(fid->lock); - - /* - * Callers of file* routines are expected to lock fsys->fs->elk - * before making any calls in order to make sure the epoch doesn't - * change underfoot. With the exception of Tversion and Tattach, - * that implies all 9P functions need to lock on entry and unlock - * on exit. Fortunately, the general case is the 9P functions do - * fidGet on entry and fidPut on exit, so this is a convenient place - * to do the locking. - * No fsys->fs->elk lock is required if the fid is being created - * (Tauth, Tattach and Twalk). FidFCreate is always accompanied by - * FidFWlock so the setting and testing of FidFCreate here and in - * fidUnlock below is always done under fid->lock. - * A side effect is that fidFree is called with the fid locked, and - * must call fidUnlock only after it has disposed of any File - * resources still held. - */ - if(!(flags & FidFCreate)) - fsysFsRlock(fid->fsys); -} - -static void -fidUnlock(Fid* fid) -{ - if(!(fid->flags & FidFCreate)) - fsysFsRUnlock(fid->fsys); - if(fid->flags & FidFWlock){ - fid->flags = 0; - vtUnlock(fid->lock); - return; - } - vtRUnlock(fid->lock); -} - -static Fid* -fidAlloc(void) -{ - Fid *fid; - - vtLock(fbox.lock); - if(fbox.nfree > 0){ - fid = fbox.free; - fbox.free = fid->hash; - fbox.nfree--; - } - else{ - fid = vtMemAllocZ(sizeof(Fid)); - fid->lock = vtLockAlloc(); - fid->alock = vtLockAlloc(); - } - fbox.inuse++; - vtUnlock(fbox.lock); - - fid->con = nil; - fid->fidno = NOFID; - fid->ref = 0; - fid->flags = 0; - fid->open = FidOCreate; - assert(fid->fsys == nil); - assert(fid->file == nil); - fid->qid = (Qid){0, 0, 0}; - assert(fid->uid == nil); - assert(fid->uname == nil); - assert(fid->db == nil); - assert(fid->excl == nil); - assert(fid->rpc == nil); - assert(fid->cuname == nil); - fid->hash = fid->next = fid->prev = nil; - - return fid; -} - -static void -fidFree(Fid* fid) -{ - if(fid->file != nil){ - fileDecRef(fid->file); - fid->file = nil; - } - if(fid->db != nil){ - dirBufFree(fid->db); - fid->db = nil; - } - fidUnlock(fid); - - if(fid->uid != nil){ - vtMemFree(fid->uid); - fid->uid = nil; - } - if(fid->uname != nil){ - vtMemFree(fid->uname); - fid->uname = nil; - } - if(fid->excl != nil) - exclFree(fid); - if(fid->rpc != nil){ - close(fid->rpc->afd); - auth_freerpc(fid->rpc); - fid->rpc = nil; - } - if(fid->fsys != nil){ - fsysPut(fid->fsys); - fid->fsys = nil; - } - if(fid->cuname != nil){ - vtMemFree(fid->cuname); - fid->cuname = nil; - } - - vtLock(fbox.lock); - fbox.inuse--; - if(fbox.nfree < 10){ - fid->hash = fbox.free; - fbox.free = fid; - fbox.nfree++; - } - else{ - vtLockFree(fid->alock); - vtLockFree(fid->lock); - vtMemFree(fid); - } - vtUnlock(fbox.lock); -} - -static void -fidUnHash(Fid* fid) -{ - Fid *fp, **hash; - - assert(fid->ref == 0); - - hash = &fid->con->fidhash[fid->fidno % NFidHash]; - for(fp = *hash; fp != nil; fp = fp->hash){ - if(fp == fid){ - *hash = fp->hash; - break; - } - hash = &fp->hash; - } - assert(fp == fid); - - if(fid->prev != nil) - fid->prev->next = fid->next; - else - fid->con->fhead = fid->next; - if(fid->next != nil) - fid->next->prev = fid->prev; - else - fid->con->ftail = fid->prev; - fid->prev = fid->next = nil; - - fid->con->nfid--; -} - -Fid* -fidGet(Con* con, u32int fidno, int flags) -{ - Fid *fid, **hash; - - if(fidno == NOFID) - return nil; - - hash = &con->fidhash[fidno % NFidHash]; - vtLock(con->fidlock); - for(fid = *hash; fid != nil; fid = fid->hash){ - if(fid->fidno != fidno) - continue; - - /* - * Already in use is an error - * when called from attach, clone or walk. - */ - if(flags & FidFCreate){ - vtUnlock(con->fidlock); - vtSetError("%s: fid 0x%ud in use", argv0, fidno); - return nil; - } - fid->ref++; - vtUnlock(con->fidlock); - - fidLock(fid, flags); - if((fid->open & FidOCreate) || fid->fidno == NOFID){ - fidPut(fid); - vtSetError("%s: fid invalid", argv0); - return nil; - } - return fid; - } - - if((flags & FidFCreate) && (fid = fidAlloc()) != nil){ - assert(flags & FidFWlock); - fid->con = con; - fid->fidno = fidno; - fid->ref = 1; - - fid->hash = *hash; - *hash = fid; - if(con->ftail != nil){ - fid->prev = con->ftail; - con->ftail->next = fid; - } - else{ - con->fhead = fid; - fid->prev = nil; - } - con->ftail = fid; - fid->next = nil; - - con->nfid++; - vtUnlock(con->fidlock); - - /* - * The FidOCreate flag is used to prevent any - * accidental access to the Fid between unlocking the - * hash and acquiring the Fid lock for return. - */ - fidLock(fid, flags); - fid->open &= ~FidOCreate; - return fid; - } - vtUnlock(con->fidlock); - - vtSetError("%s: fid not found", argv0); - return nil; -} - -void -fidPut(Fid* fid) -{ - vtLock(fid->con->fidlock); - assert(fid->ref > 0); - fid->ref--; - vtUnlock(fid->con->fidlock); - - if(fid->ref == 0 && fid->fidno == NOFID){ - fidFree(fid); - return; - } - fidUnlock(fid); -} - -void -fidClunk(Fid* fid) -{ - assert(fid->flags & FidFWlock); - - vtLock(fid->con->fidlock); - assert(fid->ref > 0); - fid->ref--; - fidUnHash(fid); - fid->fidno = NOFID; - vtUnlock(fid->con->fidlock); - - if(fid->ref > 0){ - /* not reached - fidUnHash requires ref == 0 */ - fidUnlock(fid); - return; - } - fidFree(fid); -} - -void -fidClunkAll(Con* con) -{ - Fid *fid; - u32int fidno; - - vtLock(con->fidlock); - while(con->fhead != nil){ - fidno = con->fhead->fidno; - vtUnlock(con->fidlock); - if((fid = fidGet(con, fidno, FidFWlock)) != nil) - fidClunk(fid); - vtLock(con->fidlock); - } - vtUnlock(con->fidlock); -} - -void -fidInit(void) -{ - fbox.lock = vtLockAlloc(); -} diff --git a/sys/src/cmd/fossil/9fsys.c b/sys/src/cmd/fossil/9fsys.c deleted file mode 100644 index fdc3affbc..000000000 --- a/sys/src/cmd/fossil/9fsys.c +++ /dev/null @@ -1,1889 +0,0 @@ -#include "stdinc.h" -#include <bio.h> -#include "dat.h" -#include "fns.h" -#include "9.h" - -typedef struct Fsys Fsys; - -struct Fsys { - VtLock* lock; - - char* name; /* copy here & Fs to ease error reporting */ - char* dev; - char* venti; - - Fs* fs; - VtSession* session; - int ref; - - int noauth; - int noperm; - int wstatallow; - - Fsys* next; -}; - -int mempcnt; /* from fossil.c */ - -int fsGetBlockSize(Fs *fs); - -static struct { - VtLock* lock; - Fsys* head; - Fsys* tail; - - char* curfsys; -} sbox; - -static char *_argv0; -#define argv0 _argv0 - -static char FsysAll[] = "all"; - -static char EFsysBusy[] = "fsys: '%s' busy"; -static char EFsysExists[] = "fsys: '%s' already exists"; -static char EFsysNoCurrent[] = "fsys: no current fsys"; -static char EFsysNotFound[] = "fsys: '%s' not found"; -static char EFsysNotOpen[] = "fsys: '%s' not open"; - -static char * -ventihost(char *host) -{ - if(host != nil) - return strdup(host); - host = getenv("venti"); - if(host == nil) - host = strdup("$venti"); - return host; -} - -static void -prventihost(char *host) -{ - char *vh; - - vh = ventihost(host); - fprint(2, "%s: dialing venti at %s\n", - argv0, netmkaddr(vh, 0, "venti")); - free(vh); -} - -static VtSession * -myDial(char *host, int canfail) -{ - prventihost(host); - return vtDial(host, canfail); -} - -static int -myRedial(VtSession *z, char *host) -{ - prventihost(host); - return vtRedial(z, host); -} - -static Fsys* -_fsysGet(char* name) -{ - Fsys *fsys; - - if(name == nil || name[0] == '\0') - name = "main"; - - vtRLock(sbox.lock); - for(fsys = sbox.head; fsys != nil; fsys = fsys->next){ - if(strcmp(name, fsys->name) == 0){ - fsys->ref++; - break; - } - } - vtRUnlock(sbox.lock); - if(fsys == nil) - vtSetError(EFsysNotFound, name); - return fsys; -} - -static int -cmdPrintConfig(int argc, char* argv[]) -{ - Fsys *fsys; - char *usage = "usage: printconfig"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - - if(argc) - return cliError(usage); - - vtRLock(sbox.lock); - for(fsys = sbox.head; fsys != nil; fsys = fsys->next){ - consPrint("\tfsys %s config %s\n", fsys->name, fsys->dev); - if(fsys->venti && fsys->venti[0]) - consPrint("\tfsys %s venti %q\n", fsys->name, - fsys->venti); - } - vtRUnlock(sbox.lock); - return 1; -} - -Fsys* -fsysGet(char* name) -{ - Fsys *fsys; - - if((fsys = _fsysGet(name)) == nil) - return nil; - - vtLock(fsys->lock); - if(fsys->fs == nil){ - vtSetError(EFsysNotOpen, fsys->name); - vtUnlock(fsys->lock); - fsysPut(fsys); - return nil; - } - vtUnlock(fsys->lock); - - return fsys; -} - -char* -fsysGetName(Fsys* fsys) -{ - return fsys->name; -} - -Fsys* -fsysIncRef(Fsys* fsys) -{ - vtLock(sbox.lock); - fsys->ref++; - vtUnlock(sbox.lock); - - return fsys; -} - -void -fsysPut(Fsys* fsys) -{ - vtLock(sbox.lock); - assert(fsys->ref > 0); - fsys->ref--; - vtUnlock(sbox.lock); -} - -Fs* -fsysGetFs(Fsys* fsys) -{ - assert(fsys != nil && fsys->fs != nil); - - return fsys->fs; -} - -void -fsysFsRlock(Fsys* fsys) -{ - vtRLock(fsys->fs->elk); -} - -void -fsysFsRUnlock(Fsys* fsys) -{ - vtRUnlock(fsys->fs->elk); -} - -int -fsysNoAuthCheck(Fsys* fsys) -{ - return fsys->noauth; -} - -int -fsysNoPermCheck(Fsys* fsys) -{ - return fsys->noperm; -} - -int -fsysWstatAllow(Fsys* fsys) -{ - return fsys->wstatallow; -} - -static char modechars[] = "YUGalLdHSATs"; -static ulong modebits[] = { - ModeSticky, - ModeSetUid, - ModeSetGid, - ModeAppend, - ModeExclusive, - ModeLink, - ModeDir, - ModeHidden, - ModeSystem, - ModeArchive, - ModeTemporary, - ModeSnapshot, - 0 -}; - -char* -fsysModeString(ulong mode, char *buf) -{ - int i; - char *p; - - p = buf; - for(i=0; modebits[i]; i++) - if(mode & modebits[i]) - *p++ = modechars[i]; - sprint(p, "%luo", mode&0777); - return buf; -} - -int -fsysParseMode(char* s, ulong* mode) -{ - ulong x, y; - char *p; - - x = 0; - for(; *s < '0' || *s > '9'; s++){ - if(*s == 0) - return 0; - p = strchr(modechars, *s); - if(p == nil) - return 0; - x |= modebits[p-modechars]; - } - y = strtoul(s, &p, 8); - if(*p != '\0' || y > 0777) - return 0; - *mode = x|y; - return 1; -} - -File* -fsysGetRoot(Fsys* fsys, char* name) -{ - File *root, *sub; - - assert(fsys != nil && fsys->fs != nil); - - root = fsGetRoot(fsys->fs); - if(name == nil || strcmp(name, "") == 0) - return root; - - sub = fileWalk(root, name); - fileDecRef(root); - - return sub; -} - -static Fsys* -fsysAlloc(char* name, char* dev) -{ - Fsys *fsys; - - vtLock(sbox.lock); - for(fsys = sbox.head; fsys != nil; fsys = fsys->next){ - if(strcmp(fsys->name, name) != 0) - continue; - vtSetError(EFsysExists, name); - vtUnlock(sbox.lock); - return nil; - } - - fsys = vtMemAllocZ(sizeof(Fsys)); - fsys->lock = vtLockAlloc(); - fsys->name = vtStrDup(name); - fsys->dev = vtStrDup(dev); - - fsys->ref = 1; - - if(sbox.tail != nil) - sbox.tail->next = fsys; - else - sbox.head = fsys; - sbox.tail = fsys; - vtUnlock(sbox.lock); - - return fsys; -} - -static int -fsysClose(Fsys* fsys, int argc, char* argv[]) -{ - char *usage = "usage: [fsys name] close"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc) - return cliError(usage); - - return cliError("close isn't working yet; halt %s and then kill fossil", - fsys->name); - - /* - * Oooh. This could be hard. What if fsys->ref != 1? - * Also, fsClose() either does the job or panics, can we - * gracefully detect it's still busy? - * - * More thought and care needed here. - fsClose(fsys->fs); - fsys->fs = nil; - vtClose(fsys->session); - fsys->session = nil; - - if(sbox.curfsys != nil && strcmp(fsys->name, sbox.curfsys) == 0){ - sbox.curfsys = nil; - consPrompt(nil); - } - - return 1; - */ -} - -static int -fsysVac(Fsys* fsys, int argc, char* argv[]) -{ - uchar score[VtScoreSize]; - char *usage = "usage: [fsys name] vac path"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc != 1) - return cliError(usage); - - if(!fsVac(fsys->fs, argv[0], score)) - return 0; - - consPrint("vac:%V\n", score); - return 1; -} - -static int -fsysSnap(Fsys* fsys, int argc, char* argv[]) -{ - int doarchive; - char *usage = "usage: [fsys name] snap [-a] [-s /active] [-d /archive/yyyy/mmmm]"; - char *src, *dst; - - src = nil; - dst = nil; - doarchive = 0; - ARGBEGIN{ - default: - return cliError(usage); - case 'a': - doarchive = 1; - break; - case 'd': - if((dst = ARGF()) == nil) - return cliError(usage); - break; - case 's': - if((src = ARGF()) == nil) - return cliError(usage); - break; - }ARGEND - if(argc) - return cliError(usage); - - if(!fsSnapshot(fsys->fs, src, dst, doarchive)) - return 0; - - return 1; -} - -static int -fsysSnapClean(Fsys *fsys, int argc, char* argv[]) -{ - u32int arch, snap, life; - char *usage = "usage: [fsys name] snapclean [maxminutes]\n"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - - if(argc > 1) - return cliError(usage); - if(argc == 1) - life = atoi(argv[0]); - else - snapGetTimes(fsys->fs->snap, &arch, &snap, &life); - - fsSnapshotCleanup(fsys->fs, life); - return 1; -} - -static int -fsysSnapTime(Fsys* fsys, int argc, char* argv[]) -{ - char buf[128], *x; - int hh, mm, changed; - u32int arch, snap, life; - char *usage = "usage: [fsys name] snaptime [-a hhmm] [-s snapminutes] [-t maxminutes]"; - - changed = 0; - snapGetTimes(fsys->fs->snap, &arch, &snap, &life); - ARGBEGIN{ - case 'a': - changed = 1; - x = ARGF(); - if(x == nil) - return cliError(usage); - if(strcmp(x, "none") == 0){ - arch = ~(u32int)0; - break; - } - if(strlen(x) != 4 || strspn(x, "0123456789") != 4) - return cliError(usage); - hh = (x[0]-'0')*10 + x[1]-'0'; - mm = (x[2]-'0')*10 + x[3]-'0'; - if(hh >= 24 || mm >= 60) - return cliError(usage); - arch = hh*60+mm; - break; - case 's': - changed = 1; - x = ARGF(); - if(x == nil) - return cliError(usage); - if(strcmp(x, "none") == 0){ - snap = ~(u32int)0; - break; - } - snap = atoi(x); - break; - case 't': - changed = 1; - x = ARGF(); - if(x == nil) - return cliError(usage); - if(strcmp(x, "none") == 0){ - life = ~(u32int)0; - break; - } - life = atoi(x); - break; - default: - return cliError(usage); - }ARGEND - if(argc > 0) - return cliError(usage); - - if(changed){ - snapSetTimes(fsys->fs->snap, arch, snap, life); - return 1; - } - snapGetTimes(fsys->fs->snap, &arch, &snap, &life); - if(arch != ~(u32int)0) - sprint(buf, "-a %02d%02d", arch/60, arch%60); - else - sprint(buf, "-a none"); - if(snap != ~(u32int)0) - sprint(buf+strlen(buf), " -s %d", snap); - else - sprint(buf+strlen(buf), " -s none"); - if(life != ~(u32int)0) - sprint(buf+strlen(buf), " -t %ud", life); - else - sprint(buf+strlen(buf), " -t none"); - consPrint("\tsnaptime %s\n", buf); - return 1; -} - -static int -fsysSync(Fsys* fsys, int argc, char* argv[]) -{ - char *usage = "usage: [fsys name] sync"; - int n; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc > 0) - return cliError(usage); - - n = cacheDirty(fsys->fs->cache); - fsSync(fsys->fs); - consPrint("\t%s sync: wrote %d blocks\n", fsys->name, n); - return 1; -} - -static int -fsysHalt(Fsys *fsys, int argc, char* argv[]) -{ - char *usage = "usage: [fsys name] halt"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc > 0) - return cliError(usage); - - fsHalt(fsys->fs); - return 1; -} - -static int -fsysUnhalt(Fsys *fsys, int argc, char* argv[]) -{ - char *usage = "usage: [fsys name] unhalt"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc > 0) - return cliError(usage); - - if(!fsys->fs->halted) - return cliError("file system %s not halted", fsys->name); - - fsUnhalt(fsys->fs); - return 1; -} - -static int -fsysRemove(Fsys* fsys, int argc, char* argv[]) -{ - File *file; - char *usage = "usage: [fsys name] remove path ..."; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc == 0) - return cliError(usage); - - vtRLock(fsys->fs->elk); - while(argc > 0){ - if((file = fileOpen(fsys->fs, argv[0])) == nil) - consPrint("%s: %R\n", argv[0]); - else{ - if(!fileRemove(file, uidadm)) - consPrint("%s: %R\n", argv[0]); - fileDecRef(file); - } - argc--; - argv++; - } - vtRUnlock(fsys->fs->elk); - - return 1; -} - -static int -fsysClri(Fsys* fsys, int argc, char* argv[]) -{ - char *usage = "usage: [fsys name] clri path ..."; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc == 0) - return cliError(usage); - - vtRLock(fsys->fs->elk); - while(argc > 0){ - if(!fileClriPath(fsys->fs, argv[0], uidadm)) - consPrint("clri %s: %R\n", argv[0]); - argc--; - argv++; - } - vtRUnlock(fsys->fs->elk); - - return 1; -} - -/* - * Inspect and edit the labels for blocks on disk. - */ -static int -fsysLabel(Fsys* fsys, int argc, char* argv[]) -{ - Fs *fs; - Label l; - int n, r; - u32int addr; - Block *b, *bb; - char *usage = "usage: [fsys name] label addr [type state epoch epochClose tag]"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc != 1 && argc != 6) - return cliError(usage); - - r = 0; - vtRLock(fsys->fs->elk); - - fs = fsys->fs; - addr = strtoul(argv[0], 0, 0); - b = cacheLocal(fs->cache, PartData, addr, OReadOnly); - if(b == nil) - goto Out0; - - l = b->l; - consPrint("%slabel %#ux %ud %ud %ud %ud %#x\n", - argc==6 ? "old: " : "", addr, l.type, l.state, - l.epoch, l.epochClose, l.tag); - - if(argc == 6){ - if(strcmp(argv[1], "-") != 0) - l.type = atoi(argv[1]); - if(strcmp(argv[2], "-") != 0) - l.state = atoi(argv[2]); - if(strcmp(argv[3], "-") != 0) - l.epoch = strtoul(argv[3], 0, 0); - if(strcmp(argv[4], "-") != 0) - l.epochClose = strtoul(argv[4], 0, 0); - if(strcmp(argv[5], "-") != 0) - l.tag = strtoul(argv[5], 0, 0); - - consPrint("new: label %#ux %ud %ud %ud %ud %#x\n", - addr, l.type, l.state, l.epoch, l.epochClose, l.tag); - bb = _blockSetLabel(b, &l); - if(bb == nil) - goto Out1; - n = 0; - for(;;){ - if(blockWrite(bb)){ - while(bb->iostate != BioClean){ - assert(bb->iostate == BioWriting); - vtSleep(bb->ioready); - } - break; - } - consPrint("blockWrite: %R\n"); - if(n++ >= 5){ - consPrint("giving up\n"); - break; - } - sleep(5*1000); - } - blockPut(bb); - } - r = 1; -Out1: - blockPut(b); -Out0: - vtRUnlock(fs->elk); - - return r; -} - -/* - * Inspect and edit the blocks on disk. - */ -static int -fsysBlock(Fsys* fsys, int argc, char* argv[]) -{ - Fs *fs; - char *s; - Block *b; - uchar *buf; - u32int addr; - int c, count, i, offset; - char *usage = "usage: [fsys name] block addr offset [count [data]]"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc < 2 || argc > 4) - return cliError(usage); - - fs = fsys->fs; - addr = strtoul(argv[0], 0, 0); - offset = strtoul(argv[1], 0, 0); - if(offset < 0 || offset >= fs->blockSize){ - vtSetError("bad offset"); - return 0; - } - if(argc > 2) - count = strtoul(argv[2], 0, 0); - else - count = 100000000; - if(offset+count > fs->blockSize) - count = fs->blockSize - count; - - vtRLock(fs->elk); - - b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly); - if(b == nil){ - vtSetError("cacheLocal %#ux: %R", addr); - vtRUnlock(fs->elk); - return 0; - } - - consPrint("\t%sblock %#ux %ud %ud %.*H\n", - argc==4 ? "old: " : "", addr, offset, count, count, b->data+offset); - - if(argc == 4){ - s = argv[3]; - if(strlen(s) != 2*count){ - vtSetError("bad data count"); - goto Out; - } - buf = vtMemAllocZ(count); - for(i = 0; i < count*2; i++){ - if(s[i] >= '0' && s[i] <= '9') - c = s[i] - '0'; - else if(s[i] >= 'a' && s[i] <= 'f') - c = s[i] - 'a' + 10; - else if(s[i] >= 'A' && s[i] <= 'F') - c = s[i] - 'A' + 10; - else{ - vtSetError("bad hex"); - vtMemFree(buf); - goto Out; - } - if((i & 1) == 0) - c <<= 4; - buf[i>>1] |= c; - } - memmove(b->data+offset, buf, count); - consPrint("\tnew: block %#ux %ud %ud %.*H\n", - addr, offset, count, count, b->data+offset); - blockDirty(b); - } - -Out: - blockPut(b); - vtRUnlock(fs->elk); - - return 1; -} - -/* - * Free a disk block. - */ -static int -fsysBfree(Fsys* fsys, int argc, char* argv[]) -{ - Fs *fs; - Label l; - char *p; - Block *b; - u32int addr; - char *usage = "usage: [fsys name] bfree addr ..."; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc == 0) - return cliError(usage); - - fs = fsys->fs; - vtRLock(fs->elk); - while(argc > 0){ - addr = strtoul(argv[0], &p, 0); - if(*p != '\0'){ - consPrint("bad address - '%ud'\n", addr); - /* syntax error; let's stop */ - vtRUnlock(fs->elk); - return 0; - } - b = cacheLocal(fs->cache, PartData, addr, OReadOnly); - if(b == nil){ - consPrint("loading %#ux: %R\n", addr); - continue; - } - l = b->l; - if(l.state == BsFree) - consPrint("%#ux is already free\n", addr); - else{ - consPrint("label %#ux %ud %ud %ud %ud %#x\n", - addr, l.type, l.state, l.epoch, l.epochClose, l.tag); - l.state = BsFree; - l.type = BtMax; - l.tag = 0; - l.epoch = 0; - l.epochClose = 0; - if(!blockSetLabel(b, &l, 0)) - consPrint("freeing %#ux: %R\n", addr); - } - blockPut(b); - argc--; - argv++; - } - vtRUnlock(fs->elk); - - return 1; -} - -static int -fsysDf(Fsys *fsys, int argc, char* argv[]) -{ - char *usage = "usage: [fsys name] df"; - u32int used, tot, bsize; - Fs *fs; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc != 0) - return cliError(usage); - - fs = fsys->fs; - cacheCountUsed(fs->cache, fs->elo, &used, &tot, &bsize); - consPrint("\t%s: %,llud used + %,llud free = %,llud (%llud%% used)\n", - fsys->name, used*(vlong)bsize, (tot-used)*(vlong)bsize, - tot*(vlong)bsize, used*100LL/tot); - return 1; -} - -/* - * Zero an entry or a pointer. - */ -static int -fsysClrep(Fsys* fsys, int argc, char* argv[], int ch) -{ - Fs *fs; - Entry e; - Block *b; - u32int addr; - int i, max, offset, sz; - uchar zero[VtEntrySize]; - char *usage = "usage: [fsys name] clr%c addr offset ..."; - - ARGBEGIN{ - default: - return cliError(usage, ch); - }ARGEND - if(argc < 2) - return cliError(usage, ch); - - fs = fsys->fs; - vtRLock(fsys->fs->elk); - - addr = strtoul(argv[0], 0, 0); - b = cacheLocal(fs->cache, PartData, addr, argc==4 ? OReadWrite : OReadOnly); - if(b == nil){ - vtSetError("cacheLocal %#ux: %R", addr); - Err: - vtRUnlock(fsys->fs->elk); - return 0; - } - - switch(ch){ - default: - vtSetError("clrep"); - goto Err; - case 'e': - if(b->l.type != BtDir){ - vtSetError("wrong block type"); - goto Err; - } - sz = VtEntrySize; - memset(&e, 0, sizeof e); - entryPack(&e, zero, 0); - break; - case 'p': - if(b->l.type == BtDir || b->l.type == BtData){ - vtSetError("wrong block type"); - goto Err; - } - sz = VtScoreSize; - memmove(zero, vtZeroScore, VtScoreSize); - break; - } - max = fs->blockSize/sz; - - for(i = 1; i < argc; i++){ - offset = atoi(argv[i]); - if(offset >= max){ - consPrint("\toffset %d too large (>= %d)\n", i, max); - continue; - } - consPrint("\tblock %#ux %d %d %.*H\n", addr, offset*sz, sz, sz, b->data+offset*sz); - memmove(b->data+offset*sz, zero, sz); - } - blockDirty(b); - blockPut(b); - vtRUnlock(fsys->fs->elk); - - return 1; -} - -static int -fsysClre(Fsys* fsys, int argc, char* argv[]) -{ - return fsysClrep(fsys, argc, argv, 'e'); -} - -static int -fsysClrp(Fsys* fsys, int argc, char* argv[]) -{ - return fsysClrep(fsys, argc, argv, 'p'); -} - -static int -fsysEsearch1(File* f, char* s, u32int elo) -{ - int n, r; - DirEntry de; - DirEntryEnum *dee; - File *ff; - Entry e, ee; - char *t; - - dee = deeOpen(f); - if(dee == nil) - return 0; - - n = 0; - for(;;){ - r = deeRead(dee, &de); - if(r < 0){ - consPrint("\tdeeRead %s/%s: %R\n", s, de.elem); - break; - } - if(r == 0) - break; - if(de.mode & ModeSnapshot){ - if((ff = fileWalk(f, de.elem)) == nil) - consPrint("\tcannot walk %s/%s: %R\n", s, de.elem); - else{ - if(!fileGetSources(ff, &e, &ee)) - consPrint("\tcannot get sources for %s/%s: %R\n", s, de.elem); - else if(e.snap != 0 && e.snap < elo){ - consPrint("\t%ud\tclri %s/%s\n", e.snap, s, de.elem); - n++; - } - fileDecRef(ff); - } - } - else if(de.mode & ModeDir){ - if((ff = fileWalk(f, de.elem)) == nil) - consPrint("\tcannot walk %s/%s: %R\n", s, de.elem); - else{ - t = smprint("%s/%s", s, de.elem); - n += fsysEsearch1(ff, t, elo); - vtMemFree(t); - fileDecRef(ff); - } - } - deCleanup(&de); - if(r < 0) - break; - } - deeClose(dee); - - return n; -} - -static int -fsysEsearch(Fs* fs, char* path, u32int elo) -{ - int n; - File *f; - DirEntry de; - - f = fileOpen(fs, path); - if(f == nil) - return 0; - if(!fileGetDir(f, &de)){ - consPrint("\tfileGetDir %s failed: %R\n", path); - fileDecRef(f); - return 0; - } - if((de.mode & ModeDir) == 0){ - fileDecRef(f); - deCleanup(&de); - return 0; - } - deCleanup(&de); - n = fsysEsearch1(f, path, elo); - fileDecRef(f); - return n; -} - -static int -fsysEpoch(Fsys* fsys, int argc, char* argv[]) -{ - Fs *fs; - int force, n, remove; - u32int low, old; - char *usage = "usage: [fsys name] epoch [[-ry] low]"; - - force = 0; - remove = 0; - ARGBEGIN{ - case 'y': - force = 1; - break; - case 'r': - remove = 1; - break; - default: - return cliError(usage); - }ARGEND - if(argc > 1) - return cliError(usage); - if(argc > 0) - low = strtoul(argv[0], 0, 0); - else - low = ~(u32int)0; - - if(low == 0) - return cliError("low epoch cannot be zero"); - - fs = fsys->fs; - - vtRLock(fs->elk); - consPrint("\tlow %ud hi %ud\n", fs->elo, fs->ehi); - if(low == ~(u32int)0){ - vtRUnlock(fs->elk); - return 1; - } - n = fsysEsearch(fsys->fs, "/archive", low); - n += fsysEsearch(fsys->fs, "/snapshot", low); - consPrint("\t%d snapshot%s found with epoch < %ud\n", n, n==1 ? "" : "s", low); - vtRUnlock(fs->elk); - - /* - * There's a small race here -- a new snapshot with epoch < low might - * get introduced now that we unlocked fs->elk. Low has to - * be <= fs->ehi. Of course, in order for this to happen low has - * to be equal to the current fs->ehi _and_ a snapshot has to - * run right now. This is a small enough window that I don't care. - */ - if(n != 0 && !force){ - consPrint("\tnot setting low epoch\n"); - return 1; - } - old = fs->elo; - if(!fsEpochLow(fs, low)) - consPrint("\tfsEpochLow: %R\n"); - else{ - consPrint("\told: epoch%s %ud\n", force ? " -y" : "", old); - consPrint("\tnew: epoch%s %ud\n", force ? " -y" : "", fs->elo); - if(fs->elo < low) - consPrint("\twarning: new low epoch < old low epoch\n"); - if(force && remove) - fsSnapshotRemove(fs); - } - - return 1; -} - -static int -fsysCreate(Fsys* fsys, int argc, char* argv[]) -{ - int r; - ulong mode; - char *elem, *p, *path; - char *usage = "usage: [fsys name] create path uid gid perm"; - DirEntry de; - File *file, *parent; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc != 4) - return cliError(usage); - - if(!fsysParseMode(argv[3], &mode)) - return cliError(usage); - if(mode&ModeSnapshot) - return cliError("create - cannot create with snapshot bit set"); - - if(strcmp(argv[1], uidnoworld) == 0) - return cliError("permission denied"); - - vtRLock(fsys->fs->elk); - path = vtStrDup(argv[0]); - if((p = strrchr(path, '/')) != nil){ - *p++ = '\0'; - elem = p; - p = path; - if(*p == '\0') - p = "/"; - } - else{ - p = "/"; - elem = path; - } - - r = 0; - if((parent = fileOpen(fsys->fs, p)) == nil) - goto out; - - file = fileCreate(parent, elem, mode, argv[1]); - fileDecRef(parent); - if(file == nil){ - vtSetError("create %s/%s: %R", p, elem); - goto out; - } - - if(!fileGetDir(file, &de)){ - vtSetError("stat failed after create: %R"); - goto out1; - } - - if(strcmp(de.gid, argv[2]) != 0){ - vtMemFree(de.gid); - de.gid = vtStrDup(argv[2]); - if(!fileSetDir(file, &de, argv[1])){ - vtSetError("wstat failed after create: %R"); - goto out2; - } - } - r = 1; - -out2: - deCleanup(&de); -out1: - fileDecRef(file); -out: - vtMemFree(path); - vtRUnlock(fsys->fs->elk); - - return r; -} - -static void -fsysPrintStat(char *prefix, char *file, DirEntry *de) -{ - char buf[64]; - - if(prefix == nil) - prefix = ""; - consPrint("%sstat %q %q %q %q %s %llud\n", prefix, - file, de->elem, de->uid, de->gid, fsysModeString(de->mode, buf), de->size); -} - -static int -fsysStat(Fsys* fsys, int argc, char* argv[]) -{ - int i; - File *f; - DirEntry de; - char *usage = "usage: [fsys name] stat files..."; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - - if(argc == 0) - return cliError(usage); - - vtRLock(fsys->fs->elk); - for(i=0; i<argc; i++){ - if((f = fileOpen(fsys->fs, argv[i])) == nil){ - consPrint("%s: %R\n", argv[i]); - continue; - } - if(!fileGetDir(f, &de)){ - consPrint("%s: %R\n", argv[i]); - fileDecRef(f); - continue; - } - fsysPrintStat("\t", argv[i], &de); - deCleanup(&de); - fileDecRef(f); - } - vtRUnlock(fsys->fs->elk); - return 1; -} - -static int -fsysWstat(Fsys *fsys, int argc, char* argv[]) -{ - File *f; - char *p; - DirEntry de; - char *usage = "usage: [fsys name] wstat file elem uid gid mode length\n" - "\tuse - for any field to mean don't change"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - - if(argc != 6) - return cliError(usage); - - vtRLock(fsys->fs->elk); - if((f = fileOpen(fsys->fs, argv[0])) == nil){ - vtSetError("console wstat - walk - %R"); - vtRUnlock(fsys->fs->elk); - return 0; - } - if(!fileGetDir(f, &de)){ - vtSetError("console wstat - stat - %R"); - fileDecRef(f); - vtRUnlock(fsys->fs->elk); - return 0; - } - fsysPrintStat("\told: w", argv[0], &de); - - if(strcmp(argv[1], "-") != 0){ - if(!validFileName(argv[1])){ - vtSetError("console wstat - bad elem"); - goto error; - } - vtMemFree(de.elem); - de.elem = vtStrDup(argv[1]); - } - if(strcmp(argv[2], "-") != 0){ - if(!validUserName(argv[2])){ - vtSetError("console wstat - bad uid"); - goto error; - } - vtMemFree(de.uid); - de.uid = vtStrDup(argv[2]); - } - if(strcmp(argv[3], "-") != 0){ - if(!validUserName(argv[3])){ - vtSetError("console wstat - bad gid"); - goto error; - } - vtMemFree(de.gid); - de.gid = vtStrDup(argv[3]); - } - if(strcmp(argv[4], "-") != 0){ - if(!fsysParseMode(argv[4], &de.mode)){ - vtSetError("console wstat - bad mode"); - goto error; - } - } - if(strcmp(argv[5], "-") != 0){ - de.size = strtoull(argv[5], &p, 0); - if(argv[5][0] == '\0' || *p != '\0' || (vlong)de.size < 0){ - vtSetError("console wstat - bad length"); - goto error; - } - } - - if(!fileSetDir(f, &de, uidadm)){ - vtSetError("console wstat - %R"); - goto error; - } - deCleanup(&de); - - if(!fileGetDir(f, &de)){ - vtSetError("console wstat - stat2 - %R"); - goto error; - } - fsysPrintStat("\tnew: w", argv[0], &de); - deCleanup(&de); - fileDecRef(f); - vtRUnlock(fsys->fs->elk); - - return 1; - -error: - deCleanup(&de); /* okay to do this twice */ - fileDecRef(f); - vtRUnlock(fsys->fs->elk); - return 0; -} - -static void -fsckClri(Fsck *fsck, char *name, MetaBlock *mb, int i, Block *b) -{ - USED(name); - - if((fsck->flags&DoClri) == 0) - return; - - mbDelete(mb, i); - mbPack(mb); - blockDirty(b); -} - -static void -fsckClose(Fsck *fsck, Block *b, u32int epoch) -{ - Label l; - - if((fsck->flags&DoClose) == 0) - return; - l = b->l; - if(l.state == BsFree || (l.state&BsClosed)){ - consPrint("%#ux is already closed\n", b->addr); - return; - } - if(epoch){ - l.state |= BsClosed; - l.epochClose = epoch; - }else - l.state = BsFree; - - if(!blockSetLabel(b, &l, 0)) - consPrint("%#ux setlabel: %R\n", b->addr); -} - -static void -fsckClre(Fsck *fsck, Block *b, int offset) -{ - Entry e; - - if((fsck->flags&DoClre) == 0) - return; - if(offset<0 || offset*VtEntrySize >= fsck->bsize){ - consPrint("bad clre\n"); - return; - } - memset(&e, 0, sizeof e); - entryPack(&e, b->data, offset); - blockDirty(b); -} - -static void -fsckClrp(Fsck *fsck, Block *b, int offset) -{ - if((fsck->flags&DoClrp) == 0) - return; - if(offset<0 || offset*VtScoreSize >= fsck->bsize){ - consPrint("bad clre\n"); - return; - } - memmove(b->data+offset*VtScoreSize, vtZeroScore, VtScoreSize); - blockDirty(b); -} - -static int -fsysCheck(Fsys *fsys, int argc, char *argv[]) -{ - int i, halting; - char *usage = "usage: [fsys name] check [-v] [options]"; - Fsck fsck; - Block *b; - Super super; - - memset(&fsck, 0, sizeof fsck); - fsck.fs = fsys->fs; - fsck.clri = fsckClri; - fsck.clre = fsckClre; - fsck.clrp = fsckClrp; - fsck.close = fsckClose; - fsck.print = consPrint; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - - for(i=0; i<argc; i++){ - if(strcmp(argv[i], "pblock") == 0) - fsck.printblocks = 1; - else if(strcmp(argv[i], "pdir") == 0) - fsck.printdirs = 1; - else if(strcmp(argv[i], "pfile") == 0) - fsck.printfiles = 1; - else if(strcmp(argv[i], "bclose") == 0) - fsck.flags |= DoClose; - else if(strcmp(argv[i], "clri") == 0) - fsck.flags |= DoClri; - else if(strcmp(argv[i], "clre") == 0) - fsck.flags |= DoClre; - else if(strcmp(argv[i], "clrp") == 0) - fsck.flags |= DoClrp; - else if(strcmp(argv[i], "fix") == 0) - fsck.flags |= DoClose|DoClri|DoClre|DoClrp; - else if(strcmp(argv[i], "venti") == 0) - fsck.useventi = 1; - else if(strcmp(argv[i], "snapshot") == 0) - fsck.walksnapshots = 1; - else{ - consPrint("unknown option '%s'\n", argv[i]); - return cliError(usage); - } - } - - halting = fsys->fs->halted==0; - if(halting) - fsHalt(fsys->fs); - if(fsys->fs->arch){ - b = superGet(fsys->fs->cache, &super); - if(b == nil){ - consPrint("could not load super block\n"); - goto Out; - } - blockPut(b); - if(super.current != NilBlock){ - consPrint("cannot check fs while archiver is running; " - "wait for it to finish\n"); - goto Out; - } - } - fsCheck(&fsck); - consPrint("fsck: %d clri, %d clre, %d clrp, %d bclose\n", - fsck.nclri, fsck.nclre, fsck.nclrp, fsck.nclose); -Out: - if(halting) - fsUnhalt(fsys->fs); - return 1; -} - -static int -fsysVenti(char* name, int argc, char* argv[]) -{ - int r; - char *host; - char *usage = "usage: [fsys name] venti [address]"; - Fsys *fsys; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - - if(argc == 0) - host = nil; - else if(argc == 1) - host = argv[0]; - else - return cliError(usage); - - if((fsys = _fsysGet(name)) == nil) - return 0; - - vtLock(fsys->lock); - if(host == nil) - host = fsys->venti; - else{ - vtMemFree(fsys->venti); - if(host[0]) - fsys->venti = vtStrDup(host); - else{ - host = nil; - fsys->venti = nil; - } - } - - /* already open: do a redial */ - if(fsys->fs != nil){ - if(fsys->session == nil){ - vtSetError("file system was opened with -V"); - r = 0; - goto out; - } - r = 1; - if(!myRedial(fsys->session, host) - || !vtConnect(fsys->session, 0)) - r = 0; - goto out; - } - - /* not yet open: try to dial */ - if(fsys->session) - vtClose(fsys->session); - r = 1; - if((fsys->session = myDial(host, 0)) == nil - || !vtConnect(fsys->session, 0)) - r = 0; -out: - vtUnlock(fsys->lock); - fsysPut(fsys); - return r; -} - -static ulong -freemem(void) -{ - int nf, pgsize = 0; - uvlong size, userpgs = 0, userused = 0; - char *ln, *sl; - char *fields[2]; - Biobuf *bp; - - size = 64*1024*1024; - bp = Bopen("#c/swap", OREAD); - if (bp != nil) { - while ((ln = Brdline(bp, '\n')) != nil) { - ln[Blinelen(bp)-1] = '\0'; - nf = tokenize(ln, fields, nelem(fields)); - if (nf != 2) - continue; - if (strcmp(fields[1], "pagesize") == 0) - pgsize = atoi(fields[0]); - else if (strcmp(fields[1], "user") == 0) { - sl = strchr(fields[0], '/'); - if (sl == nil) - continue; - userpgs = atoll(sl+1); - userused = atoll(fields[0]); - } - } - Bterm(bp); - if (pgsize > 0 && userpgs > 0) - size = (userpgs - userused) * pgsize; - } - /* cap it to keep the size within 32 bits */ - if (size >= 3840UL * 1024 * 1024) - size = 3840UL * 1024 * 1024; - return size; -} - -static int -fsysOpen(char* name, int argc, char* argv[]) -{ - char *p, *host; - Fsys *fsys; - int noauth, noventi, noperm, rflag, wstatallow; - long ncache; - char *usage = "usage: fsys name open [-APVWr] [-c ncache]"; - - ncache = 1000; - noauth = noperm = wstatallow = noventi = 0; - rflag = OReadWrite; - - ARGBEGIN{ - default: - return cliError(usage); - case 'A': - noauth = 1; - break; - case 'P': - noperm = 1; - break; - case 'V': - noventi = 1; - break; - case 'W': - wstatallow = 1; - break; - case 'c': - p = ARGF(); - if(p == nil) - return cliError(usage); - ncache = strtol(argv[0], &p, 0); - if(ncache <= 0 || p == argv[0] || *p != '\0') - return cliError(usage); - break; - case 'r': - rflag = OReadOnly; - break; - }ARGEND - if(argc) - return cliError(usage); - - if((fsys = _fsysGet(name)) == nil) - return 0; - - /* automatic memory sizing? */ - if(mempcnt > 0) { - /* TODO: 8K is a hack; use the actual block size */ - ncache = (((vlong)freemem() * mempcnt) / 100) / (8*1024); - if (ncache < 100) - ncache = 100; - } - - vtLock(fsys->lock); - if(fsys->fs != nil){ - vtSetError(EFsysBusy, fsys->name); - vtUnlock(fsys->lock); - fsysPut(fsys); - return 0; - } - - if(noventi){ - if(fsys->session){ - vtClose(fsys->session); - fsys->session = nil; - } - } - else if(fsys->session == nil){ - if(fsys->venti && fsys->venti[0]) - host = fsys->venti; - else - host = nil; - fsys->session = myDial(host, 1); - if(!vtConnect(fsys->session, nil) && !noventi) - fprint(2, "warning: connecting to venti: %R\n"); - } - if((fsys->fs = fsOpen(fsys->dev, fsys->session, ncache, rflag)) == nil){ - vtSetError("fsOpen: %R"); - vtUnlock(fsys->lock); - fsysPut(fsys); - return 0; - } - fsys->fs->name = fsys->name; /* for better error messages */ - fsys->noauth = noauth; - fsys->noperm = noperm; - fsys->wstatallow = wstatallow; - vtUnlock(fsys->lock); - fsysPut(fsys); - - if(strcmp(name, "main") == 0) - usersFileRead(nil); - - return 1; -} - -static int -fsysUnconfig(char* name, int argc, char* argv[]) -{ - Fsys *fsys, **fp; - char *usage = "usage: fsys name unconfig"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc) - return cliError(usage); - - vtLock(sbox.lock); - fp = &sbox.head; - for(fsys = *fp; fsys != nil; fsys = fsys->next){ - if(strcmp(fsys->name, name) == 0) - break; - fp = &fsys->next; - } - if(fsys == nil){ - vtSetError(EFsysNotFound, name); - vtUnlock(sbox.lock); - return 0; - } - if(fsys->ref != 0 || fsys->fs != nil){ - vtSetError(EFsysBusy, fsys->name); - vtUnlock(sbox.lock); - return 0; - } - *fp = fsys->next; - vtUnlock(sbox.lock); - - if(fsys->session != nil){ - vtClose(fsys->session); - vtFree(fsys->session); - } - if(fsys->venti != nil) - vtMemFree(fsys->venti); - if(fsys->dev != nil) - vtMemFree(fsys->dev); - if(fsys->name != nil) - vtMemFree(fsys->name); - vtMemFree(fsys); - - return 1; -} - -static int -fsysConfig(char* name, int argc, char* argv[]) -{ - Fsys *fsys; - char *usage = "usage: fsys name config dev"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc != 1) - return cliError(usage); - - if((fsys = _fsysGet(argv[0])) != nil){ - vtLock(fsys->lock); - if(fsys->fs != nil){ - vtSetError(EFsysBusy, fsys->name); - vtUnlock(fsys->lock); - fsysPut(fsys); - return 0; - } - vtMemFree(fsys->dev); - fsys->dev = vtStrDup(argv[0]); - vtUnlock(fsys->lock); - } - else if((fsys = fsysAlloc(name, argv[0])) == nil) - return 0; - - fsysPut(fsys); - - return 1; -} - -static struct { - char* cmd; - int (*f)(Fsys*, int, char**); - int (*f1)(char*, int, char**); -} fsyscmd[] = { - { "close", fsysClose, }, - { "config", nil, fsysConfig, }, - { "open", nil, fsysOpen, }, - { "unconfig", nil, fsysUnconfig, }, - { "venti", nil, fsysVenti, }, - - { "bfree", fsysBfree, }, - { "block", fsysBlock, }, - { "check", fsysCheck, }, - { "clre", fsysClre, }, - { "clri", fsysClri, }, - { "clrp", fsysClrp, }, - { "create", fsysCreate, }, - { "df", fsysDf, }, - { "epoch", fsysEpoch, }, - { "halt", fsysHalt, }, - { "label", fsysLabel, }, - { "remove", fsysRemove, }, - { "snap", fsysSnap, }, - { "snaptime", fsysSnapTime, }, - { "snapclean", fsysSnapClean, }, - { "stat", fsysStat, }, - { "sync", fsysSync, }, - { "unhalt", fsysUnhalt, }, - { "wstat", fsysWstat, }, - { "vac", fsysVac, }, - - { nil, nil, }, -}; - -static int -fsysXXX1(Fsys *fsys, int i, int argc, char* argv[]) -{ - int r; - - vtLock(fsys->lock); - if(fsys->fs == nil){ - vtUnlock(fsys->lock); - vtSetError(EFsysNotOpen, fsys->name); - return 0; - } - - if(fsys->fs->halted - && fsyscmd[i].f != fsysUnhalt && fsyscmd[i].f != fsysCheck){ - vtSetError("file system %s is halted", fsys->name); - vtUnlock(fsys->lock); - return 0; - } - - r = (*fsyscmd[i].f)(fsys, argc, argv); - vtUnlock(fsys->lock); - return r; -} - -static int -fsysXXX(char* name, int argc, char* argv[]) -{ - int i, r; - Fsys *fsys; - - for(i = 0; fsyscmd[i].cmd != nil; i++){ - if(strcmp(fsyscmd[i].cmd, argv[0]) == 0) - break; - } - - if(fsyscmd[i].cmd == nil){ - vtSetError("unknown command - '%s'", argv[0]); - return 0; - } - - /* some commands want the name... */ - if(fsyscmd[i].f1 != nil){ - if(strcmp(name, FsysAll) == 0){ - vtSetError("cannot use fsys %#q with %#q command", FsysAll, argv[0]); - return 0; - } - return (*fsyscmd[i].f1)(name, argc, argv); - } - - /* ... but most commands want the Fsys */ - if(strcmp(name, FsysAll) == 0){ - r = 1; - vtRLock(sbox.lock); - for(fsys = sbox.head; fsys != nil; fsys = fsys->next){ - fsys->ref++; - r = fsysXXX1(fsys, i, argc, argv) && r; - fsys->ref--; - } - vtRUnlock(sbox.lock); - }else{ - if((fsys = _fsysGet(name)) == nil) - return 0; - r = fsysXXX1(fsys, i, argc, argv); - fsysPut(fsys); - } - return r; -} - -static int -cmdFsysXXX(int argc, char* argv[]) -{ - char *name; - - if((name = sbox.curfsys) == nil){ - vtSetError(EFsysNoCurrent, argv[0]); - return 0; - } - - return fsysXXX(name, argc, argv); -} - -static int -cmdFsys(int argc, char* argv[]) -{ - Fsys *fsys; - char *usage = "usage: fsys [name ...]"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - - if(argc == 0){ - vtRLock(sbox.lock); - currfsysname = sbox.head->name; - for(fsys = sbox.head; fsys != nil; fsys = fsys->next) - consPrint("\t%s\n", fsys->name); - vtRUnlock(sbox.lock); - return 1; - } - if(argc == 1){ - fsys = nil; - if(strcmp(argv[0], FsysAll) != 0 && (fsys = fsysGet(argv[0])) == nil) - return 0; - sbox.curfsys = vtStrDup(argv[0]); - consPrompt(sbox.curfsys); - if(fsys) - fsysPut(fsys); - return 1; - } - - return fsysXXX(argv[0], argc-1, argv+1); -} - -int -fsysInit(void) -{ - int i; - - fmtinstall('H', encodefmt); - fmtinstall('V', scoreFmt); - fmtinstall('R', vtErrFmt); - fmtinstall('L', labelFmt); - - sbox.lock = vtLockAlloc(); - - cliAddCmd("fsys", cmdFsys); - for(i = 0; fsyscmd[i].cmd != nil; i++){ - if(fsyscmd[i].f != nil) - cliAddCmd(fsyscmd[i].cmd, cmdFsysXXX); - } - /* the venti cmd is special: the fs can be either open or closed */ - cliAddCmd("venti", cmdFsysXXX); - cliAddCmd("printconfig", cmdPrintConfig); - - return 1; -} diff --git a/sys/src/cmd/fossil/9lstn.c b/sys/src/cmd/fossil/9lstn.c deleted file mode 100644 index 1f26a1134..000000000 --- a/sys/src/cmd/fossil/9lstn.c +++ /dev/null @@ -1,184 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -typedef struct Lstn Lstn; -typedef struct Lstn { - int afd; - int flags; - char* address; - char dir[NETPATHLEN]; - - Lstn* next; - Lstn* prev; -} Lstn; - -static struct { - VtLock* lock; - - Lstn* head; - Lstn* tail; -} lbox; - -static void -lstnFree(Lstn* lstn) -{ - vtLock(lbox.lock); - if(lstn->prev != nil) - lstn->prev->next = lstn->next; - else - lbox.head = lstn->next; - if(lstn->next != nil) - lstn->next->prev = lstn->prev; - else - lbox.tail = lstn->prev; - vtUnlock(lbox.lock); - - if(lstn->afd != -1) - close(lstn->afd); - vtMemFree(lstn->address); - vtMemFree(lstn); -} - -static void -lstnListen(void* a) -{ - Lstn *lstn; - int dfd, lfd; - char newdir[NETPATHLEN]; - - vtThreadSetName("listen"); - - lstn = a; - for(;;){ - if((lfd = listen(lstn->dir, newdir)) < 0){ - fprint(2, "listen: listen '%s': %r", lstn->dir); - break; - } - if((dfd = accept(lfd, newdir)) >= 0) - conAlloc(dfd, newdir, lstn->flags); - else - fprint(2, "listen: accept %s: %r\n", newdir); - close(lfd); - } - lstnFree(lstn); -} - -static Lstn* -lstnAlloc(char* address, int flags) -{ - int afd; - Lstn *lstn; - char dir[NETPATHLEN]; - - vtLock(lbox.lock); - for(lstn = lbox.head; lstn != nil; lstn = lstn->next){ - if(strcmp(lstn->address, address) != 0) - continue; - vtSetError("listen: already serving '%s'", address); - vtUnlock(lbox.lock); - return nil; - } - - if((afd = announce(address, dir)) < 0){ - vtSetError("listen: announce '%s': %r", address); - vtUnlock(lbox.lock); - return nil; - } - - lstn = vtMemAllocZ(sizeof(Lstn)); - lstn->afd = afd; - lstn->address = vtStrDup(address); - lstn->flags = flags; - memmove(lstn->dir, dir, NETPATHLEN); - - if(lbox.tail != nil){ - lstn->prev = lbox.tail; - lbox.tail->next = lstn; - } - else{ - lbox.head = lstn; - lstn->prev = nil; - } - lbox.tail = lstn; - vtUnlock(lbox.lock); - - if(vtThread(lstnListen, lstn) < 0){ - vtSetError("listen: thread '%s': %r", lstn->address); - lstnFree(lstn); - return nil; - } - - return lstn; -} - -static int -cmdLstn(int argc, char* argv[]) -{ - int dflag, flags; - Lstn *lstn; - char *usage = "usage: listen [-dIN] [address]"; - - dflag = 0; - flags = 0; - ARGBEGIN{ - default: - return cliError(usage); - case 'd': - dflag = 1; - break; - case 'I': - flags |= ConIPCheck; - break; - case 'N': - flags |= ConNoneAllow; - break; - }ARGEND - - switch(argc){ - default: - return cliError(usage); - case 0: - vtRLock(lbox.lock); - for(lstn = lbox.head; lstn != nil; lstn = lstn->next) - consPrint("\t%s\t%s\n", lstn->address, lstn->dir); - vtRUnlock(lbox.lock); - break; - case 1: - if(!dflag){ - if(lstnAlloc(argv[0], flags) == nil) - return 0; - break; - } - - vtLock(lbox.lock); - for(lstn = lbox.head; lstn != nil; lstn = lstn->next){ - if(strcmp(lstn->address, argv[0]) != 0) - continue; - if(lstn->afd != -1){ - close(lstn->afd); - lstn->afd = -1; - } - break; - } - vtUnlock(lbox.lock); - - if(lstn == nil){ - vtSetError("listen: '%s' not found", argv[0]); - return 0; - } - break; - } - - return 1; -} - -int -lstnInit(void) -{ - lbox.lock = vtLockAlloc(); - - cliAddCmd("listen", cmdLstn); - - return 1; -} diff --git a/sys/src/cmd/fossil/9p.c b/sys/src/cmd/fossil/9p.c deleted file mode 100644 index 0db657d09..000000000 --- a/sys/src/cmd/fossil/9p.c +++ /dev/null @@ -1,1175 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -enum { - OMODE = 0x7, /* Topen/Tcreate mode */ -}; - -enum { - PermX = 1, - PermW = 2, - PermR = 4, -}; - -static char EPermission[] = "permission denied"; - -static int -permFile(File* file, Fid* fid, int perm) -{ - char *u; - DirEntry de; - - if(!fileGetDir(file, &de)) - return -1; - - /* - * User none only gets other permissions. - */ - if(strcmp(fid->uname, unamenone) != 0){ - /* - * There is only one uid<->uname mapping - * and it's already cached in the Fid, but - * it might have changed during the lifetime - * if this Fid. - */ - if((u = unameByUid(de.uid)) != nil){ - if(strcmp(fid->uname, u) == 0 && ((perm<<6) & de.mode)){ - vtMemFree(u); - deCleanup(&de); - return 1; - } - vtMemFree(u); - } - if(groupMember(de.gid, fid->uname) && ((perm<<3) & de.mode)){ - deCleanup(&de); - return 1; - } - } - if(perm & de.mode){ - if(perm == PermX && (de.mode & ModeDir)){ - deCleanup(&de); - return 1; - } - if(!groupMember(uidnoworld, fid->uname)){ - deCleanup(&de); - return 1; - } - } - if(fsysNoPermCheck(fid->fsys) || (fid->con->flags&ConNoPermCheck)){ - deCleanup(&de); - return 1; - } - vtSetError(EPermission); - - deCleanup(&de); - return 0; -} - -static int -permFid(Fid* fid, int p) -{ - return permFile(fid->file, fid, p); -} - -static int -permParent(Fid* fid, int p) -{ - int r; - File *parent; - - parent = fileGetParent(fid->file); - r = permFile(parent, fid, p); - fileDecRef(parent); - - return r; -} - -int -validFileName(char* name) -{ - char *p; - - if(name == nil || name[0] == '\0'){ - vtSetError("no file name"); - return 0; - } - if(name[0] == '.'){ - if(name[1] == '\0' || (name[1] == '.' && name[2] == '\0')){ - vtSetError(". and .. illegal as file name"); - return 0; - } - } - - for(p = name; *p != '\0'; p++){ - if((*p & 0xFF) < 040){ - vtSetError("bad character in file name"); - return 0; - } - } - - return 1; -} - -static int -rTwstat(Msg* m) -{ - Dir dir; - Fid *fid; - ulong mode, oldmode; - DirEntry de; - char *gid, *strs, *uid; - int gl, op, retval, tsync, wstatallow; - - if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) - return 0; - - gid = uid = nil; - retval = 0; - - if(strcmp(fid->uname, unamenone) == 0 || (fid->qid.type & QTAUTH)){ - vtSetError(EPermission); - goto error0; - } - if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){ - vtSetError("read-only filesystem"); - goto error0; - } - - if(!fileGetDir(fid->file, &de)) - goto error0; - - strs = vtMemAlloc(m->t.nstat); - if(convM2D(m->t.stat, m->t.nstat, &dir, strs) == 0){ - vtSetError("wstat -- protocol botch"); - goto error; - } - - /* - * Run through each of the (sub-)fields in the provided Dir - * checking for validity and whether it's a default: - * .type, .dev and .atime are completely ignored and not checked; - * .qid.path, .qid.vers and .muid are checked for validity but - * any attempt to change them is an error. - * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can - * possibly be changed. - * - * 'Op' flags there are changed fields, i.e. it's not a no-op. - * 'Tsync' flags all fields are defaulted. - */ - tsync = 1; - if(dir.qid.path != ~0){ - if(dir.qid.path != de.qid){ - vtSetError("wstat -- attempt to change qid.path"); - goto error; - } - tsync = 0; - } - if(dir.qid.vers != ~0){ - if(dir.qid.vers != de.mcount){ - vtSetError("wstat -- attempt to change qid.vers"); - goto error; - } - tsync = 0; - } - if(dir.muid != nil && *dir.muid != '\0'){ - if((uid = uidByUname(dir.muid)) == nil){ - vtSetError("wstat -- unknown muid"); - goto error; - } - if(strcmp(uid, de.mid) != 0){ - vtSetError("wstat -- attempt to change muid"); - goto error; - } - vtMemFree(uid); - uid = nil; - tsync = 0; - } - - /* - * Check .qid.type and .mode agree if neither is defaulted. - */ - if(dir.qid.type != (uchar)~0 && dir.mode != ~0){ - if(dir.qid.type != ((dir.mode>>24) & 0xFF)){ - vtSetError("wstat -- qid.type/mode mismatch"); - goto error; - } - } - - op = 0; - - oldmode = de.mode; - if(dir.qid.type != (uchar)~0 || dir.mode != ~0){ - /* - * .qid.type or .mode isn't defaulted, check for unknown bits. - */ - if(dir.mode == ~0) - dir.mode = (dir.qid.type<<24)|(de.mode & 0777); - if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|DMTMP|0777)){ - vtSetError("wstat -- unknown bits in qid.type/mode"); - goto error; - } - - /* - * Synthesise a mode to check against the current settings. - */ - mode = dir.mode & 0777; - if(dir.mode & DMEXCL) - mode |= ModeExclusive; - if(dir.mode & DMAPPEND) - mode |= ModeAppend; - if(dir.mode & DMDIR) - mode |= ModeDir; - if(dir.mode & DMTMP) - mode |= ModeTemporary; - - if((de.mode^mode) & ModeDir){ - vtSetError("wstat -- attempt to change directory bit"); - goto error; - } - - if((de.mode & (ModeAppend|ModeExclusive|ModeTemporary|0777)) != mode){ - de.mode &= ~(ModeAppend|ModeExclusive|ModeTemporary|0777); - de.mode |= mode; - op = 1; - } - tsync = 0; - } - - if(dir.mtime != ~0){ - if(dir.mtime != de.mtime){ - de.mtime = dir.mtime; - op = 1; - } - tsync = 0; - } - - if(dir.length != ~0){ - if(dir.length != de.size){ - /* - * Cannot change length on append-only files. - * If we're changing the append bit, it's okay. - */ - if(de.mode & oldmode & ModeAppend){ - vtSetError("wstat -- attempt to change length of append-only file"); - goto error; - } - if(de.mode & ModeDir){ - vtSetError("wstat -- attempt to change length of directory"); - goto error; - } - de.size = dir.length; - op = 1; - } - tsync = 0; - } - - /* - * Check for permission to change .mode, .mtime or .length, - * must be owner or leader of either group, for which test gid - * is needed; permission checks on gid will be done later. - */ - if(dir.gid != nil && *dir.gid != '\0'){ - if((gid = uidByUname(dir.gid)) == nil){ - vtSetError("wstat -- unknown gid"); - goto error; - } - tsync = 0; - } - else - gid = vtStrDup(de.gid); - - wstatallow = (fsysWstatAllow(fid->fsys) || (m->con->flags&ConWstatAllow)); - - /* - * 'Gl' counts whether neither, one or both groups are led. - */ - gl = groupLeader(gid, fid->uname) != 0; - gl += groupLeader(de.gid, fid->uname) != 0; - - if(op && !wstatallow){ - if(strcmp(fid->uid, de.uid) != 0 && !gl){ - vtSetError("wstat -- not owner or group leader"); - goto error; - } - } - - /* - * Check for permission to change group, must be - * either owner and in new group or leader of both groups. - * If gid is nil here then - */ - if(strcmp(gid, de.gid) != 0){ - if(!wstatallow - && !(strcmp(fid->uid, de.uid) == 0 && groupMember(gid, fid->uname)) - && !(gl == 2)){ - vtSetError("wstat -- not owner and not group leaders"); - goto error; - } - vtMemFree(de.gid); - de.gid = gid; - gid = nil; - op = 1; - tsync = 0; - } - - /* - * Rename. - * Check .name is valid and different to the current. - * If so, check write permission in parent. - */ - if(dir.name != nil && *dir.name != '\0'){ - if(!validFileName(dir.name)) - goto error; - if(strcmp(dir.name, de.elem) != 0){ - if(permParent(fid, PermW) <= 0) - goto error; - vtMemFree(de.elem); - de.elem = vtStrDup(dir.name); - op = 1; - } - tsync = 0; - } - - /* - * Check for permission to change owner - must be god. - */ - if(dir.uid != nil && *dir.uid != '\0'){ - if((uid = uidByUname(dir.uid)) == nil){ - vtSetError("wstat -- unknown uid"); - goto error; - } - if(strcmp(uid, de.uid) != 0){ - if(!wstatallow){ - vtSetError("wstat -- not owner"); - goto error; - } - if(strcmp(uid, uidnoworld) == 0){ - vtSetError(EPermission); - goto error; - } - vtMemFree(de.uid); - de.uid = uid; - uid = nil; - op = 1; - } - tsync = 0; - } - - if(op) - retval = fileSetDir(fid->file, &de, fid->uid); - else - retval = 1; - - if(tsync){ - /* - * All values were defaulted, - * make the state of the file exactly what it - * claims to be before returning... - */ - USED(tsync); - } - -error: - deCleanup(&de); - vtMemFree(strs); - if(gid != nil) - vtMemFree(gid); - if(uid != nil) - vtMemFree(uid); -error0: - fidPut(fid); - return retval; -}; - -static int -rTstat(Msg* m) -{ - Dir dir; - Fid *fid; - DirEntry de; - - if((fid = fidGet(m->con, m->t.fid, 0)) == nil) - return 0; - if(fid->qid.type & QTAUTH){ - memset(&dir, 0, sizeof(Dir)); - dir.qid = fid->qid; - dir.mode = DMAUTH; - dir.atime = time(0L); - dir.mtime = dir.atime; - dir.length = 0; - dir.name = "#¿"; - dir.uid = fid->uname; - dir.gid = fid->uname; - dir.muid = fid->uname; - - if((m->r.nstat = convD2M(&dir, m->data, m->con->msize)) == 0){ - vtSetError("stat QTAUTH botch"); - fidPut(fid); - return 0; - } - m->r.stat = m->data; - - fidPut(fid); - return 1; - } - if(!fileGetDir(fid->file, &de)){ - fidPut(fid); - return 0; - } - fidPut(fid); - - /* - * TODO: optimise this copy (in convS2M) away somehow. - * This pettifoggery with m->data will do for the moment. - */ - m->r.nstat = dirDe2M(&de, m->data, m->con->msize); - m->r.stat = m->data; - deCleanup(&de); - - return 1; -} - -static int -_rTclunk(Fid* fid, int remove) -{ - int rok; - - if(fid->excl) - exclFree(fid); - - rok = 1; - if(remove && !(fid->qid.type & QTAUTH)){ - if((rok = permParent(fid, PermW)) > 0) - rok = fileRemove(fid->file, fid->uid); - } - fidClunk(fid); - - return rok; -} - -static int -rTremove(Msg* m) -{ - Fid *fid; - - if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) - return 0; - return _rTclunk(fid, 1); -} - -static int -rTclunk(Msg* m) -{ - Fid *fid; - - if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) - return 0; - _rTclunk(fid, (fid->open & FidORclose)); - - return 1; -} - -static int -rTwrite(Msg* m) -{ - Fid *fid; - int count, n; - - if((fid = fidGet(m->con, m->t.fid, 0)) == nil) - return 0; - if(!(fid->open & FidOWrite)){ - vtSetError("fid not open for write"); - goto error; - } - - count = m->t.count; - if(count < 0 || count > m->con->msize-IOHDRSZ){ - vtSetError("write count too big"); - goto error; - } - if(m->t.offset < 0){ - vtSetError("write offset negative"); - goto error; - } - if(fid->excl != nil && !exclUpdate(fid)) - goto error; - - if(fid->qid.type & QTDIR){ - vtSetError("is a directory"); - goto error; - } - else if(fid->qid.type & QTAUTH) - n = authWrite(fid, m->t.data, count); - else - n = fileWrite(fid->file, m->t.data, count, m->t.offset, fid->uid); - if(n < 0) - goto error; - - - m->r.count = n; - - fidPut(fid); - return 1; - -error: - fidPut(fid); - return 0; -} - -static int -rTread(Msg* m) -{ - Fid *fid; - uchar *data; - int count, n; - - if((fid = fidGet(m->con, m->t.fid, 0)) == nil) - return 0; - if(!(fid->open & FidORead)){ - vtSetError("fid not open for read"); - goto error; - } - - count = m->t.count; - if(count < 0 || count > m->con->msize-IOHDRSZ){ - vtSetError("read count too big"); - goto error; - } - if(m->t.offset < 0){ - vtSetError("read offset negative"); - goto error; - } - if(fid->excl != nil && !exclUpdate(fid)) - goto error; - - /* - * TODO: optimise this copy (in convS2M) away somehow. - * This pettifoggery with m->data will do for the moment. - */ - data = m->data+IOHDRSZ; - if(fid->qid.type & QTDIR) - n = dirRead(fid, data, count, m->t.offset); - else if(fid->qid.type & QTAUTH) - n = authRead(fid, data, count); - else - n = fileRead(fid->file, data, count, m->t.offset); - if(n < 0) - goto error; - - m->r.count = n; - m->r.data = (char*)data; - - fidPut(fid); - return 1; - -error: - fidPut(fid); - return 0; -} - -static int -rTcreate(Msg* m) -{ - Fid *fid; - File *file; - ulong mode; - int omode, open, perm; - - if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) - return 0; - if(fid->open){ - vtSetError("fid open for I/O"); - goto error; - } - if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){ - vtSetError("read-only filesystem"); - goto error; - } - if(!fileIsDir(fid->file)){ - vtSetError("not a directory"); - goto error; - } - if(permFid(fid, PermW) <= 0) - goto error; - if(!validFileName(m->t.name)) - goto error; - if(strcmp(fid->uid, uidnoworld) == 0){ - vtSetError(EPermission); - goto error; - } - - omode = m->t.mode & OMODE; - open = 0; - - if(omode == OREAD || omode == ORDWR || omode == OEXEC) - open |= FidORead; - if(omode == OWRITE || omode == ORDWR) - open |= FidOWrite; - if((open & (FidOWrite|FidORead)) == 0){ - vtSetError("unknown mode"); - goto error; - } - if(m->t.perm & DMDIR){ - if((m->t.mode & (ORCLOSE|OTRUNC)) || (open & FidOWrite)){ - vtSetError("illegal mode"); - goto error; - } - if(m->t.perm & DMAPPEND){ - vtSetError("illegal perm"); - goto error; - } - } - - mode = fileGetMode(fid->file); - perm = m->t.perm; - if(m->t.perm & DMDIR) - perm &= ~0777|(mode & 0777); - else - perm &= ~0666|(mode & 0666); - mode = perm & 0777; - if(m->t.perm & DMDIR) - mode |= ModeDir; - if(m->t.perm & DMAPPEND) - mode |= ModeAppend; - if(m->t.perm & DMEXCL) - mode |= ModeExclusive; - if(m->t.perm & DMTMP) - mode |= ModeTemporary; - - if((file = fileCreate(fid->file, m->t.name, mode, fid->uid)) == nil){ - fidPut(fid); - return 0; - } - fileDecRef(fid->file); - - fid->qid.vers = fileGetMcount(file); - fid->qid.path = fileGetId(file); - fid->file = file; - mode = fileGetMode(fid->file); - if(mode & ModeDir) - fid->qid.type = QTDIR; - else - fid->qid.type = QTFILE; - if(mode & ModeAppend) - fid->qid.type |= QTAPPEND; - if(mode & ModeExclusive){ - fid->qid.type |= QTEXCL; - assert(exclAlloc(fid) != 0); - } - if(m->t.mode & ORCLOSE) - open |= FidORclose; - fid->open = open; - - m->r.qid = fid->qid; - m->r.iounit = m->con->msize-IOHDRSZ; - - fidPut(fid); - return 1; - -error: - fidPut(fid); - return 0; -} - -static int -rTopen(Msg* m) -{ - Fid *fid; - int isdir, mode, omode, open, rofs; - - if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil) - return 0; - if(fid->open){ - vtSetError("fid open for I/O"); - goto error; - } - - isdir = fileIsDir(fid->file); - open = 0; - rofs = fileIsRoFs(fid->file) || !groupWriteMember(fid->uname); - - if(m->t.mode & ORCLOSE){ - if(isdir){ - vtSetError("is a directory"); - goto error; - } - if(rofs){ - vtSetError("read-only filesystem"); - goto error; - } - if(permParent(fid, PermW) <= 0) - goto error; - - open |= FidORclose; - } - - omode = m->t.mode & OMODE; - if(omode == OREAD || omode == ORDWR){ - if(permFid(fid, PermR) <= 0) - goto error; - open |= FidORead; - } - if(omode == OWRITE || omode == ORDWR || (m->t.mode & OTRUNC)){ - if(isdir){ - vtSetError("is a directory"); - goto error; - } - if(rofs){ - vtSetError("read-only filesystem"); - goto error; - } - if(permFid(fid, PermW) <= 0) - goto error; - open |= FidOWrite; - } - if(omode == OEXEC){ - if(isdir){ - vtSetError("is a directory"); - goto error; - } - if(permFid(fid, PermX) <= 0) - goto error; - open |= FidORead; - } - if((open & (FidOWrite|FidORead)) == 0){ - vtSetError("unknown mode"); - goto error; - } - - mode = fileGetMode(fid->file); - if((mode & ModeExclusive) && exclAlloc(fid) == 0) - goto error; - - /* - * Everything checks out, try to commit any changes. - */ - if((m->t.mode & OTRUNC) && !(mode & ModeAppend)) - if(!fileTruncate(fid->file, fid->uid)) - goto error; - - if(isdir && fid->db != nil){ - dirBufFree(fid->db); - fid->db = nil; - } - - fid->qid.vers = fileGetMcount(fid->file); - m->r.qid = fid->qid; - m->r.iounit = m->con->msize-IOHDRSZ; - - fid->open = open; - - fidPut(fid); - return 1; - -error: - if(fid->excl != nil) - exclFree(fid); - fidPut(fid); - return 0; -} - -static int -rTwalk(Msg* m) -{ - Qid qid; - Fcall *r, *t; - int nwname, wlock; - File *file, *nfile; - Fid *fid, *ofid, *nfid; - - t = &m->t; - if(t->fid == t->newfid) - wlock = FidFWlock; - else - wlock = 0; - - /* - * The file identified by t->fid must be valid in the - * current session and must not have been opened for I/O - * by an open or create message. - */ - if((ofid = fidGet(m->con, t->fid, wlock)) == nil) - return 0; - if(ofid->open){ - vtSetError("file open for I/O"); - fidPut(ofid); - return 0; - } - - /* - * If newfid is not the same as fid, allocate a new file; - * a side effect is checking newfid is not already in use (error); - * if there are no names to walk this will be equivalent to a - * simple 'clone' operation. - * It's a no-op if newfid is the same as fid and t->nwname is 0. - */ - nfid = nil; - if(t->fid != t->newfid){ - nfid = fidGet(m->con, t->newfid, FidFWlock|FidFCreate); - if(nfid == nil){ - vtSetError("%s: walk: newfid 0x%ud in use", - argv0, t->newfid); - fidPut(ofid); - return 0; - } - nfid->open = ofid->open & ~FidORclose; - nfid->file = fileIncRef(ofid->file); - nfid->qid = ofid->qid; - nfid->uid = vtStrDup(ofid->uid); - nfid->uname = vtStrDup(ofid->uname); - nfid->fsys = fsysIncRef(ofid->fsys); - fid = nfid; - } - else - fid = ofid; - - r = &m->r; - r->nwqid = 0; - - if(t->nwname == 0){ - if(nfid != nil) - fidPut(nfid); - fidPut(ofid); - - return 1; - } - - file = fid->file; - fileIncRef(file); - qid = fid->qid; - - for(nwname = 0; nwname < t->nwname; nwname++){ - /* - * Walked elements must represent a directory and - * the implied user must have permission to search - * the directory. Walking .. is always allowed, so that - * you can't walk into a directory and then not be able - * to walk out of it. - */ - if(!(qid.type & QTDIR)){ - vtSetError("not a directory"); - break; - } - switch(permFile(file, fid, PermX)){ - case 1: - break; - case 0: - if(strcmp(t->wname[nwname], "..") == 0) - break; - case -1: - goto Out; - } - if((nfile = fileWalk(file, t->wname[nwname])) == nil) - break; - fileDecRef(file); - file = nfile; - qid.type = QTFILE; - if(fileIsDir(file)) - qid.type = QTDIR; - qid.vers = fileGetMcount(file); - qid.path = fileGetId(file); - r->wqid[r->nwqid++] = qid; - } - - if(nwname == t->nwname){ - /* - * Walked all elements. Update the target fid - * from the temporary qid used during the walk, - * and tidy up. - */ - fid->qid = r->wqid[r->nwqid-1]; - fileDecRef(fid->file); - fid->file = file; - - if(nfid != nil) - fidPut(nfid); - - fidPut(ofid); - return 1; - } - -Out: - /* - * Didn't walk all elements, 'clunk' nfid if it exists - * and leave fid untouched. - * It's not an error if some of the elements were walked OK. - */ - fileDecRef(file); - if(nfid != nil) - fidClunk(nfid); - - fidPut(ofid); - if(nwname == 0) - return 0; - return 1; -} - -static int -rTflush(Msg* m) -{ - if(m->t.oldtag != NOTAG) - msgFlush(m); - return 1; -} - -static void -parseAname(char *aname, char **fsname, char **path) -{ - char *s; - - if(aname && aname[0]) - s = vtStrDup(aname); - else - s = vtStrDup("main/active"); - *fsname = s; - if((*path = strchr(s, '/')) != nil) - *(*path)++ = '\0'; - else - *path = ""; -} - -/* - * Check remote IP address against /mnt/ipok. - * Sources.cs.bell-labs.com uses this to disallow - * network connections from Sudan, Libya, etc., - * following U.S. cryptography export regulations. - */ -static int -conIPCheck(Con* con) -{ - char ok[256], *p; - int fd; - - if(con->flags&ConIPCheck){ - if(con->remote[0] == 0){ - vtSetError("cannot verify unknown remote address"); - return 0; - } - if(access("/mnt/ipok/ok", AEXIST) < 0){ - /* mount closes the fd on success */ - if((fd = open("/srv/ipok", ORDWR)) >= 0 - && mount(fd, -1, "/mnt/ipok", MREPL, "") < 0) - close(fd); - if(access("/mnt/ipok/ok", AEXIST) < 0){ - vtSetError("cannot verify remote address"); - return 0; - } - } - snprint(ok, sizeof ok, "/mnt/ipok/ok/%s", con->remote); - if((p = strchr(ok, '!')) != nil) - *p = 0; - if(access(ok, AEXIST) < 0){ - vtSetError("restricted remote address"); - return 0; - } - } - return 1; -} - -static int -rTattach(Msg* m) -{ - Fid *fid; - Fsys *fsys; - char *fsname, *path; - - if((fid = fidGet(m->con, m->t.fid, FidFWlock|FidFCreate)) == nil) - return 0; - - parseAname(m->t.aname, &fsname, &path); - if((fsys = fsysGet(fsname)) == nil){ - fidClunk(fid); - vtMemFree(fsname); - return 0; - } - fid->fsys = fsys; - - if(m->t.uname[0] != '\0') - fid->uname = vtStrDup(m->t.uname); - else - fid->uname = vtStrDup(unamenone); - - if((fid->con->flags&ConIPCheck) && !conIPCheck(fid->con)){ - consPrint("reject %s from %s: %R\n", fid->uname, fid->con->remote); - fidClunk(fid); - vtMemFree(fsname); - return 0; - } - if(fsysNoAuthCheck(fsys) || (m->con->flags&ConNoAuthCheck)){ - if((fid->uid = uidByUname(fid->uname)) == nil) - fid->uid = vtStrDup(unamenone); - } - else if(!authCheck(&m->t, fid, fsys)){ - fidClunk(fid); - vtMemFree(fsname); - return 0; - } - - fsysFsRlock(fsys); - if((fid->file = fsysGetRoot(fsys, path)) == nil){ - fsysFsRUnlock(fsys); - fidClunk(fid); - vtMemFree(fsname); - return 0; - } - fsysFsRUnlock(fsys); - vtMemFree(fsname); - - fid->qid = (Qid){fileGetId(fid->file), 0, QTDIR}; - m->r.qid = fid->qid; - - fidPut(fid); - return 1; -} - -static int -rTauth(Msg* m) -{ - int afd; - Con *con; - Fid *afid; - Fsys *fsys; - char *fsname, *path; - - parseAname(m->t.aname, &fsname, &path); - if((fsys = fsysGet(fsname)) == nil){ - vtMemFree(fsname); - return 0; - } - vtMemFree(fsname); - - if(fsysNoAuthCheck(fsys) || (m->con->flags&ConNoAuthCheck)){ - m->con->aok = 1; - vtSetError("authentication disabled"); - fsysPut(fsys); - return 0; - } - if(strcmp(m->t.uname, unamenone) == 0){ - vtSetError("user 'none' requires no authentication"); - fsysPut(fsys); - return 0; - } - - con = m->con; - if((afid = fidGet(con, m->t.afid, FidFWlock|FidFCreate)) == nil){ - fsysPut(fsys); - return 0; - } - afid->fsys = fsys; - - if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ - vtSetError("can't open \"/mnt/factotum/rpc\""); - fidClunk(afid); - return 0; - } - if((afid->rpc = auth_allocrpc(afd)) == nil){ - close(afd); - vtSetError("can't auth_allocrpc"); - fidClunk(afid); - return 0; - } - if(auth_rpc(afid->rpc, "start", "proto=p9any role=server", 23) != ARok){ - vtSetError("can't auth_rpc"); - fidClunk(afid); - return 0; - } - - afid->open = FidOWrite|FidORead; - afid->qid.type = QTAUTH; - afid->qid.path = m->t.afid; - afid->uname = vtStrDup(m->t.uname); - - m->r.qid = afid->qid; - - fidPut(afid); - return 1; -} - -static int -rTversion(Msg* m) -{ - int v; - Con *con; - Fcall *r, *t; - - t = &m->t; - r = &m->r; - con = m->con; - - vtLock(con->lock); - if(con->state != ConInit){ - vtUnlock(con->lock); - vtSetError("Tversion: down"); - return 0; - } - con->state = ConNew; - - /* - * Release the karma of past lives and suffering. - * Should this be done before or after checking the - * validity of the Tversion? - */ - fidClunkAll(con); - - if(t->tag != NOTAG){ - vtUnlock(con->lock); - vtSetError("Tversion: invalid tag"); - return 0; - } - - if(t->msize < 256){ - vtUnlock(con->lock); - vtSetError("Tversion: message size too small"); - return 0; - } - if(t->msize < con->msize) - r->msize = t->msize; - else - r->msize = con->msize; - - r->version = "unknown"; - if(t->version[0] == '9' && t->version[1] == 'P'){ - /* - * Currently, the only defined version - * is "9P2000"; ignore any later versions. - */ - v = strtol(&t->version[2], 0, 10); - if(v >= 2000){ - r->version = VERSION9P; - con->msize = r->msize; - con->state = ConUp; - } - else if(strcmp(t->version, "9PEoF") == 0){ - r->version = "9PEoF"; - con->msize = r->msize; - con->state = ConMoribund; - - /* - * Don't want to attempt to write this - * message as the connection may be already - * closed. - */ - m->state = MsgF; - } - } - vtUnlock(con->lock); - - return 1; -} - -int (*rFcall[Tmax])(Msg*) = { - [Tversion] = rTversion, - [Tauth] = rTauth, - [Tattach] = rTattach, - [Tflush] = rTflush, - [Twalk] = rTwalk, - [Topen] = rTopen, - [Tcreate] = rTcreate, - [Tread] = rTread, - [Twrite] = rTwrite, - [Tclunk] = rTclunk, - [Tremove] = rTremove, - [Tstat] = rTstat, - [Twstat] = rTwstat, -}; diff --git a/sys/src/cmd/fossil/9ping.c b/sys/src/cmd/fossil/9ping.c deleted file mode 100644 index a21eea9b7..000000000 --- a/sys/src/cmd/fossil/9ping.c +++ /dev/null @@ -1,109 +0,0 @@ -#include <u.h> -#include <libc.h> - -typedef uvlong u64int; - -#define TWID64 ((u64int)~(u64int)0) - - -u64int -unittoull(char *s) -{ - char *es; - u64int n; - - if(s == nil) - return TWID64; - n = strtoul(s, &es, 0); - if(*es == 'k' || *es == 'K'){ - n *= 1024; - es++; - }else if(*es == 'm' || *es == 'M'){ - n *= 1024*1024; - es++; - }else if(*es == 'g' || *es == 'G'){ - n *= 1024*1024*1024; - es++; - } - if(*es != '\0') - return TWID64; - return n; -} - -void -main(int argc, char *argv[]) -{ - int fd, i; - int n = 1000, m; - int s = 1; - double *t, t0, t1; - uchar *buf; - double a, d, max, min; - - m = OREAD; - ARGBEGIN{ - case 'n': - n = atoi(ARGF()); - break; - case 's': - s = unittoull(ARGF()); - if(s < 1 || s > 1024*1024) - sysfatal("bad size"); - break; - case 'r': - m = OREAD; - break; - case 'w': - m = OWRITE; - break; - }ARGEND - - fd = 0; - if(argc == 1){ - fd = open(argv[0], m); - if(fd < 0) - sysfatal("could not open file: %s: %r", argv[0]); - } - - buf = malloc(s); - t = malloc(n*sizeof(double)); - - t0 = nsec(); - for(i=0; i<n; i++){ - if(m == OREAD){ - if(pread(fd, buf, s, 0) < s) - sysfatal("bad read: %r"); - }else{ - if(pwrite(fd, buf, s, 0) < s) - sysfatal("bad write: %r"); - } - t1 = nsec(); - t[i] = (t1 - t0)*1e-3; - t0 = t1; - } - - a = 0.; - d = 0.; - max = 0.; - min = 1e12; - - for(i=0; i<n; i++){ - a += t[i]; - if(max < t[i]) - max = t[i]; - if(min > t[i]) - min = t[i]; - } - - a /= n; - - for(i=0; i<n; i++) - d += (a - t[i]) * (a - t[i]); - d /= n; - d = sqrt(d); - - print("avg = %.0fµs min = %.0fµs max = %.0fµs dev = %.0fµs\n", a, min, max, d); - - exits(0); -} - diff --git a/sys/src/cmd/fossil/9proc.c b/sys/src/cmd/fossil/9proc.c deleted file mode 100644 index bddd3baa1..000000000 --- a/sys/src/cmd/fossil/9proc.c +++ /dev/null @@ -1,825 +0,0 @@ -#include "stdinc.h" - -#include "9.h" -#include "dat.h" -#include "fns.h" - -enum { - NConInit = 128, - NMsgInit = 384, - NMsgProcInit = 64, - NMsizeInit = 8192+IOHDRSZ, -}; - -static struct { - VtLock* alock; /* alloc */ - Msg* ahead; - VtRendez* arendez; - - int maxmsg; - int nmsg; - int nmsgstarve; - - VtLock* rlock; /* read */ - Msg* rhead; - Msg* rtail; - VtRendez* rrendez; - - int maxproc; - int nproc; - int nprocstarve; - - u32int msize; /* immutable */ -} mbox; - -static struct { - VtLock* alock; /* alloc */ - Con* ahead; - VtRendez* arendez; - - VtLock* clock; - Con* chead; - Con* ctail; - - int maxcon; - int ncon; - int nconstarve; - - u32int msize; -} cbox; - -static void -conFree(Con* con) -{ - assert(con->version == nil); - assert(con->mhead == nil); - assert(con->whead == nil); - assert(con->nfid == 0); - assert(con->state == ConMoribund); - - if(con->fd >= 0){ - close(con->fd); - con->fd = -1; - } - con->state = ConDead; - con->aok = 0; - con->flags = 0; - con->isconsole = 0; - - vtLock(cbox.alock); - if(con->cprev != nil) - con->cprev->cnext = con->cnext; - else - cbox.chead = con->cnext; - if(con->cnext != nil) - con->cnext->cprev = con->cprev; - else - cbox.ctail = con->cprev; - con->cprev = con->cnext = nil; - - if(cbox.ncon > cbox.maxcon){ - if(con->name != nil) - vtMemFree(con->name); - vtLockFree(con->fidlock); - vtMemFree(con->data); - vtRendezFree(con->wrendez); - vtLockFree(con->wlock); - vtRendezFree(con->mrendez); - vtLockFree(con->mlock); - vtRendezFree(con->rendez); - vtLockFree(con->lock); - vtMemFree(con); - cbox.ncon--; - vtUnlock(cbox.alock); - return; - } - con->anext = cbox.ahead; - cbox.ahead = con; - if(con->anext == nil) - vtWakeup(cbox.arendez); - vtUnlock(cbox.alock); -} - -static void -msgFree(Msg* m) -{ - assert(m->rwnext == nil); - assert(m->flush == nil); - - vtLock(mbox.alock); - if(mbox.nmsg > mbox.maxmsg){ - vtMemFree(m->data); - vtMemFree(m); - mbox.nmsg--; - vtUnlock(mbox.alock); - return; - } - m->anext = mbox.ahead; - mbox.ahead = m; - if(m->anext == nil) - vtWakeup(mbox.arendez); - vtUnlock(mbox.alock); -} - -static Msg* -msgAlloc(Con* con) -{ - Msg *m; - - vtLock(mbox.alock); - while(mbox.ahead == nil){ - if(mbox.nmsg >= mbox.maxmsg){ - mbox.nmsgstarve++; - vtSleep(mbox.arendez); - continue; - } - m = vtMemAllocZ(sizeof(Msg)); - m->data = vtMemAlloc(mbox.msize); - m->msize = mbox.msize; - mbox.nmsg++; - mbox.ahead = m; - break; - } - m = mbox.ahead; - mbox.ahead = m->anext; - m->anext = nil; - vtUnlock(mbox.alock); - - m->con = con; - m->state = MsgR; - m->nowq = 0; - - return m; -} - -static void -msgMunlink(Msg* m) -{ - Con *con; - - con = m->con; - - if(m->mprev != nil) - m->mprev->mnext = m->mnext; - else - con->mhead = m->mnext; - if(m->mnext != nil) - m->mnext->mprev = m->mprev; - else - con->mtail = m->mprev; - m->mprev = m->mnext = nil; -} - -void -msgFlush(Msg* m) -{ - Con *con; - Msg *flush, *old; - - con = m->con; - - if(Dflag) - fprint(2, "msgFlush %F\n", &m->t); - - /* - * If this Tflush has been flushed, nothing to do. - * Look for the message to be flushed in the - * queue of all messages still on this connection. - * If it's not found must assume Elvis has already - * left the building and reply normally. - */ - vtLock(con->mlock); - if(m->state == MsgF){ - vtUnlock(con->mlock); - return; - } - for(old = con->mhead; old != nil; old = old->mnext) - if(old->t.tag == m->t.oldtag) - break; - if(old == nil){ - if(Dflag) - fprint(2, "msgFlush: cannot find %d\n", m->t.oldtag); - vtUnlock(con->mlock); - return; - } - - if(Dflag) - fprint(2, "\tmsgFlush found %F\n", &old->t); - - /* - * Found it. - * There are two cases where the old message can be - * truly flushed and no reply to the original message given. - * The first is when the old message is in MsgR state; no - * processing has been done yet and it is still on the read - * queue. The second is if old is a Tflush, which doesn't - * affect the server state. In both cases, put the old - * message into MsgF state and let MsgWrite toss it after - * pulling it off the queue. - */ - if(old->state == MsgR || old->t.type == Tflush){ - old->state = MsgF; - if(Dflag) - fprint(2, "msgFlush: change %d from MsgR to MsgF\n", - m->t.oldtag); - } - - /* - * Link this flush message and the old message - * so multiple flushes can be coalesced (if there are - * multiple Tflush messages for a particular pending - * request, it is only necessary to respond to the last - * one, so any previous can be removed) and to be - * sure flushes wait for their corresponding old - * message to go out first. - * Waiting flush messages do not go on the write queue, - * they are processed after the old message is dealt - * with. There's no real need to protect the setting of - * Msg.nowq, the only code to check it runs in this - * process after this routine returns. - */ - if((flush = old->flush) != nil){ - if(Dflag) - fprint(2, "msgFlush: remove %d from %d list\n", - old->flush->t.tag, old->t.tag); - m->flush = flush->flush; - flush->flush = nil; - msgMunlink(flush); - msgFree(flush); - } - old->flush = m; - m->nowq = 1; - - if(Dflag) - fprint(2, "msgFlush: add %d to %d queue\n", - m->t.tag, old->t.tag); - vtUnlock(con->mlock); -} - -static void -msgProc(void*) -{ - Msg *m; - char *e; - Con *con; - - vtThreadSetName("msgProc"); - - for(;;){ - /* - * If surplus to requirements, exit. - * If not, wait for and pull a message off - * the read queue. - */ - vtLock(mbox.rlock); - if(mbox.nproc > mbox.maxproc){ - mbox.nproc--; - vtUnlock(mbox.rlock); - break; - } - while(mbox.rhead == nil) - vtSleep(mbox.rrendez); - m = mbox.rhead; - mbox.rhead = m->rwnext; - m->rwnext = nil; - vtUnlock(mbox.rlock); - - con = m->con; - e = nil; - - /* - * If the message has been flushed before - * any 9P processing has started, mark it so - * none will be attempted. - */ - vtLock(con->mlock); - if(m->state == MsgF) - e = "flushed"; - else - m->state = Msg9; - vtUnlock(con->mlock); - - if(e == nil){ - /* - * explain this - */ - vtLock(con->lock); - if(m->t.type == Tversion){ - con->version = m; - con->state = ConDown; - while(con->mhead != m) - vtSleep(con->rendez); - assert(con->state == ConDown); - if(con->version == m){ - con->version = nil; - con->state = ConInit; - } - else - e = "Tversion aborted"; - } - else if(con->state != ConUp) - e = "connection not ready"; - vtUnlock(con->lock); - } - - /* - * Dispatch if not error already. - */ - m->r.tag = m->t.tag; - if(e == nil && !(*rFcall[m->t.type])(m)) - e = vtGetError(); - if(e != nil){ - m->r.type = Rerror; - m->r.ename = e; - } - else - m->r.type = m->t.type+1; - - /* - * Put the message (with reply) on the - * write queue and wakeup the write process. - */ - if(!m->nowq){ - vtLock(con->wlock); - if(con->whead == nil) - con->whead = m; - else - con->wtail->rwnext = m; - con->wtail = m; - vtWakeup(con->wrendez); - vtUnlock(con->wlock); - } - } -} - -static void -msgRead(void* v) -{ - Msg *m; - Con *con; - int eof, fd, n; - - vtThreadSetName("msgRead"); - - con = v; - fd = con->fd; - eof = 0; - - while(!eof){ - m = msgAlloc(con); - - while((n = read9pmsg(fd, m->data, con->msize)) == 0) - ; - if(n < 0){ - m->t.type = Tversion; - m->t.fid = NOFID; - m->t.tag = NOTAG; - m->t.msize = con->msize; - m->t.version = "9PEoF"; - eof = 1; - } - else if(convM2S(m->data, n, &m->t) != n){ - if(Dflag) - fprint(2, "msgRead: convM2S error: %s\n", - con->name); - msgFree(m); - continue; - } - if(Dflag) - fprint(2, "msgRead %p: t %F\n", con, &m->t); - - vtLock(con->mlock); - if(con->mtail != nil){ - m->mprev = con->mtail; - con->mtail->mnext = m; - } - else{ - con->mhead = m; - m->mprev = nil; - } - con->mtail = m; - vtUnlock(con->mlock); - - vtLock(mbox.rlock); - if(mbox.rhead == nil){ - mbox.rhead = m; - if(!vtWakeup(mbox.rrendez)){ - if(mbox.nproc < mbox.maxproc){ - if(vtThread(msgProc, nil) > 0) - mbox.nproc++; - } - else - mbox.nprocstarve++; - } - /* - * don't need this surely? - vtWakeup(mbox.rrendez); - */ - } - else - mbox.rtail->rwnext = m; - mbox.rtail = m; - vtUnlock(mbox.rlock); - } -} - -static void -msgWrite(void* v) -{ - Con *con; - int eof, n; - Msg *flush, *m; - - vtThreadSetName("msgWrite"); - - con = v; - if(vtThread(msgRead, con) < 0){ - conFree(con); - return; - } - - for(;;){ - /* - * Wait for and pull a message off the write queue. - */ - vtLock(con->wlock); - while(con->whead == nil) - vtSleep(con->wrendez); - m = con->whead; - con->whead = m->rwnext; - m->rwnext = nil; - assert(!m->nowq); - vtUnlock(con->wlock); - - eof = 0; - - /* - * Write each message (if it hasn't been flushed) - * followed by any messages waiting for it to complete. - */ - vtLock(con->mlock); - while(m != nil){ - msgMunlink(m); - - if(Dflag) - fprint(2, "msgWrite %d: r %F\n", - m->state, &m->r); - - if(m->state != MsgF){ - m->state = MsgW; - vtUnlock(con->mlock); - - n = convS2M(&m->r, con->data, con->msize); - if(write(con->fd, con->data, n) != n) - eof = 1; - - vtLock(con->mlock); - } - - if((flush = m->flush) != nil){ - assert(flush->nowq); - m->flush = nil; - } - msgFree(m); - m = flush; - } - vtUnlock(con->mlock); - - vtLock(con->lock); - if(eof && con->fd >= 0){ - close(con->fd); - con->fd = -1; - } - if(con->state == ConDown) - vtWakeup(con->rendez); - if(con->state == ConMoribund && con->mhead == nil){ - vtUnlock(con->lock); - conFree(con); - break; - } - vtUnlock(con->lock); - } -} - -Con* -conAlloc(int fd, char* name, int flags) -{ - Con *con; - char buf[128], *p; - int rfd, n; - - vtLock(cbox.alock); - while(cbox.ahead == nil){ - if(cbox.ncon >= cbox.maxcon){ - cbox.nconstarve++; - vtSleep(cbox.arendez); - continue; - } - con = vtMemAllocZ(sizeof(Con)); - con->lock = vtLockAlloc(); - con->rendez = vtRendezAlloc(con->lock); - con->data = vtMemAlloc(cbox.msize); - con->msize = cbox.msize; - con->alock = vtLockAlloc(); - con->mlock = vtLockAlloc(); - con->mrendez = vtRendezAlloc(con->mlock); - con->wlock = vtLockAlloc(); - con->wrendez = vtRendezAlloc(con->wlock); - con->fidlock = vtLockAlloc(); - - cbox.ncon++; - cbox.ahead = con; - break; - } - con = cbox.ahead; - cbox.ahead = con->anext; - con->anext = nil; - - if(cbox.ctail != nil){ - con->cprev = cbox.ctail; - cbox.ctail->cnext = con; - } - else{ - cbox.chead = con; - con->cprev = nil; - } - cbox.ctail = con; - - assert(con->mhead == nil); - assert(con->whead == nil); - assert(con->fhead == nil); - assert(con->nfid == 0); - - con->state = ConNew; - con->fd = fd; - if(con->name != nil){ - vtMemFree(con->name); - con->name = nil; - } - if(name != nil) - con->name = vtStrDup(name); - else - con->name = vtStrDup("unknown"); - con->remote[0] = 0; - snprint(buf, sizeof buf, "%s/remote", con->name); - if((rfd = open(buf, OREAD)) >= 0){ - n = read(rfd, buf, sizeof buf-1); - close(rfd); - if(n > 0){ - buf[n] = 0; - if((p = strchr(buf, '\n')) != nil) - *p = 0; - strecpy(con->remote, con->remote+sizeof con->remote, buf); - } - } - con->flags = flags; - con->isconsole = 0; - vtUnlock(cbox.alock); - - if(vtThread(msgWrite, con) < 0){ - conFree(con); - return nil; - } - - return con; -} - -static int -cmdMsg(int argc, char* argv[]) -{ - char *p; - char *usage = "usage: msg [-m nmsg] [-p nproc]"; - int maxmsg, nmsg, nmsgstarve, maxproc, nproc, nprocstarve; - - maxmsg = maxproc = 0; - - ARGBEGIN{ - default: - return cliError(usage); - case 'm': - p = ARGF(); - if(p == nil) - return cliError(usage); - maxmsg = strtol(argv[0], &p, 0); - if(maxmsg <= 0 || p == argv[0] || *p != '\0') - return cliError(usage); - break; - case 'p': - p = ARGF(); - if(p == nil) - return cliError(usage); - maxproc = strtol(argv[0], &p, 0); - if(maxproc <= 0 || p == argv[0] || *p != '\0') - return cliError(usage); - break; - }ARGEND - if(argc) - return cliError(usage); - - vtLock(mbox.alock); - if(maxmsg) - mbox.maxmsg = maxmsg; - maxmsg = mbox.maxmsg; - nmsg = mbox.nmsg; - nmsgstarve = mbox.nmsgstarve; - vtUnlock(mbox.alock); - - vtLock(mbox.rlock); - if(maxproc) - mbox.maxproc = maxproc; - maxproc = mbox.maxproc; - nproc = mbox.nproc; - nprocstarve = mbox.nprocstarve; - vtUnlock(mbox.rlock); - - consPrint("\tmsg -m %d -p %d\n", maxmsg, maxproc); - consPrint("\tnmsg %d nmsgstarve %d nproc %d nprocstarve %d\n", - nmsg, nmsgstarve, nproc, nprocstarve); - - return 1; -} - -static int -scmp(Fid *a, Fid *b) -{ - if(a == 0) - return 1; - if(b == 0) - return -1; - return strcmp(a->uname, b->uname); -} - -static Fid* -fidMerge(Fid *a, Fid *b) -{ - Fid *s, **l; - - l = &s; - while(a || b){ - if(scmp(a, b) < 0){ - *l = a; - l = &a->sort; - a = a->sort; - }else{ - *l = b; - l = &b->sort; - b = b->sort; - } - } - *l = 0; - return s; -} - -static Fid* -fidMergeSort(Fid *f) -{ - int delay; - Fid *a, *b; - - if(f == nil) - return nil; - if(f->sort == nil) - return f; - - a = b = f; - delay = 1; - while(a && b){ - if(delay) /* easy way to handle 2-element list */ - delay = 0; - else - a = a->sort; - if(b = b->sort) - b = b->sort; - } - - b = a->sort; - a->sort = nil; - - a = fidMergeSort(f); - b = fidMergeSort(b); - - return fidMerge(a, b); -} - -static int -cmdWho(int argc, char* argv[]) -{ - char *usage = "usage: who"; - int i, l1, l2, l; - Con *con; - Fid *fid, *last; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - - if(argc > 0) - return cliError(usage); - - vtRLock(cbox.clock); - l1 = 0; - l2 = 0; - for(con=cbox.chead; con; con=con->cnext){ - if((l = strlen(con->name)) > l1) - l1 = l; - if((l = strlen(con->remote)) > l2) - l2 = l; - } - for(con=cbox.chead; con; con=con->cnext){ - consPrint("\t%-*s %-*s", l1, con->name, l2, con->remote); - vtLock(con->fidlock); - last = nil; - for(i=0; i<NFidHash; i++) - for(fid=con->fidhash[i]; fid; fid=fid->hash) - if(fid->fidno != NOFID && fid->uname){ - fid->sort = last; - last = fid; - } - fid = fidMergeSort(last); - last = nil; - for(; fid; last=fid, fid=fid->sort) - if(last==nil || strcmp(fid->uname, last->uname) != 0) - consPrint(" %q", fid->uname); - vtUnlock(con->fidlock); - consPrint("\n"); - } - vtRUnlock(cbox.clock); - return 1; -} - -void -msgInit(void) -{ - mbox.alock = vtLockAlloc(); - mbox.arendez = vtRendezAlloc(mbox.alock); - - mbox.rlock = vtLockAlloc(); - mbox.rrendez = vtRendezAlloc(mbox.rlock); - - mbox.maxmsg = NMsgInit; - mbox.maxproc = NMsgProcInit; - mbox.msize = NMsizeInit; - - cliAddCmd("msg", cmdMsg); -} - -static int -cmdCon(int argc, char* argv[]) -{ - char *p; - Con *con; - char *usage = "usage: con [-m ncon]"; - int maxcon, ncon, nconstarve; - - maxcon = 0; - - ARGBEGIN{ - default: - return cliError(usage); - case 'm': - p = ARGF(); - if(p == nil) - return cliError(usage); - maxcon = strtol(argv[0], &p, 0); - if(maxcon <= 0 || p == argv[0] || *p != '\0') - return cliError(usage); - break; - }ARGEND - if(argc) - return cliError(usage); - - vtLock(cbox.clock); - if(maxcon) - cbox.maxcon = maxcon; - maxcon = cbox.maxcon; - ncon = cbox.ncon; - nconstarve = cbox.nconstarve; - vtUnlock(cbox.clock); - - consPrint("\tcon -m %d\n", maxcon); - consPrint("\tncon %d nconstarve %d\n", ncon, nconstarve); - - vtRLock(cbox.clock); - for(con = cbox.chead; con != nil; con = con->cnext){ - consPrint("\t%s\n", con->name); - } - vtRUnlock(cbox.clock); - - return 1; -} - -void -conInit(void) -{ - cbox.alock = vtLockAlloc(); - cbox.arendez = vtRendezAlloc(cbox.alock); - - cbox.clock = vtLockAlloc(); - - cbox.maxcon = NConInit; - cbox.msize = NMsizeInit; - - cliAddCmd("con", cmdCon); - cliAddCmd("who", cmdWho); -} diff --git a/sys/src/cmd/fossil/9srv.c b/sys/src/cmd/fossil/9srv.c deleted file mode 100644 index dd6a6b6d2..000000000 --- a/sys/src/cmd/fossil/9srv.c +++ /dev/null @@ -1,242 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -typedef struct Srv Srv; -typedef struct Srv { - int fd; - int srvfd; - char* service; - char* mntpnt; - - Srv* next; - Srv* prev; -} Srv; - -static struct { - VtLock* lock; - - Srv* head; - Srv* tail; -} sbox; - -static int -srvFd(char* name, int mode, int fd, char** mntpnt) -{ - int n, srvfd; - char *p, buf[10]; - - /* - * Drop a file descriptor with given name and mode into /srv. - * Create with ORCLOSE and don't close srvfd so it will be removed - * automatically on process exit. - */ - p = smprint("/srv/%s", name); - if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ - vtMemFree(p); - p = smprint("#s/%s", name); - if((srvfd = create(p, ORCLOSE|OWRITE, mode)) < 0){ - vtSetError("create %s: %r", p); - vtMemFree(p); - return -1; - } - } - - n = snprint(buf, sizeof(buf), "%d", fd); - if(write(srvfd, buf, n) < 0){ - close(srvfd); - vtSetError("write %s: %r", p); - vtMemFree(p); - return -1; - } - - *mntpnt = p; - - return srvfd; -} - -static void -srvFree(Srv* srv) -{ - if(srv->prev != nil) - srv->prev->next = srv->next; - else - sbox.head = srv->next; - if(srv->next != nil) - srv->next->prev = srv->prev; - else - sbox.tail = srv->prev; - - if(srv->srvfd != -1) - close(srv->srvfd); - vtMemFree(srv->service); - vtMemFree(srv->mntpnt); - vtMemFree(srv); -} - -static Srv* -srvAlloc(char* service, int mode, int fd) -{ - Dir *dir; - Srv *srv; - int srvfd; - char *mntpnt; - - vtLock(sbox.lock); - for(srv = sbox.head; srv != nil; srv = srv->next){ - if(strcmp(srv->service, service) != 0) - continue; - /* - * If the service exists, but is stale, - * free it up and let the name be reused. - */ - if((dir = dirfstat(srv->srvfd)) != nil){ - free(dir); - vtSetError("srv: already serving '%s'", service); - vtUnlock(sbox.lock); - return nil; - } - srvFree(srv); - break; - } - - if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){ - vtUnlock(sbox.lock); - return nil; - } - close(fd); - - srv = vtMemAllocZ(sizeof(Srv)); - srv->srvfd = srvfd; - srv->service = vtStrDup(service); - srv->mntpnt = mntpnt; - - if(sbox.tail != nil){ - srv->prev = sbox.tail; - sbox.tail->next = srv; - } - else{ - sbox.head = srv; - srv->prev = nil; - } - sbox.tail = srv; - vtUnlock(sbox.lock); - - return srv; -} - -static int -cmdSrv(int argc, char* argv[]) -{ - Con *con; - Srv *srv; - char *usage = "usage: srv [-APWdp] [service]"; - int conflags, dflag, fd[2], mode, pflag, r; - - dflag = 0; - pflag = 0; - conflags = 0; - mode = 0666; - - ARGBEGIN{ - default: - return cliError(usage); - case 'A': - conflags |= ConNoAuthCheck; - break; - case 'I': - conflags |= ConIPCheck; - break; - case 'N': - conflags |= ConNoneAllow; - break; - case 'P': - conflags |= ConNoPermCheck; - mode = 0600; - break; - case 'W': - conflags |= ConWstatAllow; - mode = 0600; - break; - case 'd': - dflag = 1; - break; - case 'p': - pflag = 1; - mode = 0600; - break; - }ARGEND - - if(pflag && (conflags&ConNoPermCheck)){ - vtSetError("srv: cannot use -P with -p"); - return 0; - } - - switch(argc){ - default: - return cliError(usage); - case 0: - vtRLock(sbox.lock); - for(srv = sbox.head; srv != nil; srv = srv->next) - consPrint("\t%s\t%d\n", srv->service, srv->srvfd); - vtRUnlock(sbox.lock); - - return 1; - case 1: - if(!dflag) - break; - - vtLock(sbox.lock); - for(srv = sbox.head; srv != nil; srv = srv->next){ - if(strcmp(srv->service, argv[0]) != 0) - continue; - srvFree(srv); - break; - } - vtUnlock(sbox.lock); - - if(srv == nil){ - vtSetError("srv: '%s' not found", argv[0]); - return 0; - } - - return 1; - } - - if(pipe(fd) < 0){ - vtSetError("srv pipe: %r"); - return 0; - } - if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ - close(fd[0]); close(fd[1]); - return 0; - } - - if(pflag) - r = consOpen(fd[1], srv->srvfd, -1); - else{ - con = conAlloc(fd[1], srv->mntpnt, conflags); - if(con == nil) - r = 0; - else - r = 1; - } - if(r == 0){ - close(fd[1]); - vtLock(sbox.lock); - srvFree(srv); - vtUnlock(sbox.lock); - } - - return r; -} - -int -srvInit(void) -{ - sbox.lock = vtLockAlloc(); - - cliAddCmd("srv", cmdSrv); - - return 1; -} diff --git a/sys/src/cmd/fossil/9user.c b/sys/src/cmd/fossil/9user.c deleted file mode 100644 index 960bbae86..000000000 --- a/sys/src/cmd/fossil/9user.c +++ /dev/null @@ -1,948 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -enum { - NUserHash = 1009, -}; - -typedef struct Ubox Ubox; -typedef struct User User; - -typedef struct User { - char* uid; - char* uname; - char* leader; - char** group; - int ngroup; - - User* next; /* */ - User* ihash; /* lookup by .uid */ - User* nhash; /* lookup by .uname */ -} User; - -#pragma varargck type "U" User* - -typedef struct Ubox { - User* head; - User* tail; - int nuser; - int len; - - User* ihash[NUserHash]; /* lookup by .uid */ - User* nhash[NUserHash]; /* lookup by .uname */ -} Ubox; - -static struct { - VtLock* lock; - - Ubox* box; -} ubox; - -static char usersDefault[] = { - "adm:adm:adm:sys\n" - "none:none::\n" - "noworld:noworld::\n" - "sys:sys::glenda\n" - "glenda:glenda:glenda:\n" -}; - -static char* usersMandatory[] = { - "adm", - "none", - "noworld", - "sys", - nil, -}; - -char* uidadm = "adm"; -char* unamenone = "none"; -char* uidnoworld = "noworld"; - -static u32int -userHash(char* s) -{ - uchar *p; - u32int hash; - - hash = 0; - for(p = (uchar*)s; *p != '\0'; p++) - hash = hash*7 + *p; - - return hash % NUserHash; -} - -static User* -_userByUid(Ubox* box, char* uid) -{ - User *u; - - if(box != nil){ - for(u = box->ihash[userHash(uid)]; u != nil; u = u->ihash){ - if(strcmp(u->uid, uid) == 0) - return u; - } - } - vtSetError("uname: uid '%s' not found", uid); - return nil; -} - -char* -unameByUid(char* uid) -{ - User *u; - char *uname; - - vtRLock(ubox.lock); - if((u = _userByUid(ubox.box, uid)) == nil){ - vtRUnlock(ubox.lock); - return nil; - } - uname = vtStrDup(u->uname); - vtRUnlock(ubox.lock); - - return uname; -} - -static User* -_userByUname(Ubox* box, char* uname) -{ - User *u; - - if(box != nil){ - for(u = box->nhash[userHash(uname)]; u != nil; u = u->nhash){ - if(strcmp(u->uname, uname) == 0) - return u; - } - } - vtSetError("uname: uname '%s' not found", uname); - return nil; -} - -char* -uidByUname(char* uname) -{ - User *u; - char *uid; - - vtRLock(ubox.lock); - if((u = _userByUname(ubox.box, uname)) == nil){ - vtRUnlock(ubox.lock); - return nil; - } - uid = vtStrDup(u->uid); - vtRUnlock(ubox.lock); - - return uid; -} - -static int -_groupMember(Ubox* box, char* group, char* member, int whenNoGroup) -{ - int i; - User *g, *m; - - /* - * Is 'member' a member of 'group'? - * Note that 'group' is a 'uid' and not a 'uname'. - * A 'member' is automatically in their own group. - */ - if((g = _userByUid(box, group)) == nil) - return whenNoGroup; - if((m = _userByUname(box, member)) == nil) - return 0; - if(m == g) - return 1; - for(i = 0; i < g->ngroup; i++){ - if(strcmp(g->group[i], member) == 0) - return 1; - } - return 0; -} - -int -groupWriteMember(char* uname) -{ - int ret; - - /* - * If there is a ``write'' group, then only its members can write - * to the file system, no matter what the permission bits say. - * - * To users not in the ``write'' group, the file system appears - * read only. This is used to serve sources.cs.bell-labs.com - * to the world. - * - * Note that if there is no ``write'' group, then this routine - * makes it look like everyone is a member -- the opposite - * of what groupMember does. - * - * We use this for sources.cs.bell-labs.com. - * If this slows things down too much on systems that don't - * use this functionality, we could cache the write group lookup. - */ - - vtRLock(ubox.lock); - ret = _groupMember(ubox.box, "write", uname, 1); - vtRUnlock(ubox.lock); - return ret; -} - -static int -_groupRemMember(Ubox* box, User* g, char* member) -{ - int i; - - if(_userByUname(box, member) == nil) - return 0; - - for(i = 0; i < g->ngroup; i++){ - if(strcmp(g->group[i], member) == 0) - break; - } - if(i >= g->ngroup){ - if(strcmp(g->uname, member) == 0) - vtSetError("uname: '%s' always in own group", member); - else - vtSetError("uname: '%s' not in group '%s'", - member, g->uname); - return 0; - } - - vtMemFree(g->group[i]); - - box->len -= strlen(member); - if(g->ngroup > 1) - box->len--; - g->ngroup--; - switch(g->ngroup){ - case 0: - vtMemFree(g->group); - g->group = nil; - break; - default: - for(; i < g->ngroup; i++) - g->group[i] = g->group[i+1]; - g->group[i] = nil; /* prevent accidents */ - g->group = vtMemRealloc(g->group, g->ngroup * sizeof(char*)); - break; - } - - return 1; -} - -static int -_groupAddMember(Ubox* box, User* g, char* member) -{ - User *u; - - if((u = _userByUname(box, member)) == nil) - return 0; - if(_groupMember(box, g->uid, u->uname, 0)){ - if(strcmp(g->uname, member) == 0) - vtSetError("uname: '%s' always in own group", member); - else - vtSetError("uname: '%s' already in group '%s'", - member, g->uname); - return 0; - } - - g->group = vtMemRealloc(g->group, (g->ngroup+1)*sizeof(char*)); - g->group[g->ngroup] = vtStrDup(member); - box->len += strlen(member); - g->ngroup++; - if(g->ngroup > 1) - box->len++; - - return 1; -} - -int -groupMember(char* group, char* member) -{ - int r; - - if(group == nil) - return 0; - - vtRLock(ubox.lock); - r = _groupMember(ubox.box, group, member, 0); - vtRUnlock(ubox.lock); - - return r; -} - -int -groupLeader(char* group, char* member) -{ - int r; - User *g; - - /* - * Is 'member' the leader of 'group'? - * Note that 'group' is a 'uid' and not a 'uname'. - * Uname 'none' cannot be a group leader. - */ - if(strcmp(member, unamenone) == 0 || group == nil) - return 0; - - vtRLock(ubox.lock); - if((g = _userByUid(ubox.box, group)) == nil){ - vtRUnlock(ubox.lock); - return 0; - } - if(g->leader != nil){ - if(strcmp(g->leader, member) == 0){ - vtRUnlock(ubox.lock); - return 1; - } - r = 0; - } - else - r = _groupMember(ubox.box, group, member, 0); - vtRUnlock(ubox.lock); - - return r; -} - -static void -userFree(User* u) -{ - int i; - - vtMemFree(u->uid); - vtMemFree(u->uname); - if(u->leader != nil) - vtMemFree(u->leader); - if(u->ngroup){ - for(i = 0; i < u->ngroup; i++) - vtMemFree(u->group[i]); - vtMemFree(u->group); - } - vtMemFree(u); -} - -static User* -userAlloc(char* uid, char* uname) -{ - User *u; - - u = vtMemAllocZ(sizeof(User)); - u->uid = vtStrDup(uid); - u->uname = vtStrDup(uname); - - return u; -} - -int -validUserName(char* name) -{ - Rune *r; - static Rune invalid[] = L"#:,()"; - - for(r = invalid; *r != '\0'; r++){ - if(utfrune(name, *r)) - return 0; - } - return 1; -} - -static int -userFmt(Fmt* fmt) -{ - User *u; - int i, r; - - u = va_arg(fmt->args, User*); - - r = fmtprint(fmt, "%s:%s:", u->uid, u->uname); - if(u->leader != nil) - r += fmtprint(fmt, u->leader); - r += fmtprint(fmt, ":"); - if(u->ngroup){ - r += fmtprint(fmt, u->group[0]); - for(i = 1; i < u->ngroup; i++) - r += fmtprint(fmt, ",%s", u->group[i]); - } - - return r; -} - -static int -usersFileWrite(Ubox* box) -{ - Fs *fs; - User *u; - int i, r; - Fsys *fsys; - char *p, *q, *s; - File *dir, *file; - - if((fsys = fsysGet("main")) == nil) - return 0; - fsysFsRlock(fsys); - fs = fsysGetFs(fsys); - - /* - * BUG: - * the owner/group/permissions need to be thought out. - */ - r = 0; - if((dir = fileOpen(fs, "/active")) == nil) - goto tidy0; - if((file = fileWalk(dir, uidadm)) == nil) - file = fileCreate(dir, uidadm, ModeDir|0775, uidadm); - fileDecRef(dir); - if(file == nil) - goto tidy; - dir = file; - if((file = fileWalk(dir, "users")) == nil) - file = fileCreate(dir, "users", 0664, uidadm); - fileDecRef(dir); - if(file == nil) - goto tidy; - if(!fileTruncate(file, uidadm)) - goto tidy; - - p = s = vtMemAlloc(box->len+1); - q = p + box->len+1; - for(u = box->head; u != nil; u = u->next){ - p += snprint(p, q-p, "%s:%s:", u->uid, u->uname); - if(u->leader != nil) - p+= snprint(p, q-p, u->leader); - p += snprint(p, q-p, ":"); - if(u->ngroup){ - p += snprint(p, q-p, u->group[0]); - for(i = 1; i < u->ngroup; i++) - p += snprint(p, q-p, ",%s", u->group[i]); - } - p += snprint(p, q-p, "\n"); - } - r = fileWrite(file, s, box->len, 0, uidadm); - vtMemFree(s); - -tidy: - if(file != nil) - fileDecRef(file); -tidy0: - fsysFsRUnlock(fsys); - fsysPut(fsys); - - return r; -} - -static void -uboxRemUser(Ubox* box, User *u) -{ - User **h, *up; - - h = &box->ihash[userHash(u->uid)]; - for(up = *h; up != nil && up != u; up = up->ihash) - h = &up->ihash; - assert(up == u); - *h = up->ihash; - box->len -= strlen(u->uid); - - h = &box->nhash[userHash(u->uname)]; - for(up = *h; up != nil && up != u; up = up->nhash) - h = &up->nhash; - assert(up == u); - *h = up->nhash; - box->len -= strlen(u->uname); - - h = &box->head; - for(up = *h; up != nil && strcmp(up->uid, u->uid) != 0; up = up->next) - h = &up->next; - assert(up == u); - *h = u->next; - u->next = nil; - - box->len -= 4; - box->nuser--; -} - -static void -uboxAddUser(Ubox* box, User* u) -{ - User **h, *up; - - h = &box->ihash[userHash(u->uid)]; - u->ihash = *h; - *h = u; - box->len += strlen(u->uid); - - h = &box->nhash[userHash(u->uname)]; - u->nhash = *h; - *h = u; - box->len += strlen(u->uname); - - h = &box->head; - for(up = *h; up != nil && strcmp(up->uid, u->uid) < 0; up = up->next) - h = &up->next; - u->next = *h; - *h = u; - - box->len += 4; - box->nuser++; -} - -static void -uboxDump(Ubox* box) -{ - User* u; - - consPrint("nuser %d len = %d\n", box->nuser, box->len); - - for(u = box->head; u != nil; u = u->next) - consPrint("%U\n", u); -} - -static void -uboxFree(Ubox* box) -{ - User *next, *u; - - for(u = box->head; u != nil; u = next){ - next = u->next; - userFree(u); - } - vtMemFree(box); -} - -static int -uboxInit(char* users, int len) -{ - User *g, *u; - Ubox *box, *obox; - int blank, comment, i, nline, nuser; - char *buf, *f[5], **line, *p, *q, *s; - - /* - * Strip out whitespace and comments. - * Note that comments are pointless, they disappear - * when the server writes the database back out. - */ - blank = 1; - comment = nline = 0; - - s = p = buf = vtMemAlloc(len+1); - for(q = users; *q != '\0'; q++){ - if(*q == '\r' || *q == '\t' || *q == ' ') - continue; - if(*q == '\n'){ - if(!blank){ - if(p != s){ - *p++ = '\n'; - nline++; - s = p; - } - blank = 1; - } - comment = 0; - continue; - } - if(*q == '#') - comment = 1; - blank = 0; - if(!comment) - *p++ = *q; - } - *p = '\0'; - - line = vtMemAllocZ((nline+2)*sizeof(char*)); - if((i = gettokens(buf, line, nline+2, "\n")) != nline){ - fprint(2, "nline %d (%d) botch\n", nline, i); - vtMemFree(line); - vtMemFree(buf); - return 0; - } - - /* - * Everything is updated in a local Ubox until verified. - */ - box = vtMemAllocZ(sizeof(Ubox)); - - /* - * First pass - check format, check for duplicates - * and enter in hash buckets. - */ - nuser = 0; - for(i = 0; i < nline; i++){ - s = vtStrDup(line[i]); - if(getfields(s, f, nelem(f), 0, ":") != 4){ - fprint(2, "bad line '%s'\n", line[i]); - vtMemFree(s); - continue; - } - if(*f[0] == '\0' || *f[1] == '\0'){ - fprint(2, "bad line '%s'\n", line[i]); - vtMemFree(s); - continue; - } - if(!validUserName(f[0])){ - fprint(2, "invalid uid '%s'\n", f[0]); - vtMemFree(s); - continue; - } - if(_userByUid(box, f[0]) != nil){ - fprint(2, "duplicate uid '%s'\n", f[0]); - vtMemFree(s); - continue; - } - if(!validUserName(f[1])){ - fprint(2, "invalid uname '%s'\n", f[0]); - vtMemFree(s); - continue; - } - if(_userByUname(box, f[1]) != nil){ - fprint(2, "duplicate uname '%s'\n", f[1]); - vtMemFree(s); - continue; - } - - u = userAlloc(f[0], f[1]); - uboxAddUser(box, u); - line[nuser] = line[i]; - nuser++; - - vtMemFree(s); - } - assert(box->nuser == nuser); - - /* - * Second pass - fill in leader and group information. - */ - for(i = 0; i < nuser; i++){ - s = vtStrDup(line[i]); - getfields(s, f, nelem(f), 0, ":"); - - assert(g = _userByUname(box, f[1])); - if(*f[2] != '\0'){ - if((u = _userByUname(box, f[2])) == nil) - g->leader = vtStrDup(g->uname); - else - g->leader = vtStrDup(u->uname); - box->len += strlen(g->leader); - } - for(p = f[3]; p != nil; p = q){ - if((q = utfrune(p, L',')) != nil) - *q++ = '\0'; - if(!_groupAddMember(box, g, p)){ - // print/log error here - } - } - - vtMemFree(s); - } - - vtMemFree(line); - vtMemFree(buf); - - for(i = 0; usersMandatory[i] != nil; i++){ - if((u = _userByUid(box, usersMandatory[i])) == nil){ - vtSetError("user '%s' is mandatory", usersMandatory[i]); - uboxFree(box); - return 0; - } - if(strcmp(u->uid, u->uname) != 0){ - vtSetError("uid/uname for user '%s' must match", - usersMandatory[i]); - uboxFree(box); - return 0; - } - } - - vtLock(ubox.lock); - obox = ubox.box; - ubox.box = box; - vtUnlock(ubox.lock); - - if(obox != nil) - uboxFree(obox); - - return 1; -} - -int -usersFileRead(char* path) -{ - char *p; - File *file; - Fsys *fsys; - int len, r; - uvlong size; - - if((fsys = fsysGet("main")) == nil) - return 0; - fsysFsRlock(fsys); - - if(path == nil) - path = "/active/adm/users"; - - r = 0; - if((file = fileOpen(fsysGetFs(fsys), path)) != nil){ - if(fileGetSize(file, &size)){ - len = size; - p = vtMemAlloc(size+1); - if(fileRead(file, p, len, 0) == len){ - p[len] = '\0'; - r = uboxInit(p, len); - } - } - fileDecRef(file); - } - - fsysFsRUnlock(fsys); - fsysPut(fsys); - - return r; -} - -static int -cmdUname(int argc, char* argv[]) -{ - User *u, *up; - int d, dflag, i, r; - char *p, *uid, *uname; - char *createfmt = "fsys main create /active/usr/%s %s %s d775"; - char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]"; - - dflag = 0; - - ARGBEGIN{ - default: - return cliError(usage); - case 'd': - dflag = 1; - break; - }ARGEND - - if(argc < 1){ - if(!dflag) - return cliError(usage); - vtRLock(ubox.lock); - uboxDump(ubox.box); - vtRUnlock(ubox.lock); - return 1; - } - - uname = argv[0]; - argc--; argv++; - - if(argc == 0){ - vtRLock(ubox.lock); - if((u = _userByUname(ubox.box, uname)) == nil){ - vtRUnlock(ubox.lock); - return 0; - } - consPrint("\t%U\n", u); - vtRUnlock(ubox.lock); - return 1; - } - - vtLock(ubox.lock); - u = _userByUname(ubox.box, uname); - while(argc--){ - if(argv[0][0] == '%'){ - if(u == nil){ - vtUnlock(ubox.lock); - return 0; - } - p = &argv[0][1]; - if((up = _userByUname(ubox.box, p)) != nil){ - vtSetError("uname: uname '%s' already exists", - up->uname); - vtUnlock(ubox.lock); - return 0; - } - for(i = 0; usersMandatory[i] != nil; i++){ - if(strcmp(usersMandatory[i], uname) != 0) - continue; - vtSetError("uname: uname '%s' is mandatory", - uname); - vtUnlock(ubox.lock); - return 0; - } - - d = strlen(p) - strlen(u->uname); - for(up = ubox.box->head; up != nil; up = up->next){ - if(up->leader != nil){ - if(strcmp(up->leader, u->uname) == 0){ - vtMemFree(up->leader); - up->leader = vtStrDup(p); - ubox.box->len += d; - } - } - for(i = 0; i < up->ngroup; i++){ - if(strcmp(up->group[i], u->uname) != 0) - continue; - vtMemFree(up->group[i]); - up->group[i] = vtStrDup(p); - ubox.box->len += d; - break; - } - } - - uboxRemUser(ubox.box, u); - vtMemFree(u->uname); - u->uname = vtStrDup(p); - uboxAddUser(ubox.box, u); - } - else if(argv[0][0] == '='){ - if(u == nil){ - vtUnlock(ubox.lock); - return 0; - } - if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ - if(argv[0][1] != '\0'){ - vtUnlock(ubox.lock); - return 0; - } - } - if(u->leader != nil){ - ubox.box->len -= strlen(u->leader); - vtMemFree(u->leader); - u->leader = nil; - } - if(up != nil){ - u->leader = vtStrDup(up->uname); - ubox.box->len += strlen(u->leader); - } - } - else if(argv[0][0] == '+'){ - if(u == nil){ - vtUnlock(ubox.lock); - return 0; - } - if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ - vtUnlock(ubox.lock); - return 0; - } - if(!_groupAddMember(ubox.box, u, up->uname)){ - vtUnlock(ubox.lock); - return 0; - } - } - else if(argv[0][0] == '-'){ - if(u == nil){ - vtUnlock(ubox.lock); - return 0; - } - if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ - vtUnlock(ubox.lock); - return 0; - } - if(!_groupRemMember(ubox.box, u, up->uname)){ - vtUnlock(ubox.lock); - return 0; - } - } - else{ - if(u != nil){ - vtSetError("uname: uname '%s' already exists", - u->uname); - vtUnlock(ubox.lock); - return 0; - } - - uid = argv[0]; - if(*uid == ':') - uid++; - if((u = _userByUid(ubox.box, uid)) != nil){ - vtSetError("uname: uid '%s' already exists", - u->uid); - vtUnlock(ubox.lock); - return 0; - } - - u = userAlloc(uid, uname); - uboxAddUser(ubox.box, u); - if(argv[0][0] != ':'){ - // should have an option for the mode and gid - p = smprint(createfmt, uname, uname, uname); - r = cliExec(p); - vtMemFree(p); - if(r == 0){ - vtUnlock(ubox.lock); - return 0; - } - } - } - argv++; - } - - if(usersFileWrite(ubox.box) == 0){ - vtUnlock(ubox.lock); - return 0; - } - if(dflag) - uboxDump(ubox.box); - vtUnlock(ubox.lock); - - return 1; -} - -static int -cmdUsers(int argc, char* argv[]) -{ - Ubox *box; - int dflag, r, wflag; - char *file; - char *usage = "usage: users [-d | -r file] [-w]"; - - dflag = wflag = 0; - file = nil; - - ARGBEGIN{ - default: - return cliError(usage); - case 'd': - dflag = 1; - break; - case 'r': - file = ARGF(); - if(file == nil) - return cliError(usage); - break; - case 'w': - wflag = 1; - break; - }ARGEND - - if(argc) - return cliError(usage); - - if(dflag && file) - return cliError("cannot use -d and -r together"); - - if(dflag) - uboxInit(usersDefault, sizeof(usersDefault)); - else if(file){ - if(usersFileRead(file) == 0) - return 0; - } - - vtRLock(ubox.lock); - box = ubox.box; - consPrint("\tnuser %d len %d\n", box->nuser, box->len); - - r = 1; - if(wflag) - r = usersFileWrite(box); - vtRUnlock(ubox.lock); - return r; -} - -int -usersInit(void) -{ - fmtinstall('U', userFmt); - - ubox.lock = vtLockAlloc(); - uboxInit(usersDefault, sizeof(usersDefault)); - - cliAddCmd("users", cmdUsers); - cliAddCmd("uname", cmdUname); - - return 1; -} diff --git a/sys/src/cmd/fossil/Ccli.c b/sys/src/cmd/fossil/Ccli.c deleted file mode 100644 index 775cb6206..000000000 --- a/sys/src/cmd/fossil/Ccli.c +++ /dev/null @@ -1,112 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -typedef struct { - char* argv0; - int (*cmd)(int, char*[]); -} Cmd; - -static struct { - VtLock* lock; - Cmd* cmd; - int ncmd; - int hi; -} cbox; - -enum { - NCmdIncr = 20, -}; - -int -cliError(char* fmt, ...) -{ - char *p; - va_list arg; - - va_start(arg, fmt); - p = vsmprint(fmt, arg); - vtSetError("%s", p); - free(p); - va_end(arg); - - return 0; -} - -int -cliExec(char* buf) -{ - int argc, i, r; - char *argv[20], *p; - - p = vtStrDup(buf); - if((argc = tokenize(p, argv, nelem(argv)-1)) == 0){ - vtMemFree(p); - return 1; - } - argv[argc] = 0; - - if(argv[0][0] == '#'){ - vtMemFree(p); - return 1; - } - - vtLock(cbox.lock); - for(i = 0; i < cbox.hi; i++){ - if(strcmp(cbox.cmd[i].argv0, argv[0]) == 0){ - vtUnlock(cbox.lock); - if(!(r = cbox.cmd[i].cmd(argc, argv))) - consPrint("%s\n", vtGetError()); - vtMemFree(p); - return r; - } - } - vtUnlock(cbox.lock); - - consPrint("%s: - eh?\n", argv[0]); - vtMemFree(p); - - return 0; -} - -int -cliAddCmd(char* argv0, int (*cmd)(int, char*[])) -{ - int i; - Cmd *opt; - - vtLock(cbox.lock); - for(i = 0; i < cbox.hi; i++){ - if(strcmp(argv0, cbox.cmd[i].argv0) == 0){ - vtUnlock(cbox.lock); - return 0; - } - } - if(i >= cbox.hi){ - if(cbox.hi >= cbox.ncmd){ - cbox.cmd = vtMemRealloc(cbox.cmd, - (cbox.ncmd+NCmdIncr)*sizeof(Cmd)); - memset(&cbox.cmd[cbox.ncmd], 0, NCmdIncr*sizeof(Cmd)); - cbox.ncmd += NCmdIncr; - } - } - - opt = &cbox.cmd[cbox.hi]; - opt->argv0 = argv0; - opt->cmd = cmd; - cbox.hi++; - vtUnlock(cbox.lock); - - return 1; -} - -int -cliInit(void) -{ - cbox.lock = vtLockAlloc(); - cbox.cmd = vtMemAllocZ(NCmdIncr*sizeof(Cmd)); - cbox.ncmd = NCmdIncr; - cbox.hi = 0; - - return 1; -} diff --git a/sys/src/cmd/fossil/Ccmd.c b/sys/src/cmd/fossil/Ccmd.c deleted file mode 100644 index 806c62fff..000000000 --- a/sys/src/cmd/fossil/Ccmd.c +++ /dev/null @@ -1,459 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -static struct { - VtLock* lock; - - Con* con; - int confd[2]; - ushort tag; -} cbox; - -static ulong -cmd9pStrtoul(char* s) -{ - if(strcmp(s, "~0") == 0) - return ~0UL; - return strtoul(s, 0, 0); -} - -static uvlong -cmd9pStrtoull(char* s) -{ - if(strcmp(s, "~0") == 0) - return ~0ULL; - return strtoull(s, 0, 0); -} - -static int -cmd9pTag(Fcall*, int, char **argv) -{ - cbox.tag = strtoul(argv[0], 0, 0)-1; - - return 1; -} - -static int -cmd9pTwstat(Fcall* f, int, char **argv) -{ - Dir d; - static uchar buf[DIRMAX]; - - memset(&d, 0, sizeof d); - nulldir(&d); - d.name = argv[1]; - d.uid = argv[2]; - d.gid = argv[3]; - d.mode = cmd9pStrtoul(argv[4]); - d.mtime = cmd9pStrtoul(argv[5]); - d.length = cmd9pStrtoull(argv[6]); - - f->fid = strtol(argv[0], 0, 0); - f->stat = buf; - f->nstat = convD2M(&d, buf, sizeof buf); - if(f->nstat < BIT16SZ){ - vtSetError("Twstat: convD2M failed (internal error)"); - return 0; - } - - return 1; -} - -static int -cmd9pTstat(Fcall* f, int, char** argv) -{ - f->fid = strtol(argv[0], 0, 0); - - return 1; -} - -static int -cmd9pTremove(Fcall* f, int, char** argv) -{ - f->fid = strtol(argv[0], 0, 0); - - return 1; -} - -static int -cmd9pTclunk(Fcall* f, int, char** argv) -{ - f->fid = strtol(argv[0], 0, 0); - - return 1; -} - -static int -cmd9pTwrite(Fcall* f, int, char** argv) -{ - f->fid = strtol(argv[0], 0, 0); - f->offset = strtoll(argv[1], 0, 0); - f->data = argv[2]; - f->count = strlen(argv[2]); - - return 1; -} - -static int -cmd9pTread(Fcall* f, int, char** argv) -{ - f->fid = strtol(argv[0], 0, 0); - f->offset = strtoll(argv[1], 0, 0); - f->count = strtol(argv[2], 0, 0); - - return 1; -} - -static int -cmd9pTcreate(Fcall* f, int, char** argv) -{ - f->fid = strtol(argv[0], 0, 0); - f->name = argv[1]; - f->perm = strtol(argv[2], 0, 8); - f->mode = strtol(argv[3], 0, 0); - - return 1; -} - -static int -cmd9pTopen(Fcall* f, int, char** argv) -{ - f->fid = strtol(argv[0], 0, 0); - f->mode = strtol(argv[1], 0, 0); - - return 1; -} - -static int -cmd9pTwalk(Fcall* f, int argc, char** argv) -{ - int i; - - if(argc < 2){ - vtSetError("usage: Twalk tag fid newfid [name...]"); - return 0; - } - f->fid = strtol(argv[0], 0, 0); - f->newfid = strtol(argv[1], 0, 0); - f->nwname = argc-2; - if(f->nwname > MAXWELEM){ - vtSetError("Twalk: too many names"); - return 0; - } - for(i = 0; i < argc-2; i++) - f->wname[i] = argv[2+i]; - - return 1; -} - -static int -cmd9pTflush(Fcall* f, int, char** argv) -{ - f->oldtag = strtol(argv[0], 0, 0); - - return 1; -} - -static int -cmd9pTattach(Fcall* f, int, char** argv) -{ - f->fid = strtol(argv[0], 0, 0); - f->afid = strtol(argv[1], 0, 0); - f->uname = argv[2]; - f->aname = argv[3]; - - return 1; -} - -static int -cmd9pTauth(Fcall* f, int, char** argv) -{ - f->afid = strtol(argv[0], 0, 0); - f->uname = argv[1]; - f->aname = argv[2]; - - return 1; -} - -static int -cmd9pTversion(Fcall* f, int, char** argv) -{ - f->msize = strtoul(argv[0], 0, 0); - if(f->msize > cbox.con->msize){ - vtSetError("msize too big"); - return 0; - } - f->version = argv[1]; - - return 1; -} - -typedef struct Cmd9p Cmd9p; -struct Cmd9p { - char* name; - int type; - int argc; - char* usage; - int (*f)(Fcall*, int, char**); -}; - -static Cmd9p cmd9pTmsg[] = { - "Tversion", Tversion, 2, "msize version", cmd9pTversion, - "Tauth", Tauth, 3, "afid uname aname", cmd9pTauth, - "Tflush", Tflush, 1, "oldtag", cmd9pTflush, - "Tattach", Tattach, 4, "fid afid uname aname", cmd9pTattach, - "Twalk", Twalk, 0, "fid newfid [name...]", cmd9pTwalk, - "Topen", Topen, 2, "fid mode", cmd9pTopen, - "Tcreate", Tcreate, 4, "fid name perm mode", cmd9pTcreate, - "Tread", Tread, 3, "fid offset count", cmd9pTread, - "Twrite", Twrite, 3, "fid offset data", cmd9pTwrite, - "Tclunk", Tclunk, 1, "fid", cmd9pTclunk, - "Tremove", Tremove, 1, "fid", cmd9pTremove, - "Tstat", Tstat, 1, "fid", cmd9pTstat, - "Twstat", Twstat, 7, "fid name uid gid mode mtime length", cmd9pTwstat, - "nexttag", 0, 0, "", cmd9pTag, -}; - -static int -cmd9p(int argc, char* argv[]) -{ - int i, n; - Fcall f, t; - uchar *buf; - char *usage; - u32int msize; - - usage = "usage: 9p T-message ..."; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc < 1) - return cliError(usage); - - for(i = 0; i < nelem(cmd9pTmsg); i++){ - if(strcmp(cmd9pTmsg[i].name, argv[0]) == 0) - break; - } - if(i == nelem(cmd9pTmsg)) - return cliError(usage); - argc--; - argv++; - if(cmd9pTmsg[i].argc && argc != cmd9pTmsg[i].argc){ - vtSetError("usage: %s %s", - cmd9pTmsg[i].name, cmd9pTmsg[i].usage); - return 0; - } - - memset(&t, 0, sizeof(t)); - t.type = cmd9pTmsg[i].type; - if(t.type == Tversion) - t.tag = NOTAG; - else - t.tag = ++cbox.tag; - msize = cbox.con->msize; - if(!cmd9pTmsg[i].f(&t, argc, argv)) - return 0; - buf = vtMemAlloc(msize); - n = convS2M(&t, buf, msize); - if(n <= BIT16SZ){ - vtSetError("%s: convS2M error", cmd9pTmsg[i].name); - vtMemFree(buf); - return 0; - } - if(write(cbox.confd[0], buf, n) != n){ - vtSetError("%s: write error: %r", cmd9pTmsg[i].name); - vtMemFree(buf); - return 0; - } - consPrint("\t-> %F\n", &t); - - if((n = read9pmsg(cbox.confd[0], buf, msize)) <= 0){ - vtSetError("%s: read error: %r", cmd9pTmsg[i].name); - vtMemFree(buf); - return 0; - } - if(convM2S(buf, n, &f) == 0){ - vtSetError("%s: convM2S error", cmd9pTmsg[i].name); - vtMemFree(buf); - return 0; - } - consPrint("\t<- %F\n", &f); - - vtMemFree(buf); - return 1; -} - -static int -cmdDot(int argc, char* argv[]) -{ - long l; - Dir *dir; - int fd, r; - vlong length; - char *f, *p, *s, *usage; - - usage = "usage: . file"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc != 1) - return cliError(usage); - - if((dir = dirstat(argv[0])) == nil) - return cliError(". dirstat %s: %r", argv[0]); - length = dir->length; - free(dir); - - r = 1; - if(length != 0){ - /* - * Read the whole file in. - */ - if((fd = open(argv[0], OREAD)) < 0) - return cliError(". open %s: %r", argv[0]); - f = vtMemAlloc(dir->length+1); - if((l = read(fd, f, length)) < 0){ - vtMemFree(f); - close(fd); - return cliError(". read %s: %r", argv[0]); - } - close(fd); - f[l] = '\0'; - - /* - * Call cliExec() for each line. - */ - for(p = s = f; *p != '\0'; p++){ - if(*p == '\n'){ - *p = '\0'; - if(cliExec(s) == 0){ - r = 0; - consPrint("%s: %R\n", s); - } - s = p+1; - } - } - vtMemFree(f); - } - - if(r == 0) - vtSetError("errors in . %#q", argv[0]); - return r; -} - -static int -cmdDflag(int argc, char* argv[]) -{ - char *usage; - - usage = "usage: dflag"; - - ARGBEGIN{ - default: - return cliError(usage); - }ARGEND - if(argc) - return cliError(usage); - - Dflag ^= 1; - consPrint("dflag %d\n", Dflag); - - return 1; -} - -static int -cmdEcho(int argc, char* argv[]) -{ - char *usage; - int i, nflag; - - nflag = 0; - usage = "usage: echo [-n] ..."; - - ARGBEGIN{ - default: - return cliError(usage); - case 'n': - nflag = 1; - break; - }ARGEND - - for(i = 0; i < argc; i++){ - if(i != 0) - consPrint(" %s", argv[i]); - else - consPrint(argv[i]); - } - if(!nflag) - consPrint("\n"); - - return 1; -} - -static int -cmdBind(int argc, char* argv[]) -{ - ulong flag = 0; - char *usage; - - usage = "usage: bind [-b|-a|-c|-bc|-ac] new old"; - - ARGBEGIN{ - case 'a': - flag |= MAFTER; - break; - case 'b': - flag |= MBEFORE; - break; - case 'c': - flag |= MCREATE; - break; - default: - return cliError(usage); - }ARGEND - - if(argc != 2 || (flag&MAFTER)&&(flag&MBEFORE)) - return cliError(usage); - - if(bind(argv[0], argv[1], flag) < 0){ - /* try to give a less confusing error than the default */ - if(access(argv[0], 0) < 0) - return cliError("bind: %s: %r", argv[0]); - else if(access(argv[1], 0) < 0) - return cliError("bind: %s: %r", argv[1]); - else - return cliError("bind %s %s: %r", argv[0], argv[1]); - } - return 1; -} - -int -cmdInit(void) -{ - cbox.lock = vtLockAlloc(); - cbox.confd[0] = cbox.confd[1] = -1; - - cliAddCmd(".", cmdDot); - cliAddCmd("9p", cmd9p); - cliAddCmd("dflag", cmdDflag); - cliAddCmd("echo", cmdEcho); - cliAddCmd("bind", cmdBind); - - if(pipe(cbox.confd) < 0) - return 0; - if((cbox.con = conAlloc(cbox.confd[1], "console", 0)) == nil){ - close(cbox.confd[0]); - close(cbox.confd[1]); - cbox.confd[0] = cbox.confd[1] = -1; - return 0; - - } - cbox.con->isconsole = 1; - - return 1; -} diff --git a/sys/src/cmd/fossil/Ccons.c b/sys/src/cmd/fossil/Ccons.c deleted file mode 100644 index 65b9a4098..000000000 --- a/sys/src/cmd/fossil/Ccons.c +++ /dev/null @@ -1,398 +0,0 @@ -#include "stdinc.h" - -#include "9.h" - -enum { - Nl = 256, /* max. command line length */ - Nq = 8*1024, /* amount of I/O buffered */ -}; - -typedef struct Q { - VtLock* lock; - VtRendez* full; - VtRendez* empty; - - char q[Nq]; - int n; - int r; - int w; -} Q; - -typedef struct Cons { - VtLock* lock; - int ref; - int closed; - int fd; - int srvfd; - int ctlfd; - Q* iq; /* points to console.iq */ - Q* oq; /* points to console.oq */ -} Cons; - -char *currfsysname; - -static struct { - Q* iq; /* input */ - Q* oq; /* output */ - char l[Nl]; /* command line assembly */ - int nl; /* current line length */ - int nopens; - - char* prompt; - int np; -} console; - -static void -consClose(Cons* cons) -{ - vtLock(cons->lock); - cons->closed = 1; - - cons->ref--; - if(cons->ref > 0){ - vtLock(cons->iq->lock); - vtWakeup(cons->iq->full); - vtUnlock(cons->iq->lock); - vtLock(cons->oq->lock); - vtWakeup(cons->oq->empty); - vtUnlock(cons->oq->lock); - vtUnlock(cons->lock); - return; - } - - if(cons->ctlfd != -1){ - close(cons->ctlfd); - cons->srvfd = -1; - } - if(cons->srvfd != -1){ - close(cons->srvfd); - cons->srvfd = -1; - } - if(cons->fd != -1){ - close(cons->fd); - cons->fd = -1; - } - vtUnlock(cons->lock); - vtLockFree(cons->lock); - vtMemFree(cons); - console.nopens--; -} - -static void -consIProc(void* v) -{ - Q *q; - Cons *cons; - int n, w; - char buf[Nq/4]; - - vtThreadSetName("consI"); - - cons = v; - q = cons->iq; - for(;;){ - /* - * Can't tell the difference between zero-length read - * and eof, so keep calling read until we get an error. - */ - if(cons->closed || (n = read(cons->fd, buf, Nq/4)) < 0) - break; - vtLock(q->lock); - while(Nq - q->n < n && !cons->closed) - vtSleep(q->full); - w = Nq - q->w; - if(w < n){ - memmove(&q->q[q->w], buf, w); - memmove(&q->q[0], buf + w, n - w); - } - else - memmove(&q->q[q->w], buf, n); - q->w = (q->w + n) % Nq; - q->n += n; - vtWakeup(q->empty); - vtUnlock(q->lock); - } - consClose(cons); -} - -static void -consOProc(void* v) -{ - Q *q; - Cons *cons; - char buf[Nq]; - int lastn, n, r; - - vtThreadSetName("consO"); - - cons = v; - q = cons->oq; - vtLock(q->lock); - lastn = 0; - for(;;){ - while(lastn == q->n && !cons->closed) - vtSleep(q->empty); - if((n = q->n - lastn) > Nq) - n = Nq; - if(n > q->w){ - r = n - q->w; - memmove(buf, &q->q[Nq - r], r); - memmove(buf+r, &q->q[0], n - r); - } - else - memmove(buf, &q->q[q->w - n], n); - lastn = q->n; - vtUnlock(q->lock); - if(cons->closed || write(cons->fd, buf, n) < 0) - break; - vtLock(q->lock); - vtWakeup(q->empty); - } - consClose(cons); -} - -int -consOpen(int fd, int srvfd, int ctlfd) -{ - Cons *cons; - - cons = vtMemAllocZ(sizeof(Cons)); - cons->lock = vtLockAlloc(); - cons->fd = fd; - cons->srvfd = srvfd; - cons->ctlfd = ctlfd; - cons->iq = console.iq; - cons->oq = console.oq; - console.nopens++; - - vtLock(cons->lock); - cons->ref = 2; - cons->closed = 0; - if(vtThread(consOProc, cons) < 0){ - cons->ref--; - vtUnlock(cons->lock); - consClose(cons); - return 0; - } - vtUnlock(cons->lock); - - if(ctlfd >= 0) - consIProc(cons); - else if(vtThread(consIProc, cons) < 0){ - consClose(cons); - return 0; - } - - return 1; -} - -static int -qWrite(Q* q, char* p, int n) -{ - int w; - - vtLock(q->lock); - if(n > Nq - q->w){ - w = Nq - q->w; - memmove(&q->q[q->w], p, w); - memmove(&q->q[0], p + w, n - w); - q->w = n - w; - } - else{ - memmove(&q->q[q->w], p, n); - q->w += n; - } - q->n += n; - vtWakeup(q->empty); - vtUnlock(q->lock); - - return n; -} - -static Q* -qAlloc(void) -{ - Q *q; - - q = vtMemAllocZ(sizeof(Q)); - q->lock = vtLockAlloc(); - q->full = vtRendezAlloc(q->lock); - q->empty = vtRendezAlloc(q->lock); - q->n = q->r = q->w = 0; - - return q; -} - -static void -consProc(void*) -{ - Q *q; - int argc, i, n, r; - char *argv[20], buf[Nq], *lp, *wbuf; - char procname[64]; - - snprint(procname, sizeof procname, "cons %s", currfsysname); - vtThreadSetName(procname); - - q = console.iq; - qWrite(console.oq, console.prompt, console.np); - vtLock(q->lock); - for(;;){ - while((n = q->n) == 0) - vtSleep(q->empty); - r = Nq - q->r; - if(r < n){ - memmove(buf, &q->q[q->r], r); - memmove(buf + r, &q->q[0], n - r); - } - else - memmove(buf, &q->q[q->r], n); - q->r = (q->r + n) % Nq; - q->n -= n; - vtWakeup(q->full); - vtUnlock(q->lock); - - for(i = 0; i < n; i++){ - switch(buf[i]){ - case '\004': /* ^D */ - if(console.nl == 0){ - qWrite(console.oq, "\n", 1); - break; - } - /*FALLTHROUGH*/ - default: - if(console.nl < Nl-1){ - qWrite(console.oq, &buf[i], 1); - console.l[console.nl++] = buf[i]; - } - continue; - case '\b': - if(console.nl != 0){ - qWrite(console.oq, &buf[i], 1); - console.nl--; - } - continue; - case '\n': - qWrite(console.oq, &buf[i], 1); - break; - case '\025': /* ^U */ - qWrite(console.oq, "^U\n", 3); - console.nl = 0; - break; - case '\027': /* ^W */ - console.l[console.nl] = '\0'; - wbuf = vtMemAlloc(console.nl+1); - memmove(wbuf, console.l, console.nl+1); - argc = tokenize(wbuf, argv, nelem(argv)); - if(argc > 0) - argc--; - console.nl = 0; - lp = console.l; - for(i = 0; i < argc; i++) - lp += sprint(lp, "%q ", argv[i]); - console.nl = lp - console.l; - vtMemFree(wbuf); - qWrite(console.oq, "^W\n", 3); - if(console.nl == 0) - break; - qWrite(console.oq, console.l, console.nl); - continue; - case '\177': - qWrite(console.oq, "\n", 1); - console.nl = 0; - break; - } - - console.l[console.nl] = '\0'; - if(console.nl != 0) - cliExec(console.l); - - console.nl = 0; - qWrite(console.oq, console.prompt, console.np); - } - - vtLock(q->lock); - } -} - -int -consWrite(char* buf, int len) -{ - if(console.oq == nil) - return write(2, buf, len); - if(console.nopens == 0) - write(2, buf, len); - return qWrite(console.oq, buf, len); -} - -int -consPrompt(char* prompt) -{ - char buf[ERRMAX]; - - if(prompt == nil) - prompt = "prompt"; - - vtMemFree(console.prompt); - console.np = snprint(buf, sizeof(buf), "%s: ", prompt); - console.prompt = vtStrDup(buf); - - return console.np; -} - -int -consTTY(void) -{ - int ctl, fd; - char *name, *p; - - name = "/dev/cons"; - if((fd = open(name, ORDWR)) < 0){ - name = "#c/cons"; - if((fd = open(name, ORDWR)) < 0){ - vtSetError("consTTY: open %s: %r", name); - return 0; - } - } - - p = smprint("%sctl", name); - if((ctl = open(p, OWRITE)) < 0){ - close(fd); - vtSetError("consTTY: open %s: %r", p); - free(p); - return 0; - } - if(write(ctl, "rawon", 5) < 0){ - close(ctl); - close(fd); - vtSetError("consTTY: write %s: %r", p); - free(p); - return 0; - } - free(p); - - if(consOpen(fd, fd, ctl) == 0){ - close(ctl); - close(fd); - return 0; - } - - return 1; -} - -int -consInit(void) -{ - console.iq = qAlloc(); - console.oq = qAlloc(); - console.nl = 0; - - consPrompt(nil); - - if(vtThread(consProc, nil) < 0){ - vtFatal("can't start console proc"); - return 0; - } - - return 1; -} diff --git a/sys/src/cmd/fossil/Clog.c b/sys/src/cmd/fossil/Clog.c deleted file mode 100644 index 957553453..000000000 --- a/sys/src/cmd/fossil/Clog.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "stdinc.h" -#include "9.h" - -/* - * To do: This will become something else ('vprint'?). - */ -int -consVPrint(char* fmt, va_list args) -{ - int len, ret; - char buf[256]; - - len = vsnprint(buf, sizeof(buf), fmt, args); - ret = consWrite(buf, len); - - while (len-- > 0 && buf[len] == '\n') - buf[len] = '\0'; - /* - * if we do this, checking the root fossil (if /sys/log/fossil is there) - * will spew all over the console. - */ - if (0) - syslog(0, "fossil", "%s", buf); - return ret; -} - -/* - * To do: This will become 'print'. - */ -int -consPrint(char* fmt, ...) -{ - int ret; - va_list args; - - va_start(args, fmt); - ret = consVPrint(fmt, args); - va_end(args); - return ret; -} diff --git a/sys/src/cmd/fossil/archive.c b/sys/src/cmd/fossil/archive.c deleted file mode 100644 index fc09e7195..000000000 --- a/sys/src/cmd/fossil/archive.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Archiver. In charge of sending blocks to Venti. - */ - -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -#include "9.h" /* for consPrint */ - -#define DEBUG 0 - -static void archThread(void*); - -struct Arch -{ - int ref; - uint blockSize; - uint diskSize; - Cache *c; - Fs *fs; - VtSession *z; - - VtLock *lk; - VtRendez *starve; - VtRendez *die; -}; - -Arch * -archInit(Cache *c, Disk *disk, Fs *fs, VtSession *z) -{ - Arch *a; - - a = vtMemAllocZ(sizeof(Arch)); - - a->c = c; - a->z = z; - a->fs = fs; - a->blockSize = diskBlockSize(disk); - a->lk = vtLockAlloc(); - a->starve = vtRendezAlloc(a->lk); - - a->ref = 2; - vtThread(archThread, a); - - return a; -} - -void -archFree(Arch *a) -{ - /* kill slave */ - vtLock(a->lk); - a->die = vtRendezAlloc(a->lk); - vtWakeup(a->starve); - while(a->ref > 1) - vtSleep(a->die); - vtUnlock(a->lk); - vtRendezFree(a->starve); - vtRendezFree(a->die); - vtLockFree(a->lk); - vtMemFree(a); -} - -static int -ventiSend(Arch *a, Block *b, uchar *data) -{ - uint n; - uchar score[VtScoreSize]; - - if(DEBUG > 1) - fprint(2, "ventiSend: sending %#ux %L to venti\n", b->addr, &b->l); - n = vtZeroTruncate(vtType[b->l.type], data, a->blockSize); - if(DEBUG > 1) - fprint(2, "ventiSend: truncate %d to %d\n", a->blockSize, n); - if(!vtWrite(a->z, score, vtType[b->l.type], data, n)){ - fprint(2, "ventiSend: vtWrite block %#ux failed: %R\n", b->addr); - return 0; - } - if(!vtSha1Check(score, data, n)){ - uchar score2[VtScoreSize]; - vtSha1(score2, data, n); - fprint(2, "ventiSend: vtWrite block %#ux failed vtSha1Check %V %V\n", - b->addr, score, score2); - return 0; - } - if(!vtSync(a->z)) - return 0; - return 1; -} - -/* - * parameters for recursion; there are so many, - * and some only change occasionally. this is - * easier than spelling things out at each call. - */ -typedef struct Param Param; -struct Param -{ - /* these never change */ - uint snapEpoch; /* epoch for snapshot being archived */ - uint blockSize; - Cache *c; - Arch *a; - - /* changes on every call */ - uint depth; - - /* statistics */ - uint nfixed; - uint nsend; - uint nvisit; - uint nfailsend; - uint maxdepth; - uint nreclaim; - uint nfake; - uint nreal; - - /* these occasionally change (must save old values and put back) */ - uint dsize; - uint psize; - - /* return value; avoids using stack space */ - Label l; - uchar score[VtScoreSize]; -}; - -static void -shaBlock(uchar score[VtScoreSize], Block *b, uchar *data, uint bsize) -{ - vtSha1(score, data, vtZeroTruncate(vtType[b->l.type], data, bsize)); -} - -static uint -etype(Entry *e) -{ - uint t; - - if(e->flags&VtEntryDir) - t = BtDir; - else - t = BtData; - return t+e->depth; -} - -static uchar* -copyBlock(Block *b, u32int blockSize) -{ - uchar *data; - - data = vtMemAlloc(blockSize); - if(data == nil) - return nil; - memmove(data, b->data, blockSize); - return data; -} - -/* - * Walk over the block tree, archiving it to Venti. - * - * We don't archive the snapshots. Instead we zero the - * entries in a temporary copy of the block and archive that. - * - * Return value is: - * - * ArchFailure some error occurred - * ArchSuccess block and all children archived - * ArchFaked success, but block or children got copied - */ -enum -{ - ArchFailure, - ArchSuccess, - ArchFaked, -}; -static int -archWalk(Param *p, u32int addr, uchar type, u32int tag) -{ - int ret, i, x, psize, dsize; - uchar *data, score[VtScoreSize]; - Block *b; - Label l; - Entry *e; - WalkPtr w; - - p->nvisit++; - - b = cacheLocalData(p->c, addr, type, tag, OReadWrite,0); - if(b == nil){ - fprint(2, "archive(%ud, %#ux): cannot find block: %R\n", p->snapEpoch, addr); - if(strcmp(vtGetError(), ELabelMismatch) == 0){ - /* might as well plod on so we write _something_ to Venti */ - memmove(p->score, vtZeroScore, VtScoreSize); - return ArchFaked; - } - return ArchFailure; - } - - if(DEBUG) fprint(2, "%*sarchive(%ud, %#ux): block label %L\n", - p->depth*2, "", p->snapEpoch, b->addr, &b->l); - p->depth++; - if(p->depth > p->maxdepth) - p->maxdepth = p->depth; - - data = b->data; - if((b->l.state&BsVenti) == 0){ - initWalk(&w, b, b->l.type==BtDir ? p->dsize : p->psize); - for(i=0; nextWalk(&w, score, &type, &tag, &e); i++){ - if(e){ - if(!(e->flags&VtEntryActive)) - continue; - if((e->snap && !e->archive) - || (e->flags&VtEntryNoArchive)){ - if(0) fprint(2, "snap; faking %#ux\n", b->addr); - if(data == b->data){ - data = copyBlock(b, p->blockSize); - if(data == nil){ - ret = ArchFailure; - goto Out; - } - w.data = data; - } - memmove(e->score, vtZeroScore, VtScoreSize); - e->depth = 0; - e->size = 0; - e->tag = 0; - e->flags &= ~VtEntryLocal; - entryPack(e, data, w.n-1); - continue; - } - } - addr = globalToLocal(score); - if(addr == NilBlock) - continue; - dsize = p->dsize; - psize = p->psize; - if(e){ - p->dsize= e->dsize; - p->psize = e->psize; - } - vtUnlock(b->lk); - x = archWalk(p, addr, type, tag); - vtLock(b->lk); - if(e){ - p->dsize = dsize; - p->psize = psize; - } - while(b->iostate != BioClean && b->iostate != BioDirty) - vtSleep(b->ioready); - switch(x){ - case ArchFailure: - fprint(2, "archWalk %#ux failed; ptr is in %#ux offset %d\n", - addr, b->addr, i); - ret = ArchFailure; - goto Out; - case ArchFaked: - /* - * When we're writing the entry for an archive directory - * (like /archive/2003/1215) then even if we've faked - * any data, record the score unconditionally. - * This way, we will always record the Venti score here. - * Otherwise, temporary data or corrupted file system - * would cause us to keep holding onto the on-disk - * copy of the archive. - */ - if(e==nil || !e->archive) - if(data == b->data){ -if(0) fprint(2, "faked %#ux, faking %#ux (%V)\n", addr, b->addr, p->score); - data = copyBlock(b, p->blockSize); - if(data == nil){ - ret = ArchFailure; - goto Out; - } - w.data = data; - } - /* fall through */ -if(0) fprint(2, "falling\n"); - case ArchSuccess: - if(e){ - memmove(e->score, p->score, VtScoreSize); - e->flags &= ~VtEntryLocal; - entryPack(e, data, w.n-1); - }else - memmove(data+(w.n-1)*VtScoreSize, p->score, VtScoreSize); - if(data == b->data){ - blockDirty(b); - /* - * If b is in the active tree, then we need to note that we've - * just removed addr from the active tree (replacing it with the - * copy we just stored to Venti). If addr is in other snapshots, - * this will close addr but not free it, since it has a non-empty - * epoch range. - * - * If b is in the active tree but has been copied (this can happen - * if we get killed at just the right moment), then we will - * mistakenly leak its kids. - * - * The children of an archive directory (e.g., /archive/2004/0604) - * are not treated as in the active tree. - */ - if((b->l.state&BsCopied)==0 && (e==nil || e->snap==0)) - blockRemoveLink(b, addr, p->l.type, p->l.tag, 0); - } - break; - } - } - - if(!ventiSend(p->a, b, data)){ - p->nfailsend++; - ret = ArchFailure; - goto Out; - } - p->nsend++; - if(data != b->data) - p->nfake++; - if(data == b->data){ /* not faking it, so update state */ - p->nreal++; - l = b->l; - l.state |= BsVenti; - if(!blockSetLabel(b, &l, 0)){ - ret = ArchFailure; - goto Out; - } - } - } - - shaBlock(p->score, b, data, p->blockSize); -if(0) fprint(2, "ventisend %V %p %p %p\n", p->score, data, b->data, w.data); - ret = data!=b->data ? ArchFaked : ArchSuccess; - p->l = b->l; -Out: - if(data != b->data) - vtMemFree(data); - p->depth--; - blockPut(b); - return ret; -} - -static void -archThread(void *v) -{ - Arch *a = v; - Block *b; - Param p; - Super super; - int ret; - u32int addr; - uchar rbuf[VtRootSize]; - VtRoot root; - - vtThreadSetName("arch"); - - for(;;){ - /* look for work */ - vtLock(a->fs->elk); - b = superGet(a->c, &super); - if(b == nil){ - vtUnlock(a->fs->elk); - fprint(2, "archThread: superGet: %R\n"); - sleep(60*1000); - continue; - } - addr = super.next; - if(addr != NilBlock && super.current == NilBlock){ - super.current = addr; - super.next = NilBlock; - superPack(&super, b->data); - blockDirty(b); - }else - addr = super.current; - blockPut(b); - vtUnlock(a->fs->elk); - - if(addr == NilBlock){ - /* wait for work */ - vtLock(a->lk); - vtSleep(a->starve); - if(a->die != nil) - goto Done; - vtUnlock(a->lk); - continue; - } - -sleep(10*1000); /* window of opportunity to provoke races */ - - /* do work */ - memset(&p, 0, sizeof p); - p.blockSize = a->blockSize; - p.dsize = 3*VtEntrySize; /* root has three Entries */ - p.c = a->c; - p.a = a; - - ret = archWalk(&p, addr, BtDir, RootTag); - switch(ret){ - default: - abort(); - case ArchFailure: - fprint(2, "archiveBlock %#ux: %R\n", addr); - sleep(60*1000); - continue; - case ArchSuccess: - case ArchFaked: - break; - } - - if(0) fprint(2, "archiveSnapshot 0x%#ux: maxdepth %ud nfixed %ud" - " send %ud nfailsend %ud nvisit %ud" - " nreclaim %ud nfake %ud nreal %ud\n", - addr, p.maxdepth, p.nfixed, - p.nsend, p.nfailsend, p.nvisit, - p.nreclaim, p.nfake, p.nreal); - if(0) fprint(2, "archiveBlock %V (%ud)\n", p.score, p.blockSize); - - /* tie up vac root */ - memset(&root, 0, sizeof root); - root.version = VtRootVersion; - strecpy(root.type, root.type+sizeof root.type, "vac"); - strecpy(root.name, root.name+sizeof root.name, "fossil"); - memmove(root.score, p.score, VtScoreSize); - memmove(root.prev, super.last, VtScoreSize); - root.blockSize = a->blockSize; - vtRootPack(&root, rbuf); - if(!vtWrite(a->z, p.score, VtRootType, rbuf, VtRootSize) - || !vtSha1Check(p.score, rbuf, VtRootSize)){ - fprint(2, "vtWriteBlock %#ux: %R\n", addr); - sleep(60*1000); - continue; - } - - /* record success */ - vtLock(a->fs->elk); - b = superGet(a->c, &super); - if(b == nil){ - vtUnlock(a->fs->elk); - fprint(2, "archThread: superGet: %R\n"); - sleep(60*1000); - continue; - } - super.current = NilBlock; - memmove(super.last, p.score, VtScoreSize); - superPack(&super, b->data); - blockDirty(b); - blockPut(b); - vtUnlock(a->fs->elk); - - consPrint("archive vac:%V\n", p.score); - } - -Done: - a->ref--; - vtWakeup(a->die); - vtUnlock(a->lk); -} - -void -archKick(Arch *a) -{ - if(a == nil){ - fprint(2, "warning: archKick nil\n"); - return; - } - vtLock(a->lk); - vtWakeup(a->starve); - vtUnlock(a->lk); -} diff --git a/sys/src/cmd/fossil/build b/sys/src/cmd/fossil/build deleted file mode 100644 index a1b7d3f70..000000000 --- a/sys/src/cmd/fossil/build +++ /dev/null @@ -1,19 +0,0 @@ -# once that works, this script from /usr/rob/dist/buildnotes -# should build. note it cross-builds for a different arch -# because you can't overwrite running binaries safely. - -NPROC=8 -fileserver=emelie -objtype=386 -cd /sys/src/ape -mk install # so awk can be cross-compiled (needs to run pcc for maketab) -cd /sys/src/cmd/vc -mk install -cd /sys/src/cmd/vl -mk install -cd /sys/src/cmd/va -mk install -mkdir /mips/bin/usb -objtype=mips -cd /sys/src -mk install diff --git a/sys/src/cmd/fossil/buildsh b/sys/src/cmd/fossil/buildsh deleted file mode 100644 index 56c3eadc9..000000000 --- a/sys/src/cmd/fossil/buildsh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/rc - -rfork en -9fs ehime - -# adapted from /lib/namespace - -root = /n/ehime/testplan9 -#root = /n/emelieother/seanq/testplan9 -echo setting up $root -fn bind{ - /$cputype/bin/bind $* -} - -# pass terminal through -bind /mnt/term $root/mnt/term -# root -bind $root / -bind -b '#/' / - -# kernel devices -bind '#c' /dev -bind '#d' /fd -bind -c '#e' /env -bind '#p' /proc -bind -c '#s' /srv -bind -a /mnt/term/dev/ /dev/ -bind /mnt/term/dev/draw /dev/draw - -# standard bin -bind /$cputype/bin /bin -bind -a /rc/bin /bin - -# ramfs -cd /sys/src -prompt=('test-ehime=; ' ' ') -fn cd -rc -i - - diff --git a/sys/src/cmd/fossil/bwatch.c b/sys/src/cmd/fossil/bwatch.c deleted file mode 100644 index 51deb762f..000000000 --- a/sys/src/cmd/fossil/bwatch.c +++ /dev/null @@ -1,421 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -/* - * Lock watcher. Check that locking of blocks is always down. - * - * This is REALLY slow, and it won't work when the blocks aren't - * arranged in a tree (e.g., after the first snapshot). But it's great - * for debugging. - */ -enum -{ - MaxLock = 16, - HashSize = 1009, -}; - -/* - * Thread-specific watch state. - */ -typedef struct WThread WThread; -struct WThread -{ - Block *b[MaxLock]; /* blocks currently held */ - uint nb; - uint pid; -}; - -typedef struct WMap WMap; -typedef struct WEntry WEntry; - -struct WEntry -{ - uchar c[VtScoreSize]; - uchar p[VtScoreSize]; - int off; - - WEntry *cprev; - WEntry *cnext; - WEntry *pprev; - WEntry *pnext; -}; - -struct WMap -{ - VtLock *lk; - - WEntry *hchild[HashSize]; - WEntry *hparent[HashSize]; -}; - -static WMap map; -static void **wp; -static uint blockSize; -static WEntry *pool; -uint bwatchDisabled; - -static uint -hash(uchar score[VtScoreSize]) -{ - uint i, h; - - h = 0; - for(i=0; i<VtScoreSize; i++) - h = h*37 + score[i]; - return h%HashSize; -} - -#include <pool.h> -static void -freeWEntry(WEntry *e) -{ - memset(e, 0, sizeof(WEntry)); - e->pnext = pool; - pool = e; -} - -static WEntry* -allocWEntry(void) -{ - int i; - WEntry *w; - - w = pool; - if(w == nil){ - w = vtMemAllocZ(1024*sizeof(WEntry)); - for(i=0; i<1024; i++) - freeWEntry(&w[i]); - w = pool; - } - pool = w->pnext; - memset(w, 0, sizeof(WEntry)); - return w; -} - -/* - * remove all dependencies with score as a parent - */ -static void -_bwatchResetParent(uchar *score) -{ - WEntry *w, *next; - uint h; - - h = hash(score); - for(w=map.hparent[h]; w; w=next){ - next = w->pnext; - if(memcmp(w->p, score, VtScoreSize) == 0){ - if(w->pnext) - w->pnext->pprev = w->pprev; - if(w->pprev) - w->pprev->pnext = w->pnext; - else - map.hparent[h] = w->pnext; - if(w->cnext) - w->cnext->cprev = w->cprev; - if(w->cprev) - w->cprev->cnext = w->cnext; - else - map.hchild[hash(w->c)] = w->cnext; - freeWEntry(w); - } - } -} -/* - * and child - */ -static void -_bwatchResetChild(uchar *score) -{ - WEntry *w, *next; - uint h; - - h = hash(score); - for(w=map.hchild[h]; w; w=next){ - next = w->cnext; - if(memcmp(w->c, score, VtScoreSize) == 0){ - if(w->pnext) - w->pnext->pprev = w->pprev; - if(w->pprev) - w->pprev->pnext = w->pnext; - else - map.hparent[hash(w->p)] = w->pnext; - if(w->cnext) - w->cnext->cprev = w->cprev; - if(w->cprev) - w->cprev->cnext = w->cnext; - else - map.hchild[h] = w->cnext; - freeWEntry(w); - } - } -} - -static uchar* -parent(uchar c[VtScoreSize], int *off) -{ - WEntry *w; - uint h; - - h = hash(c); - for(w=map.hchild[h]; w; w=w->cnext) - if(memcmp(w->c, c, VtScoreSize) == 0){ - *off = w->off; - return w->p; - } - return nil; -} - -static void -addChild(uchar p[VtEntrySize], uchar c[VtEntrySize], int off) -{ - uint h; - WEntry *w; - - w = allocWEntry(); - memmove(w->p, p, VtScoreSize); - memmove(w->c, c, VtScoreSize); - w->off = off; - - h = hash(p); - w->pnext = map.hparent[h]; - if(w->pnext) - w->pnext->pprev = w; - map.hparent[h] = w; - - h = hash(c); - w->cnext = map.hchild[h]; - if(w->cnext) - w->cnext->cprev = w; - map.hchild[h] = w; -} - -void -bwatchReset(uchar score[VtScoreSize]) -{ - vtLock(map.lk); - _bwatchResetParent(score); - _bwatchResetChild(score); - vtUnlock(map.lk); -} - -void -bwatchInit(void) -{ - map.lk = vtLockAlloc(); - wp = privalloc(); - *wp = nil; -} - -void -bwatchSetBlockSize(uint bs) -{ - blockSize = bs; -} - -static WThread* -getWThread(void) -{ - WThread *w; - - w = *wp; - if(w == nil || w->pid != getpid()){ - w = vtMemAllocZ(sizeof(WThread)); - *wp = w; - w->pid = getpid(); - } - return w; -} - -/* - * Derive dependencies from the contents of b. - */ -void -bwatchDependency(Block *b) -{ - int i, epb, ppb; - Entry e; - - if(bwatchDisabled) - return; - - vtLock(map.lk); - _bwatchResetParent(b->score); - - switch(b->l.type){ - case BtData: - break; - - case BtDir: - epb = blockSize / VtEntrySize; - for(i=0; i<epb; i++){ - entryUnpack(&e, b->data, i); - if(!(e.flags & VtEntryActive)) - continue; - addChild(b->score, e.score, i); - } - break; - - default: - ppb = blockSize / VtScoreSize; - for(i=0; i<ppb; i++) - addChild(b->score, b->data+i*VtScoreSize, i); - break; - } - vtUnlock(map.lk); -} - -static int -depth(uchar *s) -{ - int d, x; - - d = -1; - while(s){ - d++; - s = parent(s, &x); - } - return d; -} - -static int -lockConflicts(uchar xhave[VtScoreSize], uchar xwant[VtScoreSize]) -{ - uchar *have, *want; - int havedepth, wantdepth, havepos, wantpos; - - have = xhave; - want = xwant; - - havedepth = depth(have); - wantdepth = depth(want); - - /* - * walk one or the other up until they're both - * at the same level. - */ - havepos = -1; - wantpos = -1; - have = xhave; - want = xwant; - while(wantdepth > havedepth){ - wantdepth--; - want = parent(want, &wantpos); - } - while(havedepth > wantdepth){ - havedepth--; - have = parent(have, &havepos); - } - - /* - * walk them up simultaneously until we reach - * a common ancestor. - */ - while(have && want && memcmp(have, want, VtScoreSize) != 0){ - have = parent(have, &havepos); - want = parent(want, &wantpos); - } - - /* - * not part of same tree. happens mainly with - * newly allocated blocks. - */ - if(!have || !want) - return 0; - - /* - * never walked want: means we want to lock - * an ancestor of have. no no. - */ - if(wantpos == -1) - return 1; - - /* - * never walked have: means we want to lock a - * child of have. that's okay. - */ - if(havepos == -1) - return 0; - - /* - * walked both: they're from different places in the tree. - * require that the left one be locked before the right one. - * (this is questionable, but it puts a total order on the block tree). - */ - return havepos < wantpos; -} - -static void -stop(void) -{ - int fd; - char buf[32]; - - snprint(buf, sizeof buf, "#p/%d/ctl", getpid()); - fd = open(buf, OWRITE); - write(fd, "stop", 4); - close(fd); -} - -/* - * Check whether the calling thread can validly lock b. - * That is, check that the calling thread doesn't hold - * locks for any of b's children. - */ -void -bwatchLock(Block *b) -{ - int i; - WThread *w; - - if(bwatchDisabled) - return; - - if(b->part != PartData) - return; - - vtLock(map.lk); - w = getWThread(); - for(i=0; i<w->nb; i++){ - if(lockConflicts(w->b[i]->score, b->score)){ - fprint(2, "%d: have block %V; shouldn't lock %V\n", - w->pid, w->b[i]->score, b->score); - stop(); - } - } - vtUnlock(map.lk); - if(w->nb >= MaxLock){ - fprint(2, "%d: too many blocks held\n", w->pid); - stop(); - }else - w->b[w->nb++] = b; -} - -/* - * Note that the calling thread is about to unlock b. - */ -void -bwatchUnlock(Block *b) -{ - int i; - WThread *w; - - if(bwatchDisabled) - return; - - if(b->part != PartData) - return; - - w = getWThread(); - for(i=0; i<w->nb; i++) - if(w->b[i] == b) - break; - if(i>=w->nb){ - fprint(2, "%d: unlock of unlocked block %V\n", w->pid, b->score); - stop(); - }else - w->b[i] = w->b[--w->nb]; -} - diff --git a/sys/src/cmd/fossil/cache.c b/sys/src/cmd/fossil/cache.c deleted file mode 100644 index eb879d87c..000000000 --- a/sys/src/cmd/fossil/cache.c +++ /dev/null @@ -1,2119 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -#include "9.h" /* for cacheFlush */ - -typedef struct FreeList FreeList; -typedef struct BAddr BAddr; - -enum { - BadHeap = ~0, -}; - -/* - * Store data to the memory cache in c->size blocks - * with the block zero extended to fill it out. When writing to - * Venti, the block will be zero truncated. The walker will also check - * that the block fits within psize or dsize as the case may be. - */ - -struct Cache -{ - VtLock *lk; - VtLock *dirtylk; - int ref; - int mode; - - Disk *disk; - int size; /* block size */ - int ndmap; /* size of per-block dirty pointer map used in blockWrite */ - VtSession *z; - u32int now; /* ticks for usage timestamps */ - Block **heads; /* hash table for finding address */ - int nheap; /* number of available victims */ - Block **heap; /* heap for locating victims */ - long nblocks; /* number of blocks allocated */ - Block *blocks; /* array of block descriptors */ - u8int *mem; /* memory for all block data & blists */ - - BList *blfree; - VtRendez *blrend; - - int ndirty; /* number of dirty blocks in the cache */ - int maxdirty; /* max number of dirty blocks */ - u32int vers; - - long hashSize; - - FreeList *fl; - - VtRendez *die; /* daemon threads should die when != nil */ - - VtRendez *flush; - VtRendez *flushwait; - VtRendez *heapwait; - BAddr *baddr; - int bw, br, be; - int nflush; - - Periodic *sync; - - /* unlink daemon */ - BList *uhead; - BList *utail; - VtRendez *unlink; - - /* block counts */ - int nused; - int ndisk; -}; - -struct BList { - int part; - u32int addr; - uchar type; - u32int tag; - u32int epoch; - u32int vers; - - int recurse; /* for block unlink */ - - /* for roll back */ - int index; /* -1 indicates not valid */ - union { - uchar score[VtScoreSize]; - uchar entry[VtEntrySize]; - } old; - BList *next; -}; - -struct BAddr { - int part; - u32int addr; - u32int vers; -}; - -struct FreeList { - VtLock *lk; - u32int last; /* last block allocated */ - u32int end; /* end of data partition */ - u32int nused; /* number of used blocks */ - u32int epochLow; /* low epoch when last updated nused */ -}; - -static FreeList *flAlloc(u32int end); -static void flFree(FreeList *fl); - -static Block *cacheBumpBlock(Cache *c); -static void heapDel(Block*); -static void heapIns(Block*); -static void cacheCheck(Cache*); -static void unlinkThread(void *a); -static void flushThread(void *a); -static void flushBody(Cache *c); -static void unlinkBody(Cache *c); -static int cacheFlushBlock(Cache *c); -static void cacheSync(void*); -static BList *blistAlloc(Block*); -static void blistFree(Cache*, BList*); -static void doRemoveLink(Cache*, BList*); -static void doRemoveLinkList(Cache*, BList*); - -/* - * Mapping from local block type to Venti type - */ -int vtType[BtMax] = { - VtDataType, /* BtData | 0 */ - VtPointerType0, /* BtData | 1 */ - VtPointerType1, /* BtData | 2 */ - VtPointerType2, /* BtData | 3 */ - VtPointerType3, /* BtData | 4 */ - VtPointerType4, /* BtData | 5 */ - VtPointerType5, /* BtData | 6 */ - VtPointerType6, /* BtData | 7 */ - VtDirType, /* BtDir | 0 */ - VtPointerType0, /* BtDir | 1 */ - VtPointerType1, /* BtDir | 2 */ - VtPointerType2, /* BtDir | 3 */ - VtPointerType3, /* BtDir | 4 */ - VtPointerType4, /* BtDir | 5 */ - VtPointerType5, /* BtDir | 6 */ - VtPointerType6, /* BtDir | 7 */ -}; - -/* - * Allocate the memory cache. - */ -Cache * -cacheAlloc(Disk *disk, VtSession *z, ulong nblocks, int mode) -{ - int i; - Cache *c; - Block *b; - BList *bl; - u8int *p; - int nbl; - - c = vtMemAllocZ(sizeof(Cache)); - - /* reasonable number of BList elements */ - nbl = nblocks * 4; - - c->lk = vtLockAlloc(); - c->dirtylk = vtLockAlloc(); /* allowed to dirty blocks */ - c->ref = 1; - c->disk = disk; - c->z = z; - c->size = diskBlockSize(disk); -bwatchSetBlockSize(c->size); - /* round c->size up to be a nice multiple */ - c->size = (c->size + 127) & ~127; - c->ndmap = (c->size/20 + 7) / 8; - c->nblocks = nblocks; - c->hashSize = nblocks; - c->heads = vtMemAllocZ(c->hashSize*sizeof(Block*)); - c->heap = vtMemAllocZ(nblocks*sizeof(Block*)); - c->blocks = vtMemAllocZ(nblocks*sizeof(Block)); - c->mem = vtMemAllocZ(nblocks * (c->size + c->ndmap) + nbl * sizeof(BList)); - c->baddr = vtMemAllocZ(nblocks * sizeof(BAddr)); - c->mode = mode; - c->vers++; - p = c->mem; - for(i = 0; i < nblocks; i++){ - b = &c->blocks[i]; - b->lk = vtLockAlloc(); - b->c = c; - b->data = p; - b->heap = i; - b->ioready = vtRendezAlloc(b->lk); - c->heap[i] = b; - p += c->size; - } - c->nheap = nblocks; - for(i = 0; i < nbl; i++){ - bl = (BList*)p; - bl->next = c->blfree; - c->blfree = bl; - p += sizeof(BList); - } - /* separate loop to keep blocks and blists reasonably aligned */ - for(i = 0; i < nblocks; i++){ - b = &c->blocks[i]; - b->dmap = p; - p += c->ndmap; - } - - c->blrend = vtRendezAlloc(c->lk); - - c->maxdirty = nblocks*(DirtyPercentage*0.01); - - c->fl = flAlloc(diskSize(disk, PartData)); - - c->unlink = vtRendezAlloc(c->lk); - c->flush = vtRendezAlloc(c->lk); - c->flushwait = vtRendezAlloc(c->lk); - c->heapwait = vtRendezAlloc(c->lk); - c->sync = periodicAlloc(cacheSync, c, 30*1000); - - if(mode == OReadWrite){ - c->ref += 2; - vtThread(unlinkThread, c); - vtThread(flushThread, c); - } - cacheCheck(c); - - return c; -} - -/* - * Free the whole memory cache, flushing all dirty blocks to the disk. - */ -void -cacheFree(Cache *c) -{ - int i; - - /* kill off daemon threads */ - vtLock(c->lk); - c->die = vtRendezAlloc(c->lk); - periodicKill(c->sync); - vtWakeup(c->flush); - vtWakeup(c->unlink); - while(c->ref > 1) - vtSleep(c->die); - - /* flush everything out */ - do { - unlinkBody(c); - vtUnlock(c->lk); - while(cacheFlushBlock(c)) - ; - diskFlush(c->disk); - vtLock(c->lk); - } while(c->uhead || c->ndirty); - vtUnlock(c->lk); - - cacheCheck(c); - - for(i = 0; i < c->nblocks; i++){ - assert(c->blocks[i].ref == 0); - vtRendezFree(c->blocks[i].ioready); - vtLockFree(c->blocks[i].lk); - } - flFree(c->fl); - vtMemFree(c->baddr); - vtMemFree(c->heads); - vtMemFree(c->blocks); - vtMemFree(c->mem); - vtLockFree(c->lk); - diskFree(c->disk); - vtRendezFree(c->blrend); - /* don't close vtSession */ - vtMemFree(c); -} - -static void -cacheDump(Cache *c) -{ - int i; - Block *b; - - for(i = 0; i < c->nblocks; i++){ - b = &c->blocks[i]; - fprint(2, "%d. p=%d a=%ud %V t=%d ref=%d state=%s io=%s pc=%#p\n", - i, b->part, b->addr, b->score, b->l.type, b->ref, - bsStr(b->l.state), bioStr(b->iostate), b->pc); - } -} - -static void -cacheCheck(Cache *c) -{ - u32int size, now; - int i, k, refed; - static uchar zero[VtScoreSize]; - Block *b; - - size = c->size; - now = c->now; - - for(i = 0; i < c->nheap; i++){ - if(c->heap[i]->heap != i) - vtFatal("mis-heaped at %d: %d", i, c->heap[i]->heap); - if(i > 0 && c->heap[(i - 1) >> 1]->used - now > c->heap[i]->used - now) - vtFatal("bad heap ordering"); - k = (i << 1) + 1; - if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now) - vtFatal("bad heap ordering"); - k++; - if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now) - vtFatal("bad heap ordering"); - } - - refed = 0; - for(i = 0; i < c->nblocks; i++){ - b = &c->blocks[i]; - if(b->data != &c->mem[i * size]) - vtFatal("mis-blocked at %d", i); - if(b->ref && b->heap == BadHeap){ - refed++; - } - } -if(c->nheap + refed != c->nblocks){ -fprint(2, "%s: cacheCheck: nheap %d refed %d nblocks %ld\n", argv0, c->nheap, refed, c->nblocks); -cacheDump(c); -} - assert(c->nheap + refed == c->nblocks); - refed = 0; - for(i = 0; i < c->nblocks; i++){ - b = &c->blocks[i]; - if(b->ref){ -if(1)fprint(2, "%s: p=%d a=%ud %V ref=%d %L\n", argv0, b->part, b->addr, b->score, b->ref, &b->l); - refed++; - } - } -if(refed > 0)fprint(2, "%s: cacheCheck: in used %d\n", argv0, refed); -} - - -/* - * locate the block with the oldest second to last use. - * remove it from the heap, and fix up the heap. - */ -/* called with c->lk held */ -static Block * -cacheBumpBlock(Cache *c) -{ - int printed; - Block *b; - - /* - * locate the block with the oldest second to last use. - * remove it from the heap, and fix up the heap. - */ - printed = 0; - if(c->nheap == 0){ - while(c->nheap == 0){ - vtWakeup(c->flush); - vtSleep(c->heapwait); - if(c->nheap == 0){ - printed = 1; - fprint(2, "%s: entire cache is busy, %d dirty " - "-- waking flush thread\n", - argv0, c->ndirty); - } - } - if(printed) - fprint(2, "%s: cache is okay again, %d dirty\n", - argv0, c->ndirty); - } - - b = c->heap[0]; - heapDel(b); - - assert(b->heap == BadHeap); - assert(b->ref == 0); - assert(b->iostate != BioDirty && b->iostate != BioReading && b->iostate != BioWriting); - assert(b->prior == nil); - assert(b->uhead == nil); - - /* - * unchain the block from hash chain - */ - if(b->prev){ - *(b->prev) = b->next; - if(b->next) - b->next->prev = b->prev; - b->prev = nil; - } - - -if(0)fprint(2, "%s: dropping %d:%x:%V\n", argv0, b->part, b->addr, b->score); - /* set block to a reasonable state */ - b->ref = 1; - b->part = PartError; - memset(&b->l, 0, sizeof(b->l)); - b->iostate = BioEmpty; - - return b; -} - -/* - * look for a particular version of the block in the memory cache. - */ -static Block * -_cacheLocalLookup(Cache *c, int part, u32int addr, u32int vers, - int waitlock, int *lockfailure) -{ - Block *b; - ulong h; - - h = addr % c->hashSize; - - if(lockfailure) - *lockfailure = 0; - - /* - * look for the block in the cache - */ - vtLock(c->lk); - for(b = c->heads[h]; b != nil; b = b->next){ - if(b->part == part && b->addr == addr) - break; - } - if(b == nil || b->vers != vers){ - vtUnlock(c->lk); - return nil; - } - if(!waitlock && !vtCanLock(b->lk)){ - *lockfailure = 1; - vtUnlock(c->lk); - return nil; - } - heapDel(b); - b->ref++; - vtUnlock(c->lk); - - bwatchLock(b); - if(waitlock) - vtLock(b->lk); - b->nlock = 1; - - for(;;){ - switch(b->iostate){ - default: - abort(); - case BioEmpty: - case BioLabel: - case BioClean: - case BioDirty: - if(b->vers != vers){ - blockPut(b); - return nil; - } - return b; - case BioReading: - case BioWriting: - vtSleep(b->ioready); - break; - case BioVentiError: - blockPut(b); - vtSetError("venti i/o error block 0x%.8ux", addr); - return nil; - case BioReadError: - blockPut(b); - vtSetError("error reading block 0x%.8ux", addr); - return nil; - } - } - /* NOT REACHED */ -} -static Block* -cacheLocalLookup(Cache *c, int part, u32int addr, u32int vers) -{ - return _cacheLocalLookup(c, part, addr, vers, 1, 0); -} - - -/* - * fetch a local (on-disk) block from the memory cache. - * if it's not there, load it, bumping some other block. - */ -Block * -_cacheLocal(Cache *c, int part, u32int addr, int mode, u32int epoch) -{ - Block *b; - ulong h; - - assert(part != PartVenti); - - h = addr % c->hashSize; - - /* - * look for the block in the cache - */ - vtLock(c->lk); - for(b = c->heads[h]; b != nil; b = b->next){ - if(b->part != part || b->addr != addr) - continue; - if(epoch && b->l.epoch != epoch){ -fprint(2, "%s: _cacheLocal want epoch %ud got %ud\n", argv0, epoch, b->l.epoch); - vtUnlock(c->lk); - vtSetError(ELabelMismatch); - return nil; - } - heapDel(b); - b->ref++; - break; - } - - if(b == nil){ - b = cacheBumpBlock(c); - - b->part = part; - b->addr = addr; - localToGlobal(addr, b->score); - - /* chain onto correct hash */ - b->next = c->heads[h]; - c->heads[h] = b; - if(b->next != nil) - b->next->prev = &b->next; - b->prev = &c->heads[h]; - } - - vtUnlock(c->lk); - - /* - * BUG: what if the epoch changes right here? - * In the worst case, we could end up in some weird - * lock loop, because the block we want no longer exists, - * and instead we're trying to lock a block we have no - * business grabbing. - * - * For now, I'm not going to worry about it. - */ - -if(0)fprint(2, "%s: cacheLocal: %d: %d %x\n", argv0, getpid(), b->part, b->addr); - bwatchLock(b); - vtLock(b->lk); - b->nlock = 1; - - if(part == PartData && b->iostate == BioEmpty){ - if(!readLabel(c, &b->l, addr)){ - blockPut(b); - return nil; - } - blockSetIOState(b, BioLabel); - } - if(epoch && b->l.epoch != epoch){ - blockPut(b); -fprint(2, "%s: _cacheLocal want epoch %ud got %ud\n", argv0, epoch, b->l.epoch); - vtSetError(ELabelMismatch); - return nil; - } - - b->pc = getcallerpc(&c); - for(;;){ - switch(b->iostate){ - default: - abort(); - case BioEmpty: - case BioLabel: - if(mode == OOverWrite){ - blockSetIOState(b, BioClean); - return b; - } - diskRead(c->disk, b); - vtSleep(b->ioready); - break; - case BioClean: - case BioDirty: - return b; - case BioReading: - case BioWriting: - vtSleep(b->ioready); - break; - case BioReadError: - blockSetIOState(b, BioEmpty); - blockPut(b); - vtSetError("error reading block 0x%.8ux", addr); - return nil; - } - } - /* NOT REACHED */ -} - -Block * -cacheLocal(Cache *c, int part, u32int addr, int mode) -{ - return _cacheLocal(c, part, addr, mode, 0); -} - -/* - * fetch a local (on-disk) block from the memory cache. - * if it's not there, load it, bumping some other block. - * check tag and type. - */ -Block * -cacheLocalData(Cache *c, u32int addr, int type, u32int tag, int mode, u32int epoch) -{ - Block *b; - - b = _cacheLocal(c, PartData, addr, mode, epoch); - if(b == nil) - return nil; - if(b->l.type != type || b->l.tag != tag){ - fprint(2, "%s: cacheLocalData: addr=%d type got %d exp %d: tag got %ux exp %ux\n", - argv0, addr, b->l.type, type, b->l.tag, tag); - vtSetError(ELabelMismatch); - blockPut(b); - return nil; - } - b->pc = getcallerpc(&c); - return b; -} - -/* - * fetch a global (Venti) block from the memory cache. - * if it's not there, load it, bumping some other block. - * check tag and type if it's really a local block in disguise. - */ -Block * -cacheGlobal(Cache *c, uchar score[VtScoreSize], int type, u32int tag, int mode) -{ - int n; - Block *b; - ulong h; - u32int addr; - - addr = globalToLocal(score); - if(addr != NilBlock){ - b = cacheLocalData(c, addr, type, tag, mode, 0); - if(b) - b->pc = getcallerpc(&c); - return b; - } - - h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->hashSize; - - /* - * look for the block in the cache - */ - vtLock(c->lk); - for(b = c->heads[h]; b != nil; b = b->next){ - if(b->part != PartVenti || memcmp(b->score, score, VtScoreSize) != 0 || b->l.type != type) - continue; - heapDel(b); - b->ref++; - break; - } - - if(b == nil){ -if(0)fprint(2, "%s: cacheGlobal %V %d\n", argv0, score, type); - - b = cacheBumpBlock(c); - - b->part = PartVenti; - b->addr = NilBlock; - b->l.type = type; - memmove(b->score, score, VtScoreSize); - - /* chain onto correct hash */ - b->next = c->heads[h]; - c->heads[h] = b; - if(b->next != nil) - b->next->prev = &b->next; - b->prev = &c->heads[h]; - } - vtUnlock(c->lk); - - bwatchLock(b); - vtLock(b->lk); - b->nlock = 1; - b->pc = getcallerpc(&c); - - switch(b->iostate){ - default: - abort(); - case BioEmpty: - n = vtRead(c->z, score, vtType[type], b->data, c->size); - if(n < 0 || !vtSha1Check(score, b->data, n)){ - blockSetIOState(b, BioVentiError); - blockPut(b); - vtSetError( - "venti error reading block %V or wrong score: %r", - score); - return nil; - } - vtZeroExtend(vtType[type], b->data, n, c->size); - blockSetIOState(b, BioClean); - return b; - case BioClean: - return b; - case BioVentiError: - blockPut(b); - vtSetError("venti i/o error or wrong score, block %V", score); - return nil; - case BioReadError: - blockPut(b); - vtSetError("error reading block %V", b->score); - return nil; - } - /* NOT REACHED */ -} - -/* - * allocate a new on-disk block and load it into the memory cache. - * BUG: if the disk is full, should we flush some of it to Venti? - */ -static u32int lastAlloc; - -Block * -cacheAllocBlock(Cache *c, int type, u32int tag, u32int epoch, u32int epochLow) -{ - FreeList *fl; - u32int addr; - Block *b; - int n, nwrap; - Label lab; - - n = c->size / LabelSize; - fl = c->fl; - - vtLock(fl->lk); - addr = fl->last; - b = cacheLocal(c, PartLabel, addr/n, OReadOnly); - if(b == nil){ - fprint(2, "%s: cacheAllocBlock: xxx %R\n", argv0); - vtUnlock(fl->lk); - return nil; - } - nwrap = 0; - for(;;){ - if(++addr >= fl->end){ - addr = 0; - if(++nwrap >= 2){ - blockPut(b); - vtSetError("disk is full"); - /* - * try to avoid a continuous spew of console - * messages. - */ - if (fl->last != 0) - fprint(2, "%s: cacheAllocBlock: xxx1 %R\n", - argv0); - fl->last = 0; - vtUnlock(fl->lk); - return nil; - } - } - if(addr%n == 0){ - blockPut(b); - b = cacheLocal(c, PartLabel, addr/n, OReadOnly); - if(b == nil){ - fl->last = addr; - fprint(2, "%s: cacheAllocBlock: xxx2 %R\n", argv0); - vtUnlock(fl->lk); - return nil; - } - } - if(!labelUnpack(&lab, b->data, addr%n)) - continue; - if(lab.state == BsFree) - goto Found; - if(lab.state&BsClosed) - if(lab.epochClose <= epochLow || lab.epoch==lab.epochClose) - goto Found; - } -Found: - blockPut(b); - b = cacheLocal(c, PartData, addr, OOverWrite); - if(b == nil){ - fprint(2, "%s: cacheAllocBlock: xxx3 %R\n", argv0); - return nil; - } -assert(b->iostate == BioLabel || b->iostate == BioClean); - fl->last = addr; - lab.type = type; - lab.tag = tag; - lab.state = BsAlloc; - lab.epoch = epoch; - lab.epochClose = ~(u32int)0; - if(!blockSetLabel(b, &lab, 1)){ - fprint(2, "%s: cacheAllocBlock: xxx4 %R\n", argv0); - blockPut(b); - return nil; - } - vtZeroExtend(vtType[type], b->data, 0, c->size); -if(0)diskWrite(c->disk, b); - -if(0)fprint(2, "%s: fsAlloc %ud type=%d tag = %ux\n", argv0, addr, type, tag); - lastAlloc = addr; - fl->nused++; - vtUnlock(fl->lk); - b->pc = getcallerpc(&c); - return b; -} - -int -cacheDirty(Cache *c) -{ - return c->ndirty; -} - -void -cacheCountUsed(Cache *c, u32int epochLow, u32int *used, u32int *total, u32int *bsize) -{ - int n; - u32int addr, nused; - Block *b; - Label lab; - FreeList *fl; - - fl = c->fl; - n = c->size / LabelSize; - *bsize = c->size; - vtLock(fl->lk); - if(fl->epochLow == epochLow){ - *used = fl->nused; - *total = fl->end; - vtUnlock(fl->lk); - return; - } - b = nil; - nused = 0; - for(addr=0; addr<fl->end; addr++){ - if(addr%n == 0){ - blockPut(b); - b = cacheLocal(c, PartLabel, addr/n, OReadOnly); - if(b == nil){ - fprint(2, "%s: flCountUsed: loading %ux: %R\n", - argv0, addr/n); - break; - } - } - if(!labelUnpack(&lab, b->data, addr%n)) - continue; - if(lab.state == BsFree) - continue; - if(lab.state&BsClosed) - if(lab.epochClose <= epochLow || lab.epoch==lab.epochClose) - continue; - nused++; - } - blockPut(b); - if(addr == fl->end){ - fl->nused = nused; - fl->epochLow = epochLow; - } - *used = nused; - *total = fl->end; - vtUnlock(fl->lk); - return; -} - -static FreeList * -flAlloc(u32int end) -{ - FreeList *fl; - - fl = vtMemAllocZ(sizeof(*fl)); - fl->lk = vtLockAlloc(); - fl->last = 0; - fl->end = end; - return fl; -} - -static void -flFree(FreeList *fl) -{ - vtLockFree(fl->lk); - vtMemFree(fl); -} - -u32int -cacheLocalSize(Cache *c, int part) -{ - return diskSize(c->disk, part); -} - -/* - * The thread that has locked b may refer to it by - * multiple names. Nlock counts the number of - * references the locking thread holds. It will call - * blockPut once per reference. - */ -void -blockDupLock(Block *b) -{ - assert(b->nlock > 0); - b->nlock++; -} - -/* - * we're done with the block. - * unlock it. can't use it after calling this. - */ -void -blockPut(Block* b) -{ - Cache *c; - - if(b == nil) - return; - -if(0)fprint(2, "%s: blockPut: %d: %d %x %d %s\n", argv0, getpid(), b->part, b->addr, c->nheap, bioStr(b->iostate)); - - if(b->iostate == BioDirty) - bwatchDependency(b); - - if(--b->nlock > 0) - return; - - /* - * b->nlock should probably stay at zero while - * the block is unlocked, but diskThread and vtSleep - * conspire to assume that they can just vtLock(b->lk); blockPut(b), - * so we have to keep b->nlock set to 1 even - * when the block is unlocked. - */ - assert(b->nlock == 0); - b->nlock = 1; -// b->pc = 0; - - bwatchUnlock(b); - vtUnlock(b->lk); - c = b->c; - vtLock(c->lk); - - if(--b->ref > 0){ - vtUnlock(c->lk); - return; - } - - assert(b->ref == 0); - switch(b->iostate){ - default: - b->used = c->now++; - heapIns(b); - break; - case BioEmpty: - case BioLabel: - if(c->nheap == 0) - b->used = c->now++; - else - b->used = c->heap[0]->used; - heapIns(b); - break; - case BioDirty: - break; - } - vtUnlock(c->lk); -} - -/* - * set the label associated with a block. - */ -Block* -_blockSetLabel(Block *b, Label *l) -{ - int lpb; - Block *bb; - u32int a; - Cache *c; - - c = b->c; - - assert(b->part == PartData); - assert(b->iostate == BioLabel || b->iostate == BioClean || b->iostate == BioDirty); - lpb = c->size / LabelSize; - a = b->addr / lpb; - bb = cacheLocal(c, PartLabel, a, OReadWrite); - if(bb == nil){ - blockPut(b); - return nil; - } - b->l = *l; - labelPack(l, bb->data, b->addr%lpb); - blockDirty(bb); - return bb; -} - -int -blockSetLabel(Block *b, Label *l, int allocating) -{ - Block *lb; - Label oldl; - - oldl = b->l; - lb = _blockSetLabel(b, l); - if(lb == nil) - return 0; - - /* - * If we're allocating the block, make sure the label (bl) - * goes to disk before the data block (b) itself. This is to help - * the blocks that in turn depend on b. - * - * Suppose bx depends on (must be written out after) b. - * Once we write b we'll think it's safe to write bx. - * Bx can't get at b unless it has a valid label, though. - * - * Allocation is the only case in which having a current label - * is vital because: - * - * - l.type is set at allocation and never changes. - * - l.tag is set at allocation and never changes. - * - l.state is not checked when we load blocks. - * - the archiver cares deeply about l.state being - * BaActive vs. BaCopied, but that's handled - * by direct calls to _blockSetLabel. - */ - - if(allocating) - blockDependency(b, lb, -1, nil, nil); - blockPut(lb); - return 1; -} - -/* - * Record that bb must be written out before b. - * If index is given, we're about to overwrite the score/e - * at that index in the block. Save the old value so we - * can write a safer ``old'' version of the block if pressed. - */ -void -blockDependency(Block *b, Block *bb, int index, uchar *score, Entry *e) -{ - BList *p; - - if(bb->iostate == BioClean) - return; - - /* - * Dependencies for blocks containing Entry structures - * or scores must always be explained. The problem with - * only explaining some of them is this. Suppose we have two - * dependencies for the same field, the first explained - * and the second not. We try to write the block when the first - * dependency is not written but the second is. We will roll back - * the first change even though the second trumps it. - */ - if(index == -1 && bb->part == PartData) - assert(b->l.type == BtData); - - if(bb->iostate != BioDirty){ - fprint(2, "%s: %d:%x:%d iostate is %d in blockDependency\n", - argv0, bb->part, bb->addr, bb->l.type, bb->iostate); - abort(); - } - - p = blistAlloc(bb); - if(p == nil) - return; - - assert(bb->iostate == BioDirty); -if(0)fprint(2, "%s: %d:%x:%d depends on %d:%x:%d\n", argv0, b->part, b->addr, b->l.type, bb->part, bb->addr, bb->l.type); - - p->part = bb->part; - p->addr = bb->addr; - p->type = bb->l.type; - p->vers = bb->vers; - p->index = index; - if(p->index >= 0){ - /* - * This test would just be b->l.type==BtDir except - * we need to exclude the super block. - */ - if(b->l.type == BtDir && b->part == PartData) - entryPack(e, p->old.entry, 0); - else - memmove(p->old.score, score, VtScoreSize); - } - p->next = b->prior; - b->prior = p; -} - -/* - * Mark an in-memory block as dirty. If there are too many - * dirty blocks, start writing some out to disk. - * - * If there were way too many dirty blocks, we used to - * try to do some flushing ourselves, but it's just too dangerous -- - * it implies that the callers cannot have any of our priors locked, - * but this is hard to avoid in some cases. - */ -int -blockDirty(Block *b) -{ - Cache *c; - - c = b->c; - - assert(b->part != PartVenti); - - if(b->iostate == BioDirty) - return 1; - assert(b->iostate == BioClean); - - vtLock(c->dirtylk); - vtLock(c->lk); - b->iostate = BioDirty; - c->ndirty++; - if(c->ndirty > (c->maxdirty>>1)) - vtWakeup(c->flush); - vtUnlock(c->lk); - vtUnlock(c->dirtylk); - - return 1; -} - -/* - * We've decided to write out b. Maybe b has some pointers to blocks - * that haven't yet been written to disk. If so, construct a slightly out-of-date - * copy of b that is safe to write out. (diskThread will make sure the block - * remains marked as dirty.) - */ -uchar * -blockRollback(Block *b, uchar *buf) -{ - u32int addr; - BList *p; - Super super; - - /* easy case */ - if(b->prior == nil) - return b->data; - - memmove(buf, b->data, b->c->size); - for(p=b->prior; p; p=p->next){ - /* - * we know p->index >= 0 because blockWrite has vetted this block for us. - */ - assert(p->index >= 0); - assert(b->part == PartSuper || (b->part == PartData && b->l.type != BtData)); - if(b->part == PartSuper){ - assert(p->index == 0); - superUnpack(&super, buf); - addr = globalToLocal(p->old.score); - if(addr == NilBlock){ - fprint(2, "%s: rolling back super block: " - "bad replacement addr %V\n", - argv0, p->old.score); - abort(); - } - super.active = addr; - superPack(&super, buf); - continue; - } - if(b->l.type == BtDir) - memmove(buf+p->index*VtEntrySize, p->old.entry, VtEntrySize); - else - memmove(buf+p->index*VtScoreSize, p->old.score, VtScoreSize); - } - return buf; -} - -/* - * Try to write block b. - * If b depends on other blocks: - * - * If the block has been written out, remove the dependency. - * If the dependency is replaced by a more recent dependency, - * throw it out. - * If we know how to write out an old version of b that doesn't - * depend on it, do that. - * - * Otherwise, bail. - */ -int -blockWrite(Block *b) -{ - uchar *dmap; - Cache *c; - BList *p, **pp; - Block *bb; - int lockfail; - - c = b->c; - - if(b->iostate != BioDirty) - return 1; - - dmap = b->dmap; - memset(dmap, 0, c->ndmap); - pp = &b->prior; - for(p=*pp; p; p=*pp){ - if(p->index >= 0){ - /* more recent dependency has succeeded; this one can go */ - if(dmap[p->index/8] & (1<<(p->index%8))) - goto ignblock; - } - - lockfail = 0; - bb = _cacheLocalLookup(c, p->part, p->addr, p->vers, 0, &lockfail); - if(bb == nil){ - if(lockfail) - return 0; - /* block not in cache => was written already */ - dmap[p->index/8] |= 1<<(p->index%8); - goto ignblock; - } - - /* - * same version of block is still in cache. - * - * the assertion is true because the block still has version p->vers, - * which means it hasn't been written out since we last saw it. - */ - if(bb->iostate != BioDirty){ - fprint(2, "%s: %d:%x:%d iostate is %d in blockWrite\n", - argv0, bb->part, bb->addr, bb->l.type, bb->iostate); - /* probably BioWriting if it happens? */ - if(bb->iostate == BioClean) - goto ignblock; - } - - blockPut(bb); - - if(p->index < 0){ - /* - * We don't know how to temporarily undo - * b's dependency on bb, so just don't write b yet. - */ - if(0) fprint(2, "%s: blockWrite skipping %d %x %d %d; need to write %d %x %d\n", - argv0, b->part, b->addr, b->vers, b->l.type, p->part, p->addr, bb->vers); - return 0; - } - /* keep walking down the list */ - pp = &p->next; - continue; - -ignblock: - *pp = p->next; - blistFree(c, p); - continue; - } - - /* - * DiskWrite must never be called with a double-locked block. - * This call to diskWrite is okay because blockWrite is only called - * from the cache flush thread, which never double-locks a block. - */ - diskWrite(c->disk, b); - return 1; -} - -/* - * Change the I/O state of block b. - * Just an assignment except for magic in - * switch statement (read comments there). - */ -void -blockSetIOState(Block *b, int iostate) -{ - int dowakeup; - Cache *c; - BList *p, *q; - -if(0) fprint(2, "%s: iostate part=%d addr=%x %s->%s\n", argv0, b->part, b->addr, bioStr(b->iostate), bioStr(iostate)); - - c = b->c; - - dowakeup = 0; - switch(iostate){ - default: - abort(); - case BioEmpty: - assert(!b->uhead); - break; - case BioLabel: - assert(!b->uhead); - break; - case BioClean: - bwatchDependency(b); - /* - * If b->prior is set, it means a write just finished. - * The prior list isn't needed anymore. - */ - for(p=b->prior; p; p=q){ - q = p->next; - blistFree(c, p); - } - b->prior = nil; - /* - * Freeing a block or just finished a write. - * Move the blocks from the per-block unlink - * queue to the cache unlink queue. - */ - if(b->iostate == BioDirty || b->iostate == BioWriting){ - vtLock(c->lk); - c->ndirty--; - b->iostate = iostate; /* change here to keep in sync with ndirty */ - b->vers = c->vers++; - if(b->uhead){ - /* add unlink blocks to unlink queue */ - if(c->uhead == nil){ - c->uhead = b->uhead; - vtWakeup(c->unlink); - }else - c->utail->next = b->uhead; - c->utail = b->utail; - b->uhead = nil; - } - vtUnlock(c->lk); - } - assert(!b->uhead); - dowakeup = 1; - break; - case BioDirty: - /* - * Wrote out an old version of the block (see blockRollback). - * Bump a version count, leave it dirty. - */ - if(b->iostate == BioWriting){ - vtLock(c->lk); - b->vers = c->vers++; - vtUnlock(c->lk); - dowakeup = 1; - } - break; - case BioReading: - case BioWriting: - /* - * Adding block to disk queue. Bump reference count. - * diskThread decs the count later by calling blockPut. - * This is here because we need to lock c->lk to - * manipulate the ref count. - */ - vtLock(c->lk); - b->ref++; - vtUnlock(c->lk); - break; - case BioReadError: - case BioVentiError: - /* - * Oops. - */ - dowakeup = 1; - break; - } - b->iostate = iostate; - /* - * Now that the state has changed, we can wake the waiters. - */ - if(dowakeup) - vtWakeupAll(b->ioready); -} - -/* - * The active file system is a tree of blocks. - * When we add snapshots to the mix, the entire file system - * becomes a dag and thus requires a bit more care. - * - * The life of the file system is divided into epochs. A snapshot - * ends one epoch and begins the next. Each file system block - * is marked with the epoch in which it was created (b.epoch). - * When the block is unlinked from the file system (closed), it is marked - * with the epoch in which it was removed (b.epochClose). - * Once we have discarded or archived all snapshots up to - * b.epochClose, we can reclaim the block. - * - * If a block was created in a past epoch but is not yet closed, - * it is treated as copy-on-write. Of course, in order to insert the - * new pointer into the tree, the parent must be made writable, - * and so on up the tree. The recursion stops because the root - * block is always writable. - * - * If blocks are never closed, they will never be reused, and - * we will run out of disk space. But marking a block as closed - * requires some care about dependencies and write orderings. - * - * (1) If a block p points at a copy-on-write block b and we - * copy b to create bb, then p must be written out after bb and - * lbb (bb's label block). - * - * (2) We have to mark b as closed, but only after we switch - * the pointer, so lb must be written out after p. In fact, we - * can't even update the in-memory copy, or the cache might - * mistakenly give out b for reuse before p gets written. - * - * CacheAllocBlock's call to blockSetLabel records a "bb after lbb" dependency. - * The caller is expected to record a "p after bb" dependency - * to finish (1), and also expected to call blockRemoveLink - * to arrange for (2) to happen once p is written. - * - * Until (2) happens, some pieces of the code (e.g., the archiver) - * still need to know whether a block has been copied, so we - * set the BsCopied bit in the label and force that to disk *before* - * the copy gets written out. - */ -Block* -blockCopy(Block *b, u32int tag, u32int ehi, u32int elo) -{ - Block *bb, *lb; - Label l; - - if((b->l.state&BsClosed) || b->l.epoch >= ehi) - fprint(2, "%s: blockCopy %#ux %L but fs is [%ud,%ud]\n", - argv0, b->addr, &b->l, elo, ehi); - - bb = cacheAllocBlock(b->c, b->l.type, tag, ehi, elo); - if(bb == nil){ - blockPut(b); - return nil; - } - - /* - * Update label so we know the block has been copied. - * (It will be marked closed once it has been unlinked from - * the tree.) This must follow cacheAllocBlock since we - * can't be holding onto lb when we call cacheAllocBlock. - */ - if((b->l.state&BsCopied)==0) - if(b->part == PartData){ /* not the superblock */ - l = b->l; - l.state |= BsCopied; - lb = _blockSetLabel(b, &l); - if(lb == nil){ - /* can't set label => can't copy block */ - blockPut(b); - l.type = BtMax; - l.state = BsFree; - l.epoch = 0; - l.epochClose = 0; - l.tag = 0; - blockSetLabel(bb, &l, 0); - blockPut(bb); - return nil; - } - blockDependency(bb, lb, -1, nil, nil); - blockPut(lb); - } - - memmove(bb->data, b->data, b->c->size); - blockDirty(bb); - blockPut(b); - return bb; -} - -/* - * Block b once pointed at the block bb at addr/type/tag, but no longer does. - * If recurse is set, we are unlinking all of bb's children as well. - * - * We can't reclaim bb (or its kids) until the block b gets written to disk. We add - * the relevant information to b's list of unlinked blocks. Once b is written, - * the list will be queued for processing. - * - * If b depends on bb, it doesn't anymore, so we remove bb from the prior list. - */ -void -blockRemoveLink(Block *b, u32int addr, int type, u32int tag, int recurse) -{ - BList *p, **pp, bl; - - /* remove bb from prior list */ - for(pp=&b->prior; (p=*pp)!=nil; ){ - if(p->part == PartData && p->addr == addr){ - *pp = p->next; - blistFree(b->c, p); - }else - pp = &p->next; - } - - bl.part = PartData; - bl.addr = addr; - bl.type = type; - bl.tag = tag; - if(b->l.epoch == 0) - assert(b->part == PartSuper); - bl.epoch = b->l.epoch; - bl.next = nil; - bl.recurse = recurse; - - p = blistAlloc(b); - if(p == nil){ - /* - * We were out of blists so blistAlloc wrote b to disk. - */ - doRemoveLink(b->c, &bl); - return; - } - - /* Uhead is only processed when the block goes from Dirty -> Clean */ - assert(b->iostate == BioDirty); - - *p = bl; - if(b->uhead == nil) - b->uhead = p; - else - b->utail->next = p; - b->utail = p; -} - -/* - * Process removal of a single block and perhaps its children. - */ -static void -doRemoveLink(Cache *c, BList *p) -{ - int i, n, recurse; - u32int a; - Block *b; - Label l; - BList bl; - - recurse = (p->recurse && p->type != BtData && p->type != BtDir); - - /* - * We're not really going to overwrite b, but if we're not - * going to look at its contents, there is no point in reading - * them from the disk. - */ - b = cacheLocalData(c, p->addr, p->type, p->tag, recurse ? OReadOnly : OOverWrite, 0); - if(b == nil) - return; - - /* - * When we're unlinking from the superblock, close with the next epoch. - */ - if(p->epoch == 0) - p->epoch = b->l.epoch+1; - - /* sanity check */ - if(b->l.epoch > p->epoch){ - fprint(2, "%s: doRemoveLink: strange epoch %ud > %ud\n", - argv0, b->l.epoch, p->epoch); - blockPut(b); - return; - } - - if(recurse){ - n = c->size / VtScoreSize; - for(i=0; i<n; i++){ - a = globalToLocal(b->data + i*VtScoreSize); - if(a == NilBlock || !readLabel(c, &l, a)) - continue; - if(l.state&BsClosed) - continue; - /* - * If stack space becomes an issue... - p->addr = a; - p->type = l.type; - p->tag = l.tag; - doRemoveLink(c, p); - */ - - bl.part = PartData; - bl.addr = a; - bl.type = l.type; - bl.tag = l.tag; - bl.epoch = p->epoch; - bl.next = nil; - bl.recurse = 1; - /* give up the block lock - share with others */ - blockPut(b); - doRemoveLink(c, &bl); - b = cacheLocalData(c, p->addr, p->type, p->tag, OReadOnly, 0); - if(b == nil){ - fprint(2, "%s: warning: lost block in doRemoveLink\n", - argv0); - return; - } - } - } - - l = b->l; - l.state |= BsClosed; - l.epochClose = p->epoch; - if(l.epochClose == l.epoch){ - vtLock(c->fl->lk); - if(l.epoch == c->fl->epochLow) - c->fl->nused--; - blockSetLabel(b, &l, 0); - vtUnlock(c->fl->lk); - }else - blockSetLabel(b, &l, 0); - blockPut(b); -} - -/* - * Allocate a BList so that we can record a dependency - * or queue a removal related to block b. - * If we can't find a BList, we write out b and return nil. - */ -static BList * -blistAlloc(Block *b) -{ - Cache *c; - BList *p; - - if(b->iostate != BioDirty){ - /* - * should not happen anymore - - * blockDirty used to flush but no longer does. - */ - assert(b->iostate == BioClean); - fprint(2, "%s: blistAlloc: called on clean block\n", argv0); - return nil; - } - - c = b->c; - vtLock(c->lk); - if(c->blfree == nil){ - /* - * No free BLists. What are our options? - */ - - /* Block has no priors? Just write it. */ - if(b->prior == nil){ - vtUnlock(c->lk); - diskWriteAndWait(c->disk, b); - return nil; - } - - /* - * Wake the flush thread, which will hopefully free up - * some BLists for us. We used to flush a block from - * our own prior list and reclaim that BList, but this is - * a no-no: some of the blocks on our prior list may - * be locked by our caller. Or maybe their label blocks - * are locked by our caller. In any event, it's too hard - * to make sure we can do I/O for ourselves. Instead, - * we assume the flush thread will find something. - * (The flush thread never blocks waiting for a block, - * so it can't deadlock like we can.) - */ - while(c->blfree == nil){ - vtWakeup(c->flush); - vtSleep(c->blrend); - if(c->blfree == nil) - fprint(2, "%s: flushing for blists\n", argv0); - } - } - - p = c->blfree; - c->blfree = p->next; - vtUnlock(c->lk); - return p; -} - -static void -blistFree(Cache *c, BList *bl) -{ - vtLock(c->lk); - bl->next = c->blfree; - c->blfree = bl; - vtWakeup(c->blrend); - vtUnlock(c->lk); -} - -char* -bsStr(int state) -{ - static char s[100]; - - if(state == BsFree) - return "Free"; - if(state == BsBad) - return "Bad"; - - sprint(s, "%x", state); - if(!(state&BsAlloc)) - strcat(s, ",Free"); /* should not happen */ - if(state&BsCopied) - strcat(s, ",Copied"); - if(state&BsVenti) - strcat(s, ",Venti"); - if(state&BsClosed) - strcat(s, ",Closed"); - return s; -} - -char * -bioStr(int iostate) -{ - switch(iostate){ - default: - return "Unknown!!"; - case BioEmpty: - return "Empty"; - case BioLabel: - return "Label"; - case BioClean: - return "Clean"; - case BioDirty: - return "Dirty"; - case BioReading: - return "Reading"; - case BioWriting: - return "Writing"; - case BioReadError: - return "ReadError"; - case BioVentiError: - return "VentiError"; - case BioMax: - return "Max"; - } -} - -static char *bttab[] = { - "BtData", - "BtData+1", - "BtData+2", - "BtData+3", - "BtData+4", - "BtData+5", - "BtData+6", - "BtData+7", - "BtDir", - "BtDir+1", - "BtDir+2", - "BtDir+3", - "BtDir+4", - "BtDir+5", - "BtDir+6", - "BtDir+7", -}; - -char* -btStr(int type) -{ - if(type < nelem(bttab)) - return bttab[type]; - return "unknown"; -} - -int -labelFmt(Fmt *f) -{ - Label *l; - - l = va_arg(f->args, Label*); - return fmtprint(f, "%s,%s,e=%ud,%d,tag=%#ux", - btStr(l->type), bsStr(l->state), l->epoch, (int)l->epochClose, l->tag); -} - -int -scoreFmt(Fmt *f) -{ - uchar *v; - int i; - u32int addr; - - v = va_arg(f->args, uchar*); - if(v == nil){ - fmtprint(f, "*"); - }else if((addr = globalToLocal(v)) != NilBlock) - fmtprint(f, "0x%.8ux", addr); - else{ - for(i = 0; i < VtScoreSize; i++) - fmtprint(f, "%2.2ux", v[i]); - } - - return 0; -} - -static int -upHeap(int i, Block *b) -{ - Block *bb; - u32int now; - int p; - Cache *c; - - c = b->c; - now = c->now; - for(; i != 0; i = p){ - p = (i - 1) >> 1; - bb = c->heap[p]; - if(b->used - now >= bb->used - now) - break; - c->heap[i] = bb; - bb->heap = i; - } - c->heap[i] = b; - b->heap = i; - - return i; -} - -static int -downHeap(int i, Block *b) -{ - Block *bb; - u32int now; - int k; - Cache *c; - - c = b->c; - now = c->now; - for(; ; i = k){ - k = (i << 1) + 1; - if(k >= c->nheap) - break; - if(k + 1 < c->nheap && c->heap[k]->used - now > c->heap[k + 1]->used - now) - k++; - bb = c->heap[k]; - if(b->used - now <= bb->used - now) - break; - c->heap[i] = bb; - bb->heap = i; - } - c->heap[i] = b; - b->heap = i; - return i; -} - -/* - * Delete a block from the heap. - * Called with c->lk held. - */ -static void -heapDel(Block *b) -{ - int i, si; - Cache *c; - - c = b->c; - - si = b->heap; - if(si == BadHeap) - return; - b->heap = BadHeap; - c->nheap--; - if(si == c->nheap) - return; - b = c->heap[c->nheap]; - i = upHeap(si, b); - if(i == si) - downHeap(i, b); -} - -/* - * Insert a block into the heap. - * Called with c->lk held. - */ -static void -heapIns(Block *b) -{ - assert(b->heap == BadHeap); - upHeap(b->c->nheap++, b); - vtWakeup(b->c->heapwait); -} - -/* - * Get just the label for a block. - */ -int -readLabel(Cache *c, Label *l, u32int addr) -{ - int lpb; - Block *b; - u32int a; - - lpb = c->size / LabelSize; - a = addr / lpb; - b = cacheLocal(c, PartLabel, a, OReadOnly); - if(b == nil){ - blockPut(b); - return 0; - } - - if(!labelUnpack(l, b->data, addr%lpb)){ - blockPut(b); - return 0; - } - blockPut(b); - return 1; -} - -/* - * Process unlink queue. - * Called with c->lk held. - */ -static void -unlinkBody(Cache *c) -{ - BList *p; - - while(c->uhead != nil){ - p = c->uhead; - c->uhead = p->next; - vtUnlock(c->lk); - doRemoveLink(c, p); - vtLock(c->lk); - p->next = c->blfree; - c->blfree = p; - } -} - -/* - * Occasionally unlink the blocks on the cache unlink queue. - */ -static void -unlinkThread(void *a) -{ - Cache *c = a; - - vtThreadSetName("unlink"); - - vtLock(c->lk); - for(;;){ - while(c->uhead == nil && c->die == nil) - vtSleep(c->unlink); - if(c->die != nil) - break; - unlinkBody(c); - } - c->ref--; - vtWakeup(c->die); - vtUnlock(c->lk); -} - -static int -baddrCmp(void *a0, void *a1) -{ - BAddr *b0, *b1; - b0 = a0; - b1 = a1; - - if(b0->part < b1->part) - return -1; - if(b0->part > b1->part) - return 1; - if(b0->addr < b1->addr) - return -1; - if(b0->addr > b1->addr) - return 1; - return 0; -} - -/* - * Scan the block list for dirty blocks; add them to the list c->baddr. - */ -static void -flushFill(Cache *c) -{ - int i, ndirty; - BAddr *p; - Block *b; - - vtLock(c->lk); - if(c->ndirty == 0){ - vtUnlock(c->lk); - return; - } - - p = c->baddr; - ndirty = 0; - for(i=0; i<c->nblocks; i++){ - b = c->blocks + i; - if(b->part == PartError) - continue; - if(b->iostate == BioDirty || b->iostate == BioWriting) - ndirty++; - if(b->iostate != BioDirty) - continue; - p->part = b->part; - p->addr = b->addr; - p->vers = b->vers; - p++; - } - if(ndirty != c->ndirty){ - fprint(2, "%s: ndirty mismatch expected %d found %d\n", - argv0, c->ndirty, ndirty); - c->ndirty = ndirty; - } - vtUnlock(c->lk); - - c->bw = p - c->baddr; - qsort(c->baddr, c->bw, sizeof(BAddr), baddrCmp); -} - -/* - * This is not thread safe, i.e. it can't be called from multiple threads. - * - * It's okay how we use it, because it only gets called in - * the flushThread. And cacheFree, but only after - * cacheFree has killed off the flushThread. - */ -static int -cacheFlushBlock(Cache *c) -{ - Block *b; - BAddr *p; - int lockfail, nfail; - - nfail = 0; - for(;;){ - if(c->br == c->be){ - if(c->bw == 0 || c->bw == c->be) - flushFill(c); - c->br = 0; - c->be = c->bw; - c->bw = 0; - c->nflush = 0; - } - - if(c->br == c->be) - return 0; - p = c->baddr + c->br; - c->br++; - b = _cacheLocalLookup(c, p->part, p->addr, p->vers, 0, &lockfail); - - if(b && blockWrite(b)){ - c->nflush++; - blockPut(b); - return 1; - } - if(b) - blockPut(b); - - /* - * Why didn't we write the block? - */ - - /* Block already written out */ - if(b == nil && !lockfail) - continue; - - /* Failed to acquire lock; sleep if happens a lot. */ - if(lockfail && ++nfail > 100){ - sleep(500); - nfail = 0; - } - /* Requeue block. */ - if(c->bw < c->be) - c->baddr[c->bw++] = *p; - } -} - -/* - * Occasionally flush dirty blocks from memory to the disk. - */ -static void -flushThread(void *a) -{ - Cache *c = a; - int i; - - vtThreadSetName("flush"); - vtLock(c->lk); - while(c->die == nil){ - vtSleep(c->flush); - vtUnlock(c->lk); - for(i=0; i<FlushSize; i++) - if(!cacheFlushBlock(c)){ - /* - * If i==0, could be someone is waking us repeatedly - * to flush the cache but there's no work to do. - * Pause a little. - */ - if(i==0){ - // fprint(2, "%s: flushthread found " - // "nothing to flush - %d dirty\n", - // argv0, c->ndirty); - sleep(250); - } - break; - } - if(i==0 && c->ndirty){ - /* - * All the blocks are being written right now -- there's nothing to do. - * We might be spinning with cacheFlush though -- he'll just keep - * kicking us until c->ndirty goes down. Probably we should sleep - * on something that the diskThread can kick, but for now we'll - * just pause for a little while waiting for disks to finish. - */ - sleep(100); - } - vtLock(c->lk); - vtWakeupAll(c->flushwait); - } - c->ref--; - vtWakeup(c->die); - vtUnlock(c->lk); -} - -/* - * Flush the cache. - */ -void -cacheFlush(Cache *c, int wait) -{ - /* - * Lock c->dirtylk so that more blocks aren't being dirtied - * while we try to write out what's already here. - * Otherwise we might not ever finish! - */ - vtLock(c->dirtylk); - vtLock(c->lk); - if(wait){ - while(c->ndirty){ - // consPrint("cacheFlush: %d dirty blocks, uhead %p\n", - // c->ndirty, c->uhead); - vtWakeup(c->flush); - vtSleep(c->flushwait); - } - // consPrint("cacheFlush: done (uhead %p)\n", c->ndirty, c->uhead); - }else if(c->ndirty) - vtWakeup(c->flush); - vtUnlock(c->lk); - vtUnlock(c->dirtylk); -} - -/* - * Kick the flushThread every 30 seconds. - */ -static void -cacheSync(void *v) -{ - Cache *c; - - c = v; - cacheFlush(c, 0); -} diff --git a/sys/src/cmd/fossil/check.c b/sys/src/cmd/fossil/check.c deleted file mode 100644 index 03ece44a6..000000000 --- a/sys/src/cmd/fossil/check.c +++ /dev/null @@ -1,799 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" - -static void checkDirs(Fsck*); -static void checkEpochs(Fsck*); -static void checkLeak(Fsck*); -static void closenop(Fsck*, Block*, u32int); -static void clrenop(Fsck*, Block*, int); -static void clrinop(Fsck*, char*, MetaBlock*, int, Block*); -static void error(Fsck*, char*, ...); -static int getBit(uchar*, u32int); -static int printnop(char*, ...); -static void setBit(uchar*, u32int); -static int walkEpoch(Fsck *chk, Block *b, uchar score[VtScoreSize], - int type, u32int tag, u32int epoch); -static void warn(Fsck*, char*, ...); - -#pragma varargck argpos error 2 -#pragma varargck argpos printnop 1 -#pragma varargck argpos warn 2 - -static Fsck* -checkInit(Fsck *chk) -{ - chk->cache = chk->fs->cache; - chk->nblocks = cacheLocalSize(chk->cache, PartData);; - chk->bsize = chk->fs->blockSize; - chk->walkdepth = 0; - chk->hint = 0; - chk->quantum = chk->nblocks/100; - if(chk->quantum == 0) - chk->quantum = 1; - if(chk->print == nil) - chk->print = printnop; - if(chk->clre == nil) - chk->clre = clrenop; - if(chk->close == nil) - chk->close = closenop; - if(chk->clri == nil) - chk->clri = clrinop; - return chk; -} - -/* - * BUG: Should merge checkEpochs and checkDirs so that - * bad blocks are only reported once, and so that errors in checkEpochs - * can have the affected file names attached, and so that the file system - * is only read once. - * - * Also should summarize the errors instead of printing for every one - * (e.g., XXX bad or unreachable blocks in /active/usr/rsc/foo). - */ - -void -fsCheck(Fsck *chk) -{ - Block *b; - Super super; - - checkInit(chk); - b = superGet(chk->cache, &super); - if(b == nil){ - chk->print("could not load super block: %R"); - return; - } - blockPut(b); - - chk->hint = super.active; - checkEpochs(chk); - - chk->smap = vtMemAllocZ(chk->nblocks/8+1); - checkDirs(chk); - vtMemFree(chk->smap); -} - -static void checkEpoch(Fsck*, u32int); - -/* - * Walk through all the blocks in the write buffer. - * Then we can look for ones we missed -- those are leaks. - */ -static void -checkEpochs(Fsck *chk) -{ - u32int e; - uint nb; - - nb = chk->nblocks; - chk->amap = vtMemAllocZ(nb/8+1); - chk->emap = vtMemAllocZ(nb/8+1); - chk->xmap = vtMemAllocZ(nb/8+1); - chk->errmap = vtMemAllocZ(nb/8+1); - - for(e = chk->fs->ehi; e >= chk->fs->elo; e--){ - memset(chk->emap, 0, chk->nblocks/8+1); - memset(chk->xmap, 0, chk->nblocks/8+1); - checkEpoch(chk, e); - } - checkLeak(chk); - vtMemFree(chk->amap); - vtMemFree(chk->emap); - vtMemFree(chk->xmap); - vtMemFree(chk->errmap); -} - -static void -checkEpoch(Fsck *chk, u32int epoch) -{ - u32int a; - Block *b; - Entry e; - Label l; - - chk->print("checking epoch %ud...\n", epoch); - - for(a=0; a<chk->nblocks; a++){ - if(!readLabel(chk->cache, &l, (a+chk->hint)%chk->nblocks)){ - error(chk, "could not read label for addr 0x%.8#ux", a); - continue; - } - if(l.tag == RootTag && l.epoch == epoch) - break; - } - - if(a == chk->nblocks){ - chk->print("could not find root block for epoch %ud", epoch); - return; - } - - a = (a+chk->hint)%chk->nblocks; - b = cacheLocalData(chk->cache, a, BtDir, RootTag, OReadOnly, 0); - if(b == nil){ - error(chk, "could not read root block 0x%.8#ux: %R", a); - return; - } - - /* no one should point at root blocks */ - setBit(chk->amap, a); - setBit(chk->emap, a); - setBit(chk->xmap, a); - - /* - * First entry is the rest of the file system. - * Second entry is link to previous epoch root, - * just a convenience to help the search. - */ - if(!entryUnpack(&e, b->data, 0)){ - error(chk, "could not unpack root block 0x%.8#ux: %R", a); - blockPut(b); - return; - } - walkEpoch(chk, b, e.score, BtDir, e.tag, epoch); - if(entryUnpack(&e, b->data, 1)) - chk->hint = globalToLocal(e.score); - blockPut(b); -} - -/* - * When b points at bb, need to check: - * - * (i) b.e in [bb.e, bb.eClose) - * (ii) if b.e==bb.e, then no other b' in e points at bb. - * (iii) if !(b.state&Copied) and b.e==bb.e then no other b' points at bb. - * (iv) if b is active then no other active b' points at bb. - * (v) if b is a past life of b' then only one of b and b' is active - * (too hard to check) - */ -static int -walkEpoch(Fsck *chk, Block *b, uchar score[VtScoreSize], int type, u32int tag, - u32int epoch) -{ - int i, ret; - u32int addr, ep; - Block *bb; - Entry e; - - if(b && chk->walkdepth == 0 && chk->printblocks) - chk->print("%V %d %#.8ux %#.8ux\n", b->score, b->l.type, - b->l.tag, b->l.epoch); - - if(!chk->useventi && globalToLocal(score) == NilBlock) - return 1; - - chk->walkdepth++; - - bb = cacheGlobal(chk->cache, score, type, tag, OReadOnly); - if(bb == nil){ - error(chk, "could not load block %V type %d tag %ux: %R", - score, type, tag); - chk->walkdepth--; - return 0; - } - if(chk->printblocks) - chk->print("%*s%V %d %#.8ux %#.8ux\n", chk->walkdepth*2, "", - score, type, tag, bb->l.epoch); - - ret = 0; - addr = globalToLocal(score); - if(addr == NilBlock){ - ret = 1; - goto Exit; - } - - if(b){ - /* (i) */ - if(b->l.epoch < bb->l.epoch || bb->l.epochClose <= b->l.epoch){ - error(chk, "walk: block %#ux [%ud, %ud) points at %#ux [%ud, %ud)", - b->addr, b->l.epoch, b->l.epochClose, - bb->addr, bb->l.epoch, bb->l.epochClose); - goto Exit; - } - - /* (ii) */ - if(b->l.epoch == epoch && bb->l.epoch == epoch){ - if(getBit(chk->emap, addr)){ - error(chk, "walk: epoch join detected: addr %#ux %L", - bb->addr, &bb->l); - goto Exit; - } - setBit(chk->emap, addr); - } - - /* (iii) */ - if(!(b->l.state&BsCopied) && b->l.epoch == bb->l.epoch){ - if(getBit(chk->xmap, addr)){ - error(chk, "walk: copy join detected; addr %#ux %L", - bb->addr, &bb->l); - goto Exit; - } - setBit(chk->xmap, addr); - } - } - - /* (iv) */ - if(epoch == chk->fs->ehi){ - /* - * since epoch==fs->ehi is first, amap is same as - * ``have seen active'' - */ - if(getBit(chk->amap, addr)){ - error(chk, "walk: active join detected: addr %#ux %L", - bb->addr, &bb->l); - goto Exit; - } - if(bb->l.state&BsClosed) - error(chk, "walk: addr %#ux: block is in active tree but is closed", - addr); - }else - if(!getBit(chk->amap, addr)) - if(!(bb->l.state&BsClosed)){ - // error(chk, "walk: addr %#ux: block is not in active tree, not closed (%d)", - // addr, bb->l.epochClose); - chk->close(chk, bb, epoch+1); - chk->nclose++; - } - - if(getBit(chk->amap, addr)){ - ret = 1; - goto Exit; - } - setBit(chk->amap, addr); - - if(chk->nseen++%chk->quantum == 0) - chk->print("check: visited %d/%d blocks (%.0f%%)\n", - chk->nseen, chk->nblocks, chk->nseen*100./chk->nblocks); - - b = nil; /* make sure no more refs to parent */ - USED(b); - - switch(type){ - default: - /* pointer block */ - for(i = 0; i < chk->bsize/VtScoreSize; i++) - if(!walkEpoch(chk, bb, bb->data + i*VtScoreSize, - type-1, tag, epoch)){ - setBit(chk->errmap, bb->addr); - chk->clrp(chk, bb, i); - chk->nclrp++; - } - break; - case BtData: - break; - case BtDir: - for(i = 0; i < chk->bsize/VtEntrySize; i++){ - if(!entryUnpack(&e, bb->data, i)){ - // error(chk, "walk: could not unpack entry: %ux[%d]: %R", - // addr, i); - setBit(chk->errmap, bb->addr); - chk->clre(chk, bb, i); - chk->nclre++; - continue; - } - if(!(e.flags & VtEntryActive)) - continue; -if(0) fprint(2, "%x[%d] tag=%x snap=%d score=%V\n", - addr, i, e.tag, e.snap, e.score); - ep = epoch; - if(e.snap != 0){ - if(e.snap >= epoch){ - // error(chk, "bad snap in entry: %ux[%d] snap = %ud: epoch = %ud", - // addr, i, e.snap, epoch); - setBit(chk->errmap, bb->addr); - chk->clre(chk, bb, i); - chk->nclre++; - continue; - } - continue; - } - if(e.flags & VtEntryLocal){ - if(e.tag < UserTag) - if(e.tag != RootTag || tag != RootTag || i != 1){ - // error(chk, "bad tag in entry: %ux[%d] tag = %ux", - // addr, i, e.tag); - setBit(chk->errmap, bb->addr); - chk->clre(chk, bb, i); - chk->nclre++; - continue; - } - }else - if(e.tag != 0){ - // error(chk, "bad tag in entry: %ux[%d] tag = %ux", - // addr, i, e.tag); - setBit(chk->errmap, bb->addr); - chk->clre(chk, bb, i); - chk->nclre++; - continue; - } - if(!walkEpoch(chk, bb, e.score, entryType(&e), - e.tag, ep)){ - setBit(chk->errmap, bb->addr); - chk->clre(chk, bb, i); - chk->nclre++; - } - } - break; - } - - ret = 1; - -Exit: - chk->walkdepth--; - blockPut(bb); - return ret; -} - -/* - * We've just walked the whole write buffer. Notice blocks that - * aren't marked available but that we didn't visit. They are lost. - */ -static void -checkLeak(Fsck *chk) -{ - u32int a, nfree, nlost; - Block *b; - Label l; - - nfree = 0; - nlost = 0; - - for(a = 0; a < chk->nblocks; a++){ - if(!readLabel(chk->cache, &l, a)){ - error(chk, "could not read label: addr 0x%ux %d %d: %R", - a, l.type, l.state); - continue; - } - if(getBit(chk->amap, a)) - continue; - if(l.state == BsFree || l.epochClose <= chk->fs->elo || - l.epochClose == l.epoch){ - nfree++; - setBit(chk->amap, a); - continue; - } - if(l.state&BsClosed) - continue; - nlost++; -// warn(chk, "unreachable block: addr 0x%ux type %d tag 0x%ux " -// "state %s epoch %ud close %ud", a, l.type, l.tag, -// bsStr(l.state), l.epoch, l.epochClose); - b = cacheLocal(chk->cache, PartData, a, OReadOnly); - if(b == nil){ - error(chk, "could not read block 0x%#.8ux", a); - continue; - } - chk->close(chk, b, 0); - chk->nclose++; - setBit(chk->amap, a); - blockPut(b); - } - chk->print("fsys blocks: total=%ud used=%ud(%.1f%%) free=%ud(%.1f%%) lost=%ud(%.1f%%)\n", - chk->nblocks, - chk->nblocks - nfree-nlost, - 100.*(chk->nblocks - nfree - nlost)/chk->nblocks, - nfree, 100.*nfree/chk->nblocks, - nlost, 100.*nlost/chk->nblocks); -} - - -/* - * Check that all sources in the tree are accessible. - */ -static Source * -openSource(Fsck *chk, Source *s, char *name, uchar *bm, u32int offset, - u32int gen, int dir, MetaBlock *mb, int i, Block *b) -{ - Source *r; - - r = nil; - if(getBit(bm, offset)){ - warn(chk, "multiple references to source: %s -> %d", - name, offset); - goto Err; - } - setBit(bm, offset); - - r = sourceOpen(s, offset, OReadOnly, 0); - if(r == nil){ - warn(chk, "could not open source: %s -> %d: %R", name, offset); - goto Err; - } - - if(r->gen != gen){ - warn(chk, "source has been removed: %s -> %d", name, offset); - goto Err; - } - - if(r->dir != dir){ - warn(chk, "dir mismatch: %s -> %d", name, offset); - goto Err; - } - return r; -Err: - chk->clri(chk, name, mb, i, b); - chk->nclri++; - if(r) - sourceClose(r); - return nil; -} - -typedef struct MetaChunk MetaChunk; -struct MetaChunk { - ushort offset; - ushort size; - ushort index; -}; - -static int -offsetCmp(void *s0, void *s1) -{ - MetaChunk *mc0, *mc1; - - mc0 = s0; - mc1 = s1; - if(mc0->offset < mc1->offset) - return -1; - if(mc0->offset > mc1->offset) - return 1; - return 0; -} - -/* - * Fsck that MetaBlock has reasonable header, sorted entries, - */ -static int -chkMetaBlock(MetaBlock *mb) -{ - MetaChunk *mc; - int oo, o, n, i; - uchar *p; - - mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk)); - p = mb->buf + MetaHeaderSize; - for(i = 0; i < mb->nindex; i++){ - mc[i].offset = p[0]<<8 | p[1]; - mc[i].size = p[2]<<8 | p[3]; - mc[i].index = i; - p += MetaIndexSize; - } - - qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp); - - /* check block looks ok */ - oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; - o = oo; - n = 0; - for(i = 0; i < mb->nindex; i++){ - o = mc[i].offset; - n = mc[i].size; - if(o < oo) - goto Err; - oo += n; - } - if(o+n > mb->size || mb->size - oo != mb->free) - goto Err; - - vtMemFree(mc); - return 1; - -Err: -if(0){ - fprint(2, "metaChunks failed!\n"); - oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; - for(i=0; i<mb->nindex; i++){ - fprint(2, "\t%d: %d %d\n", i, mc[i].offset, - mc[i].offset + mc[i].size); - oo += mc[i].size; - } - fprint(2, "\tused=%d size=%d free=%d free2=%d\n", - oo, mb->size, mb->free, mb->size - oo); -} - vtMemFree(mc); - return 0; -} - -static void -scanSource(Fsck *chk, char *name, Source *r) -{ - u32int a, nb, o; - Block *b; - Entry e; - - if(!chk->useventi && globalToLocal(r->score)==NilBlock) - return; - if(!sourceGetEntry(r, &e)){ - error(chk, "could not get entry for %s", name); - return; - } - a = globalToLocal(e.score); - if(!chk->useventi && a==NilBlock) - return; - if(getBit(chk->smap, a)) - return; - setBit(chk->smap, a); - - nb = (sourceGetSize(r) + r->dsize-1) / r->dsize; - for(o = 0; o < nb; o++){ - b = sourceBlock(r, o, OReadOnly); - if(b == nil){ - error(chk, "could not read block in data file %s", name); - continue; - } - if(b->addr != NilBlock && getBit(chk->errmap, b->addr)){ - warn(chk, "previously reported error in block %ux is in file %s", - b->addr, name); - } - blockPut(b); - } -} - -/* - * Walk the source tree making sure that the BtData - * sources containing directory entries are okay. - */ -static void -chkDir(Fsck *chk, char *name, Source *source, Source *meta) -{ - int i; - u32int a1, a2, nb, o; - char *s, *nn; - uchar *bm; - Block *b, *bb; - DirEntry de; - Entry e1, e2; - MetaBlock mb; - MetaEntry me; - Source *r, *mr; - - if(!chk->useventi && globalToLocal(source->score)==NilBlock && - globalToLocal(meta->score)==NilBlock) - return; - - if(!sourceLock2(source, meta, OReadOnly)){ - warn(chk, "could not lock sources for %s: %R", name); - return; - } - if(!sourceGetEntry(source, &e1) || !sourceGetEntry(meta, &e2)){ - warn(chk, "could not load entries for %s: %R", name); - return; - } - a1 = globalToLocal(e1.score); - a2 = globalToLocal(e2.score); - if((!chk->useventi && a1==NilBlock && a2==NilBlock) - || (getBit(chk->smap, a1) && getBit(chk->smap, a2))){ - sourceUnlock(source); - sourceUnlock(meta); - return; - } - setBit(chk->smap, a1); - setBit(chk->smap, a2); - - bm = vtMemAllocZ(sourceGetDirSize(source)/8 + 1); - - nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize; - for(o = 0; o < nb; o++){ - b = sourceBlock(meta, o, OReadOnly); - if(b == nil){ - error(chk, "could not read block in meta file: %s[%ud]: %R", - name, o); - continue; - } -if(0) fprint(2, "source %V:%d block %d addr %d\n", source->score, - source->offset, o, b->addr); - if(b->addr != NilBlock && getBit(chk->errmap, b->addr)) - warn(chk, "previously reported error in block %ux is in %s", - b->addr, name); - - if(!mbUnpack(&mb, b->data, meta->dsize)){ - error(chk, "could not unpack meta block: %s[%ud]: %R", - name, o); - blockPut(b); - continue; - } - if(!chkMetaBlock(&mb)){ - error(chk, "bad meta block: %s[%ud]: %R", name, o); - blockPut(b); - continue; - } - s = nil; - for(i=mb.nindex-1; i>=0; i--){ - meUnpack(&me, &mb, i); - if(!deUnpack(&de, &me)){ - error(chk, - "could not unpack dir entry: %s[%ud][%d]: %R", - name, o, i); - continue; - } - if(s && strcmp(s, de.elem) <= 0) - error(chk, - "dir entry out of order: %s[%ud][%d] = %s last = %s", - name, o, i, de.elem, s); - vtMemFree(s); - s = vtStrDup(de.elem); - nn = smprint("%s/%s", name, de.elem); - if(nn == nil){ - error(chk, "out of memory"); - continue; - } - if(chk->printdirs) - if(de.mode&ModeDir) - chk->print("%s/\n", nn); - if(chk->printfiles) - if(!(de.mode&ModeDir)) - chk->print("%s\n", nn); - if(!(de.mode & ModeDir)){ - r = openSource(chk, source, nn, bm, de.entry, - de.gen, 0, &mb, i, b); - if(r != nil){ - if(sourceLock(r, OReadOnly)){ - scanSource(chk, nn, r); - sourceUnlock(r); - } - sourceClose(r); - } - deCleanup(&de); - free(nn); - continue; - } - - r = openSource(chk, source, nn, bm, de.entry, - de.gen, 1, &mb, i, b); - if(r == nil){ - deCleanup(&de); - free(nn); - continue; - } - - mr = openSource(chk, source, nn, bm, de.mentry, - de.mgen, 0, &mb, i, b); - if(mr == nil){ - sourceClose(r); - deCleanup(&de); - free(nn); - continue; - } - - if(!(de.mode&ModeSnapshot) || chk->walksnapshots) - chkDir(chk, nn, r, mr); - - sourceClose(mr); - sourceClose(r); - deCleanup(&de); - free(nn); - deCleanup(&de); - - } - vtMemFree(s); - blockPut(b); - } - - nb = sourceGetDirSize(source); - for(o=0; o<nb; o++){ - if(getBit(bm, o)) - continue; - r = sourceOpen(source, o, OReadOnly, 0); - if(r == nil) - continue; - warn(chk, "non referenced entry in source %s[%d]", name, o); - if((bb = sourceBlock(source, o/(source->dsize/VtEntrySize), - OReadOnly)) != nil){ - if(bb->addr != NilBlock){ - setBit(chk->errmap, bb->addr); - chk->clre(chk, bb, o%(source->dsize/VtEntrySize)); - chk->nclre++; - } - blockPut(bb); - } - sourceClose(r); - } - - sourceUnlock(source); - sourceUnlock(meta); - vtMemFree(bm); -} - -static void -checkDirs(Fsck *chk) -{ - Source *r, *mr; - - sourceLock(chk->fs->source, OReadOnly); - r = sourceOpen(chk->fs->source, 0, OReadOnly, 0); - mr = sourceOpen(chk->fs->source, 1, OReadOnly, 0); - sourceUnlock(chk->fs->source); - chkDir(chk, "", r, mr); - - sourceClose(r); - sourceClose(mr); -} - -static void -setBit(uchar *bmap, u32int addr) -{ - if(addr == NilBlock) - return; - - bmap[addr>>3] |= 1 << (addr & 7); -} - -static int -getBit(uchar *bmap, u32int addr) -{ - if(addr == NilBlock) - return 0; - - return (bmap[addr>>3] >> (addr & 7)) & 1; -} - -static void -error(Fsck *chk, char *fmt, ...) -{ - char buf[256]; - va_list arg; - static int nerr; - - va_start(arg, fmt); - vseprint(buf, buf+sizeof buf, fmt, arg); - va_end(arg); - - chk->print("error: %s\n", buf); - -// if(nerr++ > 20) -// vtFatal("too many errors"); -} - -static void -warn(Fsck *chk, char *fmt, ...) -{ - char buf[256]; - va_list arg; - static int nerr; - - va_start(arg, fmt); - vseprint(buf, buf+sizeof buf, fmt, arg); - va_end(arg); - - chk->print("error: %s\n", buf); -} - -static void -clrenop(Fsck*, Block*, int) -{ -} - -static void -closenop(Fsck*, Block*, u32int) -{ -} - -static void -clrinop(Fsck*, char*, MetaBlock*, int, Block*) -{ -} - -static int -printnop(char*, ...) -{ - return 0; -} diff --git a/sys/src/cmd/fossil/conf.rc b/sys/src/cmd/fossil/conf.rc deleted file mode 100755 index b5dfcb198..000000000 --- a/sys/src/cmd/fossil/conf.rc +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/rc - -# the fossil configuration is stored at the 127kB offset in the disk -# and extends for at most 1 kB. - -rfork e -fn usage { - echo 'usage: fossil/conf [-w] /dev/sdC0/fossil [config]' >[1=2] - exit usage -} - -wflag=no -while(! ~ $#* 0 && ~ $1 -* && ! ~ $1 --){ - switch($1){ - case -w - wflag=yes - case * - usage - } - shift -} -if(~ $1 --) - shift - -if(~ $wflag no && ! ~ $#* 1) - usage -if(~ $wflag yes && ! ~ $#* 1 2) - usage - -disk=$1 -if(! test -f $disk){ - echo 'unknown disk' $1 >[1=2] - exit nodisk -} - -fn sigexit { - rm -f /tmp/fossilconf.$pid -} - -if(~ $wflag yes){ - {echo fossil config; cat $2} >/tmp/fossilconf.$pid || exit oops - if(! test -s /tmp/fossilconf.$pid){ - echo 'config is empty; will not install' >[1=2] - exit emptyconfig - } - if(test `{ls -l /tmp/fossilconf.$pid | awk '{print $6}'} -gt 1024){ - echo 'config is too long; max is a little less than a kilobyte' >[1=2] - exit toolong - } - dd -quiet 1 -bs 1024 -count 1 -if $disk -iseek 127 \ - >/tmp/_fossilconf.old || exit backup - dd -quiet 1 -count 2 </dev/zero >>/tmp/fossilconf.$pid || exit dd - dd -quiet 1 -bs 1024 -count 1 -if /tmp/fossilconf.$pid \ - -trunc 0 -of $disk -oseek 127 || exit dd2 - exit 0 -} - -dd -quiet 1 -bs 1024 -count 1 -if $disk -iseek 127 | - aux/zerotrunc >/tmp/fossilconf.$pid - -if(! cmp -s <{sed 1q /tmp/fossilconf.$pid} <{echo fossil config}){ - echo 'config has bad header' >[1=2] - exit badconfig -} - -sed 1d /tmp/fossilconf.$pid -exit 0 - diff --git a/sys/src/cmd/fossil/dat.h b/sys/src/cmd/fossil/dat.h deleted file mode 100644 index b5797c6d7..000000000 --- a/sys/src/cmd/fossil/dat.h +++ /dev/null @@ -1,328 +0,0 @@ -typedef struct Arch Arch; -typedef struct BList BList; -typedef struct Block Block; -typedef struct Cache Cache; -typedef struct Disk Disk; -typedef struct Entry Entry; -typedef struct Fsck Fsck; -typedef struct Header Header; -typedef struct Label Label; -typedef struct Periodic Periodic; -typedef struct Snap Snap; -typedef struct Source Source; -typedef struct Super Super; -typedef struct WalkPtr WalkPtr; - -#pragma incomplete Arch -#pragma incomplete BList -#pragma incomplete Cache -#pragma incomplete Disk -#pragma incomplete Periodic -#pragma incomplete Snap - -/* tunable parameters - probably should not be constants */ -enum { - /* - * estimate of bytes per dir entries - determines number - * of index entries in the block - */ - BytesPerEntry = 100, - /* don't allocate in block if more than this percentage full */ - FullPercentage = 80, - FlushSize = 200, /* number of blocks to flush */ - DirtyPercentage = 50, /* maximum percentage of dirty blocks */ -}; - -enum { - NilBlock = (~0UL), - MaxBlock = (1UL<<31), -}; - -enum { - HeaderMagic = 0x3776ae89, - HeaderVersion = 1, - HeaderOffset = 128*1024, - HeaderSize = 512, - SuperMagic = 0x2340a3b1, - SuperSize = 512, - SuperVersion = 1, - LabelSize = 14, -}; - -/* well known tags */ -enum { - BadTag = 0, /* this tag should not be used */ - RootTag = 1, /* root of fs */ - EnumTag, /* root of a dir listing */ - UserTag = 32, /* all other tags should be >= UserTag */ -}; - -struct Super { - u16int version; - u32int epochLow; - u32int epochHigh; - u64int qid; /* next qid */ - u32int active; /* root of active file system */ - u32int next; /* root of next snapshot to archive */ - u32int current; /* root of snapshot currently archiving */ - uchar last[VtScoreSize]; /* last snapshot successfully archived */ - char name[128]; /* label */ -}; - - -struct Fs { - Arch *arch; /* immutable */ - Cache *cache; /* immutable */ - int mode; /* immutable */ - int blockSize; /* immutable */ - VtSession *z; /* immutable */ - Snap *snap; /* immutable */ - /* immutable; copy here & Fsys to ease error reporting */ - char *name; - - Periodic *metaFlush; /* periodically flushes metadata cached in files */ - - /* - * epoch lock. - * Most operations on the fs require a read lock of elk, ensuring that - * the current high and low epochs do not change under foot. - * This lock is mostly acquired via a call to fileLock or fileRlock. - * Deletion and creation of snapshots occurs under a write lock of elk, - * ensuring no file operations are occurring concurrently. - */ - VtLock *elk; /* epoch lock */ - u32int ehi; /* epoch high */ - u32int elo; /* epoch low */ - - int halted; /* epoch lock is held to halt (console initiated) */ - - Source *source; /* immutable: root of sources */ - File *file; /* immutable: root of files */ -}; - -/* - * variant on VtEntry - * there are extra fields when stored locally - */ -struct Entry { - u32int gen; /* generation number */ - ushort psize; /* pointer block size */ - ushort dsize; /* data block size */ - uchar depth; /* unpacked from flags */ - uchar flags; - uvlong size; - uchar score[VtScoreSize]; - u32int tag; /* tag for local blocks: zero if stored on Venti */ - u32int snap; /* non-zero -> entering snapshot of given epoch */ - uchar archive; /* archive this snapshot: only valid for snap != 0 */ -}; - -/* - * This is called a `stream' in the fossil paper. There used to be Sinks too. - * We believe that Sources and Files are one-to-one. - */ -struct Source { - Fs *fs; /* immutable */ - int mode; /* immutable */ - int issnapshot; /* immutable */ - u32int gen; /* immutable */ - int dsize; /* immutable */ - int dir; /* immutable */ - - Source *parent; /* immutable */ - File *file; /* immutable; point back */ - - VtLock *lk; - int ref; - /* - * epoch for the source - * for ReadWrite sources, epoch is used to lazily notice - * sources that must be split from the snapshots. - * for ReadOnly sources, the epoch represents the minimum epoch - * along the chain from the root, and is used to lazily notice - * sources that have become invalid because they belong to an old - * snapshot. - */ - u32int epoch; - Block *b; /* block containing this source */ - uchar score[VtScoreSize]; /* score of block containing this source */ - u32int scoreEpoch; /* epoch of block containing this source */ - int epb; /* immutable: entries per block in parent */ - u32int tag; /* immutable: tag of parent */ - u32int offset; /* immutable: entry offset in parent */ -}; - - -struct Header { - ushort version; - ushort blockSize; - ulong super; /* super blocks */ - ulong label; /* start of labels */ - ulong data; /* end of labels - start of data blocks */ - ulong end; /* end of data blocks */ -}; - -/* - * contains a one block buffer - * to avoid problems of the block changing underfoot - * and to enable an interface that supports unget. - */ -struct DirEntryEnum { - File *file; - - u32int boff; /* block offset */ - - int i, n; - DirEntry *buf; -}; - -/* Block states */ -enum { - BsFree = 0, /* available for allocation */ - BsBad = 0xFF, /* something is wrong with this block */ - - /* bit fields */ - BsAlloc = 1<<0, /* block is in use */ - BsCopied = 1<<1,/* block has been copied (usually in preparation for unlink) */ - BsVenti = 1<<2, /* block has been stored on Venti */ - BsClosed = 1<<3,/* block has been unlinked on disk from active file system */ - BsMask = BsAlloc|BsCopied|BsVenti|BsClosed, -}; - -/* - * block types - * more regular than Venti block types - * bit 3 -> block or data block - * bits 2-0 -> level of block - */ -enum { - BtData, - BtDir = 1<<3, - BtLevelMask = 7, - BtMax = 1<<4, -}; - -/* io states */ -enum { - BioEmpty, /* label & data are not valid */ - BioLabel, /* label is good */ - BioClean, /* data is on the disk */ - BioDirty, /* data is not yet on the disk */ - BioReading, /* in process of reading data */ - BioWriting, /* in process of writing data */ - BioReadError, /* error reading: assume disk always handles write errors */ - BioVentiError, /* error reading from venti (probably disconnected) */ - BioMax -}; - -struct Label { - uchar type; - uchar state; - u32int tag; - u32int epoch; - u32int epochClose; -}; - -struct Block { - Cache *c; - int ref; - int nlock; - uintptr pc; /* pc that fetched this block from the cache */ - - VtLock *lk; - - int part; - u32int addr; - uchar score[VtScoreSize]; /* score */ - Label l; - - uchar *dmap; - - uchar *data; - - /* the following is private; used by cache */ - - Block *next; /* doubly linked hash chains */ - Block **prev; - u32int heap; /* index in heap table */ - u32int used; /* last reference times */ - - u32int vers; /* version of dirty flag */ - - BList *uhead; /* blocks to unlink when this block is written */ - BList *utail; - - /* block ordering for cache -> disk */ - BList *prior; /* list of blocks before this one */ - - Block *ionext; - int iostate; - VtRendez *ioready; -}; - -/* tree walker, for gc and archiver */ -struct WalkPtr -{ - uchar *data; - int isEntry; - int n; - int m; - Entry e; - uchar type; - u32int tag; -}; - -enum -{ - DoClose = 1<<0, - DoClre = 1<<1, - DoClri = 1<<2, - DoClrp = 1<<3, -}; - -struct Fsck -{ - /* filled in by caller */ - int printblocks; - int useventi; - int flags; - int printdirs; - int printfiles; - int walksnapshots; - int walkfs; - Fs *fs; - int (*print)(char*, ...); - void (*clre)(Fsck*, Block*, int); - void (*clrp)(Fsck*, Block*, int); - void (*close)(Fsck*, Block*, u32int); - void (*clri)(Fsck*, char*, MetaBlock*, int, Block*); - - /* used internally */ - Cache *cache; - uchar *amap; /* all blocks seen so far */ - uchar *emap; /* all blocks seen in this epoch */ - uchar *xmap; /* all blocks in this epoch with parents in this epoch */ - uchar *errmap; /* blocks with errors */ - uchar *smap; /* walked sources */ - int nblocks; - int bsize; - int walkdepth; - u32int hint; /* where the next root probably is */ - int nseen; - int quantum; - int nclre; - int nclrp; - int nclose; - int nclri; -}; - -/* disk partitions; keep in sync with partname[] in disk.c */ -enum { - PartError, - PartSuper, - PartLabel, - PartData, - PartVenti, /* fake partition */ -}; - -extern vtType[BtMax]; diff --git a/sys/src/cmd/fossil/deadlock b/sys/src/cmd/fossil/deadlock deleted file mode 100644 index 7f3eebc3c..000000000 --- a/sys/src/cmd/fossil/deadlock +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/rc - -rfork e - -x=($*) -if(~ $#x 0){ - x=`{ps |awk '$NF=="8.fossil" {print $2}'} - ps | awk '$7=="8.fossil"' -} -if(~ $#x 0){ - x=`{ps | awk '$NF=="fossil" {print $2}'} - ps -a | awk '$7 == "fossil"' -} - -y=$x^', ' -y=$"y -echo 'include("/sys/src/cmd/fossil/fossil-acid"); -print("--XXX\n"); -deadlocklist({' ^ $y ^ '}); -print("--YYY\n");' | - acid $x(1) | - sed -n '/--XXX/,/--YYY/p' | - sed 's/acid: //g' | - grep -v '^--' - diff --git a/sys/src/cmd/fossil/disk.c b/sys/src/cmd/fossil/disk.c deleted file mode 100644 index 3ae43fb6d..000000000 --- a/sys/src/cmd/fossil/disk.c +++ /dev/null @@ -1,406 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -static void diskThread(void *a); - -enum { - /* - * disable measurement since it gets alignment faults on BG - * and the guts used to be commented out. - */ - Timing = 0, /* flag */ - QueueSize = 100, /* maximum block to queue */ -}; - -struct Disk { - VtLock *lk; - int ref; - - int fd; - Header h; - - VtRendez *flow; - VtRendez *starve; - VtRendez *flush; - VtRendez *die; - - int nqueue; - - Block *cur; /* block to do on current scan */ - Block *next; /* blocks to do next scan */ -}; - -/* keep in sync with Part* enum in dat.h */ -static char *partname[] = { - [PartError] "error", - [PartSuper] "super", - [PartLabel] "label", - [PartData] "data", - [PartVenti] "venti", -}; - -Disk * -diskAlloc(int fd) -{ - u8int buf[HeaderSize]; - Header h; - Disk *disk; - - if(pread(fd, buf, HeaderSize, HeaderOffset) < HeaderSize){ - vtSetError("short read: %r"); - vtOSError(); - return nil; - } - - if(!headerUnpack(&h, buf)){ - vtSetError("bad disk header"); - return nil; - } - disk = vtMemAllocZ(sizeof(Disk)); - disk->lk = vtLockAlloc(); - disk->starve = vtRendezAlloc(disk->lk); - disk->flow = vtRendezAlloc(disk->lk); - disk->flush = vtRendezAlloc(disk->lk); - disk->fd = fd; - disk->h = h; - - disk->ref = 2; - vtThread(diskThread, disk); - - return disk; -} - -void -diskFree(Disk *disk) -{ - diskFlush(disk); - - /* kill slave */ - vtLock(disk->lk); - disk->die = vtRendezAlloc(disk->lk); - vtWakeup(disk->starve); - while(disk->ref > 1) - vtSleep(disk->die); - vtUnlock(disk->lk); - vtRendezFree(disk->flow); - vtRendezFree(disk->starve); - vtRendezFree(disk->die); - vtLockFree(disk->lk); - close(disk->fd); - vtMemFree(disk); -} - -static u32int -partStart(Disk *disk, int part) -{ - switch(part){ - default: - assert(0); - case PartSuper: - return disk->h.super; - case PartLabel: - return disk->h.label; - case PartData: - return disk->h.data; - } -} - - -static u32int -partEnd(Disk *disk, int part) -{ - switch(part){ - default: - assert(0); - case PartSuper: - return disk->h.super+1; - case PartLabel: - return disk->h.data; - case PartData: - return disk->h.end; - } -} - -int -diskReadRaw(Disk *disk, int part, u32int addr, uchar *buf) -{ - ulong start, end; - u64int offset; - int n, nn; - - start = partStart(disk, part); - end = partEnd(disk, part); - - if(addr >= end-start){ - vtSetError(EBadAddr); - return 0; - } - - offset = ((u64int)(addr + start))*disk->h.blockSize; - n = disk->h.blockSize; - while(n > 0){ - nn = pread(disk->fd, buf, n, offset); - if(nn < 0){ - vtOSError(); - return 0; - } - if(nn == 0){ - vtSetError("eof reading disk"); - return 0; - } - n -= nn; - offset += nn; - buf += nn; - } - return 1; -} - -int -diskWriteRaw(Disk *disk, int part, u32int addr, uchar *buf) -{ - ulong start, end; - u64int offset; - int n; - - start = partStart(disk, part); - end = partEnd(disk, part); - - if(addr >= end - start){ - vtSetError(EBadAddr); - return 0; - } - - offset = ((u64int)(addr + start))*disk->h.blockSize; - n = pwrite(disk->fd, buf, disk->h.blockSize, offset); - if(n < 0){ - vtOSError(); - return 0; - } - if(n < disk->h.blockSize) { - vtSetError("short write"); - return 0; - } - - return 1; -} - -static void -diskQueue(Disk *disk, Block *b) -{ - Block **bp, *bb; - - vtLock(disk->lk); - while(disk->nqueue >= QueueSize) - vtSleep(disk->flow); - if(disk->cur == nil || b->addr > disk->cur->addr) - bp = &disk->cur; - else - bp = &disk->next; - - for(bb=*bp; bb; bb=*bp){ - if(b->addr < bb->addr) - break; - bp = &bb->ionext; - } - b->ionext = bb; - *bp = b; - if(disk->nqueue == 0) - vtWakeup(disk->starve); - disk->nqueue++; - vtUnlock(disk->lk); -} - - -void -diskRead(Disk *disk, Block *b) -{ - assert(b->iostate == BioEmpty || b->iostate == BioLabel); - blockSetIOState(b, BioReading); - diskQueue(disk, b); -} - -void -diskWrite(Disk *disk, Block *b) -{ - assert(b->nlock == 1); - assert(b->iostate == BioDirty); - blockSetIOState(b, BioWriting); - diskQueue(disk, b); -} - -void -diskWriteAndWait(Disk *disk, Block *b) -{ - int nlock; - - /* - * If b->nlock > 1, the block is aliased within - * a single thread. That thread is us. - * DiskWrite does some funny stuff with VtLock - * and blockPut that basically assumes b->nlock==1. - * We humor diskWrite by temporarily setting - * nlock to 1. This needs to be revisited. - */ - nlock = b->nlock; - if(nlock > 1) - b->nlock = 1; - diskWrite(disk, b); - while(b->iostate != BioClean) - vtSleep(b->ioready); - b->nlock = nlock; -} - -int -diskBlockSize(Disk *disk) -{ - return disk->h.blockSize; /* immuttable */ -} - -int -diskFlush(Disk *disk) -{ - Dir dir; - - vtLock(disk->lk); - while(disk->nqueue > 0) - vtSleep(disk->flush); - vtUnlock(disk->lk); - - /* there really should be a cleaner interface to flush an fd */ - nulldir(&dir); - if(dirfwstat(disk->fd, &dir) < 0){ - vtOSError(); - return 0; - } - return 1; -} - -u32int -diskSize(Disk *disk, int part) -{ - return partEnd(disk, part) - partStart(disk, part); -} - -static uintptr -mypc(int x) -{ - return getcallerpc(&x); -} - -static char * -disk2file(Disk *disk) -{ - static char buf[256]; - - if (fd2path(disk->fd, buf, sizeof buf) < 0) - strncpy(buf, "GOK", sizeof buf); - return buf; -} - -static void -diskThread(void *a) -{ - Disk *disk = a; - Block *b; - uchar *buf, *p; - double t; - int nio; - - vtThreadSetName("disk"); - -//fprint(2, "diskThread %d\n", getpid()); - - buf = vtMemAlloc(disk->h.blockSize); - - vtLock(disk->lk); - if (Timing) { - nio = 0; - t = -nsec(); - } - for(;;){ - while(disk->nqueue == 0){ - if (Timing) { - t += nsec(); - if(nio >= 10000){ - fprint(2, "disk: io=%d at %.3fms\n", - nio, t*1e-6/nio); - nio = 0; - t = 0; - } - } - if(disk->die != nil) - goto Done; - vtSleep(disk->starve); - if (Timing) - t -= nsec(); - } - assert(disk->cur != nil || disk->next != nil); - - if(disk->cur == nil){ - disk->cur = disk->next; - disk->next = nil; - } - b = disk->cur; - disk->cur = b->ionext; - vtUnlock(disk->lk); - - /* - * no one should hold onto blocking in the - * reading or writing state, so this lock should - * not cause deadlock. - */ -if(0)fprint(2, "fossil: diskThread: %d:%d %x\n", getpid(), b->part, b->addr); - bwatchLock(b); - vtLock(b->lk); - b->pc = mypc(0); - assert(b->nlock == 1); - switch(b->iostate){ - default: - abort(); - case BioReading: - if(!diskReadRaw(disk, b->part, b->addr, b->data)){ - fprint(2, "fossil: diskReadRaw failed: %s: " - "score %V: part=%s block %ud: %r\n", - disk2file(disk), b->score, - partname[b->part], b->addr); - blockSetIOState(b, BioReadError); - }else - blockSetIOState(b, BioClean); - break; - case BioWriting: - p = blockRollback(b, buf); - /* NB: ctime result ends with a newline */ - if(!diskWriteRaw(disk, b->part, b->addr, p)){ - fprint(2, "fossil: diskWriteRaw failed: %s: " - "score %V: date %s part=%s block %ud: %r\n", - disk2file(disk), b->score, - ctime(time(0)), - partname[b->part], b->addr); - break; - } - if(p != buf) - blockSetIOState(b, BioClean); - else - blockSetIOState(b, BioDirty); - break; - } - - blockPut(b); /* remove extra reference, unlock */ - vtLock(disk->lk); - disk->nqueue--; - if(disk->nqueue == QueueSize-1) - vtWakeup(disk->flow); - if(disk->nqueue == 0) - vtWakeup(disk->flush); - if(Timing) - nio++; - } -Done: -//fprint(2, "diskThread done\n"); - disk->ref--; - vtWakeup(disk->die); - vtUnlock(disk->lk); - vtMemFree(buf); -} diff --git a/sys/src/cmd/fossil/dump.c b/sys/src/cmd/fossil/dump.c deleted file mode 100644 index 4ad4f469d..000000000 --- a/sys/src/cmd/fossil/dump.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Clumsy hack to take snapshots and dumps. - */ -#include <u.h> -#include <libc.h> - -void -usage(void) -{ - fprint(2, "usage: fossil/dump [-i snap-interval] [-n name] fscons /n/fossil\n"); - exits("usage"); -} - -char* -snapnow(void) -{ - Tm t; - static char buf[100]; - - t = *localtime(time(0)-5*60*60); /* take dumps at 5:00 am */ - - sprint(buf, "archive/%d/%02d%02d", t.year+1900, t.mon+1, t.mday); - return buf; -} - -void -main(int argc, char **argv) -{ - int onlyarchive, cons, s; - ulong t, i; - char *name; - - name = "main"; - s = 0; - onlyarchive = 0; - i = 60*60; /* one hour */ - ARGBEGIN{ - case 'i': - i = atoi(EARGF(usage())); - if(i == 0){ - onlyarchive = 1; - i = 60*60; - } - break; - case 'n': - name = EARGF(usage()); - break; - case 's': - s = atoi(EARGF(usage())); - break; - }ARGEND - - if(argc != 2) - usage(); - - if((cons = open(argv[0], OWRITE)) < 0) - sysfatal("open %s: %r", argv[0]); - - if(chdir(argv[1]) < 0) - sysfatal("chdir %s: %r", argv[1]); - - rfork(RFNOTEG); - switch(fork()){ - case -1: - sysfatal("fork: %r"); - case 0: - break; - default: - exits(0); - } - - /* - * pause at boot time to let clock stabilize. - */ - if(s) - sleep(s*1000); - - for(;;){ - if(access(snapnow(), AEXIST) < 0) - fprint(cons, "\nfsys %s snap -a\n", name); - t = time(0); - sleep((i - t%i)*1000+200); - if(!onlyarchive) - fprint(cons, "\nfsys %s snap\n", name); - } -} diff --git a/sys/src/cmd/fossil/epoch.c b/sys/src/cmd/fossil/epoch.c deleted file mode 100644 index 6aa73bbf1..000000000 --- a/sys/src/cmd/fossil/epoch.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" - -uchar buf[65536]; - -void -usage(void) -{ - fprint(2, "usage: fossil/epoch fs [new-low-epoch]\n"); - exits("usage"); -} - -void -main(int argc, char **argv) -{ - int fd; - Header h; - Super s; - - ARGBEGIN{ - default: - usage(); - }ARGEND - - if(argc == 0 || argc > 2) - usage(); - - if((fd = open(argv[0], argc==2 ? ORDWR : OREAD)) < 0) - sysfatal("open %s: %r", argv[0]); - - if(pread(fd, buf, HeaderSize, HeaderOffset) != HeaderSize) - sysfatal("reading header: %r"); - if(!headerUnpack(&h, buf)) - sysfatal("unpacking header: %r"); - - if(pread(fd, buf, h.blockSize, (vlong)h.super*h.blockSize) != h.blockSize) - sysfatal("reading super block: %r"); - - if(!superUnpack(&s, buf)) - sysfatal("unpacking super block: %r"); - - print("epoch %d\n", s.epochLow); - if(argc == 2){ - s.epochLow = strtoul(argv[1], 0, 0); - superPack(&s, buf); - if(pwrite(fd, buf, h.blockSize, (vlong)h.super*h.blockSize) != h.blockSize) - sysfatal("writing super block: %r"); - } - exits(0); -} diff --git a/sys/src/cmd/fossil/error.c b/sys/src/cmd/fossil/error.c deleted file mode 100644 index 3a0b701fc..000000000 --- a/sys/src/cmd/fossil/error.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -char EBadAddr[] = "illegal block address"; -char EBadDir[] = "corrupted directory entry"; -char EBadEntry[] = "corrupted file entry"; -char EBadLabel[] = "corrupted block label"; -char EBadMeta[] = "corrupted meta data"; -char EBadMode[] = "illegal mode"; -char EBadOffset[] = "illegal offset"; -char EBadPath[] = "illegal path element"; -char EBadRoot[] = "root of file system is corrupted"; -char EBadSuper[] = "corrupted super block"; -char EBlockTooBig[] = "block too big"; -char ECacheFull[] = "no free blocks in memory cache"; -char EConvert[] = "protocol botch"; -char EExists[] = "file already exists"; -char EFsFill[] = "file system is full"; -char EIO[] = "i/o error"; -char EInUse[] = "file is in use"; -char ELabelMismatch[] = "block label mismatch"; -char ENilBlock[] = "illegal block address"; -char ENoDir[] = "directory entry is not allocated"; -char ENoFile[] = "file does not exist"; -char ENotDir[] = "not a directory"; -char ENotEmpty[] = "directory not empty"; -char ENotFile[] = "not a file"; -char EReadOnly[] = "file is read only"; -char ERemoved[] = "file has been removed"; -char ENotArchived[] = "file is not archived"; -char EResize[] = "only support truncation to zero length"; -char ERoot[] = "cannot remove root"; -char ESnapOld[] = "snapshot has been deleted"; -char ESnapRO[] = "snapshot is read only"; -char ETooBig[] = "file too big"; -char EVentiIO[] = "venti i/o error"; diff --git a/sys/src/cmd/fossil/error.h b/sys/src/cmd/fossil/error.h deleted file mode 100644 index a57d21e5b..000000000 --- a/sys/src/cmd/fossil/error.h +++ /dev/null @@ -1,33 +0,0 @@ -extern char EBadAddr[]; -extern char EBadDir[]; -extern char EBadEntry[]; -extern char EBadLabel[]; -extern char EBadMeta[]; -extern char EBadMode[]; -extern char EBadOffset[]; -extern char EBadPath[]; -extern char EBadRoot[]; -extern char EBadSuper[]; -extern char EBlockTooBig[]; -extern char ECacheFull[]; -extern char EConvert[]; -extern char EExists[]; -extern char EFsFill[]; -extern char EIO[]; -extern char EInUse[]; -extern char ELabelMismatch[]; -extern char ENilBlock[]; -extern char ENoDir[]; -extern char ENoFile[]; -extern char ENotDir[]; -extern char ENotEmpty[]; -extern char ENotFile[]; -extern char EReadOnly[]; -extern char ERemoved[]; -extern char ENotArchived[]; -extern char EResize[]; -extern char ERoot[]; -extern char ESnapOld[]; -extern char ESnapRO[]; -extern char ETooBig[]; -extern char EVentiIO[]; diff --git a/sys/src/cmd/fossil/file.c b/sys/src/cmd/fossil/file.c deleted file mode 100644 index cb96ed197..000000000 --- a/sys/src/cmd/fossil/file.c +++ /dev/null @@ -1,1842 +0,0 @@ -#include "stdinc.h" -#include "9.h" /* for consPrint */ -#include "dat.h" -#include "fns.h" -#include "error.h" - -/* - * locking order is upwards. A thread can hold the lock for a File - * and then acquire the lock of its parent - */ - -struct File { - Fs *fs; /* immutable */ - - /* meta data for file: protected by the lk in the parent */ - int ref; /* holds this data structure up */ - - int partial; /* file was never really open */ - int removed; /* file has been removed */ - int dirty; /* dir is dirty with respect to meta data in block */ - u32int boff; /* block offset within msource for this file's meta data */ - - DirEntry dir; /* meta data for this file, including component name */ - - File *up; /* parent file (directory) */ - File *next; /* sibling */ - - /* data for file */ - VtLock *lk; /* lock for the following */ - Source *source; - Source *msource; /* for directories: meta data for children */ - File *down; /* children */ - - int mode; - int issnapshot; -}; - -static int fileMetaFlush2(File*, char*); -static u32int fileMetaAlloc(File*, DirEntry*, u32int); -static int fileRLock(File*); -static void fileRUnlock(File*); -static int fileLock(File*); -static void fileUnlock(File*); -static void fileMetaLock(File*); -static void fileMetaUnlock(File*); -static void fileRAccess(File*); -static void fileWAccess(File*, char*); - -static File * -fileAlloc(Fs *fs) -{ - File *f; - - f = vtMemAllocZ(sizeof(File)); - f->lk = vtLockAlloc(); - f->ref = 1; - f->fs = fs; - f->boff = NilBlock; - f->mode = fs->mode; - return f; -} - -static void -fileFree(File *f) -{ - sourceClose(f->source); - vtLockFree(f->lk); - sourceClose(f->msource); - deCleanup(&f->dir); - - memset(f, ~0, sizeof(File)); - vtMemFree(f); -} - -/* - * the file is locked already - * f->msource is unlocked - */ -static File * -dirLookup(File *f, char *elem) -{ - int i; - MetaBlock mb; - MetaEntry me; - Block *b; - Source *meta; - File *ff; - u32int bo, nb; - - meta = f->msource; - b = nil; - if(!sourceLock(meta, -1)) - return nil; - nb = (sourceGetSize(meta)+meta->dsize-1)/meta->dsize; - for(bo=0; bo<nb; bo++){ - b = sourceBlock(meta, bo, OReadOnly); - if(b == nil) - goto Err; - if(!mbUnpack(&mb, b->data, meta->dsize)) - goto Err; - if(mbSearch(&mb, elem, &i, &me)){ - ff = fileAlloc(f->fs); - if(!deUnpack(&ff->dir, &me)){ - fileFree(ff); - goto Err; - } - sourceUnlock(meta); - blockPut(b); - ff->boff = bo; - ff->mode = f->mode; - ff->issnapshot = f->issnapshot; - return ff; - } - - blockPut(b); - b = nil; - } - vtSetError(ENoFile); - /* fall through */ -Err: - sourceUnlock(meta); - blockPut(b); - return nil; -} - -File * -fileRoot(Source *r) -{ - Block *b; - Source *r0, *r1, *r2; - MetaBlock mb; - MetaEntry me; - File *root, *mr; - Fs *fs; - - b = nil; - root = nil; - mr = nil; - r1 = nil; - r2 = nil; - - fs = r->fs; - if(!sourceLock(r, -1)) - return nil; - r0 = sourceOpen(r, 0, fs->mode, 0); - if(r0 == nil) - goto Err; - r1 = sourceOpen(r, 1, fs->mode, 0); - if(r1 == nil) - goto Err; - r2 = sourceOpen(r, 2, fs->mode, 0); - if(r2 == nil) - goto Err; - - mr = fileAlloc(fs); - mr->msource = r2; - r2 = nil; - - root = fileAlloc(fs); - root->boff = 0; - root->up = mr; - root->source = r0; - r0->file = root; /* point back to source */ - r0 = nil; - root->msource = r1; - r1 = nil; - - mr->down = root; - - if(!sourceLock(mr->msource, -1)) - goto Err; - b = sourceBlock(mr->msource, 0, OReadOnly); - sourceUnlock(mr->msource); - if(b == nil) - goto Err; - - if(!mbUnpack(&mb, b->data, mr->msource->dsize)) - goto Err; - - meUnpack(&me, &mb, 0); - if(!deUnpack(&root->dir, &me)) - goto Err; - blockPut(b); - sourceUnlock(r); - fileRAccess(root); - - return root; -Err: - blockPut(b); - if(r0) - sourceClose(r0); - if(r1) - sourceClose(r1); - if(r2) - sourceClose(r2); - if(mr) - fileFree(mr); - if(root) - fileFree(root); - sourceUnlock(r); - - return nil; -} - -static Source * -fileOpenSource(File *f, u32int offset, u32int gen, int dir, uint mode, - int issnapshot) -{ - char *rname, *fname; - Source *r; - - if(!sourceLock(f->source, mode)) - return nil; - r = sourceOpen(f->source, offset, mode, issnapshot); - sourceUnlock(f->source); - if(r == nil) - return nil; - if(r->gen != gen){ - vtSetError(ERemoved); - goto Err; - } - if(r->dir != dir && r->mode != -1){ - /* this hasn't been as useful as we hoped it would be. */ - rname = sourceName(r); - fname = fileName(f); - consPrint("%s: source %s for file %s: fileOpenSource: " - "dir mismatch %d %d\n", - f->source->fs->name, rname, fname, r->dir, dir); - free(rname); - free(fname); - - vtSetError(EBadMeta); - goto Err; - } - return r; -Err: - sourceClose(r); - return nil; -} - -File * -_fileWalk(File *f, char *elem, int partial) -{ - File *ff; - - fileRAccess(f); - - if(elem[0] == 0){ - vtSetError(EBadPath); - return nil; - } - - if(!fileIsDir(f)){ - vtSetError(ENotDir); - return nil; - } - - if(strcmp(elem, ".") == 0){ - return fileIncRef(f); - } - - if(strcmp(elem, "..") == 0){ - if(fileIsRoot(f)) - return fileIncRef(f); - return fileIncRef(f->up); - } - - if(!fileLock(f)) - return nil; - - for(ff = f->down; ff; ff=ff->next){ - if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ - ff->ref++; - goto Exit; - } - } - - ff = dirLookup(f, elem); - if(ff == nil) - goto Err; - - if(ff->dir.mode & ModeSnapshot){ - ff->mode = OReadOnly; - ff->issnapshot = 1; - } - - if(partial){ - /* - * Do nothing. We're opening this file only so we can clri it. - * Usually the sources can't be opened, hence we won't even bother. - * Be VERY careful with the returned file. If you hand it to a routine - * expecting ff->source and/or ff->msource to be non-nil, we're - * likely to dereference nil. FileClri should be the only routine - * setting partial. - */ - ff->partial = 1; - }else if(ff->dir.mode & ModeDir){ - ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen, - 1, ff->mode, ff->issnapshot); - ff->msource = fileOpenSource(f, ff->dir.mentry, ff->dir.mgen, - 0, ff->mode, ff->issnapshot); - if(ff->source == nil || ff->msource == nil) - goto Err; - }else{ - ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen, - 0, ff->mode, ff->issnapshot); - if(ff->source == nil) - goto Err; - } - - /* link in and up parent ref count */ - if (ff->source) - ff->source->file = ff; /* point back */ - ff->next = f->down; - f->down = ff; - ff->up = f; - fileIncRef(f); -Exit: - fileUnlock(f); - return ff; -Err: - fileUnlock(f); - if(ff != nil) - fileDecRef(ff); - return nil; -} - -File * -fileWalk(File *f, char *elem) -{ - return _fileWalk(f, elem, 0); -} - -File * -_fileOpen(Fs *fs, char *path, int partial) -{ - File *f, *ff; - char *p, elem[VtMaxStringSize], *opath; - int n; - - f = fs->file; - fileIncRef(f); - opath = path; - while(*path != 0){ - for(p = path; *p && *p != '/'; p++) - ; - n = p - path; - if(n > 0){ - if(n > VtMaxStringSize){ - vtSetError("%s: element too long", EBadPath); - goto Err; - } - memmove(elem, path, n); - elem[n] = 0; - ff = _fileWalk(f, elem, partial && *p=='\0'); - if(ff == nil){ - vtSetError("%.*s: %R", utfnlen(opath, p-opath), - opath); - goto Err; - } - fileDecRef(f); - f = ff; - } - if(*p == '/') - p++; - path = p; - } - return f; -Err: - fileDecRef(f); - return nil; -} - -File* -fileOpen(Fs *fs, char *path) -{ - return _fileOpen(fs, path, 0); -} - -static void -fileSetTmp(File *f, int istmp) -{ - int i; - Entry e; - Source *r; - - for(i=0; i<2; i++){ - if(i==0) - r = f->source; - else - r = f->msource; - if(r == nil) - continue; - if(!sourceGetEntry(r, &e)){ - fprint(2, "sourceGetEntry failed (cannot happen): %r\n"); - continue; - } - if(istmp) - e.flags |= VtEntryNoArchive; - else - e.flags &= ~VtEntryNoArchive; - if(!sourceSetEntry(r, &e)){ - fprint(2, "sourceSetEntry failed (cannot happen): %r\n"); - continue; - } - } -} - -File * -fileCreate(File *f, char *elem, ulong mode, char *uid) -{ - File *ff; - DirEntry *dir; - Source *pr, *r, *mr; - int isdir; - - if(!fileLock(f)) - return nil; - - r = nil; - mr = nil; - for(ff = f->down; ff; ff=ff->next){ - if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ - ff = nil; - vtSetError(EExists); - goto Err1; - } - } - - ff = dirLookup(f, elem); - if(ff != nil){ - vtSetError(EExists); - goto Err1; - } - - pr = f->source; - if(pr->mode != OReadWrite){ - vtSetError(EReadOnly); - goto Err1; - } - - if(!sourceLock2(f->source, f->msource, -1)) - goto Err1; - - ff = fileAlloc(f->fs); - isdir = mode & ModeDir; - - r = sourceCreate(pr, pr->dsize, isdir, 0); - if(r == nil) - goto Err; - if(isdir){ - mr = sourceCreate(pr, pr->dsize, 0, r->offset); - if(mr == nil) - goto Err; - } - - dir = &ff->dir; - dir->elem = vtStrDup(elem); - dir->entry = r->offset; - dir->gen = r->gen; - if(isdir){ - dir->mentry = mr->offset; - dir->mgen = mr->gen; - } - dir->size = 0; - if(!fsNextQid(f->fs, &dir->qid)) - goto Err; - dir->uid = vtStrDup(uid); - dir->gid = vtStrDup(f->dir.gid); - dir->mid = vtStrDup(uid); - dir->mtime = time(0L); - dir->mcount = 0; - dir->ctime = dir->mtime; - dir->atime = dir->mtime; - dir->mode = mode; - - ff->boff = fileMetaAlloc(f, dir, 0); - if(ff->boff == NilBlock) - goto Err; - - sourceUnlock(f->source); - sourceUnlock(f->msource); - - ff->source = r; - r->file = ff; /* point back */ - ff->msource = mr; - - if(mode&ModeTemporary){ - if(!sourceLock2(r, mr, -1)) - goto Err1; - fileSetTmp(ff, 1); - sourceUnlock(r); - if(mr) - sourceUnlock(mr); - } - - /* committed */ - - /* link in and up parent ref count */ - ff->next = f->down; - f->down = ff; - ff->up = f; - fileIncRef(f); - - fileWAccess(f, uid); - - fileUnlock(f); - return ff; - -Err: - sourceUnlock(f->source); - sourceUnlock(f->msource); -Err1: - if(r){ - sourceLock(r, -1); - sourceRemove(r); - } - if(mr){ - sourceLock(mr, -1); - sourceRemove(mr); - } - if(ff) - fileDecRef(ff); - fileUnlock(f); - return 0; -} - -int -fileRead(File *f, void *buf, int cnt, vlong offset) -{ - Source *s; - uvlong size; - u32int bn; - int off, dsize, n, nn; - Block *b; - uchar *p; - -if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset); - - if(!fileRLock(f)) - return -1; - - if(offset < 0){ - vtSetError(EBadOffset); - goto Err1; - } - - fileRAccess(f); - - if(!sourceLock(f->source, OReadOnly)) - goto Err1; - - s = f->source; - dsize = s->dsize; - size = sourceGetSize(s); - - if(offset >= size) - offset = size; - - if(cnt > size-offset) - cnt = size-offset; - bn = offset/dsize; - off = offset%dsize; - p = buf; - while(cnt > 0){ - b = sourceBlock(s, bn, OReadOnly); - if(b == nil) - goto Err; - n = cnt; - if(n > dsize-off) - n = dsize-off; - nn = dsize-off; - if(nn > n) - nn = n; - memmove(p, b->data+off, nn); - memset(p+nn, 0, nn-n); - off = 0; - bn++; - cnt -= n; - p += n; - blockPut(b); - } - sourceUnlock(s); - fileRUnlock(f); - return p-(uchar*)buf; - -Err: - sourceUnlock(s); -Err1: - fileRUnlock(f); - return -1; -} - -/* - * Changes the file block bn to be the given block score. - * Very sneaky. Only used by flfmt. - */ -int -fileMapBlock(File *f, ulong bn, uchar score[VtScoreSize], ulong tag) -{ - Block *b; - Entry e; - Source *s; - - if(!fileLock(f)) - return 0; - - s = nil; - if(f->dir.mode & ModeDir){ - vtSetError(ENotFile); - goto Err; - } - - if(f->source->mode != OReadWrite){ - vtSetError(EReadOnly); - goto Err; - } - - if(!sourceLock(f->source, -1)) - goto Err; - - s = f->source; - b = _sourceBlock(s, bn, OReadWrite, 1, tag); - if(b == nil) - goto Err; - - if(!sourceGetEntry(s, &e)) - goto Err; - if(b->l.type == BtDir){ - memmove(e.score, score, VtScoreSize); - assert(e.tag == tag || e.tag == 0); - e.tag = tag; - e.flags |= VtEntryLocal; - entryPack(&e, b->data, f->source->offset % f->source->epb); - }else - memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize); - blockDirty(b); - blockPut(b); - sourceUnlock(s); - fileUnlock(f); - return 1; - -Err: - if(s) - sourceUnlock(s); - fileUnlock(f); - return 0; -} - -int -fileSetSize(File *f, uvlong size) -{ - int r; - - if(!fileLock(f)) - return 0; - r = 0; - if(f->dir.mode & ModeDir){ - vtSetError(ENotFile); - goto Err; - } - if(f->source->mode != OReadWrite){ - vtSetError(EReadOnly); - goto Err; - } - if(!sourceLock(f->source, -1)) - goto Err; - r = sourceSetSize(f->source, size); - sourceUnlock(f->source); -Err: - fileUnlock(f); - return r; -} - -int -fileWrite(File *f, void *buf, int cnt, vlong offset, char *uid) -{ - Source *s; - ulong bn; - int off, dsize, n; - Block *b; - uchar *p; - vlong eof; - -if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset); - - if(!fileLock(f)) - return -1; - - s = nil; - if(f->dir.mode & ModeDir){ - vtSetError(ENotFile); - goto Err; - } - - if(f->source->mode != OReadWrite){ - vtSetError(EReadOnly); - goto Err; - } - if(offset < 0){ - vtSetError(EBadOffset); - goto Err; - } - - fileWAccess(f, uid); - - if(!sourceLock(f->source, -1)) - goto Err; - s = f->source; - dsize = s->dsize; - - eof = sourceGetSize(s); - if(f->dir.mode & ModeAppend) - offset = eof; - bn = offset/dsize; - off = offset%dsize; - p = buf; - while(cnt > 0){ - n = cnt; - if(n > dsize-off) - n = dsize-off; - b = sourceBlock(s, bn, n<dsize?OReadWrite:OOverWrite); - if(b == nil){ - if(offset > eof) - sourceSetSize(s, offset); - goto Err; - } - memmove(b->data+off, p, n); - off = 0; - cnt -= n; - p += n; - offset += n; - bn++; - blockDirty(b); - blockPut(b); - } - if(offset > eof && !sourceSetSize(s, offset)) - goto Err; - sourceUnlock(s); - fileUnlock(f); - return p-(uchar*)buf; -Err: - if(s) - sourceUnlock(s); - fileUnlock(f); - return -1; -} - -int -fileGetDir(File *f, DirEntry *dir) -{ - if(!fileRLock(f)) - return 0; - - fileMetaLock(f); - deCopy(dir, &f->dir); - fileMetaUnlock(f); - - if(!fileIsDir(f)){ - if(!sourceLock(f->source, OReadOnly)){ - fileRUnlock(f); - return 0; - } - dir->size = sourceGetSize(f->source); - sourceUnlock(f->source); - } - fileRUnlock(f); - - return 1; -} - -int -fileTruncate(File *f, char *uid) -{ - if(fileIsDir(f)){ - vtSetError(ENotFile); - return 0; - } - - if(!fileLock(f)) - return 0; - - if(f->source->mode != OReadWrite){ - vtSetError(EReadOnly); - fileUnlock(f); - return 0; - } - if(!sourceLock(f->source, -1)){ - fileUnlock(f); - return 0; - } - if(!sourceTruncate(f->source)){ - sourceUnlock(f->source); - fileUnlock(f); - return 0; - } - sourceUnlock(f->source); - fileUnlock(f); - - fileWAccess(f, uid); - - return 1; -} - -int -fileSetDir(File *f, DirEntry *dir, char *uid) -{ - File *ff; - char *oelem; - u32int mask; - u64int size; - - /* can not set permissions for the root */ - if(fileIsRoot(f)){ - vtSetError(ERoot); - return 0; - } - - if(!fileLock(f)) - return 0; - - if(f->source->mode != OReadWrite){ - vtSetError(EReadOnly); - fileUnlock(f); - return 0; - } - - fileMetaLock(f); - - /* check new name does not already exist */ - if(strcmp(f->dir.elem, dir->elem) != 0){ - for(ff = f->up->down; ff; ff=ff->next){ - if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){ - vtSetError(EExists); - goto Err; - } - } - - ff = dirLookup(f->up, dir->elem); - if(ff != nil){ - fileDecRef(ff); - vtSetError(EExists); - goto Err; - } - } - - if(!sourceLock2(f->source, f->msource, -1)) - goto Err; - if(!fileIsDir(f)){ - size = sourceGetSize(f->source); - if(size != dir->size){ - if(!sourceSetSize(f->source, dir->size)){ - sourceUnlock(f->source); - if(f->msource) - sourceUnlock(f->msource); - goto Err; - } - /* commited to changing it now */ - } - } - /* commited to changing it now */ - if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary)) - fileSetTmp(f, dir->mode&ModeTemporary); - sourceUnlock(f->source); - if(f->msource) - sourceUnlock(f->msource); - - oelem = nil; - if(strcmp(f->dir.elem, dir->elem) != 0){ - oelem = f->dir.elem; - f->dir.elem = vtStrDup(dir->elem); - } - - if(strcmp(f->dir.uid, dir->uid) != 0){ - vtMemFree(f->dir.uid); - f->dir.uid = vtStrDup(dir->uid); - } - - if(strcmp(f->dir.gid, dir->gid) != 0){ - vtMemFree(f->dir.gid); - f->dir.gid = vtStrDup(dir->gid); - } - - f->dir.mtime = dir->mtime; - f->dir.atime = dir->atime; - -//fprint(2, "mode %x %x ", f->dir.mode, dir->mode); - mask = ~(ModeDir|ModeSnapshot); - f->dir.mode &= ~mask; - f->dir.mode |= mask & dir->mode; - f->dirty = 1; -//fprint(2, "->%x\n", f->dir.mode); - - fileMetaFlush2(f, oelem); - vtMemFree(oelem); - - fileMetaUnlock(f); - fileUnlock(f); - - fileWAccess(f->up, uid); - - return 1; -Err: - fileMetaUnlock(f); - fileUnlock(f); - return 0; -} - -int -fileSetQidSpace(File *f, u64int offset, u64int max) -{ - int ret; - - if(!fileLock(f)) - return 0; - fileMetaLock(f); - f->dir.qidSpace = 1; - f->dir.qidOffset = offset; - f->dir.qidMax = max; - ret = fileMetaFlush2(f, nil)>=0; - fileMetaUnlock(f); - fileUnlock(f); - return ret; -} - - -uvlong -fileGetId(File *f) -{ - /* immutable */ - return f->dir.qid; -} - -ulong -fileGetMcount(File *f) -{ - ulong mcount; - - fileMetaLock(f); - mcount = f->dir.mcount; - fileMetaUnlock(f); - return mcount; -} - -ulong -fileGetMode(File *f) -{ - ulong mode; - - fileMetaLock(f); - mode = f->dir.mode; - fileMetaUnlock(f); - return mode; -} - -int -fileIsDir(File *f) -{ - /* immutable */ - return (f->dir.mode & ModeDir) != 0; -} - -int -fileIsRoot(File *f) -{ - return f == f->fs->file; -} - -int -fileIsRoFs(File *f) -{ - return f->fs->mode == OReadOnly; -} - -int -fileGetSize(File *f, uvlong *size) -{ - if(!fileRLock(f)) - return 0; - if(!sourceLock(f->source, OReadOnly)){ - fileRUnlock(f); - return 0; - } - *size = sourceGetSize(f->source); - sourceUnlock(f->source); - fileRUnlock(f); - - return 1; -} - -int -fileMetaFlush(File *f, int rec) -{ - File **kids, *p; - int nkids; - int i, rv; - - fileMetaLock(f); - rv = fileMetaFlush2(f, nil); - fileMetaUnlock(f); - - if(!rec || !fileIsDir(f)) - return rv; - - if(!fileLock(f)) - return rv; - nkids = 0; - for(p=f->down; p; p=p->next) - nkids++; - kids = vtMemAlloc(nkids*sizeof(File*)); - i = 0; - for(p=f->down; p; p=p->next){ - kids[i++] = p; - p->ref++; - } - fileUnlock(f); - - for(i=0; i<nkids; i++){ - rv |= fileMetaFlush(kids[i], 1); - fileDecRef(kids[i]); - } - vtMemFree(kids); - return rv; -} - -/* assumes metaLock is held */ -static int -fileMetaFlush2(File *f, char *oelem) -{ - File *fp; - Block *b, *bb; - MetaBlock mb; - MetaEntry me, me2; - int i, n; - u32int boff; - - if(!f->dirty) - return 0; - - if(oelem == nil) - oelem = f->dir.elem; - -//print("fileMetaFlush %s->%s\n", oelem, f->dir.elem); - - fp = f->up; - - if(!sourceLock(fp->msource, -1)) - return -1; - /* can happen if source is clri'ed out from under us */ - if(f->boff == NilBlock) - goto Err1; - b = sourceBlock(fp->msource, f->boff, OReadWrite); - if(b == nil) - goto Err1; - - if(!mbUnpack(&mb, b->data, fp->msource->dsize)) - goto Err; - if(!mbSearch(&mb, oelem, &i, &me)) - goto Err; - - n = deSize(&f->dir); -if(0)fprint(2, "old size %d new size %d\n", me.size, n); - - if(mbResize(&mb, &me, n)){ - /* fits in the block */ - mbDelete(&mb, i); - if(strcmp(f->dir.elem, oelem) != 0) - mbSearch(&mb, f->dir.elem, &i, &me2); - dePack(&f->dir, &me); - mbInsert(&mb, i, &me); - mbPack(&mb); - blockDirty(b); - blockPut(b); - sourceUnlock(fp->msource); - f->dirty = 0; - - return 1; - } - - /* - * moving entry to another block - * it is feasible for the fs to crash leaving two copies - * of the directory entry. This is just too much work to - * fix. Given that entries are only allocated in a block that - * is less than PercentageFull, most modifications of meta data - * will fit within the block. i.e. this code should almost - * never be executed. - */ - boff = fileMetaAlloc(fp, &f->dir, f->boff+1); - if(boff == NilBlock){ - /* mbResize might have modified block */ - mbPack(&mb); - blockDirty(b); - goto Err; - } -fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff); - f->boff = boff; - - /* make sure deletion goes to disk after new entry */ - bb = sourceBlock(fp->msource, f->boff, OReadWrite); - mbDelete(&mb, i); - mbPack(&mb); - blockDependency(b, bb, -1, nil, nil); - blockPut(bb); - blockDirty(b); - blockPut(b); - sourceUnlock(fp->msource); - - f->dirty = 0; - - return 1; - -Err: - blockPut(b); -Err1: - sourceUnlock(fp->msource); - return -1; -} - -static int -fileMetaRemove(File *f, char *uid) -{ - Block *b; - MetaBlock mb; - MetaEntry me; - int i; - File *up; - - up = f->up; - - fileWAccess(up, uid); - - fileMetaLock(f); - - sourceLock(up->msource, OReadWrite); - b = sourceBlock(up->msource, f->boff, OReadWrite); - if(b == nil) - goto Err; - - if(!mbUnpack(&mb, b->data, up->msource->dsize)) -{ -fprint(2, "U\n"); - goto Err; -} - if(!mbSearch(&mb, f->dir.elem, &i, &me)) -{ -fprint(2, "S\n"); - goto Err; -} - mbDelete(&mb, i); - mbPack(&mb); - sourceUnlock(up->msource); - - blockDirty(b); - blockPut(b); - - f->removed = 1; - f->boff = NilBlock; - f->dirty = 0; - - fileMetaUnlock(f); - return 1; - -Err: - sourceUnlock(up->msource); - blockPut(b); - fileMetaUnlock(f); - return 0; -} - -/* assume file is locked, assume f->msource is locked */ -static int -fileCheckEmpty(File *f) -{ - u32int i, n; - Block *b; - MetaBlock mb; - Source *r; - - r = f->msource; - n = (sourceGetSize(r)+r->dsize-1)/r->dsize; - for(i=0; i<n; i++){ - b = sourceBlock(r, i, OReadOnly); - if(b == nil) - goto Err; - if(!mbUnpack(&mb, b->data, r->dsize)) - goto Err; - if(mb.nindex > 0){ - vtSetError(ENotEmpty); - goto Err; - } - blockPut(b); - } - return 1; -Err: - blockPut(b); - return 0; -} - -int -fileRemove(File *f, char *uid) -{ - File *ff; - - /* can not remove the root */ - if(fileIsRoot(f)){ - vtSetError(ERoot); - return 0; - } - - if(!fileLock(f)) - return 0; - - if(f->source->mode != OReadWrite){ - vtSetError(EReadOnly); - goto Err1; - } - if(!sourceLock2(f->source, f->msource, -1)) - goto Err1; - if(fileIsDir(f) && !fileCheckEmpty(f)) - goto Err; - - for(ff=f->down; ff; ff=ff->next) - assert(ff->removed); - - sourceRemove(f->source); - f->source->file = nil; /* erase back pointer */ - f->source = nil; - if(f->msource){ - sourceRemove(f->msource); - f->msource = nil; - } - - fileUnlock(f); - - if(!fileMetaRemove(f, uid)) - return 0; - - return 1; - -Err: - sourceUnlock(f->source); - if(f->msource) - sourceUnlock(f->msource); -Err1: - fileUnlock(f); - return 0; -} - -static int -clri(File *f, char *uid) -{ - int r; - - if(f == nil) - return 0; - if(f->up->source->mode != OReadWrite){ - vtSetError(EReadOnly); - fileDecRef(f); - return 0; - } - r = fileMetaRemove(f, uid); - fileDecRef(f); - return r; -} - -int -fileClriPath(Fs *fs, char *path, char *uid) -{ - return clri(_fileOpen(fs, path, 1), uid); -} - -int -fileClri(File *dir, char *elem, char *uid) -{ - return clri(_fileWalk(dir, elem, 1), uid); -} - -File * -fileIncRef(File *vf) -{ - fileMetaLock(vf); - assert(vf->ref > 0); - vf->ref++; - fileMetaUnlock(vf); - return vf; -} - -int -fileDecRef(File *f) -{ - File *p, *q, **qq; - - if(f->up == nil){ - /* never linked in */ - assert(f->ref == 1); - fileFree(f); - return 1; - } - - fileMetaLock(f); - f->ref--; - if(f->ref > 0){ - fileMetaUnlock(f); - return 0; - } - assert(f->ref == 0); - assert(f->down == nil); - - fileMetaFlush2(f, nil); - - p = f->up; - qq = &p->down; - for(q = *qq; q; q = *qq){ - if(q == f) - break; - qq = &q->next; - } - assert(q != nil); - *qq = f->next; - - fileMetaUnlock(f); - fileFree(f); - - fileDecRef(p); - return 1; -} - -File * -fileGetParent(File *f) -{ - if(fileIsRoot(f)) - return fileIncRef(f); - return fileIncRef(f->up); -} - -DirEntryEnum * -deeOpen(File *f) -{ - DirEntryEnum *dee; - File *p; - - if(!fileIsDir(f)){ - vtSetError(ENotDir); - fileDecRef(f); - return nil; - } - - /* flush out meta data */ - if(!fileLock(f)) - return nil; - for(p=f->down; p; p=p->next) - fileMetaFlush2(p, nil); - fileUnlock(f); - - dee = vtMemAllocZ(sizeof(DirEntryEnum)); - dee->file = fileIncRef(f); - - return dee; -} - -static int -dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size) -{ - Block *b; - ulong bn; - Entry e; - int epb; - - epb = s->dsize/VtEntrySize; - bn = elem/epb; - elem -= bn*epb; - - b = sourceBlock(s, bn, OReadOnly); - if(b == nil) - goto Err; - if(!entryUnpack(&e, b->data, elem)) - goto Err; - - /* hanging entries are returned as zero size */ - if(!(e.flags & VtEntryActive) || e.gen != gen) - *size = 0; - else - *size = e.size; - blockPut(b); - return 1; - -Err: - blockPut(b); - return 0; -} - -static int -deeFill(DirEntryEnum *dee) -{ - int i, n; - Source *meta, *source; - MetaBlock mb; - MetaEntry me; - File *f; - Block *b; - DirEntry *de; - - /* clean up first */ - for(i=dee->i; i<dee->n; i++) - deCleanup(dee->buf+i); - vtMemFree(dee->buf); - dee->buf = nil; - dee->i = 0; - dee->n = 0; - - f = dee->file; - - source = f->source; - meta = f->msource; - - b = sourceBlock(meta, dee->boff, OReadOnly); - if(b == nil) - goto Err; - if(!mbUnpack(&mb, b->data, meta->dsize)) - goto Err; - - n = mb.nindex; - dee->buf = vtMemAlloc(n * sizeof(DirEntry)); - - for(i=0; i<n; i++){ - de = dee->buf + i; - meUnpack(&me, &mb, i); - if(!deUnpack(de, &me)) - goto Err; - dee->n++; - if(!(de->mode & ModeDir)) - if(!dirEntrySize(source, de->entry, de->gen, &de->size)) - goto Err; - } - dee->boff++; - blockPut(b); - return 1; -Err: - blockPut(b); - return 0; -} - -int -deeRead(DirEntryEnum *dee, DirEntry *de) -{ - int ret, didread; - File *f; - u32int nb; - - if(dee == nil){ - vtSetError("cannot happen in deeRead"); - return -1; - } - - f = dee->file; - if(!fileRLock(f)) - return -1; - - if(!sourceLock2(f->source, f->msource, OReadOnly)){ - fileRUnlock(f); - return -1; - } - - nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize; - - didread = 0; - while(dee->i >= dee->n){ - if(dee->boff >= nb){ - ret = 0; - goto Return; - } - didread = 1; - if(!deeFill(dee)){ - ret = -1; - goto Return; - } - } - - memmove(de, dee->buf + dee->i, sizeof(DirEntry)); - dee->i++; - ret = 1; - -Return: - sourceUnlock(f->source); - sourceUnlock(f->msource); - fileRUnlock(f); - - if(didread) - fileRAccess(f); - return ret; -} - -void -deeClose(DirEntryEnum *dee) -{ - int i; - if(dee == nil) - return; - for(i=dee->i; i<dee->n; i++) - deCleanup(dee->buf+i); - vtMemFree(dee->buf); - fileDecRef(dee->file); - vtMemFree(dee); -} - -/* - * caller must lock f->source and f->msource - * caller must NOT lock the source and msource - * referenced by dir. - */ -static u32int -fileMetaAlloc(File *f, DirEntry *dir, u32int start) -{ - u32int nb, bo; - Block *b, *bb; - MetaBlock mb; - int nn; - uchar *p; - int i, n, epb; - MetaEntry me; - Source *s, *ms; - - s = f->source; - ms = f->msource; - - n = deSize(dir); - nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize; - b = nil; - if(start > nb) - start = nb; - for(bo=start; bo<nb; bo++){ - b = sourceBlock(ms, bo, OReadWrite); - if(b == nil) - goto Err; - if(!mbUnpack(&mb, b->data, ms->dsize)) - goto Err; - nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free; - if(n <= nn && mb.nindex < mb.maxindex) - break; - blockPut(b); - b = nil; - } - - /* add block to meta file */ - if(b == nil){ - b = sourceBlock(ms, bo, OReadWrite); - if(b == nil) - goto Err; - sourceSetSize(ms, (nb+1)*ms->dsize); - mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry); - } - - p = mbAlloc(&mb, n); - if(p == nil){ - /* mbAlloc might have changed block */ - mbPack(&mb); - blockDirty(b); - vtSetError(EBadMeta); - goto Err; - } - - mbSearch(&mb, dir->elem, &i, &me); - assert(me.p == nil); - me.p = p; - me.size = n; - dePack(dir, &me); - mbInsert(&mb, i, &me); - mbPack(&mb); - - /* meta block depends on super block for qid ... */ - bb = cacheLocal(b->c, PartSuper, 0, OReadOnly); - blockDependency(b, bb, -1, nil, nil); - blockPut(bb); - - /* ... and one or two dir entries */ - epb = s->dsize/VtEntrySize; - bb = sourceBlock(s, dir->entry/epb, OReadOnly); - blockDependency(b, bb, -1, nil, nil); - blockPut(bb); - if(dir->mode & ModeDir){ - bb = sourceBlock(s, dir->mentry/epb, OReadOnly); - blockDependency(b, bb, -1, nil, nil); - blockPut(bb); - } - - blockDirty(b); - blockPut(b); - return bo; -Err: - blockPut(b); - return NilBlock; -} - -static int -chkSource(File *f) -{ - if(f->partial) - return 1; - - if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){ - vtSetError(ERemoved); - return 0; - } - return 1; -} - -static int -fileRLock(File *f) -{ - assert(!vtCanLock(f->fs->elk)); - vtRLock(f->lk); - if(!chkSource(f)){ - fileRUnlock(f); - return 0; - } - return 1; -} - -static void -fileRUnlock(File *f) -{ - vtRUnlock(f->lk); -} - -static int -fileLock(File *f) -{ - assert(!vtCanLock(f->fs->elk)); - vtLock(f->lk); - if(!chkSource(f)){ - fileUnlock(f); - return 0; - } - return 1; -} - -static void -fileUnlock(File *f) -{ - vtUnlock(f->lk); -} - -/* - * f->source and f->msource must NOT be locked. - * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2). - * We have to respect that ordering. - */ -static void -fileMetaLock(File *f) -{ -if(f->up == nil) -fprint(2, "f->elem = %s\n", f->dir.elem); - assert(f->up != nil); - assert(!vtCanLock(f->fs->elk)); - vtLock(f->up->lk); -} - -static void -fileMetaUnlock(File *f) -{ - vtUnlock(f->up->lk); -} - -/* - * f->source and f->msource must NOT be locked. - * see fileMetaLock. - */ -static void -fileRAccess(File* f) -{ - if(f->mode == OReadOnly) - return; - - fileMetaLock(f); - f->dir.atime = time(0L); - f->dirty = 1; - fileMetaUnlock(f); -} - -/* - * f->source and f->msource must NOT be locked. - * see fileMetaLock. - */ -static void -fileWAccess(File* f, char *mid) -{ - if(f->mode == OReadOnly) - return; - - fileMetaLock(f); - f->dir.atime = f->dir.mtime = time(0L); - if(strcmp(f->dir.mid, mid) != 0){ - vtMemFree(f->dir.mid); - f->dir.mid = vtStrDup(mid); - } - f->dir.mcount++; - f->dirty = 1; - fileMetaUnlock(f); - -/*RSC: let's try this */ -/*presotto - lets not - if(f->up) - fileWAccess(f->up, mid); -*/ -} - -static int -getEntry(Source *r, Entry *e, int checkepoch) -{ - u32int epoch; - Block *b; - - if(r == nil){ - memset(&e, 0, sizeof e); - return 1; - } - - b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly); - if(b == nil) - return 0; - if(!entryUnpack(e, b->data, r->offset % r->epb)){ - blockPut(b); - return 0; - } - epoch = b->l.epoch; - blockPut(b); - - if(checkepoch){ - b = cacheGlobal(r->fs->cache, e->score, entryType(e), e->tag, OReadOnly); - if(b){ - if(b->l.epoch >= epoch) - fprint(2, "warning: entry %p epoch not older %#.8ux/%d %V/%d in getEntry\n", - r, b->addr, b->l.epoch, r->score, epoch); - blockPut(b); - } - } - - return 1; -} - -static int -setEntry(Source *r, Entry *e) -{ - Block *b; - Entry oe; - - b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); - if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score); - if(b == nil) - return 0; - if(!entryUnpack(&oe, b->data, r->offset % r->epb)){ - blockPut(b); - return 0; - } - e->gen = oe.gen; - entryPack(e, b->data, r->offset % r->epb); - - /* BUG b should depend on the entry pointer */ - - blockDirty(b); - blockPut(b); - return 1; -} - -/* assumes hold elk */ -int -fileSnapshot(File *dst, File *src, u32int epoch, int doarchive) -{ - Entry e, ee; - - /* add link to snapshot */ - if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1)) - return 0; - - e.snap = epoch; - e.archive = doarchive; - ee.snap = epoch; - ee.archive = doarchive; - - if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee)) - return 0; - return 1; -} - -int -fileGetSources(File *f, Entry *e, Entry *ee) -{ - if(!getEntry(f->source, e, 0) - || !getEntry(f->msource, ee, 0)) - return 0; - return 1; -} - -/* - * Walk down to the block(s) containing the Entries - * for f->source and f->msource, copying as we go. - */ -int -fileWalkSources(File *f) -{ - if(f->mode == OReadOnly){ - fprint(2, "readonly in fileWalkSources\n"); - return 1; - } - if(!sourceLock2(f->source, f->msource, OReadWrite)){ - fprint(2, "sourceLock2 failed in fileWalkSources\n"); - return 0; - } - sourceUnlock(f->source); - sourceUnlock(f->msource); - return 1; -} - -/* - * convert File* to full path name in malloced string. - * this hasn't been as useful as we hoped it would be. - */ -char * -fileName(File *f) -{ - char *name, *pname; - File *p; - static char root[] = "/"; - - if (f == nil) - return strdup("/**GOK**"); - - p = fileGetParent(f); - if (p == f) - name = strdup(root); - else { - pname = fileName(p); - if (strcmp(pname, root) == 0) - name = smprint("/%s", f->dir.elem); - else - name = smprint("%s/%s", pname, f->dir.elem); - free(pname); - } - fileDecRef(p); - return name; -} diff --git a/sys/src/cmd/fossil/flchk.c b/sys/src/cmd/fossil/flchk.c deleted file mode 100644 index b19fd5be2..000000000 --- a/sys/src/cmd/fossil/flchk.c +++ /dev/null @@ -1,118 +0,0 @@ -#include "stdinc.h" -#include <bio.h> -#include "dat.h" -#include "fns.h" - -Biobuf bout; -Fsck fsck; - -static void -usage(void) -{ - fprint(2, "usage: %s [-c cachesize] [-h host] file\n", argv0); - exits("usage"); -} - -#pragma varargck argpos flprint 1 - -static int -flprint(char *fmt, ...) -{ - int n; - va_list arg; - - va_start(arg, fmt); - n = Bvprint(&bout, fmt, arg); - va_end(arg); - return n; -} - -static void -flclre(Fsck*, Block *b, int o) -{ - Bprint(&bout, "# clre 0x%ux %d\n", b->addr, o); -} - -static void -flclrp(Fsck*, Block *b, int o) -{ - Bprint(&bout, "# clrp 0x%ux %d\n", b->addr, o); -} - -static void -flclri(Fsck*, char *name, MetaBlock*, int, Block*) -{ - Bprint(&bout, "# clri %s\n", name); -} - -static void -flclose(Fsck*, Block *b, u32int epoch) -{ - Bprint(&bout, "# bclose 0x%ux %ud\n", b->addr, epoch); -} - -void -main(int argc, char *argv[]) -{ - int csize = 1000; - VtSession *z; - char *host = nil; - - fsck.useventi = 1; - Binit(&bout, 1, OWRITE); - ARGBEGIN{ - default: - usage(); - case 'c': - csize = atoi(ARGF()); - if(csize <= 0) - usage(); - break; - case 'f': - fsck.useventi = 0; - break; - case 'h': - host = ARGF(); - break; - case 'v': - fsck.printdirs = 1; - break; - }ARGEND; - - if(argc != 1) - usage(); - - vtAttach(); - - fmtinstall('L', labelFmt); - fmtinstall('V', scoreFmt); - fmtinstall('R', vtErrFmt); - - /* - * Connect to Venti. - */ - z = vtDial(host, 0); - if(z == nil){ - if(fsck.useventi) - vtFatal("could not connect to server: %s", vtGetError()); - }else if(!vtConnect(z, 0)) - vtFatal("vtConnect: %s", vtGetError()); - - /* - * Initialize file system. - */ - fsck.fs = fsOpen(argv[0], z, csize, OReadOnly); - if(fsck.fs == nil) - vtFatal("could not open file system: %R"); - - fsck.print = flprint; - fsck.clre = flclre; - fsck.clrp = flclrp; - fsck.close = flclose; - fsck.clri = flclri; - - fsCheck(&fsck); - - exits(0); -} - diff --git a/sys/src/cmd/fossil/flfmt.c b/sys/src/cmd/fossil/flfmt.c deleted file mode 100644 index b843388a0..000000000 --- a/sys/src/cmd/fossil/flfmt.c +++ /dev/null @@ -1,572 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "flfmt9660.h" - -#define blockWrite _blockWrite /* hack */ - -static void usage(void); -static u64int fdsize(int fd); -static void partition(int fd, int bsize, Header *h); -static void writeBlock(int fd, uchar *buf, int bsize, ulong bn); -static u64int unittoull(char *s); -static u32int blockAlloc(int type, u32int tag); -static void blockRead(int part, u32int addr); -static void blockWrite(int part, u32int addr); -static void superInit(char *label, u32int root, uchar[VtScoreSize]); -static void rootMetaInit(Entry *e); -static u32int rootInit(Entry *e); -static void topLevel(char *name); -static int parseScore(uchar[VtScoreSize], char*); -static u32int ventiRoot(char*, char*); -static VtSession *z; - -#define TWID64 ((u64int)~(u64int)0) - -Disk *disk; -Fs *fs; -uchar *buf; -int bsize = 8*1024; -u64int qid = 1; -int iso9660off; -char *iso9660file; - -int -confirm(char *msg) -{ - char buf[100]; - int n; - - fprint(2, "%s [y/n]: ", msg); - n = read(0, buf, sizeof buf - 1); - if(n <= 0) - return 0; - if(buf[0] == 'y') - return 1; - return 0; -} - -void -main(int argc, char *argv[]) -{ - int fd, force; - Header h; - ulong bn; - Entry e; - char *label = "vfs"; - char *host = nil; - char *score = nil; - u32int root; - Dir *d; - - force = 0; - ARGBEGIN{ - default: - usage(); - case 'b': - bsize = unittoull(EARGF(usage())); - if(bsize == ~0) - usage(); - break; - case 'h': - host = EARGF(usage()); - break; - case 'i': - iso9660file = EARGF(usage()); - iso9660off = atoi(EARGF(usage())); - break; - case 'l': - label = EARGF(usage()); - break; - case 'v': - score = EARGF(usage()); - break; - - /* - * This is -y instead of -f because flchk has a - * (frequently used) -f option. I type flfmt instead - * of flchk all the time, and want to make it hard - * to reformat my file system accidentally. - */ - case 'y': - force = 1; - break; - }ARGEND - - if(argc != 1) - usage(); - - if(iso9660file && score) - vtFatal("cannot use -i with -v"); - - vtAttach(); - - fmtinstall('V', scoreFmt); - fmtinstall('R', vtErrFmt); - fmtinstall('L', labelFmt); - - fd = open(argv[0], ORDWR); - if(fd < 0) - vtFatal("could not open file: %s: %r", argv[0]); - - buf = vtMemAllocZ(bsize); - if(pread(fd, buf, bsize, HeaderOffset) != bsize) - vtFatal("could not read fs header block: %r"); - - if(headerUnpack(&h, buf) && !force - && !confirm("fs header block already exists; are you sure?")) - goto Out; - - if((d = dirfstat(fd)) == nil) - vtFatal("dirfstat: %r"); - - if(d->type == 'M' && !force - && !confirm("fs file is mounted via devmnt (is not a kernel device); are you sure?")) - goto Out; - - partition(fd, bsize, &h); - headerPack(&h, buf); - if(pwrite(fd, buf, bsize, HeaderOffset) < bsize) - vtFatal("could not write fs header: %r"); - - disk = diskAlloc(fd); - if(disk == nil) - vtFatal("could not open disk: %r"); - - if(iso9660file) - iso9660init(fd, &h, iso9660file, iso9660off); - - /* zero labels */ - memset(buf, 0, bsize); - for(bn = 0; bn < diskSize(disk, PartLabel); bn++) - blockWrite(PartLabel, bn); - - if(iso9660file) - iso9660labels(disk, buf, blockWrite); - - if(score) - root = ventiRoot(host, score); - else{ - rootMetaInit(&e); - root = rootInit(&e); - } - - superInit(label, root, vtZeroScore); - diskFree(disk); - - if(score == nil) - topLevel(argv[0]); - -Out: - vtDetach(); - exits(0); -} - -static u64int -fdsize(int fd) -{ - Dir *dir; - u64int size; - - dir = dirfstat(fd); - if(dir == nil) - vtFatal("could not stat file: %r"); - size = dir->length; - free(dir); - return size; -} - -static void -usage(void) -{ - fprint(2, "usage: %s [-b blocksize] [-h host] [-i file offset] " - "[-l label] [-v score] [-y] file\n", argv0); - exits("usage"); -} - -static void -partition(int fd, int bsize, Header *h) -{ - ulong nblock, ndata, nlabel; - ulong lpb; - - if(bsize % 512 != 0) - sysfatal("block size must be a multiple of 512 bytes"); - if(bsize > VtMaxLumpSize) - sysfatal("block size must be less than %d", VtMaxLumpSize); - - memset(h, 0, sizeof(*h)); - h->blockSize = bsize; - - lpb = bsize/LabelSize; - - nblock = fdsize(fd)/bsize; - - /* sanity check */ - if(nblock < (HeaderOffset*10)/bsize) - vtFatal("file too small"); - - h->super = (HeaderOffset + 2*bsize)/bsize; - h->label = h->super + 1; - ndata = ((u64int)lpb)*(nblock - h->label)/(lpb+1); - nlabel = (ndata + lpb - 1)/lpb; - h->data = h->label + nlabel; - h->end = h->data + ndata; - -} - -static u32int -tagGen(void) -{ - u32int tag; - - for(;;){ - tag = lrand(); - if(tag > RootTag) - break; - } - return tag; -} - -static void -entryInit(Entry *e) -{ - e->gen = 0; - e->dsize = bsize; - e->psize = bsize/VtEntrySize*VtEntrySize; - e->flags = VtEntryActive; - e->depth = 0; - e->size = 0; - memmove(e->score, vtZeroScore, VtScoreSize); - e->tag = tagGen(); - e->snap = 0; - e->archive = 0; -} - -static void -rootMetaInit(Entry *e) -{ - u32int addr; - u32int tag; - DirEntry de; - MetaBlock mb; - MetaEntry me; - - memset(&de, 0, sizeof(de)); - de.elem = vtStrDup("root"); - de.entry = 0; - de.gen = 0; - de.mentry = 1; - de.mgen = 0; - de.size = 0; - de.qid = qid++; - de.uid = vtStrDup("adm"); - de.gid = vtStrDup("adm"); - de.mid = vtStrDup("adm"); - de.mtime = time(0); - de.mcount = 0; - de.ctime = time(0); - de.atime = time(0); - de.mode = ModeDir | 0555; - - tag = tagGen(); - addr = blockAlloc(BtData, tag); - - /* build up meta block */ - memset(buf, 0, bsize); - mbInit(&mb, buf, bsize, bsize/100); - me.size = deSize(&de); - me.p = mbAlloc(&mb, me.size); - assert(me.p != nil); - dePack(&de, &me); - mbInsert(&mb, 0, &me); - mbPack(&mb); - blockWrite(PartData, addr); - deCleanup(&de); - - /* build up entry for meta block */ - entryInit(e); - e->flags |= VtEntryLocal; - e->size = bsize; - e->tag = tag; - localToGlobal(addr, e->score); -} - -static u32int -rootInit(Entry *e) -{ - ulong addr; - u32int tag; - - tag = tagGen(); - - addr = blockAlloc(BtDir, tag); - memset(buf, 0, bsize); - - /* root meta data is in the third entry */ - entryPack(e, buf, 2); - - entryInit(e); - e->flags |= VtEntryDir; - entryPack(e, buf, 0); - - entryInit(e); - entryPack(e, buf, 1); - - blockWrite(PartData, addr); - - entryInit(e); - e->flags |= VtEntryLocal|VtEntryDir; - e->size = VtEntrySize*3; - e->tag = tag; - localToGlobal(addr, e->score); - - addr = blockAlloc(BtDir, RootTag); - memset(buf, 0, bsize); - entryPack(e, buf, 0); - - blockWrite(PartData, addr); - - return addr; -} - - -static u32int -blockAlloc(int type, u32int tag) -{ - static u32int addr; - Label l; - int lpb; - - lpb = bsize/LabelSize; - - blockRead(PartLabel, addr/lpb); - if(!labelUnpack(&l, buf, addr % lpb)) - vtFatal("bad label: %r"); - if(l.state != BsFree) - vtFatal("want to allocate block already in use"); - l.epoch = 1; - l.epochClose = ~(u32int)0; - l.type = type; - l.state = BsAlloc; - l.tag = tag; - labelPack(&l, buf, addr % lpb); - blockWrite(PartLabel, addr/lpb); - return addr++; -} - -static void -superInit(char *label, u32int root, uchar score[VtScoreSize]) -{ - Super s; - - memset(buf, 0, bsize); - memset(&s, 0, sizeof(s)); - s.version = SuperVersion; - s.epochLow = 1; - s.epochHigh = 1; - s.qid = qid; - s.active = root; - s.next = NilBlock; - s.current = NilBlock; - strecpy(s.name, s.name+sizeof(s.name), label); - memmove(s.last, score, VtScoreSize); - - superPack(&s, buf); - blockWrite(PartSuper, 0); -} - -static u64int -unittoull(char *s) -{ - char *es; - u64int n; - - if(s == nil) - return TWID64; - n = strtoul(s, &es, 0); - if(*es == 'k' || *es == 'K'){ - n *= 1024; - es++; - }else if(*es == 'm' || *es == 'M'){ - n *= 1024*1024; - es++; - }else if(*es == 'g' || *es == 'G'){ - n *= 1024*1024*1024; - es++; - } - if(*es != '\0') - return TWID64; - return n; -} - -static void -blockRead(int part, u32int addr) -{ - if(!diskReadRaw(disk, part, addr, buf)) - vtFatal("read failed: %r"); -} - -static void -blockWrite(int part, u32int addr) -{ - if(!diskWriteRaw(disk, part, addr, buf)) - vtFatal("write failed: %r"); -} - -static void -addFile(File *root, char *name, uint mode) -{ - File *f; - - f = fileCreate(root, name, mode | ModeDir, "adm"); - if(f == nil) - vtFatal("could not create file: %s: %r", name); - fileDecRef(f); -} - -static void -topLevel(char *name) -{ - Fs *fs; - File *root; - - /* ok, now we can open as a fs */ - fs = fsOpen(name, z, 100, OReadWrite); - if(fs == nil) - vtFatal("could not open file system: %r"); - vtRLock(fs->elk); - root = fsGetRoot(fs); - if(root == nil) - vtFatal("could not open root: %r"); - addFile(root, "active", 0555); - addFile(root, "archive", 0555); - addFile(root, "snapshot", 0555); - fileDecRef(root); - if(iso9660file) - iso9660copy(fs); - vtRUnlock(fs->elk); - fsClose(fs); -} - -static int -ventiRead(uchar score[VtScoreSize], int type) -{ - int n; - - n = vtRead(z, score, type, buf, bsize); - if(n < 0) - vtFatal("ventiRead %V (%d) failed: %R", score, type); - vtZeroExtend(type, buf, n, bsize); - return n; -} - -static u32int -ventiRoot(char *host, char *s) -{ - int i, n; - uchar score[VtScoreSize]; - u32int addr, tag; - DirEntry de; - MetaBlock mb; - MetaEntry me; - Entry e; - VtRoot root; - - if(!parseScore(score, s)) - vtFatal("bad score '%s'", s); - - if((z = vtDial(host, 0)) == nil - || !vtConnect(z, nil)) - vtFatal("connect to venti: %R"); - - tag = tagGen(); - addr = blockAlloc(BtDir, tag); - - ventiRead(score, VtRootType); - if(!vtRootUnpack(&root, buf)) - vtFatal("corrupted root: vtRootUnpack"); - n = ventiRead(root.score, VtDirType); - - /* - * Fossil's vac archives start with an extra layer of source, - * but vac's don't. - */ - if(n <= 2*VtEntrySize){ - if(!entryUnpack(&e, buf, 0)) - vtFatal("bad root: top entry"); - n = ventiRead(e.score, VtDirType); - } - - /* - * There should be three root sources (and nothing else) here. - */ - for(i=0; i<3; i++){ - if(!entryUnpack(&e, buf, i) - || !(e.flags&VtEntryActive) - || e.psize < 256 - || e.dsize < 256) - vtFatal("bad root: entry %d", i); - fprint(2, "%V\n", e.score); - } - if(n > 3*VtEntrySize) - vtFatal("bad root: entry count"); - - blockWrite(PartData, addr); - - /* - * Maximum qid is recorded in root's msource, entry #2 (conveniently in e). - */ - ventiRead(e.score, VtDataType); - if(!mbUnpack(&mb, buf, bsize)) - vtFatal("bad root: mbUnpack"); - meUnpack(&me, &mb, 0); - if(!deUnpack(&de, &me)) - vtFatal("bad root: dirUnpack"); - if(!de.qidSpace) - vtFatal("bad root: no qidSpace"); - qid = de.qidMax; - - /* - * Recreate the top layer of source. - */ - entryInit(&e); - e.flags |= VtEntryLocal|VtEntryDir; - e.size = VtEntrySize*3; - e.tag = tag; - localToGlobal(addr, e.score); - - addr = blockAlloc(BtDir, RootTag); - memset(buf, 0, bsize); - entryPack(&e, buf, 0); - blockWrite(PartData, addr); - - return addr; -} - -static int -parseScore(uchar *score, char *buf) -{ - int i, c; - - memset(score, 0, VtScoreSize); - - if(strlen(buf) < VtScoreSize*2) - return 0; - for(i=0; i<VtScoreSize*2; i++){ - if(buf[i] >= '0' && buf[i] <= '9') - c = buf[i] - '0'; - else if(buf[i] >= 'a' && buf[i] <= 'f') - c = buf[i] - 'a' + 10; - else if(buf[i] >= 'A' && buf[i] <= 'F') - c = buf[i] - 'A' + 10; - else - return 0; - - if((i & 1) == 0) - c <<= 4; - - score[i>>1] |= c; - } - return 1; -} diff --git a/sys/src/cmd/fossil/flfmt9660.c b/sys/src/cmd/fossil/flfmt9660.c deleted file mode 100644 index 4464c9fb2..000000000 --- a/sys/src/cmd/fossil/flfmt9660.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Initialize a fossil file system from an ISO9660 image already in the - * file system. This is a fairly bizarre thing to do, but it lets us generate - * installation CDs that double as valid Plan 9 disk partitions. - * People having trouble booting the CD can just copy it into a disk - * partition and you've got a working Plan 9 system. - * - * I've tried hard to keep all the associated cruft in this file. - * If you deleted this file and cut out the three calls into it from flfmt.c, - * no traces would remain. - */ - -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "flfmt9660.h" -#include <bio.h> -#include <ctype.h> - -static Biobuf *b; - -enum{ - Tag = 0x96609660, - Blocksize = 2048, -}; - -#pragma varargck type "s" uchar* -#pragma varargck type "L" uchar* -#pragma varargck type "B" uchar* -#pragma varargck type "N" uchar* -#pragma varargck type "T" uchar* -#pragma varargck type "D" uchar* - -typedef struct Voldesc Voldesc; -struct Voldesc { - uchar magic[8]; /* 0x01, "CD001", 0x01, 0x00 */ - uchar systemid[32]; /* system identifier */ - uchar volumeid[32]; /* volume identifier */ - uchar unused[8]; /* character set in secondary desc */ - uchar volsize[8]; /* volume size */ - uchar charset[32]; - uchar volsetsize[4]; /* volume set size = 1 */ - uchar volseqnum[4]; /* volume sequence number = 1 */ - uchar blocksize[4]; /* logical block size */ - uchar pathsize[8]; /* path table size */ - uchar lpathloc[4]; /* Lpath */ - uchar olpathloc[4]; /* optional Lpath */ - uchar mpathloc[4]; /* Mpath */ - uchar ompathloc[4]; /* optional Mpath */ - uchar rootdir[34]; /* root directory */ - uchar volsetid[128]; /* volume set identifier */ - uchar publisher[128]; - uchar prepid[128]; /* data preparer identifier */ - uchar applid[128]; /* application identifier */ - uchar notice[37]; /* copyright notice file */ - uchar abstract[37]; /* abstract file */ - uchar biblio[37]; /* bibliographic file */ - uchar cdate[17]; /* creation date */ - uchar mdate[17]; /* modification date */ - uchar xdate[17]; /* expiration date */ - uchar edate[17]; /* effective date */ - uchar fsvers; /* file system version = 1 */ -}; - -static void -dumpbootvol(void *a) -{ - Voldesc *v; - - v = a; - print("magic %.2ux %.5s %.2ux %2ux\n", - v->magic[0], v->magic+1, v->magic[6], v->magic[7]); - if(v->magic[0] == 0xFF) - return; - - print("system %.32T\n", v->systemid); - print("volume %.32T\n", v->volumeid); - print("volume size %.4N\n", v->volsize); - print("charset %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", - v->charset[0], v->charset[1], v->charset[2], v->charset[3], - v->charset[4], v->charset[5], v->charset[6], v->charset[7]); - print("volume set size %.2N\n", v->volsetsize); - print("volume sequence number %.2N\n", v->volseqnum); - print("logical block size %.2N\n", v->blocksize); - print("path size %.4L\n", v->pathsize); - print("lpath loc %.4L\n", v->lpathloc); - print("opt lpath loc %.4L\n", v->olpathloc); - print("mpath loc %.4B\n", v->mpathloc); - print("opt mpath loc %.4B\n", v->ompathloc); - print("rootdir %D\n", v->rootdir); - print("volume set identifier %.128T\n", v->volsetid); - print("publisher %.128T\n", v->publisher); - print("preparer %.128T\n", v->prepid); - print("application %.128T\n", v->applid); - print("notice %.37T\n", v->notice); - print("abstract %.37T\n", v->abstract); - print("biblio %.37T\n", v->biblio); - print("creation date %.17s\n", v->cdate); - print("modification date %.17s\n", v->mdate); - print("expiration date %.17s\n", v->xdate); - print("effective date %.17s\n", v->edate); - print("fs version %d\n", v->fsvers); -} - -typedef struct Cdir Cdir; -struct Cdir { - uchar len; - uchar xlen; - uchar dloc[8]; - uchar dlen[8]; - uchar date[7]; - uchar flags; - uchar unitsize; - uchar gapsize; - uchar volseqnum[4]; - uchar namelen; - uchar name[1]; /* chumminess */ -}; -#pragma varargck type "D" Cdir* - -static int -Dfmt(Fmt *fmt) -{ - char buf[128]; - Cdir *c; - - c = va_arg(fmt->args, Cdir*); - if(c->namelen == 1 && c->name[0] == '\0' || c->name[0] == '\001') { - snprint(buf, sizeof buf, ".%s dloc %.4N dlen %.4N", - c->name[0] ? "." : "", c->dloc, c->dlen); - } else { - snprint(buf, sizeof buf, "%.*T dloc %.4N dlen %.4N", c->namelen, c->name, - c->dloc, c->dlen); - } - fmtstrcpy(fmt, buf); - return 0; -} - -char longc, shortc; -static void -bigend(void) -{ - longc = 'B'; -} - -static void -littleend(void) -{ - longc = 'L'; -} - -static ulong -big(void *a, int n) -{ - uchar *p; - ulong v; - int i; - - p = a; - v = 0; - for(i=0; i<n; i++) - v = (v<<8) | *p++; - return v; -} - -static ulong -little(void *a, int n) -{ - uchar *p; - ulong v; - int i; - - p = a; - v = 0; - for(i=0; i<n; i++) - v |= (*p++<<(i*8)); - return v; -} - -/* numbers in big or little endian. */ -static int -BLfmt(Fmt *fmt) -{ - ulong v; - uchar *p; - char buf[20]; - - p = va_arg(fmt->args, uchar*); - - if(!(fmt->flags&FmtPrec)) { - fmtstrcpy(fmt, "*BL*"); - return 0; - } - - if(fmt->r == 'B') - v = big(p, fmt->prec); - else - v = little(p, fmt->prec); - - sprint(buf, "0x%.*lux", fmt->prec*2, v); - fmt->flags &= ~FmtPrec; - fmtstrcpy(fmt, buf); - return 0; -} - -/* numbers in both little and big endian */ -static int -Nfmt(Fmt *fmt) -{ - char buf[100]; - uchar *p; - - p = va_arg(fmt->args, uchar*); - - sprint(buf, "%.*L %.*B", fmt->prec, p, fmt->prec, p+fmt->prec); - fmt->flags &= ~FmtPrec; - fmtstrcpy(fmt, buf); - return 0; -} - -static int -asciiTfmt(Fmt *fmt) -{ - char *p, buf[256]; - int i; - - p = va_arg(fmt->args, char*); - for(i=0; i<fmt->prec; i++) - buf[i] = *p++; - buf[i] = '\0'; - for(p=buf+strlen(buf); p>buf && p[-1]==' '; p--) - ; - p[0] = '\0'; - fmt->flags &= ~FmtPrec; - fmtstrcpy(fmt, buf); - return 0; -} - -static void -ascii(void) -{ - fmtinstall('T', asciiTfmt); -} - -static int -runeTfmt(Fmt *fmt) -{ - Rune buf[256], *r; - int i; - uchar *p; - - p = va_arg(fmt->args, uchar*); - for(i=0; i*2+2<=fmt->prec; i++, p+=2) - buf[i] = (p[0]<<8)|p[1]; - buf[i] = L'\0'; - for(r=buf+i; r>buf && r[-1]==L' '; r--) - ; - r[0] = L'\0'; - fmt->flags &= ~FmtPrec; - return fmtprint(fmt, "%S", buf); -} - -static void -getsect(uchar *buf, int n) -{ - if(Bseek(b, n*2048, 0) != n*2048 || Bread(b, buf, 2048) != 2048) -{ -abort(); - sysfatal("reading block at %,d: %r", n*2048); -} -} - -static Header *h; -static int fd; -static char *file9660; -static int off9660; -static ulong startoff; -static ulong endoff; -static ulong fsoff; -static uchar root[2048]; -static Voldesc *v; -static ulong iso9660start(Cdir*); -static void iso9660copydir(Fs*, File*, Cdir*); -static void iso9660copyfile(Fs*, File*, Cdir*); - -void -iso9660init(int xfd, Header *xh, char *xfile9660, int xoff9660) -{ - uchar sect[2048], sect2[2048]; - - fmtinstall('L', BLfmt); - fmtinstall('B', BLfmt); - fmtinstall('N', Nfmt); - fmtinstall('D', Dfmt); - - fd = xfd; - h = xh; - file9660 = xfile9660; - off9660 = xoff9660; - - if((b = Bopen(file9660, OREAD)) == nil) - vtFatal("Bopen %s: %r", file9660); - - getsect(root, 16); - ascii(); - - v = (Voldesc*)root; - if(memcmp(v->magic, "\x01CD001\x01\x00", 8) != 0) - vtFatal("%s not a cd image", file9660); - - startoff = iso9660start((Cdir*)v->rootdir)*Blocksize; - endoff = little(v->volsize, 4); /* already in bytes */ - - fsoff = off9660 + h->data*h->blockSize; - if(fsoff > startoff) - vtFatal("fossil data starts after cd data"); - if(off9660 + (vlong)h->end*h->blockSize < endoff) - vtFatal("fossil data ends before cd data"); - if(fsoff%h->blockSize) - vtFatal("cd offset not a multiple of fossil block size"); - - /* Read "same" block via CD image and via Fossil image */ - getsect(sect, startoff/Blocksize); - if(seek(fd, startoff-off9660, 0) < 0) - vtFatal("cannot seek to first data sector on cd via fossil"); -fprint(2, "look for %lud at %lud\n", startoff, startoff-off9660); - if(readn(fd, sect2, Blocksize) != Blocksize) - vtFatal("cannot read first data sector on cd via fossil"); - if(memcmp(sect, sect2, Blocksize) != 0) - vtFatal("iso9660 offset is a lie %08ux %08ux", *(long*)sect, *(long*)sect2); -} - -void -iso9660labels(Disk *disk, uchar *buf, void (*write)(int, u32int)) -{ - ulong sb, eb, bn, lb, llb; - Label l; - int lpb; - uchar sect[Blocksize]; - - if(!diskReadRaw(disk, PartData, (startoff-fsoff)/h->blockSize, buf)) - vtFatal("disk read failed: %r"); - getsect(sect, startoff/Blocksize); - if(memcmp(buf, sect, Blocksize) != 0) - vtFatal("fsoff is wrong"); - - sb = (startoff-fsoff)/h->blockSize; - eb = (endoff-fsoff+h->blockSize-1)/h->blockSize; - - lpb = h->blockSize/LabelSize; - - /* for each reserved block, mark label */ - llb = ~0; - l.type = BtData; - l.state = BsAlloc; - l.tag = Tag; - l.epoch = 1; - l.epochClose = ~(u32int)0; - for(bn=sb; bn<eb; bn++){ - lb = bn/lpb; - if(lb != llb){ - if(llb != ~0) - (*write)(PartLabel, llb); - memset(buf, 0, h->blockSize); - } - llb = lb; - labelPack(&l, buf, bn%lpb); - } - if(llb != ~0) - (*write)(PartLabel, llb); -} - -void -iso9660copy(Fs *fs) -{ - File *root; - - root = fileOpen(fs, "/active"); - iso9660copydir(fs, root, (Cdir*)v->rootdir); - fileDecRef(root); - vtRUnlock(fs->elk); - if(!fsSnapshot(fs, nil, nil, 0)) - vtFatal("snapshot failed: %R"); - vtRLock(fs->elk); -} - -/* - * The first block used is the first data block of the leftmost file in the tree. - * (Just an artifact of how mk9660 works.) - */ -static ulong -iso9660start(Cdir *c) -{ - uchar sect[Blocksize]; - - while(c->flags&2){ - getsect(sect, little(c->dloc, 4)); - c = (Cdir*)sect; - c = (Cdir*)((uchar*)c+c->len); /* skip dot */ - c = (Cdir*)((uchar*)c+c->len); /* skip dotdot */ - /* oops: might happen if leftmost directory is empty or leftmost file is zero length! */ - if(little(c->dloc, 4) == 0) - vtFatal("error parsing cd image or unfortunate cd image"); - } - return little(c->dloc, 4); -} - -static void -iso9660copydir(Fs *fs, File *dir, Cdir *cd) -{ - ulong off, end, len; - uchar sect[Blocksize], *esect, *p; - Cdir *c; - - len = little(cd->dlen, 4); - off = little(cd->dloc, 4)*Blocksize; - end = off+len; - esect = sect+Blocksize; - - for(; off<end; off+=Blocksize){ - getsect(sect, off/Blocksize); - p = sect; - while(p < esect){ - c = (Cdir*)p; - if(c->len <= 0) - break; - if(c->namelen!=1 || c->name[0]>1) - iso9660copyfile(fs, dir, c); - p += c->len; - } - } -} - -static char* -getname(uchar **pp) -{ - uchar *p; - int l; - - p = *pp; - l = *p; - *pp = p+1+l; - if(l == 0) - return ""; - memmove(p, p+1, l); - p[l] = 0; - return (char*)p; -} - -static char* -getcname(Cdir *c) -{ - uchar *up; - char *p, *q; - - up = &c->namelen; - p = getname(&up); - for(q=p; *q; q++) - *q = tolower(*q); - return p; -} - -static char -dmsize[12] = -{ - 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -}; - -static ulong -getcdate(uchar *p) /* yMdhmsz */ -{ - Tm tm; - int y, M, d, h, m, s, tz; - - y=p[0]; M=p[1]; d=p[2]; - h=p[3]; m=p[4]; s=p[5]; tz=p[6]; - USED(tz); - if (y < 70) - return 0; - if (M < 1 || M > 12) - return 0; - if (d < 1 || d > dmsize[M-1]) - return 0; - if (h > 23) - return 0; - if (m > 59) - return 0; - if (s > 59) - return 0; - - memset(&tm, 0, sizeof tm); - tm.sec = s; - tm.min = m; - tm.hour = h; - tm.mday = d; - tm.mon = M-1; - tm.year = 1900+y; - tm.zone[0] = 0; - return tm2sec(&tm); -} - -static int ind; - -static void -iso9660copyfile(Fs *fs, File *dir, Cdir *c) -{ - Dir d; - DirEntry de; - int sysl; - uchar score[VtScoreSize]; - ulong off, foff, len, mode; - uchar *p; - File *f; - - ind++; - memset(&d, 0, sizeof d); - p = c->name + c->namelen; - if(((uintptr)p) & 1) - p++; - sysl = (uchar*)c + c->len - p; - if(sysl <= 0) - vtFatal("missing plan9 directory entry on %d/%d/%.*s", c->namelen, c->name[0], c->namelen, c->name); - d.name = getname(&p); - d.uid = getname(&p); - d.gid = getname(&p); - if((uintptr)p & 1) - p++; - d.mode = little(p, 4); - if(d.name[0] == 0) - d.name = getcname(c); - d.mtime = getcdate(c->date); - d.atime = d.mtime; - -if(d.mode&DMDIR) print("%*scopy %s %s %s %luo\n", ind*2, "", d.name, d.uid, d.gid, d.mode); - - mode = d.mode&0777; - if(d.mode&DMDIR) - mode |= ModeDir; - if((f = fileCreate(dir, d.name, mode, d.uid)) == nil) - vtFatal("could not create file '%s': %r", d.name); - if(d.mode&DMDIR) - iso9660copydir(fs, f, c); - else{ - len = little(c->dlen, 4); - off = little(c->dloc, 4)*Blocksize; - for(foff=0; foff<len; foff+=h->blockSize){ - localToGlobal((off+foff-fsoff)/h->blockSize, score); - if(!fileMapBlock(f, foff/h->blockSize, score, Tag)) - vtFatal("fileMapBlock: %R"); - } - if(!fileSetSize(f, len)) - vtFatal("fileSetSize: %R"); - } - if(!fileGetDir(f, &de)) - vtFatal("fileGetDir: %R"); - de.uid = d.uid; - de.gid = d.gid; - de.mtime = d.mtime; - de.atime = d.atime; - de.mode = d.mode&0777; - if(!fileSetDir(f, &de, "sys")) - vtFatal("fileSetDir: %R"); - fileDecRef(f); - ind--; -} diff --git a/sys/src/cmd/fossil/flfmt9660.h b/sys/src/cmd/fossil/flfmt9660.h deleted file mode 100644 index f9be9ed8b..000000000 --- a/sys/src/cmd/fossil/flfmt9660.h +++ /dev/null @@ -1,3 +0,0 @@ -void iso9660init(int fd, Header *h, char*, int); -void iso9660labels(Disk*, uchar*, void(*write)(int, u32int)); -void iso9660copy(Fs*); diff --git a/sys/src/cmd/fossil/flproto b/sys/src/cmd/fossil/flproto deleted file mode 100644 index 6ffe268ba..000000000 --- a/sys/src/cmd/fossil/flproto +++ /dev/null @@ -1,14 +0,0 @@ -# -# Test filesystem. -# -fsys main config /tmp/fossil -fsys main open -fsys main -uname geoff :geoff -uname sys +geoff -uname jmk :jmk -uname sys +jmk -srv -p test.fscons -srv test.fossil -create /active/tmp sys sys d777 -srv -N test.none diff --git a/sys/src/cmd/fossil/fns.h b/sys/src/cmd/fossil/fns.h deleted file mode 100644 index 348112ef5..000000000 --- a/sys/src/cmd/fossil/fns.h +++ /dev/null @@ -1,106 +0,0 @@ -Block* sourceBlock(Source*, ulong, int); -Block* _sourceBlock(Source*, ulong, int, int, ulong); -void sourceClose(Source*); -Source* sourceCreate(Source*, int, int, u32int); -ulong sourceGetDirSize(Source*); -int sourceGetEntry(Source*, Entry*); -uvlong sourceGetSize(Source*); -int sourceLock2(Source*, Source*, int); -int sourceLock(Source*, int); -char *sourceName(Source *s); -Source* sourceOpen(Source*, ulong, int, int); -int sourceRemove(Source*); -Source* sourceRoot(Fs*, u32int, int); -int sourceSetDirSize(Source*, ulong); -int sourceSetEntry(Source*, Entry*); -int sourceSetSize(Source*, uvlong); -int sourceTruncate(Source*); -void sourceUnlock(Source*); - -Block* cacheAllocBlock(Cache*, int, u32int, u32int, u32int); -Cache* cacheAlloc(Disk*, VtSession*, ulong, int); -void cacheCountUsed(Cache*, u32int, u32int*, u32int*, u32int*); -int cacheDirty(Cache*); -void cacheFlush(Cache*, int); -void cacheFree(Cache*); -Block* cacheGlobal(Cache*, uchar[VtScoreSize], int, u32int, int); -Block* cacheLocal(Cache*, int, u32int, int); -Block* cacheLocalData(Cache*, u32int, int, u32int, int, u32int); -u32int cacheLocalSize(Cache*, int); -int readLabel(Cache*, Label*, u32int addr); - -Block* blockCopy(Block*, u32int, u32int, u32int); -void blockDependency(Block*, Block*, int, uchar*, Entry*); -int blockDirty(Block*); -void blockDupLock(Block*); -void blockPut(Block*); -void blockRemoveLink(Block*, u32int, int, u32int, int); -uchar* blockRollback(Block*, uchar*); -void blockSetIOState(Block*, int); -Block* _blockSetLabel(Block*, Label*); -int blockSetLabel(Block*, Label*, int); -int blockWrite(Block*); - -Disk* diskAlloc(int); -int diskBlockSize(Disk*); -int diskFlush(Disk*); -void diskFree(Disk*); -void diskRead(Disk*, Block*); -int diskReadRaw(Disk*, int, u32int, uchar*); -u32int diskSize(Disk*, int); -void diskWriteAndWait(Disk*, Block*); -void diskWrite(Disk*, Block*); -int diskWriteRaw(Disk*, int, u32int, uchar*); - -char* bioStr(int); -char* bsStr(int); -char* btStr(int); -u32int globalToLocal(uchar[VtScoreSize]); -void localToGlobal(u32int, uchar[VtScoreSize]); - -void headerPack(Header*, uchar*); -int headerUnpack(Header*, uchar*); - -int labelFmt(Fmt*); -void labelPack(Label*, uchar*, int); -int labelUnpack(Label*, uchar*, int); - -int scoreFmt(Fmt*); - -void superPack(Super*, uchar*); -int superUnpack(Super*, uchar*); - -void entryPack(Entry*, uchar*, int); -int entryType(Entry*); -int entryUnpack(Entry*, uchar*, int); - -Periodic* periodicAlloc(void (*)(void*), void*, int); -void periodicKill(Periodic*); - -int fileGetSources(File*, Entry*, Entry*); -File* fileRoot(Source*); -int fileSnapshot(File*, File*, u32int, int); -int fsNextQid(Fs*, u64int*); -int mkVac(VtSession*, uint, Entry*, Entry*, DirEntry*, uchar[VtScoreSize]); -Block* superGet(Cache*, Super*); - -void archFree(Arch*); -Arch* archInit(Cache*, Disk*, Fs*, VtSession*); -void archKick(Arch*); - -void bwatchDependency(Block*); -void bwatchInit(void); -void bwatchLock(Block*); -void bwatchReset(uchar[VtScoreSize]); -void bwatchSetBlockSize(uint); -void bwatchUnlock(Block*); - -void initWalk(WalkPtr*, Block*, uint); -int nextWalk(WalkPtr*, uchar[VtScoreSize], uchar*, u32int*, Entry**); - -void snapGetTimes(Snap*, u32int*, u32int*, u32int*); -void snapSetTimes(Snap*, u32int, u32int, u32int); - -void fsCheck(Fsck*); - -#pragma varargck type "L" Label* diff --git a/sys/src/cmd/fossil/fossil-acid b/sys/src/cmd/fossil/fossil-acid deleted file mode 100644 index 10f99e65c..000000000 --- a/sys/src/cmd/fossil/fossil-acid +++ /dev/null @@ -1,200 +0,0 @@ -// pick up the common data structures - -rc("cd /sys/src/cmd/fossil; mk 9fsys.acid"); -include("/sys/src/cmd/fossil/9fsys.acid"); -rc("cd /sys/src/cmd/fossil; mk cache.acid"); -include("/sys/src/cmd/fossil/cache.acid"); -rc("cd /sys/src/cmd/fossil; mk disk.acid"); -include("/sys/src/cmd/fossil/disk.acid"); -rc("cd /sys/src/cmd/fossil; mk fs.acid"); -include("/sys/src/cmd/fossil/fs.acid"); -rc("cd /sys/src/liboventi; mk plan9-thread.acid"); -include("/sys/src/liboventi/plan9-thread.acid"); - -// make a list of pids from a list of Thread structures -defn _threadlist(t) -{ - local l; - - l = {}; - while t do { - t = (Thread)t; - l = append l, t.pid; - t = t.next; - } - return l; -} - -// print info about a VtRendez -defn vtrendez(r) -{ - local l, t, w, q; - - r = (VtRendez)r; - w = _threadlist(r.wfirst); - if match(pid, w) >= 0 then - print("\twaiting for wakeup\n"); - - l = (VtLock)r.lk; - q = _threadlist(l.qfirst); - if match(pid, q) >= 0 then - print("\tawakened; waiting for lock\n"); - - print("\tr=(VtRendez)", r\X, "\n"); - print("\tl=(VtLock)", l\X, "\n"); - if l.writer != 0 then { - t = (Thread)l.writer; - print("\tvtLock is held by ", t.pid\D, "\n"); - } -} - -// print info about a VtLock -defn vtlock(l) -{ - local t; - - l = (VtLock)l; - print("\tl=(VtLock)", l\X, "\n"); - if l.writer then { - t = (Thread)l.writer; - print("\tvtLock is held by ", t.pid\D, "\n"); - } else if l.readers then - print("\tvtLock is held by ", l.readers\D, " readers\n"); - else - print("\tvtLock is not held!\n"); -} - -// try to say something intelligent about why a process is stuck. -_pauses = { - open, - pread, - pwrite, - sleep, - vtSleep, - vtLock, - vtRLock, -}; - -defn deadlocklist(l) -{ - while l do { - setproc(head l); - deadlock(); - l = tail l; - } -} - -defn deadlock() -{ - local stk, frame, name, stallframe, fossilframe, stallname; - - stk = strace(*PC, *SP, linkreg(0)); - - print("setproc(", pid, ") // ", readfile("/proc/"+itoa(pid)+"/args"), "\n"); - stallframe = 0; - stallname = ""; - fossilframe = 0; - frame = {0}; - while stk do { - lastframe = frame; - frame = head stk; - name = fmt(frame[0], 'a'); - if !stallframe && match(name, _pauses) >= 0 then { - stallframe = frame; - stallname = name; - print("\t", fmt(frame[0], 'a'), "("); - params(frame[2]); - print(") ", pcfile(frame[0]), ":", pcline(frame[0])); - print("\n\t\tcalled from ", fmt(frame[1], 'a'), " "); - pfl(frame[1]); - } - if !fossilframe && regexp("^/sys/src/cmd/fossil/.*", pcfile(frame[0])) then { - if !stallframe then { - stallframe = lastframe; - stallname = fmt(lastframe[0], 'a'); - print("\tunexpected stall: ", stallname, "\n"); - if match(stallname, _pauses) >= 0 then - print("\t\t but it matches!\n"); - } - fossilframe = frame; - print("\t", fmt(frame[0], 'a'), "("); - params(frame[2]); - print(") ", pcfile(frame[0]), ":", pcline(frame[0])); - print("\n\t\tcalled from ", fmt(frame[1], 'a'), " "); - pfl(frame[1]); - - if name == cacheLocalLookup && stallname == vtLock then - print("\twaiting to lock block b=(Block)", *cacheLocalLookup:b\X, "\n"); - if name == cacheLocal && stallname == vtSleep then - print("\tsleeping on block b=(Block)", *cacheLocal:b\X, "\n"); - if name == blockWrite && stallname == vtSleep then - print("\tsleeping on block b=(Block)", *blockFlush:b\X, "\n"); - } - stk = tail stk; - } - - if stallname == vtSleep then - vtrendez(*vtSleep:q); - if stallname == vtLock then - vtlock(*vtLock:p); - if !stallframe || !fossilframe then { - print("\tconfused:"); - if !stallframe then print(" stallframe?"); - if !fossilframe then print(" fossilframe?"); - print("\n"); - } - print("\n"); -} - -// fetch fsys -defn -fsysGet(name) -{ - return fsysmain; -} - -// dump information about the cache -defn -cacheDump(c) -{ - local i, b, x; - - c = (Cache)c; - x = c.blocks; - i=0; - loop 1,c.nblocks do { - b = (Block)(x+i); - print(b\X, " ", b.pc\X, " ", b.ref\D, "\n"); - i = i+sizeofBlock; - } -} - -// print block info -defn -printblist(bl) -{ - bl = (BList)bl; - while bl != 0 do { - print("[", bl.part\D, " ", bl.addr\X, " ", bl.vers\D, "]"); - bl = bl.next; - if bl != 0 then - print(", "); - } -} - -defn -block(b) -{ - local i; - - b = (Block)b; - print("b=(Block)", b\X, "\n"); - print("\tref ", b.ref\D, " nlock ", b.nlock\D, "\n"); - print("\tpav=[", b.part\D, " ", b.addr\X, " ", b.vers\D, "]\n"); - print("\tprior="); - printblist(b.prior); - print("\n"); - print("\tunlink="); - printblist(b.uhead); - print("\n"); -} diff --git a/sys/src/cmd/fossil/fossil.c b/sys/src/cmd/fossil/fossil.c deleted file mode 100644 index c317d0cfe..000000000 --- a/sys/src/cmd/fossil/fossil.c +++ /dev/null @@ -1,142 +0,0 @@ -#include "stdinc.h" -#include <ctype.h> - -#include "9.h" - -int Dflag; -int mempcnt; /* for 9fsys.c */ -char* none = "none"; - -static void -usage(void) -{ - fprint(2, "usage: %s [-Dt] [-c cmd] [-f partition] [-m %%]\n", argv0); - exits("usage"); -} - -static void -readCmdPart(char *file, char ***pcmd, int *pncmd) -{ - char buf[1024+1], *f[1024]; - char tbuf[1024]; - int nf; - int i, fd, n; - char **cmd, *p; - int ncmd; - - cmd = *pcmd; - ncmd = *pncmd; - - if((fd = open(file, OREAD)) < 0) - sysfatal("open %s: %r", file); - if(seek(fd, 127*1024, 0) != 127*1024) - sysfatal("seek %s 127kB: %r", file); - n = readn(fd, buf, sizeof buf-1); - if(n == 0) - sysfatal("short read of %s at 127kB", file); - if(n < 0) - sysfatal("read %s: %r", file); - buf[n] = 0; - if(memcmp(buf, "fossil config\n", 6+1+6+1) != 0) - sysfatal("bad config magic in %s", file); - nf = getfields(buf+6+1+6+1, f, nelem(f), 1, "\n"); - for(i=0; i<nf; i++){ - if(f[i][0] == '#') - continue; - cmd = vtMemRealloc(cmd, (ncmd+1)*sizeof(char*)); - /* expand argument '*' to mean current file */ - if((p = strchr(f[i], '*')) && (p==f[i]||isspace(p[-1])) && (p[1]==0||isspace(p[1]))){ - memmove(tbuf, f[i], p-f[i]); - strecpy(tbuf+(p-f[i]), tbuf+sizeof tbuf, file); - strecpy(tbuf+strlen(tbuf), tbuf+sizeof tbuf, p+1); - f[i] = tbuf; - } - cmd[ncmd++] = vtStrDup(f[i]); - } - close(fd); - *pcmd = cmd; - *pncmd = ncmd; -} - -void -main(int argc, char* argv[]) -{ - char **cmd, *p; - int i, ncmd, tflag; - - fmtinstall('D', dirfmt); - fmtinstall('F', fcallfmt); - fmtinstall('M', dirmodefmt); - quotefmtinstall(); - - /* - * Insulate from the invoker's environment. - */ - if(rfork(RFREND|RFNOTEG|RFNAMEG) < 0) - sysfatal("rfork: %r"); - - close(0); - open("/dev/null", OREAD); - close(1); - open("/dev/null", OWRITE); - - cmd = nil; - ncmd = tflag = 0; - - vtAttach(); - - ARGBEGIN{ - case '?': - default: - usage(); - break; - case 'c': - p = EARGF(usage()); - currfsysname = p; - cmd = vtMemRealloc(cmd, (ncmd+1)*sizeof(char*)); - cmd[ncmd++] = p; - break; - case 'D': - Dflag ^= 1; - break; - case 'f': - p = EARGF(usage()); - currfsysname = p; - readCmdPart(p, &cmd, &ncmd); - break; - case 'm': - mempcnt = atoi(EARGF(usage())); - if(mempcnt <= 0 || mempcnt >= 100) - usage(); - break; - case 't': - tflag = 1; - break; - }ARGEND - if(argc != 0) - usage(); - - consInit(); - cliInit(); - msgInit(); - conInit(); - cmdInit(); - fsysInit(); - exclInit(); - fidInit(); - - srvInit(); - lstnInit(); - usersInit(); - - for(i = 0; i < ncmd; i++) - if(cliExec(cmd[i]) == 0) - fprint(2, "%s: %R\n", cmd[i]); - vtMemFree(cmd); - - if(tflag && consTTY() == 0) - consPrint("%s\n", vtGetError()); - - vtDetach(); - exits(0); -} diff --git a/sys/src/cmd/fossil/fs.c b/sys/src/cmd/fossil/fs.c deleted file mode 100644 index 78c6be2ce..000000000 --- a/sys/src/cmd/fossil/fs.c +++ /dev/null @@ -1,1099 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -static void fsMetaFlush(void *a); -static Snap *snapInit(Fs*); -static void snapClose(Snap*); - -Fs * -fsOpen(char *file, VtSession *z, long ncache, int mode) -{ - int fd, m; - uchar oscore[VtScoreSize]; - Block *b, *bs; - Disk *disk; - Fs *fs; - Super super; - - switch(mode){ - default: - vtSetError(EBadMode); - return nil; - case OReadOnly: - m = OREAD; - break; - case OReadWrite: - m = ORDWR; - break; - } - fd = open(file, m); - if(fd < 0){ - vtSetError("open %s: %r", file); - return nil; - } - - bwatchInit(); - disk = diskAlloc(fd); - if(disk == nil){ - vtSetError("diskAlloc: %R"); - close(fd); - return nil; - } - - fs = vtMemAllocZ(sizeof(Fs)); - fs->mode = mode; - fs->name = vtStrDup(file); - fs->blockSize = diskBlockSize(disk); - fs->elk = vtLockAlloc(); - fs->cache = cacheAlloc(disk, z, ncache, mode); - if(mode == OReadWrite && z) - fs->arch = archInit(fs->cache, disk, fs, z); - fs->z = z; - - b = cacheLocal(fs->cache, PartSuper, 0, mode); - if(b == nil) - goto Err; - if(!superUnpack(&super, b->data)){ - blockPut(b); - vtSetError("bad super block"); - goto Err; - } - blockPut(b); - - fs->ehi = super.epochHigh; - fs->elo = super.epochLow; - -//fprint(2, "%s: fs->ehi %d fs->elo %d active=%d\n", argv0, fs->ehi, fs->elo, super.active); - - fs->source = sourceRoot(fs, super.active, mode); - if(fs->source == nil){ - /* - * Perhaps it failed because the block is copy-on-write. - * Do the copy and try again. - */ - if(mode == OReadOnly || strcmp(vtGetError(), EBadRoot) != 0) - goto Err; - b = cacheLocalData(fs->cache, super.active, BtDir, RootTag, - OReadWrite, 0); - if(b == nil){ - vtSetError("cacheLocalData: %R"); - goto Err; - } - if(b->l.epoch == fs->ehi){ - blockPut(b); - vtSetError("bad root source block"); - goto Err; - } - b = blockCopy(b, RootTag, fs->ehi, fs->elo); - if(b == nil) - goto Err; - localToGlobal(super.active, oscore); - super.active = b->addr; - bs = cacheLocal(fs->cache, PartSuper, 0, OReadWrite); - if(bs == nil){ - blockPut(b); - vtSetError("cacheLocal: %R"); - goto Err; - } - superPack(&super, bs->data); - blockDependency(bs, b, 0, oscore, nil); - blockPut(b); - blockDirty(bs); - blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); - blockPut(bs); - fs->source = sourceRoot(fs, super.active, mode); - if(fs->source == nil){ - vtSetError("sourceRoot: %R"); - goto Err; - } - } - -//fprint(2, "%s: got fs source\n", argv0); - - vtRLock(fs->elk); - fs->file = fileRoot(fs->source); - fs->source->file = fs->file; /* point back */ - vtRUnlock(fs->elk); - if(fs->file == nil){ - vtSetError("fileRoot: %R"); - goto Err; - } - -//fprint(2, "%s: got file root\n", argv0); - - if(mode == OReadWrite){ - fs->metaFlush = periodicAlloc(fsMetaFlush, fs, 1000); - fs->snap = snapInit(fs); - } - return fs; - -Err: -fprint(2, "%s: fsOpen error\n", argv0); - fsClose(fs); - return nil; -} - -void -fsClose(Fs *fs) -{ - vtRLock(fs->elk); - periodicKill(fs->metaFlush); - snapClose(fs->snap); - if(fs->file){ - fileMetaFlush(fs->file, 0); - if(!fileDecRef(fs->file)) - vtFatal("fsClose: files still in use: %r\n"); - } - fs->file = nil; - sourceClose(fs->source); - cacheFree(fs->cache); - if(fs->arch) - archFree(fs->arch); - vtMemFree(fs->name); - vtRUnlock(fs->elk); - vtLockFree(fs->elk); - memset(fs, ~0, sizeof(Fs)); - vtMemFree(fs); -} - -int -fsRedial(Fs *fs, char *host) -{ - if(!vtRedial(fs->z, host)) - return 0; - if(!vtConnect(fs->z, 0)) - return 0; - return 1; -} - -File * -fsGetRoot(Fs *fs) -{ - return fileIncRef(fs->file); -} - -int -fsGetBlockSize(Fs *fs) -{ - return fs->blockSize; -} - -Block* -superGet(Cache *c, Super* super) -{ - Block *b; - - if((b = cacheLocal(c, PartSuper, 0, OReadWrite)) == nil){ - fprint(2, "%s: superGet: cacheLocal failed: %R\n", argv0); - return nil; - } - if(!superUnpack(super, b->data)){ - fprint(2, "%s: superGet: superUnpack failed: %R\n", argv0); - blockPut(b); - return nil; - } - - return b; -} - -void -superWrite(Block* b, Super* super, int forceWrite) -{ - superPack(super, b->data); - blockDirty(b); - if(forceWrite){ - while(!blockWrite(b)){ - /* BUG: what should really happen here? */ - fprint(2, "%s: could not write super block; " - "waiting 10 seconds\n", argv0); - sleep(10*1000); - } - while(b->iostate != BioClean && b->iostate != BioDirty){ - assert(b->iostate == BioWriting); - vtSleep(b->ioready); - } - /* - * it's okay that b might still be dirty. - * that means it got written out but with an old root pointer, - * but the other fields went out, and those are the ones - * we really care about. (specifically, epochHigh; see fsSnapshot). - */ - } -} - -/* - * Prepare the directory to store a snapshot. - * Temporary snapshots go into /snapshot/yyyy/mmdd/hhmm[.#] - * Archival snapshots go into /archive/yyyy/mmdd[.#]. - * - * TODO This should be rewritten to eliminate most of the duplication. - */ -static File* -fileOpenSnapshot(Fs *fs, char *dstpath, int doarchive) -{ - int n; - char buf[30], *s, *p, *elem; - File *dir, *f; - Tm now; - - if(dstpath){ - if((p = strrchr(dstpath, '/')) != nil){ - *p++ = '\0'; - elem = p; - p = dstpath; - if(*p == '\0') - p = "/"; - }else{ - p = "/"; - elem = dstpath; - } - if((dir = fileOpen(fs, p)) == nil) - return nil; - f = fileCreate(dir, elem, ModeDir|ModeSnapshot|0555, "adm"); - fileDecRef(dir); - return f; - }else if(doarchive){ - /* - * a snapshot intended to be archived to venti. - */ - dir = fileOpen(fs, "/archive"); - if(dir == nil) - return nil; - now = *localtime(time(0)); - - /* yyyy */ - snprint(buf, sizeof(buf), "%d", now.year+1900); - f = fileWalk(dir, buf); - if(f == nil) - f = fileCreate(dir, buf, ModeDir|0555, "adm"); - fileDecRef(dir); - if(f == nil) - return nil; - dir = f; - - /* mmdd[#] */ - snprint(buf, sizeof(buf), "%02d%02d", now.mon+1, now.mday); - s = buf+strlen(buf); - for(n=0;; n++){ - if(n) - seprint(s, buf+sizeof(buf), ".%d", n); - f = fileWalk(dir, buf); - if(f != nil){ - fileDecRef(f); - continue; - } - f = fileCreate(dir, buf, ModeDir|ModeSnapshot|0555, "adm"); - break; - } - fileDecRef(dir); - return f; - }else{ - /* - * Just a temporary snapshot - * We'll use /snapshot/yyyy/mmdd/hhmm. - * There may well be a better naming scheme. - * (I'd have used hh:mm but ':' is reserved in Microsoft file systems.) - */ - dir = fileOpen(fs, "/snapshot"); - if(dir == nil) - return nil; - - now = *localtime(time(0)); - - /* yyyy */ - snprint(buf, sizeof(buf), "%d", now.year+1900); - f = fileWalk(dir, buf); - if(f == nil) - f = fileCreate(dir, buf, ModeDir|0555, "adm"); - fileDecRef(dir); - if(f == nil) - return nil; - dir = f; - - /* mmdd */ - snprint(buf, sizeof(buf), "%02d%02d", now.mon+1, now.mday); - f = fileWalk(dir, buf); - if(f == nil) - f = fileCreate(dir, buf, ModeDir|0555, "adm"); - fileDecRef(dir); - if(f == nil) - return nil; - dir = f; - - /* hhmm[.#] */ - snprint(buf, sizeof buf, "%02d%02d", now.hour, now.min); - s = buf+strlen(buf); - for(n=0;; n++){ - if(n) - seprint(s, buf+sizeof(buf), ".%d", n); - f = fileWalk(dir, buf); - if(f != nil){ - fileDecRef(f); - continue; - } - f = fileCreate(dir, buf, ModeDir|ModeSnapshot|0555, "adm"); - break; - } - fileDecRef(dir); - return f; - } -} - -static int -fsNeedArch(Fs *fs, uint archMinute) -{ - int need; - File *f; - char buf[100]; - Tm now; - ulong then; - - then = time(0); - now = *localtime(then); - - /* back up to yesterday if necessary */ - if(now.hour < archMinute/60 - || now.hour == archMinute/60 && now.min < archMinute%60) - now = *localtime(then-86400); - - snprint(buf, sizeof buf, "/archive/%d/%02d%02d", - now.year+1900, now.mon+1, now.mday); - need = 1; - vtRLock(fs->elk); - f = fileOpen(fs, buf); - if(f){ - need = 0; - fileDecRef(f); - } - vtRUnlock(fs->elk); - return need; -} - -int -fsEpochLow(Fs *fs, u32int low) -{ - Block *bs; - Super super; - - vtLock(fs->elk); - if(low > fs->ehi){ - vtSetError("bad low epoch (must be <= %ud)", fs->ehi); - vtUnlock(fs->elk); - return 0; - } - - if((bs = superGet(fs->cache, &super)) == nil){ - vtUnlock(fs->elk); - return 0; - } - - super.epochLow = low; - fs->elo = low; - superWrite(bs, &super, 1); - blockPut(bs); - vtUnlock(fs->elk); - - return 1; -} - -static int -bumpEpoch(Fs *fs, int doarchive) -{ - uchar oscore[VtScoreSize]; - u32int oldaddr; - Block *b, *bs; - Entry e; - Source *r; - Super super; - - /* - * Duplicate the root block. - * - * As a hint to flchk, the garbage collector, - * and any (human) debuggers, store a pointer - * to the old root block in entry 1 of the new root block. - */ - r = fs->source; - b = cacheGlobal(fs->cache, r->score, BtDir, RootTag, OReadOnly); - if(b == nil) - return 0; - - memset(&e, 0, sizeof e); - e.flags = VtEntryActive | VtEntryLocal | VtEntryDir; - memmove(e.score, b->score, VtScoreSize); - e.tag = RootTag; - e.snap = b->l.epoch; - - b = blockCopy(b, RootTag, fs->ehi+1, fs->elo); - if(b == nil){ - fprint(2, "%s: bumpEpoch: blockCopy: %R\n", argv0); - return 0; - } - - if(0) fprint(2, "%s: snapshot root from %d to %d\n", argv0, oldaddr, b->addr); - entryPack(&e, b->data, 1); - blockDirty(b); - - /* - * Update the superblock with the new root and epoch. - */ - if((bs = superGet(fs->cache, &super)) == nil) - return 0; - - fs->ehi++; - memmove(r->score, b->score, VtScoreSize); - r->epoch = fs->ehi; - - super.epochHigh = fs->ehi; - oldaddr = super.active; - super.active = b->addr; - if(doarchive) - super.next = oldaddr; - - /* - * Record that the new super.active can't get written out until - * the new b gets written out. Until then, use the old value. - */ - localToGlobal(oldaddr, oscore); - blockDependency(bs, b, 0, oscore, nil); - blockPut(b); - - /* - * We force the super block to disk so that super.epochHigh gets updated. - * Otherwise, if we crash and come back, we might incorrectly treat as active - * some of the blocks that making up the snapshot we just created. - * Basically every block in the active file system and all the blocks in - * the recently-created snapshot depend on the super block now. - * Rather than record all those dependencies, we just force the block to disk. - * - * Note that blockWrite might actually (will probably) send a slightly outdated - * super.active to disk. It will be the address of the most recent root that has - * gone to disk. - */ - superWrite(bs, &super, 1); - blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); - blockPut(bs); - - return 1; -} - -int -saveQid(Fs *fs) -{ - Block *b; - Super super; - u64int qidMax; - - if((b = superGet(fs->cache, &super)) == nil) - return 0; - qidMax = super.qid; - blockPut(b); - - if(!fileSetQidSpace(fs->file, 0, qidMax)) - return 0; - - return 1; -} - -int -fsSnapshot(Fs *fs, char *srcpath, char *dstpath, int doarchive) -{ - File *src, *dst; - - assert(fs->mode == OReadWrite); - - dst = nil; - - if(fs->halted){ - vtSetError("file system is halted"); - return 0; - } - - /* - * Freeze file system activity. - */ - vtLock(fs->elk); - - /* - * Get the root of the directory we're going to save. - */ - if(srcpath == nil) - srcpath = "/active"; - src = fileOpen(fs, srcpath); - if(src == nil) - goto Err; - - /* - * It is important that we maintain the invariant that: - * if both b and bb are marked as Active with start epoch e - * and b points at bb, then no other pointers to bb exist. - * - * When bb is unlinked from b, its close epoch is set to b's epoch. - * A block with epoch == close epoch is - * treated as free by cacheAllocBlock; this aggressively - * reclaims blocks after they have been stored to Venti. - * - * Let's say src->source is block sb, and src->msource is block - * mb. Let's also say that block b holds the Entry structures for - * both src->source and src->msource (their Entry structures might - * be in different blocks, but the argument is the same). - * That is, right now we have: - * - * b Active w/ epoch e, holds ptrs to sb and mb. - * sb Active w/ epoch e. - * mb Active w/ epoch e. - * - * With things as they are now, the invariant requires that - * b holds the only pointers to sb and mb. We want to record - * pointers to sb and mb in new Entries corresponding to dst, - * which breaks the invariant. Thus we need to do something - * about b. Specifically, we bump the file system's epoch and - * then rewalk the path from the root down to and including b. - * This will copy-on-write as we walk, so now the state will be: - * - * b Snap w/ epoch e, holds ptrs to sb and mb. - * new-b Active w/ epoch e+1, holds ptrs to sb and mb. - * sb Active w/ epoch e. - * mb Active w/ epoch e. - * - * In this state, it's perfectly okay to make more pointers to sb and mb. - */ - if(!bumpEpoch(fs, 0) || !fileWalkSources(src)) - goto Err; - - /* - * Sync to disk. I'm not sure this is necessary, but better safe than sorry. - */ - cacheFlush(fs->cache, 1); - - /* - * Create the directory where we will store the copy of src. - */ - dst = fileOpenSnapshot(fs, dstpath, doarchive); - if(dst == nil) - goto Err; - - /* - * Actually make the copy by setting dst's source and msource - * to be src's. - */ - if(!fileSnapshot(dst, src, fs->ehi-1, doarchive)) - goto Err; - - fileDecRef(src); - fileDecRef(dst); - src = nil; - dst = nil; - - /* - * Make another copy of the file system. This one is for the - * archiver, so that the file system we archive has the recently - * added snapshot both in /active and in /archive/yyyy/mmdd[.#]. - */ - if(doarchive){ - if(!saveQid(fs)) - goto Err; - if(!bumpEpoch(fs, 1)) - goto Err; - } - - vtUnlock(fs->elk); - - /* BUG? can fs->arch fall out from under us here? */ - if(doarchive && fs->arch) - archKick(fs->arch); - - return 1; - -Err: - fprint(2, "%s: fsSnapshot: %R\n", argv0); - if(src) - fileDecRef(src); - if(dst) - fileDecRef(dst); - vtUnlock(fs->elk); - return 0; -} - -int -fsVac(Fs *fs, char *name, uchar score[VtScoreSize]) -{ - int r; - DirEntry de; - Entry e, ee; - File *f; - - vtRLock(fs->elk); - f = fileOpen(fs, name); - if(f == nil){ - vtRUnlock(fs->elk); - return 0; - } - - if(!fileGetSources(f, &e, &ee) || !fileGetDir(f, &de)){ - fileDecRef(f); - vtRUnlock(fs->elk); - return 0; - } - fileDecRef(f); - - r = mkVac(fs->z, fs->blockSize, &e, &ee, &de, score); - vtRUnlock(fs->elk); - return r; -} - -static int -vtWriteBlock(VtSession *z, uchar *buf, uint n, uint type, uchar score[VtScoreSize]) -{ - if(!vtWrite(z, score, type, buf, n)) - return 0; - if(!vtSha1Check(score, buf, n)) - return 0; - return 1; -} - -int -mkVac(VtSession *z, uint blockSize, Entry *pe, Entry *pee, DirEntry *pde, uchar score[VtScoreSize]) -{ - uchar buf[8192]; - int i; - uchar *p; - uint n; - DirEntry de; - Entry e, ee, eee; - MetaBlock mb; - MetaEntry me; - VtRoot root; - - e = *pe; - ee = *pee; - de = *pde; - - if(globalToLocal(e.score) != NilBlock - || (ee.flags&VtEntryActive && globalToLocal(ee.score) != NilBlock)){ - vtSetError("can only vac paths already stored on venti"); - return 0; - } - - /* - * Build metadata source for root. - */ - n = deSize(&de); - if(n+MetaHeaderSize+MetaIndexSize > sizeof buf){ - vtSetError("DirEntry too big"); - return 0; - } - memset(buf, 0, sizeof buf); - mbInit(&mb, buf, n+MetaHeaderSize+MetaIndexSize, 1); - p = mbAlloc(&mb, n); - if(p == nil) - abort(); - mbSearch(&mb, de.elem, &i, &me); - assert(me.p == nil); - me.p = p; - me.size = n; - dePack(&de, &me); - mbInsert(&mb, i, &me); - mbPack(&mb); - - eee.size = n+MetaHeaderSize+MetaIndexSize; - if(!vtWriteBlock(z, buf, eee.size, VtDataType, eee.score)) - return 0; - eee.psize = 8192; - eee.dsize = 8192; - eee.depth = 0; - eee.flags = VtEntryActive; - - /* - * Build root source with three entries in it. - */ - entryPack(&e, buf, 0); - entryPack(&ee, buf, 1); - entryPack(&eee, buf, 2); - - n = VtEntrySize*3; - memset(&root, 0, sizeof root); - if(!vtWriteBlock(z, buf, n, VtDirType, root.score)) - return 0; - - /* - * Save root. - */ - root.version = VtRootVersion; - strecpy(root.type, root.type+sizeof root.type, "vac"); - strecpy(root.name, root.name+sizeof root.name, de.elem); - root.blockSize = blockSize; - vtRootPack(&root, buf); - if(!vtWriteBlock(z, buf, VtRootSize, VtRootType, score)) - return 0; - - return 1; -} - -int -fsSync(Fs *fs) -{ - vtLock(fs->elk); - fileMetaFlush(fs->file, 1); - cacheFlush(fs->cache, 1); - vtUnlock(fs->elk); - return 1; -} - -int -fsHalt(Fs *fs) -{ - vtLock(fs->elk); - fs->halted = 1; - fileMetaFlush(fs->file, 1); - cacheFlush(fs->cache, 1); - return 1; -} - -int -fsUnhalt(Fs *fs) -{ - if(!fs->halted) - return 0; - fs->halted = 0; - vtUnlock(fs->elk); - return 1; -} - -int -fsNextQid(Fs *fs, u64int *qid) -{ - Block *b; - Super super; - - if((b = superGet(fs->cache, &super)) == nil) - return 0; - - *qid = super.qid++; - - /* - * It's okay if the super block doesn't go to disk immediately, - * since fileMetaAlloc will record a dependency between the - * block holding this qid and the super block. See file.c:/^fileMetaAlloc. - */ - superWrite(b, &super, 0); - blockPut(b); - return 1; -} - -static void -fsMetaFlush(void *a) -{ - int rv; - Fs *fs = a; - - vtRLock(fs->elk); - rv = fileMetaFlush(fs->file, 1); - vtRUnlock(fs->elk); - if(rv > 0) - cacheFlush(fs->cache, 0); -} - -static int -fsEsearch1(File *f, char *path, u32int savetime, u32int *plo) -{ - int n, r; - DirEntry de; - DirEntryEnum *dee; - File *ff; - Entry e, ee; - char *t; - - dee = deeOpen(f); - if(dee == nil) - return 0; - - n = 0; - for(;;){ - r = deeRead(dee, &de); - if(r <= 0) - break; - if(de.mode & ModeSnapshot){ - if((ff = fileWalk(f, de.elem)) != nil){ - if(fileGetSources(ff, &e, &ee)) - if(de.mtime >= savetime && e.snap != 0) - if(e.snap < *plo) - *plo = e.snap; - fileDecRef(ff); - } - } - else if(de.mode & ModeDir){ - if((ff = fileWalk(f, de.elem)) != nil){ - t = smprint("%s/%s", path, de.elem); - n += fsEsearch1(ff, t, savetime, plo); - vtMemFree(t); - fileDecRef(ff); - } - } - deCleanup(&de); - if(r < 0) - break; - } - deeClose(dee); - - return n; -} - -static int -fsEsearch(Fs *fs, char *path, u32int savetime, u32int *plo) -{ - int n; - File *f; - DirEntry de; - - f = fileOpen(fs, path); - if(f == nil) - return 0; - if(!fileGetDir(f, &de)){ - fileDecRef(f); - return 0; - } - if((de.mode & ModeDir) == 0){ - fileDecRef(f); - deCleanup(&de); - return 0; - } - deCleanup(&de); - n = fsEsearch1(f, path, savetime, plo); - fileDecRef(f); - return n; -} - -void -fsSnapshotCleanup(Fs *fs, u32int age) -{ - u32int lo; - - /* - * Find the best low epoch we can use, - * given that we need to save all the unventied archives - * and all the snapshots younger than age. - */ - vtRLock(fs->elk); - lo = fs->ehi; - fsEsearch(fs, "/archive", 0, &lo); - fsEsearch(fs, "/snapshot", time(0)-age*60, &lo); - vtRUnlock(fs->elk); - - fsEpochLow(fs, lo); - fsSnapshotRemove(fs); -} - -/* remove all snapshots that have expired */ -/* return number of directory entries remaining */ -static int -fsRsearch1(File *f, char *s) -{ - int n, r; - DirEntry de; - DirEntryEnum *dee; - File *ff; - char *t; - - dee = deeOpen(f); - if(dee == nil) - return 0; - - n = 0; - for(;;){ - r = deeRead(dee, &de); - if(r <= 0) - break; - n++; - if(de.mode & ModeSnapshot){ - if((ff = fileWalk(f, de.elem)) != nil) - fileDecRef(ff); - else if(strcmp(vtGetError(), ESnapOld) == 0){ - if(fileClri(f, de.elem, "adm")) - n--; - } - } - else if(de.mode & ModeDir){ - if((ff = fileWalk(f, de.elem)) != nil){ - t = smprint("%s/%s", s, de.elem); - if(fsRsearch1(ff, t) == 0) - if(fileRemove(ff, "adm")) - n--; - vtMemFree(t); - fileDecRef(ff); - } - } - deCleanup(&de); - if(r < 0) - break; - } - deeClose(dee); - - return n; -} - -static int -fsRsearch(Fs *fs, char *path) -{ - File *f; - DirEntry de; - - f = fileOpen(fs, path); - if(f == nil) - return 0; - if(!fileGetDir(f, &de)){ - fileDecRef(f); - return 0; - } - if((de.mode & ModeDir) == 0){ - fileDecRef(f); - deCleanup(&de); - return 0; - } - deCleanup(&de); - fsRsearch1(f, path); - fileDecRef(f); - return 1; -} - -void -fsSnapshotRemove(Fs *fs) -{ - vtRLock(fs->elk); - fsRsearch(fs, "/snapshot"); - vtRUnlock(fs->elk); -} - -struct Snap -{ - Fs *fs; - Periodic*tick; - VtLock *lk; - uint snapMinutes; - uint archMinute; - uint snapLife; - u32int lastSnap; - u32int lastArch; - u32int lastCleanup; - uint ignore; -}; - -static void -snapEvent(void *v) -{ - Snap *s; - u32int now, min; - Tm tm; - int need; - u32int snaplife; - - s = v; - - now = time(0)/60; - vtLock(s->lk); - - /* - * Snapshots happen every snapMinutes minutes. - * If we miss a snapshot (for example, because we - * were down), we wait for the next one. - */ - if(s->snapMinutes != ~0 && s->snapMinutes != 0 - && now%s->snapMinutes==0 && now != s->lastSnap){ - if(!fsSnapshot(s->fs, nil, nil, 0)) - fprint(2, "%s: fsSnapshot snap: %R\n", argv0); - s->lastSnap = now; - } - - /* - * Archival snapshots happen at archMinute. - * If we miss an archive (for example, because we - * were down), we do it as soon as possible. - */ - tm = *localtime(now*60); - min = tm.hour*60+tm.min; - if(s->archMinute != ~0){ - need = 0; - if(min == s->archMinute && now != s->lastArch) - need = 1; - if(s->lastArch == 0){ - s->lastArch = 1; - if(fsNeedArch(s->fs, s->archMinute)) - need = 1; - } - if(need){ - fsSnapshot(s->fs, nil, nil, 1); - s->lastArch = now; - } - } - - /* - * Snapshot cleanup happens every snaplife or every day. - */ - snaplife = s->snapLife; - if(snaplife == ~0) - snaplife = 24*60; - if(s->lastCleanup+snaplife < now){ - fsSnapshotCleanup(s->fs, s->snapLife); - s->lastCleanup = now; - } - vtUnlock(s->lk); -} - -static Snap* -snapInit(Fs *fs) -{ - Snap *s; - - s = vtMemAllocZ(sizeof(Snap)); - s->fs = fs; - s->tick = periodicAlloc(snapEvent, s, 10*1000); - s->lk = vtLockAlloc(); - s->snapMinutes = -1; - s->archMinute = -1; - s->snapLife = -1; - s->ignore = 5*2; /* wait five minutes for clock to stabilize */ - return s; -} - -void -snapGetTimes(Snap *s, u32int *arch, u32int *snap, u32int *snaplen) -{ - if(s == nil){ - *snap = -1; - *arch = -1; - *snaplen = -1; - return; - } - - vtLock(s->lk); - *snap = s->snapMinutes; - *arch = s->archMinute; - *snaplen = s->snapLife; - vtUnlock(s->lk); -} - -void -snapSetTimes(Snap *s, u32int arch, u32int snap, u32int snaplen) -{ - if(s == nil) - return; - - vtLock(s->lk); - s->snapMinutes = snap; - s->archMinute = arch; - s->snapLife = snaplen; - vtUnlock(s->lk); -} - -static void -snapClose(Snap *s) -{ - if(s == nil) - return; - - periodicKill(s->tick); - vtMemFree(s); -} - diff --git a/sys/src/cmd/fossil/fs.h b/sys/src/cmd/fossil/fs.h deleted file mode 100644 index 30b592c89..000000000 --- a/sys/src/cmd/fossil/fs.h +++ /dev/null @@ -1,63 +0,0 @@ -typedef struct Fs Fs; -typedef struct File File; -typedef struct DirEntryEnum DirEntryEnum; - -#pragma incomplete Fs -#pragma incomplete File -#pragma incomplete DirEntryEnum - -/* modes */ - -enum { - OReadOnly, - OReadWrite, - OOverWrite, -}; - -extern char *currfsysname; - -void fsClose(Fs*); -int fsEpochLow(Fs*, u32int); -File *fsGetRoot(Fs*); -int fsHalt(Fs*); -Fs *fsOpen(char*, VtSession*, long, int); -int fsRedial(Fs*, char*); -void fsSnapshotCleanup(Fs*, u32int); -int fsSnapshot(Fs*, char*, char*, int); -void fsSnapshotRemove(Fs*); -int fsSync(Fs*); -int fsUnhalt(Fs*); -int fsVac(Fs*, char*, uchar[VtScoreSize]); - -void deeClose(DirEntryEnum*); -DirEntryEnum *deeOpen(File*); -int deeRead(DirEntryEnum*, DirEntry*); -int fileClri(File*, char*, char*); -int fileClriPath(Fs*, char*, char*); -File *fileCreate(File*, char*, ulong, char*); -int fileDecRef(File*); -int fileGetDir(File*, DirEntry*); -uvlong fileGetId(File*); -ulong fileGetMcount(File*); -ulong fileGetMode(File*); -File *fileGetParent(File*); -int fileGetSize(File*, uvlong*); -File *fileIncRef(File*); -int fileIsDir(File*); -int fileIsRoFs(File*); -int fileIsRoot(File*); -int fileMapBlock(File*, ulong, uchar[VtScoreSize], ulong); -int fileMetaFlush(File*, int); -char *fileName(File *f); -File *fileOpen(Fs*, char*); -int fileRead(File*, void *, int, vlong); -int fileRemove(File*, char*); -int fileSetDir(File*, DirEntry*, char*); -int fileSetQidSpace(File*, u64int, u64int); -int fileSetSize(File*, uvlong); -int fileSync(File*); -int fileTruncate(File*, char*); -File *fileWalk(File*, char*); -File *_fileWalk(File*, char*, int); -int fileWalkSources(File*); -int fileWrite(File*, void *, int, vlong, char*); diff --git a/sys/src/cmd/fossil/history b/sys/src/cmd/fossil/history deleted file mode 100644 index 3f8cc0e88..000000000 --- a/sys/src/cmd/fossil/history +++ /dev/null @@ -1,49 +0,0 @@ -changes since initial alpha release - -5 jan 2003 - add -v flag to flfmt as documented - add "con /srv/fscons" to fossilcons(8) synopsis - add -AWP to the initialization example in fossil(4). - change users to print "no file" if the user table is - not backed by a file. - change snapClose not to die when s==nil - correct handling of file truncation to specific size - disable the close command for now - -7 jan 2003 - make fossil chatter a bit less to stderr. errors - still go to stderr. - -11 jan 2003 - add console prints on auth failure, for debugging - mark vtConnect message as warning - fix create command in user command - add background process to sync disk periodically - allow multiple snapshots per minute - fix bugs in soft updates - add double-check of ndirty to flushFill. i've seen metadata - not get updated when you change it right before a reboot, - and i don't understand why. - -10 feb 2003 - better error messages for fossil console functions - -18 feb 2003 - correct handling of flush messages - add msgWrite procs to handle output queues - comment out an overeager assert in source.c. - move setting of fid->qid.path higher in rTcreate for exclAlloc. - -20 feb 2003 - flfmt -v was trying to create /active; bug fixed. - -16 apr 2003 - df command, who command, halt, unhalt - -15 jun 2003 - make df easier to understand - read config out of fossil disk (-f option) - fossil/conf - automatic deletion of snapshots - - diff --git a/sys/src/cmd/fossil/invariants b/sys/src/cmd/fossil/invariants deleted file mode 100644 index b674b3cfc..000000000 --- a/sys/src/cmd/fossil/invariants +++ /dev/null @@ -1,121 +0,0 @@ -.EQ -delim $# -.EN -.NH 3 -Invariants -.LP -Reclamation is tricky enough to warrant explicit statement -of the invariants that are needed and the reasons they are true. -This section will use the notation -$b.e# -and -$b.e sub 1# -to denote the allocation and -closing epochs of block -$b#. -The invariants are: -.IP (i) -If $b# points at $bb#, then $bb.e <= b.e < bb.e sub 1#. -.IP (ii) -If $b# points at $bb#, then no other block $b'# with $b'.e = b.e# points at $bb#. -.IP (iii) -If $b# is not marked -.CW BsCopied -and points at $bb# such that $b.e = bb.e#, then no other block $b'# points at $bb#. -.IP (iv) -If $b# is in the active file system and points at $bb# then no other block $b'# in the -active file system points at $bb#. -.IP (v) -If $b'# is a (possibly indirect) copy of $b#, then only one of $b# and $b'# is in the active file system. -.LP -Invariant (i) lets us reclaim blocks using the file system low epoch. -Invariant (iii) lets us reclaim some blocks immediately once they are unlinked. -Invariants (ii), (iv), and (v) are helpful in proving (i) and (iii); collectively they -say that taking snapshots doesn't break the active file system. -.PP -Freshly allocated blocks start filled with nil pointers, -and thus satisfy all the invariants. We need to check that -copying a block, zeroing a pointer, and setting a pointer -preserve the invariants. -.LP -$"BlockCopy" (b)# -allocates a new block -$b'# and copies the active and open block $b# into $b'#. -.IP (i) -Since $b# is open, all the blocks $bb# it points to are also -active, and thus they have $bb.e sub 1# set to positive infinity -(well, -.CW ~0 ). -Thus (i) is satisfied. -.IP (ii) -Since $b'.e# will be set to the current epoch, and $b.e# is less -than the current epoch (it's copy-on-write), $b.e < b'.e# so (ii) -is vacuously satisfied. -.IP (iii) -Since $b.e < b'.e#, all the pointers in $b# are to blocks with epochs less than $b'.e#. -Thus (iii) is vacuously satisfied for both $b'#. -Since $"blockCopy"# sets the -.CW BsCopied -flag, (iii) is vacuously satisfied for $b#. -.IP (iv),(v) -Since no pointers to $b# or $b'# were modified, -(iv) and (v) are unchanged. -.LP -$"BlockRemoveLink" (b -> bb)# removes from block $b# the pointer to $bb# -.IP -Zeroing a pointer only restricts the preconditions on the -invariants, so it's always okay. -By (iii), if $b# is not -.CW BsCopied -and $b.e = bb.e#, then no other $b'# anywhere -points at $bb#, so $bb# can be freed. -.LP -$"BlockSetLink" (b->bb sub 0 , bb sub 1)# changes the pointer in block $b# from $bb sub 0# to $bb sub 1#. -We derive sufficient conditions on $bb sub 1#, and then -examine the possible values of $bb sub 0# and $bb sub 1#. -.IP (i) -Since we're changing $b#, $b.e# is the current epoch. -If $bb sub 1# is open, then (i) is satisfied. -.IP (ii) -If either $b.e != bb sub 1 .e# or $bb sub 1# is an orphan, then (ii) is satisfied. -.IP (iii) -If either $b.e != bb sub 1 .e# or $b# is marked -.CW BsCopied -or $bb sub 1# is an orphan, then (iii) is satisfied. -.IP (iv) -If $bb sub 1# is not currently active or $bb sub 1# is an orphan, then (iv) is satisfied. -.IP (v) -If $bb sub 1# is a copy of $bb sub 0# or $bb sub 1# is empty, then (v) is satisfied. -.LP -$"BlockSetLink" (b -> bb sub 0 , "blockAlloc" ())# allocates a new block and points $b# at it. -.IP -Since $bb sub 1# in this case is newly allocated, it is open, an orphan, and empty, and thus -the invariants are satisfied. -.LP -$"BlockSetLink" (b -> bb sub 0 , "blockCopy" (bb sub 0 ))# copies $bb sub 0# and points -$b# at the copy. -.IP -Since $bb sub 1# is newly allocated, it is open and an orphan. Thus (i)-(iv) are satisfied. -Since $bb sub 1# is a copy of $bb sub 0#, (v) is satisfied. -.LP -$"BlockSetLink" (b -> "nil" , "oldRoot" )# changes a nil pointer to point -at a snapshot root. -.IP (i) -Invariant (i) is broken, but the -.CW snap -field in the entry will be used to make sure -we don't access the snapshot after it has been reclaimed. -.IP (ii) -Since the epoch of $"oldRoot"# is less than the current epoch but $b.e# is equal -to the current epoch, (ii) is vacuously true. -.IP (iii) -XXX -.IP (iv) -XXX -.IP (v) -XXX -.PP -Ta da! -xxx -yyyy -zzz diff --git a/sys/src/cmd/fossil/last.c b/sys/src/cmd/fossil/last.c deleted file mode 100644 index 21d80811a..000000000 --- a/sys/src/cmd/fossil/last.c +++ /dev/null @@ -1,40 +0,0 @@ -#include <u.h> -#include <libc.h> - -void -usage(void) -{ - fprint(2, "usage: fossil/last disk\n"); - exits("usage"); -} - -void -main(int argc, char **argv) -{ - int fd, bs, addr; - char buf[20]; - - ARGBEGIN{ - default: - usage(); - }ARGEND - - if(argc != 1) - usage(); - - if((fd = open(argv[0], OREAD)) < 0) - sysfatal("open %s: %r", argv[0]); - - werrstr("end of file"); - if(seek(fd, 131072, 0) < 0 || readn(fd, buf, 20) != 20) - sysfatal("error reading %s: %r", argv[0]); - fmtinstall('H', encodefmt); - if(memcmp(buf, "\x37\x76\xAE\x89", 4) != 0) - sysfatal("bad magic %.4H != 3776AE89", buf); - bs = buf[7]|(buf[6]<<8); - addr = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11]; - if(seek(fd, (vlong)bs*addr+34, 0) < 0 || readn(fd, buf, 20) != 20) - sysfatal("error reading %s: %r", argv[0]); - print("vac:%.20lH\n", buf); - exits(0); -} diff --git a/sys/src/cmd/fossil/mkfile b/sys/src/cmd/fossil/mkfile deleted file mode 100644 index cf2b0bdc7..000000000 --- a/sys/src/cmd/fossil/mkfile +++ /dev/null @@ -1,136 +0,0 @@ -</$objtype/mkfile -BIN=/$objtype/bin/fossil - -TARG=fossil flchk flfmt conf last - -LIBFILES=\ - 9p\ - 9auth\ - 9dir\ - 9excl\ - 9fid\ - 9fsys\ - 9lstn\ - 9proc\ - 9srv\ - 9user\ - Ccmd\ - Ccli\ - Ccons\ - Clog\ - archive\ - nobwatch\ - cache\ - check\ - disk\ - error\ - file\ - fs\ - pack\ - periodic\ - source\ - vac\ - walk\ - -LIBCFILES=${LIBFILES:%=%.c} -LIBOFILES=${LIBFILES:%=%.$O} -LIB=libfs.a$O - -HFILES=\ - /sys/include/oventi.h\ - stdinc.h\ - vac.h\ - dat.h\ - fns.h\ - fs.h\ - error.h\ - 9.h\ - flfmt9660.h\ - -CFILES=${TARG:%=%.c} $LIBCFILES flfmt9660.c - -UPDATE=\ - mkfile\ - $CFILES\ - $HFILES\ - -default:V: all - -test:V: all - rm -f /srv/test.fossil /srv/test.fscons - slay 8.flfmt | rc - slay 8.fossil | rc - unmount /n/fossil || status='' - {syscall seek 1 6400000000 0; echo} >>/tmp/fossil - 8.flfmt -y /tmp/fossil - 8.conf -w /tmp/fossil flproto - 8.fossil -f /tmp/fossil - cat /srv/test.fscons & - echo fsys main >>/srv/test.fscons - mount /srv/test.fossil /n/fossil - cd /n/fossil/tmp - dd -bs 1048576 -count 256 -if /dev/zero -of a - rm a - echo sync >>/srv/test.fscons - echo sync >>/srv/test.fscons - echo sync >>/srv/test.fscons - sleep 1 - echo sync >>/srv/test.fscons - sleep 1 - echo sync >>/srv/test.fscons - sleep 1 - echo sync >>/srv/test.fscons - echo check >>/srv/test.fscons - echo check >>/srv/test.fscons - echo check >>/srv/test.fscons - -# cp /env/timezone /n/fossil/tmp -# cp /lib/words /n/fossil/tmp -# dircp /n/sources/plan9/sys/src/cmd/aux /n/fossil/tmp -# >/n/fossil/tmp/lis -# chmod +t /n/fossil/tmp/lis -# echo SHOULD NOT SEE THIS >>/n/fossil/tmp/lis -# echo snap >>/srv/test.fscons -# sleep 2 -# mount /srv/test.fossil /n/dump main/archive -# cat /n/dump/*/*/tmp/lis -# @{cd /n/fossil/tmp && time tar xTf /sys/src/cmd/fossil/test.tar} -# unmount /n/fossil -# rm /srv/fossil - -</sys/src/cmd/mkmany - -$LIB(%.$O):N: %.$O -$LIB: ${LIBOFILES:%=$LIB(%)} - names = `{echo $newprereq |sed 's/ /\n/g' |sed -n 's/'$LIB'\(([^)]+)\)/\1/gp'} - ar vu $LIB $names -# rm $names - -$O.flfmt: flfmt9660.$O - -flfmt%.$O: flfmt9660.h - -%.page:V: %.ps - page -w $stem.ps - -%.ps:D: %.ms - tbl $stem.ms | pic | eqn | troff -ms | lp -dstdout >$target - -bundle:V: - rfork n - ramfs -m /n/kremvax >[2]/dev/null - bind -a /n/kremvax . - cp /sys/doc/fossil.ms /sys/doc/fossil.ps /n/kremvax - cp /sys/man/4/fossil /n/kremvax/fossil.4.man - cp /sys/man/8/fossilcons /n/kremvax/fossilcons.8.man - x=`{ls |grep -v 'TODO|test.tar|fossil.tar.gz'} - tar c $x | gzip > fossil.tar.gz - -$O.conf:D: conf.rc - { - echo '#!/bin/rc' - echo '# THIS FILE IS AUTOMATICALLY GENERATED' - echo '# FROM /sys/src/cmd/fossil/conf.rc. DO NOT EDIT.' - echo - sed 1d conf.rc - } >$target && chmod +x $target diff --git a/sys/src/cmd/fossil/nobwatch.c b/sys/src/cmd/fossil/nobwatch.c deleted file mode 100644 index 698e86f41..000000000 --- a/sys/src/cmd/fossil/nobwatch.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -void -bwatchReset(uchar score[VtScoreSize]) -{ - USED(score); -} - -void -bwatchInit(void) -{ -} - -void -bwatchSetBlockSize(uint) -{ -} - -void -bwatchDependency(Block *b) -{ - USED(b); -} - -void -bwatchLock(Block *b) -{ - USED(b); -} - -void -bwatchUnlock(Block *b) -{ - USED(b); -} - diff --git a/sys/src/cmd/fossil/pack.c b/sys/src/cmd/fossil/pack.c deleted file mode 100644 index 9fd2070c0..000000000 --- a/sys/src/cmd/fossil/pack.c +++ /dev/null @@ -1,225 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -/* - * integer conversion routines - */ -#define U8GET(p) ((p)[0]) -#define U16GET(p) (((p)[0]<<8)|(p)[1]) -#define U32GET(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3]) -#define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2)) -#define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4)) - -#define U8PUT(p,v) (p)[0]=(v) -#define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v) -#define U32PUT(p,v) (p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v) -#define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32) -#define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32) - -void -headerPack(Header *h, uchar *p) -{ - memset(p, 0, HeaderSize); - U32PUT(p, HeaderMagic); - U16PUT(p+4, HeaderVersion); - U16PUT(p+6, h->blockSize); - U32PUT(p+8, h->super); - U32PUT(p+12, h->label); - U32PUT(p+16, h->data); - U32PUT(p+20, h->end); -} - -int -headerUnpack(Header *h, uchar *p) -{ - if(U32GET(p) != HeaderMagic){ - vtSetError("vac header bad magic"); - return 0; - } - h->version = U16GET(p+4); - if(h->version != HeaderVersion){ - vtSetError("vac header bad version"); - return 0; - } - h->blockSize = U16GET(p+6); - h->super = U32GET(p+8); - h->label = U32GET(p+12); - h->data = U32GET(p+16); - h->end = U32GET(p+20); - return 1; -} - -void -labelPack(Label *l, uchar *p, int i) -{ - p += i*LabelSize; - U8PUT(p, l->state); - U8PUT(p+1, l->type); - U32PUT(p+2, l->epoch); - U32PUT(p+6, l->epochClose); - U32PUT(p+10, l->tag); -} - -int -labelUnpack(Label *l, uchar *p, int i) -{ - p += i*LabelSize; - l->state = p[0]; - l->type = p[1]; - l->epoch = U32GET(p+2); - l->epochClose = U32GET(p+6); - l->tag = U32GET(p+10); - - if(l->type > BtMax){ -Bad: - vtSetError(EBadLabel); - fprint(2, "%s: labelUnpack: bad label: 0x%.2ux 0x%.2ux 0x%.8ux " - "0x%.8ux 0x%.8ux\n", argv0, l->state, l->type, l->epoch, - l->epochClose, l->tag); - return 0; - } - if(l->state != BsBad && l->state != BsFree){ - if(!(l->state&BsAlloc) || l->state & ~BsMask) - goto Bad; - if(l->state&BsClosed){ - if(l->epochClose == ~(u32int)0) - goto Bad; - }else{ - if(l->epochClose != ~(u32int)0) - goto Bad; - } - } - return 1; -} - -u32int -globalToLocal(uchar score[VtScoreSize]) -{ - int i; - - for(i=0; i<VtScoreSize-4; i++) - if(score[i] != 0) - return NilBlock; - - return U32GET(score+VtScoreSize-4); -} - -void -localToGlobal(u32int addr, uchar score[VtScoreSize]) -{ - memset(score, 0, VtScoreSize-4); - U32PUT(score+VtScoreSize-4, addr); -} - -void -entryPack(Entry *e, uchar *p, int index) -{ - ulong t32; - int flags; - - p += index * VtEntrySize; - - U32PUT(p, e->gen); - U16PUT(p+4, e->psize); - U16PUT(p+6, e->dsize); - flags = e->flags | ((e->depth << VtEntryDepthShift) & VtEntryDepthMask); - U8PUT(p+8, flags); - memset(p+9, 0, 5); - U48PUT(p+14, e->size, t32); - - if(flags & VtEntryLocal){ - if(globalToLocal(e->score) == NilBlock) - abort(); - memset(p+20, 0, 7); - U8PUT(p+27, e->archive); - U32PUT(p+28, e->snap); - U32PUT(p+32, e->tag); - memmove(p+36, e->score+16, 4); - }else - memmove(p+20, e->score, VtScoreSize); -} - -int -entryUnpack(Entry *e, uchar *p, int index) -{ - p += index * VtEntrySize; - - e->gen = U32GET(p); - e->psize = U16GET(p+4); - e->dsize = U16GET(p+6); - e->flags = U8GET(p+8); - e->depth = (e->flags & VtEntryDepthMask) >> VtEntryDepthShift; - e->flags &= ~VtEntryDepthMask; - e->size = U48GET(p+14); - - if(e->flags & VtEntryLocal){ - e->archive = p[27]; - e->snap = U32GET(p+28); - e->tag = U32GET(p+32); - memset(e->score, 0, 16); - memmove(e->score+16, p+36, 4); - }else{ - e->archive = 0; - e->snap = 0; - e->tag = 0; - memmove(e->score, p+20, VtScoreSize); - } - - return 1; -} - -int -entryType(Entry *e) -{ - return (((e->flags & VtEntryDir) != 0) << 3) | e->depth; -} - - -void -superPack(Super *s, uchar *p) -{ - u32int t32; - - memset(p, 0, SuperSize); - U32PUT(p, SuperMagic); - assert(s->version == SuperVersion); - U16PUT(p+4, s->version); - U32PUT(p+6, s->epochLow); - U32PUT(p+10, s->epochHigh); - U64PUT(p+14, s->qid, t32); - U32PUT(p+22, s->active); - U32PUT(p+26, s->next); - U32PUT(p+30, s->current); - memmove(p+34, s->last, VtScoreSize); - memmove(p+54, s->name, sizeof(s->name)); -} - -int -superUnpack(Super *s, uchar *p) -{ - memset(s, 0, sizeof(*s)); - if(U32GET(p) != SuperMagic) - goto Err; - s->version = U16GET(p+4); - if(s->version != SuperVersion) - goto Err; - s->epochLow = U32GET(p+6); - s->epochHigh = U32GET(p+10); - s->qid = U64GET(p+14); - if(s->epochLow == 0 || s->epochLow > s->epochHigh || s->qid == 0) - goto Err; - s->active = U32GET(p+22); - s->next = U32GET(p+26); - s->current = U32GET(p+30); - memmove(s->last, p+34, VtScoreSize); - memmove(s->name, p+54, sizeof(s->name)); - s->name[sizeof(s->name)-1] = 0; - return 1; -Err: - memset(s, 0, sizeof(*s)); - vtSetError(EBadSuper); - return 0; -} - diff --git a/sys/src/cmd/fossil/periodic.c b/sys/src/cmd/fossil/periodic.c deleted file mode 100644 index 8a0c20843..000000000 --- a/sys/src/cmd/fossil/periodic.c +++ /dev/null @@ -1,84 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" - -struct Periodic { - VtLock *lk; - int die; /* flag: quit if set */ - void (*f)(void*); /* call this each period */ - void *a; /* argument to f */ - int msec; /* period */ -}; - -static void periodicThread(void *a); - -Periodic * -periodicAlloc(void (*f)(void*), void *a, int msec) -{ - Periodic *p; - - p = vtMemAllocZ(sizeof(Periodic)); - p->lk = vtLockAlloc(); - p->f = f; - p->a = a; - p->msec = msec; - if(p->msec < 10) - p->msec = 10; - - vtThread(periodicThread, p); - return p; -} - -void -periodicKill(Periodic *p) -{ - if(p == nil) - return; - vtLock(p->lk); - p->die = 1; - vtUnlock(p->lk); -} - -static void -periodicFree(Periodic *p) -{ - vtLockFree(p->lk); - vtMemFree(p); -} - -static void -periodicThread(void *a) -{ - Periodic *p = a; - vlong t, ct, ts; /* times in ms. */ - - vtThreadSetName("periodic"); - - ct = nsec() / 1000000; - t = ct + p->msec; /* call p->f at or after this time */ - - for(;;){ - ts = t - ct; /* ms. to next cycle's start */ - if(ts > 1000) - ts = 1000; /* bound sleep duration */ - if(ts > 0) - sleep(ts); /* wait for cycle's start */ - - vtLock(p->lk); - if(p->die){ - vtUnlock(p->lk); - break; - } - ct = nsec() / 1000000; - if(t <= ct){ /* due to call p->f? */ - p->f(p->a); - ct = nsec() / 1000000; - while(t <= ct) /* advance t to future cycle start */ - t += p->msec; - } - vtUnlock(p->lk); - } - periodicFree(p); -} - diff --git a/sys/src/cmd/fossil/source.c b/sys/src/cmd/fossil/source.c deleted file mode 100644 index 5f50e1921..000000000 --- a/sys/src/cmd/fossil/source.c +++ /dev/null @@ -1,1069 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include "error.h" -#include "9.h" - -static int sizeToDepth(uvlong s, int psize, int dsize); -static u32int tagGen(void); -static Block *sourceLoad(Source *r, Entry *e); -static Block *sourceLoadUnlocked(Source *r, Entry *e); -static int sourceShrinkDepth(Source*, Block*, Entry*, int); -static int sourceShrinkSize(Source*, Entry*, uvlong); -static int sourceGrowDepth(Source*, Block*, Entry*, int); - -#define sourceIsLocked(r) ((r)->b != nil) - -static Source * -sourceAlloc(Fs *fs, Block *b, Source *p, u32int offset, int mode, int issnapshot) -{ - int epb; - u32int epoch; - char *pname = nil; - Source *r; - Entry e; - - assert(p==nil || sourceIsLocked(p)); - - if(p == nil){ - assert(offset == 0); - epb = 1; - }else - epb = p->dsize / VtEntrySize; - - if(b->l.type != BtDir) - goto Bad; - - /* - * a non-active entry is the only thing that - * can legitimately happen here. all the others - * get prints. - */ - if(!entryUnpack(&e, b->data, offset % epb)){ - pname = sourceName(p); - consPrint("%s: %s %V: sourceAlloc: entryUnpack failed\n", - fs->name, pname, b->score); - goto Bad; - } - if(!(e.flags & VtEntryActive)){ - pname = sourceName(p); - if(0) consPrint("%s: %s %V: sourceAlloc: not active\n", - fs->name, pname, e.score); - goto Bad; - } - if(e.psize < 256 || e.dsize < 256){ - pname = sourceName(p); - consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud < 256\n", - fs->name, pname, e.score, e.psize, e.dsize); - goto Bad; - } - - if(e.depth < sizeToDepth(e.size, e.psize, e.dsize)){ - pname = sourceName(p); - consPrint("%s: %s %V: sourceAlloc: depth %ud size %llud " - "psize %ud dsize %ud\n", fs->name, pname, - e.score, e.depth, e.size, e.psize, e.dsize); - goto Bad; - } - - if((e.flags & VtEntryLocal) && e.tag == 0){ - pname = sourceName(p); - consPrint("%s: %s %V: sourceAlloc: flags %#ux tag %#ux\n", - fs->name, pname, e.score, e.flags, e.tag); - goto Bad; - } - - if(e.dsize > fs->blockSize || e.psize > fs->blockSize){ - pname = sourceName(p); - consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud " - "> blocksize %ud\n", fs->name, pname, e.score, - e.psize, e.dsize, fs->blockSize); - goto Bad; - } - - epoch = b->l.epoch; - if(mode == OReadWrite){ - if(e.snap != 0){ - vtSetError(ESnapRO); - return nil; - } - }else if(e.snap != 0){ - if(e.snap < fs->elo){ - vtSetError(ESnapOld); - return nil; - } - if(e.snap >= fs->ehi) - goto Bad; - epoch = e.snap; - } - - r = vtMemAllocZ(sizeof(Source)); - r->fs = fs; - r->mode = mode; - r->issnapshot = issnapshot; - r->dsize = e.dsize; - r->gen = e.gen; - r->dir = (e.flags & VtEntryDir) != 0; - r->lk = vtLockAlloc(); - r->ref = 1; - r->parent = p; - if(p){ - vtLock(p->lk); - assert(mode == OReadOnly || p->mode == OReadWrite); - p->ref++; - vtUnlock(p->lk); - } - r->epoch = epoch; -// consPrint("sourceAlloc: have %V be.%d fse.%d %s\n", b->score, -// b->l.epoch, r->fs->ehi, mode == OReadWrite? "rw": "ro"); - memmove(r->score, b->score, VtScoreSize); - r->scoreEpoch = b->l.epoch; - r->offset = offset; - r->epb = epb; - r->tag = b->l.tag; - -// consPrint("%s: sourceAlloc: %p -> %V %d\n", r, r->score, r->offset); - - return r; -Bad: - free(pname); - vtSetError(EBadEntry); - return nil; -} - -Source * -sourceRoot(Fs *fs, u32int addr, int mode) -{ - Source *r; - Block *b; - - b = cacheLocalData(fs->cache, addr, BtDir, RootTag, mode, 0); - if(b == nil) - return nil; - - if(mode == OReadWrite && b->l.epoch != fs->ehi){ - consPrint("sourceRoot: fs->ehi = %ud, b->l = %L\n", - fs->ehi, &b->l); - blockPut(b); - vtSetError(EBadRoot); - return nil; - } - - r = sourceAlloc(fs, b, nil, 0, mode, 0); - blockPut(b); - return r; -} - -Source * -sourceOpen(Source *r, ulong offset, int mode, int issnapshot) -{ - ulong bn; - Block *b; - - assert(sourceIsLocked(r)); - if(r->mode == OReadWrite) - assert(r->epoch == r->b->l.epoch); - if(!r->dir){ - vtSetError(ENotDir); - return nil; - } - - bn = offset/(r->dsize/VtEntrySize); - - b = sourceBlock(r, bn, mode); - if(b == nil) - return nil; - r = sourceAlloc(r->fs, b, r, offset, mode, issnapshot); - blockPut(b); - return r; -} - -Source * -sourceCreate(Source *r, int dsize, int dir, u32int offset) -{ - int i, epb, psize; - u32int bn, size; - Block *b; - Entry e; - Source *rr; - - assert(sourceIsLocked(r)); - - if(!r->dir){ - vtSetError(ENotDir); - return nil; - } - - epb = r->dsize/VtEntrySize; - psize = (dsize/VtScoreSize)*VtScoreSize; - - size = sourceGetDirSize(r); - if(offset == 0){ - /* - * look at a random block to see if we can find an empty entry - */ - offset = lnrand(size+1); - offset -= offset % epb; - } - - /* try the given block and then try the last block */ - for(;;){ - bn = offset/epb; - b = sourceBlock(r, bn, OReadWrite); - if(b == nil) - return nil; - for(i=offset%r->epb; i<epb; i++){ - entryUnpack(&e, b->data, i); - if((e.flags&VtEntryActive) == 0 && e.gen != ~0) - goto Found; - } - blockPut(b); - if(offset == size){ - fprint(2, "sourceCreate: cannot happen\n"); - vtSetError("sourceCreate: cannot happen"); - return nil; - } - offset = size; - } - -Found: - /* found an entry - gen already set */ - e.psize = psize; - e.dsize = dsize; - assert(psize && dsize); - e.flags = VtEntryActive; - if(dir) - e.flags |= VtEntryDir; - e.depth = 0; - e.size = 0; - memmove(e.score, vtZeroScore, VtScoreSize); - e.tag = 0; - e.snap = 0; - e.archive = 0; - entryPack(&e, b->data, i); - blockDirty(b); - - offset = bn*epb + i; - if(offset+1 > size){ - if(!sourceSetDirSize(r, offset+1)){ - blockPut(b); - return nil; - } - } - - rr = sourceAlloc(r->fs, b, r, offset, OReadWrite, 0); - blockPut(b); - return rr; -} - -static int -sourceKill(Source *r, int doremove) -{ - Entry e; - Block *b; - u32int addr; - u32int tag; - int type; - - assert(sourceIsLocked(r)); - b = sourceLoad(r, &e); - if(b == nil) - return 0; - - assert(b->l.epoch == r->fs->ehi); - - if(doremove==0 && e.size == 0){ - /* already truncated */ - blockPut(b); - return 1; - } - - /* remember info on link we are removing */ - addr = globalToLocal(e.score); - type = entryType(&e); - tag = e.tag; - - if(doremove){ - if(e.gen != ~0) - e.gen++; - e.dsize = 0; - e.psize = 0; - e.flags = 0; - }else{ - e.flags &= ~VtEntryLocal; - } - e.depth = 0; - e.size = 0; - e.tag = 0; - memmove(e.score, vtZeroScore, VtScoreSize); - entryPack(&e, b->data, r->offset % r->epb); - blockDirty(b); - if(addr != NilBlock) - blockRemoveLink(b, addr, type, tag, 1); - blockPut(b); - - if(doremove){ - sourceUnlock(r); - sourceClose(r); - } - - return 1; -} - -int -sourceRemove(Source *r) -{ - return sourceKill(r, 1); -} - -int -sourceTruncate(Source *r) -{ - return sourceKill(r, 0); -} - -uvlong -sourceGetSize(Source *r) -{ - Entry e; - Block *b; - - assert(sourceIsLocked(r)); - b = sourceLoad(r, &e); - if(b == nil) - return 0; - blockPut(b); - - return e.size; -} - -static int -sourceShrinkSize(Source *r, Entry *e, uvlong size) -{ - int i, type, ppb; - uvlong ptrsz; - u32int addr; - uchar score[VtScoreSize]; - Block *b; - - type = entryType(e); - b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite); - if(b == nil) - return 0; - - ptrsz = e->dsize; - ppb = e->psize/VtScoreSize; - for(i=0; i+1<e->depth; i++) - ptrsz *= ppb; - - while(type&BtLevelMask){ - if(b->addr == NilBlock || b->l.epoch != r->fs->ehi){ - /* not worth copying the block just so we can zero some of it */ - blockPut(b); - return 0; - } - - /* - * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes - */ - - /* zero the pointers to unnecessary blocks */ - i = (size+ptrsz-1)/ptrsz; - for(; i<ppb; i++){ - addr = globalToLocal(b->data+i*VtScoreSize); - memmove(b->data+i*VtScoreSize, vtZeroScore, VtScoreSize); - blockDirty(b); - if(addr != NilBlock) - blockRemoveLink(b, addr, type-1, e->tag, 1); - } - - /* recurse (go around again) on the partially necessary block */ - i = size/ptrsz; - size = size%ptrsz; - if(size == 0){ - blockPut(b); - return 1; - } - ptrsz /= ppb; - type--; - memmove(score, b->data+i*VtScoreSize, VtScoreSize); - blockPut(b); - b = cacheGlobal(r->fs->cache, score, type, e->tag, OReadWrite); - if(b == nil) - return 0; - } - - if(b->addr == NilBlock || b->l.epoch != r->fs->ehi){ - blockPut(b); - return 0; - } - - /* - * No one ever truncates BtDir blocks. - */ - if(type == BtData && e->dsize > size){ - memset(b->data+size, 0, e->dsize-size); - blockDirty(b); - } - blockPut(b); - return 1; -} - -int -sourceSetSize(Source *r, uvlong size) -{ - int depth; - Entry e; - Block *b; - - assert(sourceIsLocked(r)); - if(size == 0) - return sourceTruncate(r); - - if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){ - vtSetError(ETooBig); - return 0; - } - - b = sourceLoad(r, &e); - if(b == nil) - return 0; - - /* quick out */ - if(e.size == size){ - blockPut(b); - return 1; - } - - depth = sizeToDepth(size, e.psize, e.dsize); - - if(depth < e.depth){ - if(!sourceShrinkDepth(r, b, &e, depth)){ - blockPut(b); - return 0; - } - }else if(depth > e.depth){ - if(!sourceGrowDepth(r, b, &e, depth)){ - blockPut(b); - return 0; - } - } - - if(size < e.size) - sourceShrinkSize(r, &e, size); - - e.size = size; - entryPack(&e, b->data, r->offset % r->epb); - blockDirty(b); - blockPut(b); - - return 1; -} - -int -sourceSetDirSize(Source *r, ulong ds) -{ - uvlong size; - int epb; - - assert(sourceIsLocked(r)); - epb = r->dsize/VtEntrySize; - - size = (uvlong)r->dsize*(ds/epb); - size += VtEntrySize*(ds%epb); - return sourceSetSize(r, size); -} - -ulong -sourceGetDirSize(Source *r) -{ - ulong ds; - uvlong size; - int epb; - - assert(sourceIsLocked(r)); - epb = r->dsize/VtEntrySize; - - size = sourceGetSize(r); - ds = epb*(size/r->dsize); - ds += (size%r->dsize)/VtEntrySize; - return ds; -} - -int -sourceGetEntry(Source *r, Entry *e) -{ - Block *b; - - assert(sourceIsLocked(r)); - b = sourceLoad(r, e); - if(b == nil) - return 0; - blockPut(b); - - return 1; -} - -/* - * Must be careful with this. Doesn't record - * dependencies, so don't introduce any! - */ -int -sourceSetEntry(Source *r, Entry *e) -{ - Block *b; - Entry oe; - - assert(sourceIsLocked(r)); - b = sourceLoad(r, &oe); - if(b == nil) - return 0; - entryPack(e, b->data, r->offset%r->epb); - blockDirty(b); - blockPut(b); - - return 1; -} - -static Block * -blockWalk(Block *p, int index, int mode, Fs *fs, Entry *e) -{ - Block *b; - Cache *c; - u32int addr; - int type; - uchar oscore[VtScoreSize], score[VtScoreSize]; - Entry oe; - - c = fs->cache; - - if((p->l.type & BtLevelMask) == 0){ - assert(p->l.type == BtDir); - type = entryType(e); - b = cacheGlobal(c, e->score, type, e->tag, mode); - }else{ - type = p->l.type - 1; - b = cacheGlobal(c, p->data + index*VtScoreSize, type, e->tag, mode); - } - - if(b) - b->pc = getcallerpc(&p); - - if(b == nil || mode == OReadOnly) - return b; - - if(p->l.epoch != fs->ehi){ - fprint(2, "blockWalk: parent not writable\n"); - abort(); - } - if(b->l.epoch == fs->ehi) - return b; - - oe = *e; - - /* - * Copy on write. - */ - if(e->tag == 0){ - assert(p->l.type == BtDir); - e->tag = tagGen(); - e->flags |= VtEntryLocal; - } - - addr = b->addr; - b = blockCopy(b, e->tag, fs->ehi, fs->elo); - if(b == nil) - return nil; - - b->pc = getcallerpc(&p); - assert(b->l.epoch == fs->ehi); - - blockDirty(b); - memmove(score, b->score, VtScoreSize); - if(p->l.type == BtDir){ - memmove(e->score, b->score, VtScoreSize); - entryPack(e, p->data, index); - blockDependency(p, b, index, nil, &oe); - }else{ - memmove(oscore, p->data+index*VtScoreSize, VtScoreSize); - memmove(p->data+index*VtScoreSize, b->score, VtScoreSize); - blockDependency(p, b, index, oscore, nil); - } - blockDirty(p); - - if(addr != NilBlock) - blockRemoveLink(p, addr, type, e->tag, 0); - - return b; -} - -/* - * Change the depth of the source r. - * The entry e for r is contained in block p. - */ -static int -sourceGrowDepth(Source *r, Block *p, Entry *e, int depth) -{ - Block *b, *bb; - u32int tag; - int type; - Entry oe; - - assert(sourceIsLocked(r)); - assert(depth <= VtPointerDepth); - - type = entryType(e); - b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite); - if(b == nil) - return 0; - - tag = e->tag; - if(tag == 0) - tag = tagGen(); - - oe = *e; - - /* - * Keep adding layers until we get to the right depth - * or an error occurs. - */ - while(e->depth < depth){ - bb = cacheAllocBlock(r->fs->cache, type+1, tag, r->fs->ehi, r->fs->elo); - if(bb == nil) - break; -//fprint(2, "alloc %lux grow %V\n", bb->addr, b->score); - memmove(bb->data, b->score, VtScoreSize); - memmove(e->score, bb->score, VtScoreSize); - e->depth++; - type++; - e->tag = tag; - e->flags |= VtEntryLocal; - blockDependency(bb, b, 0, vtZeroScore, nil); - blockPut(b); - b = bb; - blockDirty(b); - } - - entryPack(e, p->data, r->offset % r->epb); - blockDependency(p, b, r->offset % r->epb, nil, &oe); - blockPut(b); - blockDirty(p); - - return e->depth == depth; -} - -static int -sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth) -{ - Block *b, *nb, *ob, *rb; - u32int tag; - int type, d; - Entry oe; - - assert(sourceIsLocked(r)); - assert(depth <= VtPointerDepth); - - type = entryType(e); - rb = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite); - if(rb == nil) - return 0; - - tag = e->tag; - if(tag == 0) - tag = tagGen(); - - /* - * Walk down to the new root block. - * We may stop early, but something is better than nothing. - */ - oe = *e; - - ob = nil; - b = rb; -/* BUG: explain type++. i think it is a real bug */ - for(d=e->depth; d > depth; d--, type++){ - nb = cacheGlobal(r->fs->cache, b->data, type-1, tag, OReadWrite); - if(nb == nil) - break; - if(ob!=nil && ob!=rb) - blockPut(ob); - ob = b; - b = nb; - } - - if(b == rb){ - blockPut(rb); - return 0; - } - - /* - * Right now, e points at the root block rb, b is the new root block, - * and ob points at b. To update: - * - * (i) change e to point at b - * (ii) zero the pointer ob -> b - * (iii) free the root block - * - * p (the block containing e) must be written before - * anything else. - */ - - /* (i) */ - e->depth = d; - /* might have been local and now global; reverse cannot happen */ - if(globalToLocal(b->score) == NilBlock) - e->flags &= ~VtEntryLocal; - memmove(e->score, b->score, VtScoreSize); - entryPack(e, p->data, r->offset % r->epb); - blockDependency(p, b, r->offset % r->epb, nil, &oe); - blockDirty(p); - - /* (ii) */ - memmove(ob->data, vtZeroScore, VtScoreSize); - blockDependency(ob, p, 0, b->score, nil); - blockDirty(ob); - - /* (iii) */ - if(rb->addr != NilBlock) - blockRemoveLink(p, rb->addr, rb->l.type, rb->l.tag, 1); - - blockPut(rb); - if(ob!=nil && ob!=rb) - blockPut(ob); - blockPut(b); - - return d == depth; -} - -/* - * Normally we return the block at the given number. - * If early is set, we stop earlier in the tree. Setting early - * to 1 gives us the block that contains the pointer to bn. - */ -Block * -_sourceBlock(Source *r, ulong bn, int mode, int early, ulong tag) -{ - Block *b, *bb; - int index[VtPointerDepth+1]; - Entry e; - int i, np; - int m; - - assert(sourceIsLocked(r)); - assert(bn != NilBlock); - - /* mode for intermediate block */ - m = mode; - if(m == OOverWrite) - m = OReadWrite; - - b = sourceLoad(r, &e); - if(b == nil) - return nil; - if(r->issnapshot && (e.flags & VtEntryNoArchive)){ - blockPut(b); - vtSetError(ENotArchived); - return nil; - } - - if(tag){ - if(e.tag == 0) - e.tag = tag; - else if(e.tag != tag){ - fprint(2, "tag mismatch\n"); - vtSetError("tag mismatch"); - goto Err; - } - } - - np = e.psize/VtScoreSize; - memset(index, 0, sizeof(index)); - for(i=0; bn > 0; i++){ - if(i >= VtPointerDepth){ - vtSetError(EBadAddr); - goto Err; - } - index[i] = bn % np; - bn /= np; - } - - if(i > e.depth){ - if(mode == OReadOnly){ - vtSetError(EBadAddr); - goto Err; - } - if(!sourceGrowDepth(r, b, &e, i)) - goto Err; - } - - index[e.depth] = r->offset % r->epb; - - for(i=e.depth; i>=early; i--){ - bb = blockWalk(b, index[i], m, r->fs, &e); - if(bb == nil) - goto Err; - blockPut(b); - b = bb; - } - b->pc = getcallerpc(&r); - return b; -Err: - blockPut(b); - return nil; -} - -Block* -sourceBlock(Source *r, ulong bn, int mode) -{ - Block *b; - - b = _sourceBlock(r, bn, mode, 0, 0); - if(b) - b->pc = getcallerpc(&r); - return b; -} - -void -sourceClose(Source *r) -{ - if(r == nil) - return; - vtLock(r->lk); - r->ref--; - if(r->ref){ - vtUnlock(r->lk); - return; - } - assert(r->ref == 0); - vtUnlock(r->lk); - if(r->parent) - sourceClose(r->parent); - vtLockFree(r->lk); - memset(r, ~0, sizeof(*r)); - vtMemFree(r); -} - -/* - * Retrieve the block containing the entry for r. - * If a snapshot has happened, we might need - * to get a new copy of the block. We avoid this - * in the common case by caching the score for - * the block and the last epoch in which it was valid. - * - * We use r->mode to tell the difference between active - * file system sources (OReadWrite) and sources for the - * snapshot file system (OReadOnly). - */ -static Block* -sourceLoadBlock(Source *r, int mode) -{ - u32int addr; - Block *b; - - switch(r->mode){ - default: - assert(0); - case OReadWrite: - assert(r->mode == OReadWrite); - /* - * This needn't be true -- we might bump the low epoch - * to reclaim some old blocks, but since this score is - * OReadWrite, the blocks must all still be open, so none - * are reclaimed. Thus it's okay that the epoch is so low. - * Proceed. - assert(r->epoch >= r->fs->elo); - */ - if(r->epoch == r->fs->ehi){ - b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); - if(b == nil) - return nil; - assert(r->epoch == b->l.epoch); - return b; - } - assert(r->parent != nil); - if(!sourceLock(r->parent, OReadWrite)) - return nil; - b = sourceBlock(r->parent, r->offset/r->epb, OReadWrite); - sourceUnlock(r->parent); - if(b == nil) - return nil; - assert(b->l.epoch == r->fs->ehi); - // fprint(2, "sourceLoadBlock %p %V => %V\n", r, r->score, b->score); - memmove(r->score, b->score, VtScoreSize); - r->scoreEpoch = b->l.epoch; - r->tag = b->l.tag; - r->epoch = r->fs->ehi; - return b; - - case OReadOnly: - addr = globalToLocal(r->score); - if(addr == NilBlock) - return cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, mode); - - b = cacheLocalData(r->fs->cache, addr, BtDir, r->tag, mode, r->scoreEpoch); - if(b) - return b; - - /* - * If it failed because the epochs don't match, the block has been - * archived and reclaimed. Rewalk from the parent and get the - * new pointer. This can't happen in the OReadWrite case - * above because blocks in the current epoch don't get - * reclaimed. The fact that we're OReadOnly means we're - * a snapshot. (Or else the file system is read-only, but then - * the archiver isn't going around deleting blocks.) - */ - if(strcmp(vtGetError(), ELabelMismatch) == 0){ - if(!sourceLock(r->parent, OReadOnly)) - return nil; - b = sourceBlock(r->parent, r->offset/r->epb, OReadOnly); - sourceUnlock(r->parent); - if(b){ - fprint(2, "sourceAlloc: lost %V found %V\n", - r->score, b->score); - memmove(r->score, b->score, VtScoreSize); - r->scoreEpoch = b->l.epoch; - return b; - } - } - return nil; - } -} - -int -sourceLock(Source *r, int mode) -{ - Block *b; - - if(mode == -1) - mode = r->mode; - - b = sourceLoadBlock(r, mode); - if(b == nil) - return 0; - /* - * The fact that we are holding b serves as the - * lock entitling us to write to r->b. - */ - assert(r->b == nil); - r->b = b; - if(r->mode == OReadWrite) - assert(r->epoch == r->b->l.epoch); - return 1; -} - -/* - * Lock two (usually sibling) sources. This needs special care - * because the Entries for both sources might be in the same block. - * We also try to lock blocks in left-to-right order within the tree. - */ -int -sourceLock2(Source *r, Source *rr, int mode) -{ - Block *b, *bb; - - if(rr == nil) - return sourceLock(r, mode); - - if(mode == -1) - mode = r->mode; - - if(r->parent==rr->parent && r->offset/r->epb == rr->offset/rr->epb){ - b = sourceLoadBlock(r, mode); - if(b == nil) - return 0; - if(memcmp(r->score, rr->score, VtScoreSize) != 0){ - memmove(rr->score, b->score, VtScoreSize); - rr->scoreEpoch = b->l.epoch; - rr->tag = b->l.tag; - rr->epoch = rr->fs->ehi; - } - blockDupLock(b); - bb = b; - }else if(r->parent==rr->parent || r->offset > rr->offset){ - bb = sourceLoadBlock(rr, mode); - b = sourceLoadBlock(r, mode); - }else{ - b = sourceLoadBlock(r, mode); - bb = sourceLoadBlock(rr, mode); - } - if(b == nil || bb == nil){ - if(b) - blockPut(b); - if(bb) - blockPut(bb); - return 0; - } - - /* - * The fact that we are holding b and bb serves - * as the lock entitling us to write to r->b and rr->b. - */ - r->b = b; - rr->b = bb; - return 1; -} - -void -sourceUnlock(Source *r) -{ - Block *b; - - if(r->b == nil){ - fprint(2, "sourceUnlock: already unlocked\n"); - abort(); - } - b = r->b; - r->b = nil; - blockPut(b); -} - -static Block* -sourceLoad(Source *r, Entry *e) -{ - Block *b; - - assert(sourceIsLocked(r)); - b = r->b; - if(!entryUnpack(e, b->data, r->offset % r->epb)) - return nil; - if(e->gen != r->gen){ - vtSetError(ERemoved); - return nil; - } - blockDupLock(b); - return b; -} - -static int -sizeToDepth(uvlong s, int psize, int dsize) -{ - int np; - int d; - - /* determine pointer depth */ - np = psize/VtScoreSize; - s = (s + dsize - 1)/dsize; - for(d = 0; s > 1; d++) - s = (s + np - 1)/np; - return d; -} - -static u32int -tagGen(void) -{ - u32int tag; - - for(;;){ - tag = lrand(); - if(tag >= UserTag) - break; - } - return tag; -} - -char * -sourceName(Source *s) -{ - return fileName(s->file); -} diff --git a/sys/src/cmd/fossil/srcload.c b/sys/src/cmd/fossil/srcload.c deleted file mode 100644 index 8cf63b4f6..000000000 --- a/sys/src/cmd/fossil/srcload.c +++ /dev/null @@ -1,270 +0,0 @@ -#include "stdinc.h" -#include <bio.h> -#include "dat.h" -#include "fns.h" -#include "error.h" - -int num = 100; -int length = 20*1024; -int block= 1024; -int bush = 4; -int iter = 100; -Biobuf *bout; -int maxdepth; - -Source *mkroot(Cache*); -void new(Source*, int trace, int); -int delete(Source*); -int count(Source *s, int); -void stats(Source *s); -void dump(Source *s, int ident, ulong entry); -static void bench(Source *r); - -void -main(int argc, char *argv[]) -{ - int i; - Fs *fs; - int csize = 1000; - ulong t; - Source *r; - - ARGBEGIN{ - case 'i': - iter = atoi(ARGF()); - break; - case 'n': - num = atoi(ARGF()); - break; - case 'l': - length = atoi(ARGF()); - break; - case 'b': - block = atoi(ARGF()); - break; - case 'u': - bush = atoi(ARGF()); - break; - case 'c': - csize = atoi(ARGF()); - break; - }ARGEND; - - vtAttach(); - - bout = vtMemAllocZ(sizeof(Biobuf)); - Binit(bout, 1, OWRITE); - - fmtinstall('V', vtScoreFmt); - fmtinstall('R', vtErrFmt); - - fs = fsOpen(argv[0], nil, csize, OReadWrite); - if(fs == nil) - sysfatal("could not open fs: %r"); - - t = time(0); - - srand(0); - - r = fs->source; - dump(r, 0, 0); - - fprint(2, "count = %d\n", count(r, 1)); - for(i=0; i<num; i++) - new(r, 0, 0); - - for(i=0; i<iter; i++){ - if(i % 10000 == 0) - stats(r); - new(r, 0, 0); - delete(r); - } - -// dump(r, 0, 0); - - fprint(2, "count = %d\n", count(r, 1)); -// cacheCheck(c); - - fprint(2, "deleting\n"); - for(i=0; i<num; i++) - delete(r); -// dump(r, 0, 0); - - fprint(2, "count = %d\n", count(r, 1)); - fprint(2, "total time = %ld\n", time(0)-t); - - fsClose(fs); - vtDetach(); - exits(0); -} - -static void -bench(Source *r) -{ - vlong t; - Entry e; - int i; - - t = nsec(); - - for(i=0; i<1000000; i++) - sourceGetEntry(r, &e); - - fprint(2, "%f\n", 1e-9*(nsec() - t)); -} - -void -new(Source *s, int trace, int depth) -{ - int i, n; - Source *ss; - Entry e; - - if(depth > maxdepth) - maxdepth = depth; - - Bflush(bout); - - n = sourceGetDirSize(s); - for(i=0; i<n; i++){ - ss = sourceOpen(s, nrand(n), OReadWrite); - if(ss == nil || !sourceGetEntry(ss, &e)) - continue; - if((e.flags & VtEntryDir) && frand() < 1./bush){ - if(trace){ - int j; - for(j=0; j<trace; j++) - Bprint(bout, " "); - Bprint(bout, "decend %d\n", i); - } - new(ss, trace?trace+1:0, depth+1); - sourceClose(ss); - return; - } - sourceClose(ss); - } - ss = sourceCreate(s, s->dsize, 1+frand()>.5, 0); - if(ss == nil){ - Bprint(bout, "could not create directory: %R\n"); - return; - } - if(trace){ - int j; - for(j=1; j<trace; j++) - Bprint(bout, " "); - Bprint(bout, "create %d\n", ss->offset); - } - sourceClose(ss); -} - -int -delete(Source *s) -{ - int i, n; - Source *ss; - - n = sourceGetDirSize(s); - /* check if empty */ - for(i=0; i<n; i++){ - ss = sourceOpen(s, i, OReadWrite); - if(ss != nil){ - sourceClose(ss); - break; - } - } - if(i == n) - return 0; - - for(;;){ - ss = sourceOpen(s, nrand(n), OReadWrite); - if(ss == nil) - continue; - if(s->dir && delete(ss)){ - sourceClose(ss); - return 1; - } - if(1) - break; - sourceClose(ss); - } - - - sourceRemove(ss); - return 1; -} - -void -dump(Source *s, int ident, ulong entry) -{ - ulong i, n; - Source *ss; - Entry e; - - for(i=0; i<ident; i++) - Bprint(bout, " "); - - if(!sourceGetEntry(s, &e)){ - fprint(2, "sourceGetEntry failed: %r\n"); - return; - } - - Bprint(bout, "%4lud: gen %4ud depth %d tag=%x score=%V", - entry, e.gen, e.depth, e.tag, e.score); - if(!s->dir){ - Bprint(bout, " data size: %llud\n", e.size); - return; - } - n = sourceGetDirSize(s); - Bprint(bout, " dir size: %lud\n", n); - for(i=0; i<n; i++){ - ss = sourceOpen(s, i, 1); - if(ss == nil) - continue; - dump(ss, ident+1, i); - sourceClose(ss); - } - return; -} - -int -count(Source *s, int rec) -{ - ulong i, n; - int c; - Source *ss; - - n = sourceGetDirSize(s); - c = 0; - for(i=0; i<n; i++){ - ss = sourceOpen(s, i, OReadOnly); - if(ss == nil) - continue; - if(rec) - c += count(ss, rec); - c++; - sourceClose(ss); - } - return c; -} - -void -stats(Source *s) -{ - int n, i, c, cc, max; - Source *ss; - - cc = 0; - max = 0; - n = sourceGetDirSize(s); - for(i=0; i<n; i++){ - ss = sourceOpen(s, i, 1); - if(ss == nil) - continue; - cc++; - c = count(ss, 1); - if(c > max) - max = c; - sourceClose(ss); - } -fprint(2, "count = %d top = %d depth=%d maxcount %d\n", cc, n, maxdepth, max); -} diff --git a/sys/src/cmd/fossil/stdinc.h b/sys/src/cmd/fossil/stdinc.h deleted file mode 100644 index ef6118989..000000000 --- a/sys/src/cmd/fossil/stdinc.h +++ /dev/null @@ -1,11 +0,0 @@ -#include <u.h> -#include <libc.h> - -typedef uvlong u64int; -typedef uchar u8int; -typedef ushort u16int; - -#include "oventi.h" -#include "vac.h" -#include "fs.h" - diff --git a/sys/src/cmd/fossil/trunc.c b/sys/src/cmd/fossil/trunc.c deleted file mode 100644 index db24333c0..000000000 --- a/sys/src/cmd/fossil/trunc.c +++ /dev/null @@ -1,19 +0,0 @@ -#include <u.h> -#include <libc.h> - -void -main(int argc, char **argv) -{ - Dir d; - - if(argc != 3){ - fprint(2, "usage: trunc file size\n"); - exits("usage"); - } - - nulldir(&d); - d.length = strtoull(argv[2], 0, 0); - if(dirwstat(argv[1], &d) < 0) - sysfatal("dirwstat: %r"); - exits(0); -} diff --git a/sys/src/cmd/fossil/unpack b/sys/src/cmd/fossil/unpack deleted file mode 100644 index 5dfc122ee..000000000 --- a/sys/src/cmd/fossil/unpack +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/rc - -D=/n/ehime/testplan9 - -time cp /sys/lib/dist/web.protect/plan9.iso.bz2 /n/ehime -time bunzip2 -c /n/ehime/plan9.iso.bz2 > /n/ehime/plan9.iso -rm /srv/9660 -9660srv -mount /srv/9660 /n/sid /n/ehime/plan9.iso -rm -rf $D -mkdir $D -time dircp /n/sid $D -mkdir $D/n/emelieother # for lp diff --git a/sys/src/cmd/fossil/vac.c b/sys/src/cmd/fossil/vac.c deleted file mode 100644 index 526ff9710..000000000 --- a/sys/src/cmd/fossil/vac.c +++ /dev/null @@ -1,746 +0,0 @@ -#include "stdinc.h" - -typedef struct MetaChunk MetaChunk; - -struct MetaChunk { - ushort offset; - ushort size; - ushort index; -}; - -static int stringUnpack(char **s, uchar **p, int *n); -static int meCmp(MetaEntry*, char *s); -static int meCmpOld(MetaEntry*, char *s); - - - -static char EBadMeta[] = "corrupted meta data"; -static char ENoFile[] = "file does not exist"; - -/* - * integer conversion routines - */ -#define U8GET(p) ((p)[0]) -#define U16GET(p) (((p)[0]<<8)|(p)[1]) -#define U32GET(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3]) -#define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2)) -#define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4)) - -#define U8PUT(p,v) (p)[0]=(v) -#define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v) -#define U32PUT(p,v) (p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v) -#define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32) -#define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32) - -static int -stringUnpack(char **s, uchar **p, int *n) -{ - int nn; - - if(*n < 2) - return 0; - - nn = U16GET(*p); - *p += 2; - *n -= 2; - if(nn > *n) - return 0; - *s = vtMemAlloc(nn+1); - memmove(*s, *p, nn); - (*s)[nn] = 0; - *p += nn; - *n -= nn; - return 1; -} - -static int -stringPack(char *s, uchar *p) -{ - int n; - - n = strlen(s); - U16PUT(p, n); - memmove(p+2, s, n); - return n+2; -} - -int -mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me) -{ - int i; - int b, t, x; -if(0)fprint(2, "mbSearch %s\n", elem); - - /* binary search within block */ - b = 0; - t = mb->nindex; - while(b < t){ - i = (b+t)>>1; - meUnpack(me, mb, i); - - if(mb->botch) - x = meCmpOld(me, elem); - else - x = meCmp(me, elem); - - if(x == 0){ - *ri = i; - return 1; - } - - if(x < 0) - b = i+1; - else /* x > 0 */ - t = i; - } - - assert(b == t); - - *ri = b; /* b is the index to insert this entry */ - memset(me, 0, sizeof(*me)); - - vtSetError(ENoFile); - return 0; -} - -void -mbInit(MetaBlock *mb, uchar *p, int n, int ne) -{ - memset(p, 0, n); - mb->maxsize = n; - mb->maxindex = ne; - mb->nindex = 0; - mb->free = 0; - mb->size = MetaHeaderSize + ne*MetaIndexSize; - mb->buf = p; - mb->botch = 0; -} - -int -mbUnpack(MetaBlock *mb, uchar *p, int n) -{ - u32int magic; - int i; - int eo, en, omin; - uchar *q; - - mb->maxsize = n; - mb->buf = p; - - if(n == 0){ - memset(mb, 0, sizeof(MetaBlock)); - return 1; - } - - magic = U32GET(p); - if(magic != MetaMagic && magic != MetaMagic-1) - goto Err; - mb->size = U16GET(p+4); - mb->free = U16GET(p+6); - mb->maxindex = U16GET(p+8); - mb->nindex = U16GET(p+10); - mb->botch = magic != MetaMagic; - if(mb->size > n) - goto Err; - - omin = MetaHeaderSize + mb->maxindex*MetaIndexSize; - if(n < omin) - goto Err; - - - p += MetaHeaderSize; - - /* check the index table - ensures that meUnpack and meCmp never fail */ - for(i=0; i<mb->nindex; i++){ - eo = U16GET(p); - en = U16GET(p+2); - if(eo < omin || eo+en > mb->size || en < 8) - goto Err; - q = mb->buf + eo; - if(U32GET(q) != DirMagic) - goto Err; - p += 4; - } - - return 1; -Err: - vtSetError(EBadMeta); - return 0; -} - - -void -mbPack(MetaBlock *mb) -{ - uchar *p; - - p = mb->buf; - - assert(!mb->botch); - - U32PUT(p, MetaMagic); - U16PUT(p+4, mb->size); - U16PUT(p+6, mb->free); - U16PUT(p+8, mb->maxindex); - U16PUT(p+10, mb->nindex); -} - - -void -mbDelete(MetaBlock *mb, int i) -{ - uchar *p; - int n; - MetaEntry me; - - assert(i < mb->nindex); - meUnpack(&me, mb, i); - memset(me.p, 0, me.size); - - if(me.p - mb->buf + me.size == mb->size) - mb->size -= me.size; - else - mb->free += me.size; - - p = mb->buf + MetaHeaderSize + i*MetaIndexSize; - n = (mb->nindex-i-1)*MetaIndexSize; - memmove(p, p+MetaIndexSize, n); - memset(p+n, 0, MetaIndexSize); - mb->nindex--; -} - -void -mbInsert(MetaBlock *mb, int i, MetaEntry *me) -{ - uchar *p; - int o, n; - - assert(mb->nindex < mb->maxindex); - - o = me->p - mb->buf; - n = me->size; - if(o+n > mb->size){ - mb->free -= mb->size - o; - mb->size = o + n; - }else - mb->free -= n; - - p = mb->buf + MetaHeaderSize + i*MetaIndexSize; - n = (mb->nindex-i)*MetaIndexSize; - memmove(p+MetaIndexSize, p, n); - U16PUT(p, me->p - mb->buf); - U16PUT(p+2, me->size); - mb->nindex++; -} - -int -mbResize(MetaBlock *mb, MetaEntry *me, int n) -{ - uchar *p, *ep; - - /* easy case */ - if(n <= me->size){ - me->size = n; - return 1; - } - - /* try and expand entry */ - - p = me->p + me->size; - ep = mb->buf + mb->maxsize; - while(p < ep && *p == 0) - p++; - if(n <= p - me->p){ - me->size = n; - return 1; - } - - p = mbAlloc(mb, n); - if(p != nil){ - me->p = p; - me->size = n; - return 1; - } - - return 0; -} - -void -meUnpack(MetaEntry *me, MetaBlock *mb, int i) -{ - uchar *p; - int eo, en; - - assert(i >= 0 && i < mb->nindex); - - p = mb->buf + MetaHeaderSize + i*MetaIndexSize; - eo = U16GET(p); - en = U16GET(p+2); - - me->p = mb->buf + eo; - me->size = en; - - /* checked by mbUnpack */ - assert(me->size >= 8); -} - -/* assumes a small amount of checking has been done in mbEntry */ -static int -meCmp(MetaEntry *me, char *s) -{ - int n; - uchar *p; - - p = me->p; - - /* skip magic & version */ - p += 6; - n = U16GET(p); - p += 2; - - if(n > me->size - 8) - n = me->size - 8; - - while(n > 0){ - if(*s == 0) - return 1; - if(*p < (uchar)*s) - return -1; - if(*p > (uchar)*s) - return 1; - p++; - s++; - n--; - } - return -(*s != 0); -} - -/* - * This is the old and broken meCmp. - * This cmp routine reverse the sense of the comparison - * when one string is a prefix of the other. - * In other words, it put "ab" after "abc" rather - * than before. This behaviour is ok; binary search - * and sort still work. However, it is goes against - * the usual convention. - */ -static int -meCmpOld(MetaEntry *me, char *s) -{ - int n; - uchar *p; - - p = me->p; - - /* skip magic & version */ - p += 6; - n = U16GET(p); - p += 2; - - if(n > me->size - 8) - n = me->size - 8; - - while(n > 0){ - if(*s == 0) - return -1; - if(*p < (uchar)*s) - return -1; - if(*p > (uchar)*s) - return 1; - p++; - s++; - n--; - } - return *s != 0; -} - -static int -offsetCmp(void *s0, void *s1) -{ - MetaChunk *mc0, *mc1; - - mc0 = s0; - mc1 = s1; - if(mc0->offset < mc1->offset) - return -1; - if(mc0->offset > mc1->offset) - return 1; - return 0; -} - -static MetaChunk * -metaChunks(MetaBlock *mb) -{ - MetaChunk *mc; - int oo, o, n, i; - uchar *p; - - mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk)); - p = mb->buf + MetaHeaderSize; - for(i = 0; i<mb->nindex; i++){ - mc[i].offset = U16GET(p); - mc[i].size = U16GET(p+2); - mc[i].index = i; - p += MetaIndexSize; - } - - qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp); - - /* check block looks ok */ - oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; - o = oo; - n = 0; - for(i=0; i<mb->nindex; i++){ - o = mc[i].offset; - n = mc[i].size; - if(o < oo) - goto Err; - oo += n; - } - if(o+n > mb->size) - goto Err; - if(mb->size - oo != mb->free) - goto Err; - - return mc; -Err: -fprint(2, "metaChunks failed!\n"); -oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; -for(i=0; i<mb->nindex; i++){ -fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size); -oo += mc[i].size; -} -fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo); - vtSetError(EBadMeta); - vtMemFree(mc); - return nil; -} - -static void -mbCompact(MetaBlock *mb, MetaChunk *mc) -{ - int oo, o, n, i; - - oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; - - for(i=0; i<mb->nindex; i++){ - o = mc[i].offset; - n = mc[i].size; - if(o != oo){ - memmove(mb->buf + oo, mb->buf + o, n); - U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo); - } - oo += n; - } - - mb->size = oo; - mb->free = 0; -} - -uchar * -mbAlloc(MetaBlock *mb, int n) -{ - int i, o; - MetaChunk *mc; - - /* off the end */ - if(mb->maxsize - mb->size >= n) - return mb->buf + mb->size; - - /* check if possible */ - if(mb->maxsize - mb->size + mb->free < n) - return nil; - - mc = metaChunks(mb); - if(mc == nil){ -fprint(2, "mbAlloc: metaChunks failed: %r\n"); - return nil; - } - - /* look for hole */ - o = MetaHeaderSize + mb->maxindex*MetaIndexSize; - for(i=0; i<mb->nindex; i++){ - if(mc[i].offset - o >= n){ - vtMemFree(mc); - return mb->buf + o; - } - o = mc[i].offset + mc[i].size; - } - - if(mb->maxsize - o >= n){ - vtMemFree(mc); - return mb->buf + o; - } - - /* compact and return off the end */ - mbCompact(mb, mc); - vtMemFree(mc); - - if(mb->maxsize - mb->size < n){ - vtSetError(EBadMeta); - return nil; - } - return mb->buf + mb->size; -} - -int -deSize(DirEntry *dir) -{ - int n; - - /* constant part */ - - n = 4 + /* magic */ - 2 + /* version */ - 4 + /* entry */ - 4 + /* guid */ - 4 + /* mentry */ - 4 + /* mgen */ - 8 + /* qid */ - 4 + /* mtime */ - 4 + /* mcount */ - 4 + /* ctime */ - 4 + /* atime */ - 4 + /* mode */ - 0; - - /* strings */ - n += 2 + strlen(dir->elem); - n += 2 + strlen(dir->uid); - n += 2 + strlen(dir->gid); - n += 2 + strlen(dir->mid); - - /* optional sections */ - if(dir->qidSpace){ - n += 3 + /* option header */ - 8 + /* qidOffset */ - 8; /* qid Max */ - } - - return n; -} - -void -dePack(DirEntry *dir, MetaEntry *me) -{ - uchar *p; - ulong t32; - - p = me->p; - - U32PUT(p, DirMagic); - U16PUT(p+4, 9); /* version */ - p += 6; - - p += stringPack(dir->elem, p); - - U32PUT(p, dir->entry); - U32PUT(p+4, dir->gen); - U32PUT(p+8, dir->mentry); - U32PUT(p+12, dir->mgen); - U64PUT(p+16, dir->qid, t32); - p += 24; - - p += stringPack(dir->uid, p); - p += stringPack(dir->gid, p); - p += stringPack(dir->mid, p); - - U32PUT(p, dir->mtime); - U32PUT(p+4, dir->mcount); - U32PUT(p+8, dir->ctime); - U32PUT(p+12, dir->atime); - U32PUT(p+16, dir->mode); - p += 5*4; - - if(dir->qidSpace){ - U8PUT(p, DeQidSpace); - U16PUT(p+1, 2*8); - p += 3; - U64PUT(p, dir->qidOffset, t32); - U64PUT(p+8, dir->qidMax, t32); - p += 16; - } - - assert(p == me->p + me->size); -} - - -int -deUnpack(DirEntry *dir, MetaEntry *me) -{ - int t, nn, n, version; - uchar *p; - - p = me->p; - n = me->size; - - memset(dir, 0, sizeof(DirEntry)); - -if(0)print("deUnpack\n"); - /* magic */ - if(n < 4 || U32GET(p) != DirMagic) - goto Err; - p += 4; - n -= 4; - -if(0)print("deUnpack: got magic\n"); - /* version */ - if(n < 2) - goto Err; - version = U16GET(p); - if(version < 7 || version > 9) - goto Err; - p += 2; - n -= 2; - -if(0)print("deUnpack: got version\n"); - - /* elem */ - if(!stringUnpack(&dir->elem, &p, &n)) - goto Err; - -if(0)print("deUnpack: got elem\n"); - - /* entry */ - if(n < 4) - goto Err; - dir->entry = U32GET(p); - p += 4; - n -= 4; - -if(0)print("deUnpack: got entry\n"); - - if(version < 9){ - dir->gen = 0; - dir->mentry = dir->entry+1; - dir->mgen = 0; - }else{ - if(n < 3*4) - goto Err; - dir->gen = U32GET(p); - dir->mentry = U32GET(p+4); - dir->mgen = U32GET(p+8); - p += 3*4; - n -= 3*4; - } - -if(0)print("deUnpack: got gen etc\n"); - - /* size is gotten from VtEntry */ - dir->size = 0; - - /* qid */ - if(n < 8) - goto Err; - dir->qid = U64GET(p); - p += 8; - n -= 8; - -if(0)print("deUnpack: got qid\n"); - /* skip replacement */ - if(version == 7){ - if(n < VtScoreSize) - goto Err; - p += VtScoreSize; - n -= VtScoreSize; - } - - /* uid */ - if(!stringUnpack(&dir->uid, &p, &n)) - goto Err; - - /* gid */ - if(!stringUnpack(&dir->gid, &p, &n)) - goto Err; - - /* mid */ - if(!stringUnpack(&dir->mid, &p, &n)) - goto Err; - -if(0)print("deUnpack: got ids\n"); - if(n < 5*4) - goto Err; - dir->mtime = U32GET(p); - dir->mcount = U32GET(p+4); - dir->ctime = U32GET(p+8); - dir->atime = U32GET(p+12); - dir->mode = U32GET(p+16); - p += 5*4; - n -= 5*4; - -if(0)print("deUnpack: got times\n"); - /* optional meta data */ - while(n > 0){ - if(n < 3) - goto Err; - t = p[0]; - nn = U16GET(p+1); - p += 3; - n -= 3; - if(n < nn) - goto Err; - switch(t){ - case DePlan9: - /* not valid in version >= 9 */ - if(version >= 9) - break; - if(dir->plan9 || nn != 12) - goto Err; - dir->plan9 = 1; - dir->p9path = U64GET(p); - dir->p9version = U32GET(p+8); - if(dir->mcount == 0) - dir->mcount = dir->p9version; - break; - case DeGen: - /* not valid in version >= 9 */ - if(version >= 9) - break; - break; - case DeQidSpace: - if(dir->qidSpace || nn != 16) - goto Err; - dir->qidSpace = 1; - dir->qidOffset = U64GET(p); - dir->qidMax = U64GET(p+8); - break; - } - p += nn; - n -= nn; - } -if(0)print("deUnpack: got options\n"); - - if(p != me->p + me->size) - goto Err; - -if(0)print("deUnpack: correct size\n"); - return 1; -Err: -if(0)print("deUnpack: XXXXXXXXXXXX EBadMeta\n"); - vtSetError(EBadMeta); - deCleanup(dir); - return 0; -} - -void -deCleanup(DirEntry *dir) -{ - vtMemFree(dir->elem); - dir->elem = nil; - vtMemFree(dir->uid); - dir->uid = nil; - vtMemFree(dir->gid); - dir->gid = nil; - vtMemFree(dir->mid); - dir->mid = nil; -} - -void -deCopy(DirEntry *dst, DirEntry *src) -{ - *dst = *src; - dst->elem = vtStrDup(src->elem); - dst->uid = vtStrDup(src->uid); - dst->gid = vtStrDup(src->gid); - dst->mid = vtStrDup(src->mid); -} diff --git a/sys/src/cmd/fossil/vac.h b/sys/src/cmd/fossil/vac.h deleted file mode 100644 index bd26c62d2..000000000 --- a/sys/src/cmd/fossil/vac.h +++ /dev/null @@ -1,107 +0,0 @@ -typedef struct DirEntry DirEntry; -typedef struct MetaBlock MetaBlock; -typedef struct MetaEntry MetaEntry; - -enum { - MetaMagic = 0x5656fc7a, - MetaHeaderSize = 12, - MetaIndexSize = 4, - IndexEntrySize = 8, - DirMagic = 0x1c4d9072, -}; - -/* - * Mode bits - */ -enum { - ModeOtherExec = (1<<0), - ModeOtherWrite = (1<<1), - ModeOtherRead = (1<<2), - ModeGroupExec = (1<<3), - ModeGroupWrite = (1<<4), - ModeGroupRead = (1<<5), - ModeOwnerExec = (1<<6), - ModeOwnerWrite = (1<<7), - ModeOwnerRead = (1<<8), - ModeSticky = (1<<9), - ModeSetUid = (1<<10), - ModeSetGid = (1<<11), - ModeAppend = (1<<12), /* append only file */ - ModeExclusive = (1<<13), /* lock file - plan 9 */ - ModeLink = (1<<14), /* sym link */ - ModeDir = (1<<15), /* duplicate of DirEntry */ - ModeHidden = (1<<16), /* MS-DOS */ - ModeSystem = (1<<17), /* MS-DOS */ - ModeArchive = (1<<18), /* MS-DOS */ - ModeTemporary = (1<<19), /* MS-DOS */ - ModeSnapshot = (1<<20), /* read only snapshot */ -}; - -/* optional directory entry fields */ -enum { - DePlan9 = 1, /* not valid in version >= 9 */ - DeNT, /* not valid in version >= 9 */ - DeQidSpace, - DeGen, /* not valid in version >= 9 */ -}; - -struct DirEntry { - char *elem; /* path element */ - ulong entry; /* entry in directory for data */ - ulong gen; /* generation of data entry */ - ulong mentry; /* entry in directory for meta */ - ulong mgen; /* generation of meta entry */ - uvlong size; /* size of file */ - uvlong qid; /* unique file id */ - - char *uid; /* owner id */ - char *gid; /* group id */ - char *mid; /* last modified by */ - ulong mtime; /* last modified time */ - ulong mcount; /* number of modifications: can wrap! */ - ulong ctime; /* directory entry last changed */ - ulong atime; /* last time accessed */ - ulong mode; /* various mode bits */ - - /* plan 9 */ - int plan9; - uvlong p9path; - ulong p9version; - - /* sub space of qid */ - int qidSpace; - uvlong qidOffset; /* qid offset */ - uvlong qidMax; /* qid maximum */ -}; - -struct MetaEntry { - uchar *p; - ushort size; -}; - -struct MetaBlock { - int maxsize; /* size of block */ - int size; /* size used */ - int free; /* free space within used size */ - int maxindex; /* entries allocated for table */ - int nindex; /* amount of table used */ - int botch; /* compensate for my stupidity */ - uchar *buf; -}; - -void deCleanup(DirEntry*); -void deCopy(DirEntry*, DirEntry*); -int deSize(DirEntry*); -void dePack(DirEntry*, MetaEntry*); -int deUnpack(DirEntry*, MetaEntry*); - -void mbInit(MetaBlock*, uchar*, int, int); -int mbUnpack(MetaBlock*, uchar*, int); -void mbInsert(MetaBlock*, int, MetaEntry*); -void mbDelete(MetaBlock*, int); -void mbPack(MetaBlock*); -uchar *mbAlloc(MetaBlock*, int); -int mbResize(MetaBlock*, MetaEntry*, int); -int mbSearch(MetaBlock*, char*, int*, MetaEntry*); - -void meUnpack(MetaEntry*, MetaBlock*, int); diff --git a/sys/src/cmd/fossil/view.c b/sys/src/cmd/fossil/view.c deleted file mode 100644 index c2ac99762..000000000 --- a/sys/src/cmd/fossil/view.c +++ /dev/null @@ -1,1127 +0,0 @@ -#include "stdinc.h" -#include "dat.h" -#include "fns.h" -#include <draw.h> -#include <event.h> - -/* --- tree.h */ -typedef struct Tree Tree; -typedef struct Tnode Tnode; - -struct Tree -{ - Tnode *root; - Point offset; - Image *clipr; -}; - -struct Tnode -{ - Point offset; - - char *str; -// char *(*strfn)(Tnode*); -// uint (*draw)(Tnode*, Image*, Image*, Point); - void (*expand)(Tnode*); - void (*collapse)(Tnode*); - - uint expanded; - Tnode **kid; - int nkid; - void *aux; -}; - -typedef struct Atree Atree; -struct Atree -{ - int resizefd; - Tnode *root; -}; - -Atree *atreeinit(char*); - -/* --- visfossil.c */ -Tnode *initxheader(void); -Tnode *initxcache(char *name); -Tnode *initxsuper(void); -Tnode *initxlocalroot(char *name, u32int addr); -Tnode *initxentry(Entry); -Tnode *initxsource(Entry, int); -Tnode *initxentryblock(Block*, Entry*); -Tnode *initxdatablock(Block*, uint); -Tnode *initxroot(char *name, uchar[VtScoreSize]); - -int fd; -Header h; -Super super; -VtSession *z; -VtRoot vac; -int showinactive; - -/* - * dumbed down versions of fossil routines - */ -char* -bsStr(int state) -{ - static char s[100]; - - if(state == BsFree) - return "Free"; - if(state == BsBad) - return "Bad"; - - sprint(s, "%x", state); - if(!(state&BsAlloc)) - strcat(s, ",Free"); /* should not happen */ - if(state&BsVenti) - strcat(s, ",Venti"); - if(state&BsClosed) - strcat(s, ",Closed"); - return s; -} - -char *bttab[] = { - "BtData", - "BtData+1", - "BtData+2", - "BtData+3", - "BtData+4", - "BtData+5", - "BtData+6", - "BtData+7", - "BtDir", - "BtDir+1", - "BtDir+2", - "BtDir+3", - "BtDir+4", - "BtDir+5", - "BtDir+6", - "BtDir+7", -}; - -char* -btStr(int type) -{ - if(type < nelem(bttab)) - return bttab[type]; - return "unknown"; -} -#pragma varargck argpos stringnode 1 - -Block* -allocBlock(void) -{ - Block *b; - - b = mallocz(sizeof(Block)+h.blockSize, 1); - b->data = (void*)&b[1]; - return b; -} - -void -blockPut(Block *b) -{ - free(b); -} - -static u32int -partStart(int part) -{ - switch(part){ - default: - assert(0); - case PartSuper: - return h.super; - case PartLabel: - return h.label; - case PartData: - return h.data; - } -} - - -static u32int -partEnd(int part) -{ - switch(part){ - default: - assert(0); - case PartSuper: - return h.super+1; - case PartLabel: - return h.data; - case PartData: - return h.end; - } -} - -Block* -readBlock(int part, u32int addr) -{ - u32int start, end; - u64int offset; - int n, nn; - Block *b; - uchar *buf; - - start = partStart(part); - end = partEnd(part); - if(addr >= end-start){ - werrstr("bad addr 0x%.8ux; wanted 0x%.8ux - 0x%.8ux", addr, start, end); - return nil; - } - - b = allocBlock(); - b->addr = addr; - buf = b->data; - offset = ((u64int)(addr+start))*h.blockSize; - n = h.blockSize; - while(n > 0){ - nn = pread(fd, buf, n, offset); - if(nn < 0){ - blockPut(b); - return nil; - } - if(nn == 0){ - werrstr("short read"); - blockPut(b); - return nil; - } - n -= nn; - offset += nn; - buf += nn; - } - return b; -} - -int vtType[BtMax] = { - VtDataType, /* BtData | 0 */ - VtPointerType0, /* BtData | 1 */ - VtPointerType1, /* BtData | 2 */ - VtPointerType2, /* BtData | 3 */ - VtPointerType3, /* BtData | 4 */ - VtPointerType4, /* BtData | 5 */ - VtPointerType5, /* BtData | 6 */ - VtPointerType6, /* BtData | 7 */ - VtDirType, /* BtDir | 0 */ - VtPointerType0, /* BtDir | 1 */ - VtPointerType1, /* BtDir | 2 */ - VtPointerType2, /* BtDir | 3 */ - VtPointerType3, /* BtDir | 4 */ - VtPointerType4, /* BtDir | 5 */ - VtPointerType5, /* BtDir | 6 */ - VtPointerType6, /* BtDir | 7 */ -}; - -Block* -ventiBlock(uchar score[VtScoreSize], uint type) -{ - int n; - Block *b; - - b = allocBlock(); - memmove(b->score, score, VtScoreSize); - b->addr = NilBlock; - - n = vtRead(z, b->score, vtType[type], b->data, h.blockSize); - if(n < 0){ - fprint(2, "vtRead returns %d: %R\n", n); - blockPut(b); - return nil; - } - vtZeroExtend(vtType[type], b->data, n, h.blockSize); - b->l.type = type; - b->l.state = 0; - b->l.tag = 0; - b->l.epoch = 0; - return b; -} - -Block* -dataBlock(uchar score[VtScoreSize], uint type, uint tag) -{ - Block *b, *bl; - int lpb; - Label l; - u32int addr; - - addr = globalToLocal(score); - if(addr == NilBlock) - return ventiBlock(score, type); - - lpb = h.blockSize/LabelSize; - bl = readBlock(PartLabel, addr/lpb); - if(bl == nil) - return nil; - if(!labelUnpack(&l, bl->data, addr%lpb)){ - werrstr("%R"); - blockPut(bl); - return nil; - } - blockPut(bl); - if(l.type != type){ - werrstr("type mismatch; got %d (%s) wanted %d (%s)", - l.type, btStr(l.type), type, btStr(type)); - return nil; - } - if(tag && l.tag != tag){ - werrstr("tag mismatch; got 0x%.8ux wanted 0x%.8ux", - l.tag, tag); - return nil; - } - b = readBlock(PartData, addr); - if(b == nil) - return nil; - b->l = l; - return b; -} - -Entry* -copyEntry(Entry e) -{ - Entry *p; - - p = mallocz(sizeof *p, 1); - *p = e; - return p; -} - -MetaBlock* -copyMetaBlock(MetaBlock mb) -{ - MetaBlock *p; - - p = mallocz(sizeof mb, 1); - *p = mb; - return p; -} - -/* - * visualizer - */ - -#pragma varargck argpos stringnode 1 - -Tnode* -stringnode(char *fmt, ...) -{ - va_list arg; - Tnode *t; - - t = mallocz(sizeof(Tnode), 1); - va_start(arg, fmt); - t->str = vsmprint(fmt, arg); - va_end(arg); - t->nkid = -1; - return t; -} - -void -xcacheexpand(Tnode *t) -{ - if(t->nkid >= 0) - return; - - t->nkid = 1; - t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1); - t->kid[0] = initxheader(); -} - -Tnode* -initxcache(char *name) -{ - Tnode *t; - - if((fd = open(name, OREAD)) < 0) - sysfatal("cannot open %s: %r", name); - - t = stringnode("%s", name); - t->expand = xcacheexpand; - return t; -} - -void -xheaderexpand(Tnode *t) -{ - if(t->nkid >= 0) - return; - - t->nkid = 1; - t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1); - t->kid[0] = initxsuper(); - //t->kid[1] = initxlabel(h.label); - //t->kid[2] = initxdata(h.data); -} - -Tnode* -initxheader(void) -{ - u8int buf[HeaderSize]; - Tnode *t; - - if(pread(fd, buf, HeaderSize, HeaderOffset) < HeaderSize) - return stringnode("error reading header: %r"); - if(!headerUnpack(&h, buf)) - return stringnode("error unpacking header: %R"); - - t = stringnode("header " - "version=%#ux (%d) " - "blockSize=%#ux (%d) " - "super=%#lux (%ld) " - "label=%#lux (%ld) " - "data=%#lux (%ld) " - "end=%#lux (%ld)", - h.version, h.version, h.blockSize, h.blockSize, - h.super, h.super, - h.label, h.label, h.data, h.data, h.end, h.end); - t->expand = xheaderexpand; - return t; -} - -void -xsuperexpand(Tnode *t) -{ - if(t->nkid >= 0) - return; - - t->nkid = 1; - t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1); - t->kid[0] = initxlocalroot("active", super.active); -// t->kid[1] = initxlocalroot("next", super.next); -// t->kid[2] = initxlocalroot("current", super.current); -} - -Tnode* -initxsuper(void) -{ - Block *b; - Tnode *t; - - b = readBlock(PartSuper, 0); - if(b == nil) - return stringnode("reading super: %r"); - if(!superUnpack(&super, b->data)){ - blockPut(b); - return stringnode("unpacking super: %R"); - } - blockPut(b); - t = stringnode("super " - "version=%#ux " - "epoch=[%#ux,%#ux) " - "qid=%#llux " - "active=%#x " - "next=%#x " - "current=%#x " - "last=%V " - "name=%s", - super.version, super.epochLow, super.epochHigh, - super.qid, super.active, super.next, super.current, - super.last, super.name); - t->expand = xsuperexpand; - return t; -} - -void -xvacrootexpand(Tnode *t) -{ - if(t->nkid >= 0) - return; - - t->nkid = 1; - t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1); - t->kid[0] = initxroot("root", vac.score); -} - -Tnode* -initxvacroot(uchar score[VtScoreSize]) -{ - Tnode *t; - uchar buf[VtRootSize]; - int n; - - if((n = vtRead(z, score, VtRootType, buf, VtRootSize)) < 0) - return stringnode("reading root %V: %R", score); - - if(!vtRootUnpack(&vac, buf)) - return stringnode("unpack %d-byte root: %R", n); - - h.blockSize = vac.blockSize; - t = stringnode("vac version=%#ux name=%s type=%s blockSize=%ud score=%V prev=%V", - vac.version, vac.name, vac.type, vac.blockSize, vac.score, vac.prev); - t->expand = xvacrootexpand; - return t; -} - -Tnode* -initxlabel(Label l) -{ - return stringnode("label type=%s state=%s epoch=%#ux tag=%#ux", - btStr(l.type), bsStr(l.state), l.epoch, l.tag); -} - -typedef struct Xblock Xblock; -struct Xblock -{ - Tnode; - Block *b; - int (*gen)(void*, Block*, int, Tnode**); - void *arg; - int printlabel; -}; - -void -xblockexpand(Tnode *tt) -{ - int i, j; - enum { Q = 32 }; - Xblock *t = (Xblock*)tt; - Tnode *nn; - - if(t->nkid >= 0) - return; - - j = 0; - if(t->printlabel){ - t->kid = mallocz(Q*sizeof(t->kid[0]), 1); - t->kid[0] = initxlabel(t->b->l); - j = 1; - } - - for(i=0;; i++){ - switch((*t->gen)(t->arg, t->b, i, &nn)){ - case -1: - t->nkid = j; - return; - case 0: - break; - case 1: - if(j%Q == 0) - t->kid = realloc(t->kid, (j+Q)*sizeof(t->kid[0])); - t->kid[j++] = nn; - break; - } - } -} - -int -nilgen(void*, Block*, int, Tnode**) -{ - return -1; -} - -Tnode* -initxblock(Block *b, char *s, int (*gen)(void*, Block*, int, Tnode**), void *arg) -{ - Xblock *t; - - if(gen == nil) - gen = nilgen; - t = mallocz(sizeof(Xblock), 1); - t->b = b; - t->gen = gen; - t->arg = arg; - if(b->addr == NilBlock) - t->str = smprint("Block %V: %s", b->score, s); - else - t->str = smprint("Block %#ux: %s", b->addr, s); - t->printlabel = 1; - t->nkid = -1; - t->expand = xblockexpand; - return t; -} - -int -xentrygen(void *v, Block *b, int o, Tnode **tp) -{ - Entry e; - Entry *ed; - - ed = v; - if(o >= ed->dsize/VtEntrySize) - return -1; - - entryUnpack(&e, b->data, o); - if(!showinactive && !(e.flags & VtEntryActive)) - return 0; - *tp = initxentry(e); - return 1; -} - -Tnode* -initxentryblock(Block *b, Entry *ed) -{ - return initxblock(b, "entry", xentrygen, ed); -} - -typedef struct Xentry Xentry; -struct Xentry -{ - Tnode; - Entry e; -}; - -void -xentryexpand(Tnode *tt) -{ - Xentry *t = (Xentry*)tt; - - if(t->nkid >= 0) - return; - - t->nkid = 1; - t->kid = mallocz(sizeof(t->kid[0])*t->nkid, 1); - t->kid[0] = initxsource(t->e, 1); -} - -Tnode* -initxentry(Entry e) -{ - Xentry *t; - - t = mallocz(sizeof *t, 1); - t->nkid = -1; - t->str = smprint("Entry gen=%#ux psize=%d dsize=%d depth=%d flags=%#ux size=%lld score=%V", - e.gen, e.psize, e.dsize, e.depth, e.flags, e.size, e.score); - if(e.flags & VtEntryLocal) - t->str = smprint("%s archive=%d snap=%d tag=%#ux", t->str, e.archive, e.snap, e.tag); - t->expand = xentryexpand; - t->e = e; - return t; -} - -int -ptrgen(void *v, Block *b, int o, Tnode **tp) -{ - Entry *ed; - Entry e; - - ed = v; - if(o >= ed->psize/VtScoreSize) - return -1; - - e = *ed; - e.depth--; - memmove(e.score, b->data+o*VtScoreSize, VtScoreSize); - if(memcmp(e.score, vtZeroScore, VtScoreSize) == 0) - return 0; - *tp = initxsource(e, 0); - return 1; -} - -static int -etype(int flags, int depth) -{ - uint t; - - if(flags&VtEntryDir) - t = BtDir; - else - t = BtData; - return t+depth; -} - -Tnode* -initxsource(Entry e, int dowrap) -{ - Block *b; - Tnode *t, *tt; - - b = dataBlock(e.score, etype(e.flags, e.depth), e.tag); - if(b == nil) - return stringnode("dataBlock: %r"); - - if((e.flags & VtEntryActive) == 0) - return stringnode("inactive Entry"); - - if(e.depth == 0){ - if(e.flags & VtEntryDir) - tt = initxentryblock(b, copyEntry(e)); - else - tt = initxdatablock(b, e.dsize); - }else{ - tt = initxblock(b, smprint("%s+%d pointer", (e.flags & VtEntryDir) ? "BtDir" : "BtData", e.depth), - ptrgen, copyEntry(e)); - } - - /* - * wrap the contents of the Source in a Source node, - * just so it's closer to what you see in the code. - */ - if(dowrap){ - t = stringnode("Source"); - t->nkid = 1; - t->kid = mallocz(sizeof(Tnode*)*1, 1); - t->kid[0] = tt; - tt = t; - } - return tt; -} - -int -xlocalrootgen(void*, Block *b, int o, Tnode **tp) -{ - Entry e; - - if(o >= 1) - return -1; - entryUnpack(&e, b->data, o); - *tp = initxentry(e); - return 1; -} - -Tnode* -initxlocalroot(char *name, u32int addr) -{ - uchar score[VtScoreSize]; - Block *b; - - localToGlobal(addr, score); - b = dataBlock(score, BtDir, RootTag); - if(b == nil) - return stringnode("read data block %#ux: %R", addr); - return initxblock(b, smprint("'%s' fs root", name), xlocalrootgen, nil); -} - -int -xvacrootgen(void*, Block *b, int o, Tnode **tp) -{ - Entry e; - - if(o >= 3) - return -1; - entryUnpack(&e, b->data, o); - *tp = initxentry(e); - return 1; -} - -Tnode* -initxroot(char *name, uchar score[VtScoreSize]) -{ - Block *b; - - b = dataBlock(score, BtDir, RootTag); - if(b == nil) - return stringnode("read data block %V: %R", score); - return initxblock(b, smprint("'%s' fs root", name), xvacrootgen, nil); -} -Tnode* -initxdirentry(MetaEntry *me) -{ - DirEntry dir; - Tnode *t; - - if(!deUnpack(&dir, me)) - return stringnode("deUnpack: %R"); - - t = stringnode("dirEntry elem=%s size=%llud data=%#lux/%#lux meta=%#lux/%#lux", dir.elem, dir.size, dir.entry, dir.gen, dir.mentry, dir.mgen); - t->nkid = 1; - t->kid = mallocz(sizeof(t->kid[0])*1, 1); - t->kid[0] = stringnode( - "qid=%#llux\n" - "uid=%s gid=%s mid=%s\n" - "mtime=%lud mcount=%lud ctime=%lud atime=%lud\n" - "mode=%luo\n" - "plan9 %d p9path %#llux p9version %lud\n" - "qidSpace %d offset %#llux max %#llux", - dir.qid, - dir.uid, dir.gid, dir.mid, - dir.mtime, dir.mcount, dir.ctime, dir.atime, - dir.mode, - dir.plan9, dir.p9path, dir.p9version, - dir.qidSpace, dir.qidOffset, dir.qidMax); - return t; -} - -int -metaentrygen(void *v, Block*, int o, Tnode **tp) -{ - Tnode *t; - MetaBlock *mb; - MetaEntry me; - - mb = v; - if(o >= mb->nindex) - return -1; - meUnpack(&me, mb, o); - - t = stringnode("MetaEntry %d bytes", mb->size); - t->kid = mallocz(sizeof(t->kid[0])*1, 1); - t->kid[0] = initxdirentry(&me); - t->nkid = 1; - *tp = t; - return 1; -} - -int -metablockgen(void *v, Block *b, int o, Tnode **tp) -{ - Xblock *t; - MetaBlock *mb; - - if(o >= 1) - return -1; - - /* hack: reuse initxblock as a generic iterator */ - mb = v; - t = (Xblock*)initxblock(b, "", metaentrygen, mb); - t->str = smprint("MetaBlock %d/%d space used, %d add'l free %d/%d table used%s", - mb->size, mb->maxsize, mb->free, mb->nindex, mb->maxindex, - mb->botch ? " [BOTCH]" : ""); - t->printlabel = 0; - *tp = t; - return 1; -} - -/* - * attempt to guess at the type of data in the block. - * it could just be data from a file, but we're hoping it's MetaBlocks. - */ -Tnode* -initxdatablock(Block *b, uint n) -{ - MetaBlock mb; - - if(n > h.blockSize) - n = h.blockSize; - - if(mbUnpack(&mb, b->data, n)) - return initxblock(b, "metadata", metablockgen, copyMetaBlock(mb)); - - return initxblock(b, "data", nil, nil); -} - -int -parseScore(uchar *score, char *buf, int n) -{ - int i, c; - - memset(score, 0, VtScoreSize); - - if(n < VtScoreSize*2) - return 0; - for(i=0; i<VtScoreSize*2; i++){ - if(buf[i] >= '0' && buf[i] <= '9') - c = buf[i] - '0'; - else if(buf[i] >= 'a' && buf[i] <= 'f') - c = buf[i] - 'a' + 10; - else if(buf[i] >= 'A' && buf[i] <= 'F') - c = buf[i] - 'A' + 10; - else{ - return 0; - } - - if((i & 1) == 0) - c <<= 4; - - score[i>>1] |= c; - } - return 1; -} - -int -scoreFmt(Fmt *f) -{ - uchar *v; - int i; - u32int addr; - - v = va_arg(f->args, uchar*); - if(v == nil){ - fmtprint(f, "*"); - }else if((addr = globalToLocal(v)) != NilBlock) - fmtprint(f, "0x%.8ux", addr); - else{ - for(i = 0; i < VtScoreSize; i++) - fmtprint(f, "%2.2ux", v[i]); - } - - return 0; -} - -Atree* -atreeinit(char *arg) -{ - Atree *a; - uchar score[VtScoreSize]; - - vtAttach(); - - fmtinstall('V', scoreFmt); - fmtinstall('R', vtErrFmt); - - z = vtDial(nil, 1); - if(z == nil) - fprint(2, "warning: cannot dial venti: %R\n"); - if(!vtConnect(z, 0)){ - fprint(2, "warning: cannot connect to venti: %R\n"); - z = nil; - } - a = mallocz(sizeof(Atree), 1); - if(strncmp(arg, "vac:", 4) == 0){ - if(!parseScore(score, arg+4, strlen(arg+4))){ - fprint(2, "cannot parse score\n"); - return nil; - } - a->root = initxvacroot(score); - }else - a->root = initxcache(arg); - a->resizefd = -1; - return a; -} - -/* --- tree.c */ -enum -{ - Nubwidth = 11, - Nubheight = 11, - Linewidth = Nubwidth*2+4, -}; - -uint -drawtext(char *s, Image *m, Image *clipr, Point o) -{ - char *t, *nt, *e; - uint dy; - - if(s == nil) - s = "???"; - - dy = 0; - for(t=s; t&&*t; t=nt){ - if(nt = strchr(t, '\n')){ - e = nt; - nt++; - }else - e = t+strlen(t); - - _string(m, Pt(o.x, o.y+dy), display->black, ZP, display->defaultfont, - t, nil, e-t, clipr->clipr, nil, ZP, SoverD); - dy += display->defaultfont->height; - } - return dy; -} - -void -drawnub(Image *m, Image *clipr, Point o, Tnode *t) -{ - clipr = nil; - - if(t->nkid == 0) - return; - if(t->nkid == -1 && t->expand == nil) - return; - - o.y += (display->defaultfont->height-Nubheight)/2; - draw(m, rectaddpt(Rect(0,0,1,Nubheight), o), display->black, clipr, ZP); - draw(m, rectaddpt(Rect(0,0,Nubwidth,1), o), display->black, clipr, o); - draw(m, rectaddpt(Rect(Nubwidth-1,0,Nubwidth,Nubheight), o), - display->black, clipr, addpt(o, Pt(Nubwidth-1, 0))); - draw(m, rectaddpt(Rect(0, Nubheight-1, Nubwidth, Nubheight), o), - display->black, clipr, addpt(o, Pt(0, Nubheight-1))); - - draw(m, rectaddpt(Rect(0, Nubheight/2, Nubwidth, Nubheight/2+1), o), - display->black, clipr, addpt(o, Pt(0, Nubheight/2))); - if(!t->expanded) - draw(m, rectaddpt(Rect(Nubwidth/2, 0, Nubwidth/2+1, Nubheight), o), - display->black, clipr, addpt(o, Pt(Nubwidth/2, 0))); - -} - -uint -drawnode(Tnode *t, Image *m, Image *clipr, Point o) -{ - int i; - char *fs, *s; - uint dy; - Point oo; - - if(t == nil) - return 0; - - t->offset = o; - - oo = Pt(o.x+Nubwidth+2, o.y); -// if(t->draw) -// dy = (*t->draw)(t, m, clipr, oo); -// else{ - fs = nil; - if(t->str) - s = t->str; - // else if(t->strfn) - // fs = s = (*t->strfn)(t); - else - s = "???"; - dy = drawtext(s, m, clipr, oo); - free(fs); -// } - - if(t->expanded){ - if(t->nkid == -1 && t->expand) - (*t->expand)(t); - oo = Pt(o.x+Nubwidth+(Linewidth-Nubwidth)/2, o.y+dy); - for(i=0; i<t->nkid; i++) - oo.y += drawnode(t->kid[i], m, clipr, oo); - dy = oo.y - o.y; - } - drawnub(m, clipr, o, t); - return dy; -} - -void -drawtree(Tree *t, Image *m, Rectangle r) -{ - Point p; - - draw(m, r, display->white, nil, ZP); - - replclipr(t->clipr, 1, r); - p = addpt(t->offset, r.min); - drawnode(t->root, m, t->clipr, p); -} - -Tnode* -findnode(Tnode *t, Point p) -{ - int i; - Tnode *tt; - - if(ptinrect(p, rectaddpt(Rect(0,0,Nubwidth, Nubheight), t->offset))) - return t; - if(!t->expanded) - return nil; - for(i=0; i<t->nkid; i++) - if(tt = findnode(t->kid[i], p)) - return tt; - return nil; -} - -void -usage(void) -{ - fprint(2, "usage: vtree /dev/sdC0/fossil\n"); - exits("usage"); -} - -Tree t; - -void -eresized(int new) -{ - Rectangle r; - r = screen->r; - if(new && getwindow(display, Refnone) < 0) - fprint(2,"can't reattach to window"); - drawtree(&t, screen, screen->r); -} - -enum -{ - Left = 1<<0, - Middle = 1<<1, - Right = 1<<2, - - MMenu = 2, -}; - -char *items[] = { "exit", 0 }; -enum { IExit, }; - -Menu menu; - -void -main(int argc, char **argv) -{ - int n; - char *dir; - Event e; - Point op, p; - Tnode *tn; - Mouse m; - int Eready; - Atree *fs; - - ARGBEGIN{ - case 'a': - showinactive = 1; - break; - default: - usage(); - }ARGEND - - switch(argc){ - default: - usage(); - case 1: - dir = argv[0]; - break; - } - - fs = atreeinit(dir); - initdraw(0, "/lib/font/bit/lucidasans/unicode.8.font", "tree"); - t.root = fs->root; - t.offset = ZP; - t.clipr = allocimage(display, Rect(0,0,1,1), GREY1, 1, DOpaque); - - eresized(0); - flushimage(display, 1); - - einit(Emouse); - - menu.item = items; - menu.gen = 0; - menu.lasthit = 0; - if(fs->resizefd > 0){ - Eready = 1<<3; - estart(Eready, fs->resizefd, 1); - }else - Eready = 0; - - for(;;){ - switch(n=eread(Emouse|Eready, &e)){ - default: - if(Eready && n==Eready) - eresized(0); - break; - case Emouse: - m = e.mouse; - switch(m.buttons){ - case Left: - op = t.offset; - p = m.xy; - do { - t.offset = addpt(t.offset, subpt(m.xy, p)); - p = m.xy; - eresized(0); - m = emouse(); - }while(m.buttons == Left); - if(m.buttons){ - t.offset = op; - eresized(0); - } - break; - case Middle: - n = emenuhit(MMenu, &m, &menu); - if(n == -1) - break; - switch(n){ - case IExit: - exits(nil); - } - break; - case Right: - do - m = emouse(); - while(m.buttons == Right); - if(m.buttons) - break; - tn = findnode(t.root, m.xy); - if(tn){ - tn->expanded = !tn->expanded; - eresized(0); - } - break; - } - } - } -} diff --git a/sys/src/cmd/fossil/walk.c b/sys/src/cmd/fossil/walk.c deleted file mode 100644 index 802af640e..000000000 --- a/sys/src/cmd/fossil/walk.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Generic traversal routines. - */ - -#include "stdinc.h" -#include "dat.h" -#include "fns.h" - -static uint -etype(Entry *e) -{ - uint t; - - if(e->flags&VtEntryDir) - t = BtDir; - else - t = BtData; - return t+e->depth; -} - -void -initWalk(WalkPtr *w, Block *b, uint size) -{ - memset(w, 0, sizeof *w); - switch(b->l.type){ - case BtData: - return; - - case BtDir: - w->data = b->data; - w->m = size / VtEntrySize; - w->isEntry = 1; - return; - - default: - w->data = b->data; - w->m = size / VtScoreSize; - w->type = b->l.type; - w->tag = b->l.tag; - return; - } -} - -int -nextWalk(WalkPtr *w, uchar score[VtScoreSize], uchar *type, u32int *tag, Entry **e) -{ - if(w->n >= w->m) - return 0; - - if(w->isEntry){ - *e = &w->e; - entryUnpack(&w->e, w->data, w->n); - memmove(score, w->e.score, VtScoreSize); - *type = etype(&w->e); - *tag = w->e.tag; - }else{ - *e = nil; - memmove(score, w->data+w->n*VtScoreSize, VtScoreSize); - *type = w->type-1; - *tag = w->tag; - } - w->n++; - return 1; -} - |