📄 paqfs.c
字号:
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <bio.h>#include <mp.h>#include <libsec.h>#include <flate.h>#include "paqfs.h"enum{ OPERM = 0x3, /* mask of all permission types in open mode */ OffsetSize = 4, /* size in bytes of an offset */};typedef struct Fid Fid;typedef struct Paq Paq;typedef struct Block Block;struct Fid{ short busy; short open; int fid; char *user; ulong offset; /* for directory reading */ Paq *paq; Fid *next;};struct Paq{ int ref; Paq *up; PaqDir *dir; Qid qid;};struct Block{ int ref; ulong addr; /* block byte address */ ulong age; uchar *data;};enum{ Pexec = 1, Pwrite = 2, Pread = 4, Pother = 1, Pgroup = 8, Powner = 64,};int noauth;Fid *fids;Fcall rhdr, thdr;int blocksize;int cachesize = 20;int mesgsize = 8*1024 + IOHDRSZ;Paq *root, *rootfile;Block *cache;ulong cacheage;Biobuf *bin;Fid * newfid(int);void paqstat(PaqDir*, char*);void io(int fd);void *erealloc(void*, ulong);void *emalloc(ulong);void *emallocz(ulong n);char *estrdup(char*);void usage(void);ulong getl(uchar *p);int gets(uchar *p);char *getstr(uchar *p);PaqDir *getDir(uchar*);void getHeader(uchar *p, PaqHeader *b);void getBlock(uchar *p, PaqBlock *b);void getTrailer(uchar *p, PaqTrailer *b);void init(char*, int);void paqDirFree(PaqDir*);Qid paqDirQid(PaqDir *d);Paq *paqCpy(Paq *s);Paq *paqLookup(Paq *s, char *name);void paqFree(Paq*);Paq *paqWalk(Paq *s, char *name);int perm(PaqDir *s, char *user, int p);int dirRead(Fid*, uchar*, int);Block *blockLoad(ulong addr, int type);void blockFree(Block*);int checkDirSize(uchar *p, uchar *ep);int packDir(PaqDir*, uchar*, int);int blockRead(uchar *data, ulong addr, int type);void readHeader(PaqHeader *hdr, char *name, DigestState *ds);void readBlocks(char *name, DigestState *ds);void readTrailer(PaqTrailer *tlr, char *name, DigestState *ds);char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);char *(*fcalls[])(Fid*) = { [Tflush] rflush, [Tversion] rversion, [Tattach] rattach, [Tauth] rauth, [Twalk] rwalk, [Topen] ropen, [Tcreate] rcreate, [Tread] rread, [Twrite] rwrite, [Tclunk] rclunk, [Tremove] rremove, [Tstat] rstat, [Twstat] rwstat,};char Eperm[] = "permission denied";char Enotdir[] = "not a directory";char Enoauth[] = "authentication not required";char Enotexist[] = "file does not exist";char Einuse[] = "file in use";char Eexist[] = "file exists";char Enotowner[] = "not owner";char Eisopen[] = "file already open for I/O";char Excl[] = "exclusive use file already open";char Ename[] = "illegal name";char Erdonly[] = "read only file system";char Ebadblock[] = "bad block";char Eversion[] = "bad version of P9";char Edirtoobig[] = "directory entry too big";int debug;voidmain(int argc, char *argv[]){ char *defmnt, *p; int pfd[2]; int fd; int stdio = 0; int verify = 0; defmnt = "/n/paq"; ARGBEGIN{ case 'c': p = ARGF(); if(p == nil) usage(); cachesize = atoi(p); break; case 'a': noauth = 1; break; case 'v': verify = 1; break; case 'd': debug = 1; break; case 'i': defmnt = nil; stdio = 1; pfd[0] = 0; pfd[1] = 1; break; case 's': defmnt = nil; break; case 'm': defmnt = ARGF(); if(defmnt == nil) usage(); break; case 'M': p = ARGF(); if(p == nil) usage(); mesgsize = atoi(p); if(mesgsize < 512) mesgsize = 512; if(mesgsize > 128*1024) mesgsize = 128*1024; break; default: usage(); }ARGEND if(argc != 1) usage(); init(argv[0], verify); if(!stdio){ if(pipe(pfd) < 0) sysfatal("pipe failed"); if(defmnt == 0){ fd = create("#s/paqfs", OWRITE, 0666); if(fd < 0) sysfatal("create of /srv/paqfs failed"); if(fprint(fd, "%d", pfd[0]) < 0) sysfatal("writing /srv/paqfs"); } } if(debug) fmtinstall('F', fcallfmt); switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ case -1: sysfatal("fork"); case 0: close(pfd[0]); io(pfd[1]); break; default: close(pfd[1]); /* don't deadlock if child fails */ if(defmnt && mount(pfd[0], -1, defmnt, MREPL|MCREATE, "") < 0) sysfatal("mount failed"); } exits(0);}char*rversion(Fid*){ Fid *f; for(f = fids; f; f = f->next) if(f->busy) rclunk(f); if(rhdr.msize > mesgsize) thdr.msize = mesgsize; else thdr.msize = rhdr.msize; if(strcmp(rhdr.version, "9P2000") != 0) return Eversion; thdr.version = "9P2000"; return 0;}char*rauth(Fid*){ return Enoauth;}char*rflush(Fid *f){ USED(f); return 0;}char*rattach(Fid *f){ /* no authentication! */ f->busy = 1; f->paq = paqCpy(root); thdr.qid = f->paq->qid; if(rhdr.uname[0]) f->user = estrdup(rhdr.uname); else f->user = "none"; return 0;}char*clone(Fid *f, Fid **res){ Fid *nf; if(f->open) return Eisopen; if(f->busy == 0) return Enotexist; nf = newfid(rhdr.newfid); nf->busy = 1; nf->open = 0; nf->paq = paqCpy(f->paq); nf->user = strdup(f->user); *res = nf; return 0;}char*rwalk(Fid *f){ Paq *paq, *npaq; Fid *nf; int nqid, nwname; Qid qid; char *err; if(f->busy == 0) return Enotexist; nf = nil; if(rhdr.fid != rhdr.newfid){ err = clone(f, &nf); if(err) return err; f = nf; /* walk the new fid */ } nwname = rhdr.nwname; /* easy case */ if(nwname == 0) { thdr.nwqid = 0; return 0; } paq = paqCpy(f->paq); qid = paq->qid; err = nil; for(nqid = 0; nqid < nwname; nqid++){ if((qid.type & QTDIR) == 0){ err = Enotdir; break; } if(!perm(paq->dir, f->user, Pexec)) { err = Eperm; break; } npaq = paqWalk(paq, rhdr.wname[nqid]); if(npaq == nil) { err = Enotexist; break; } paqFree(paq); paq = npaq; qid = paq->qid; thdr.wqid[nqid] = qid; } thdr.nwqid = nqid; if(nqid == nwname){ /* success */ paqFree(f->paq); f->paq = paq; return 0; } paqFree(paq); if(nf != nil) rclunk(nf); /* only error on the first element */ if(nqid == 0) return err; return 0;}char *ropen(Fid *f){ int mode, trunc; if(f->open) return Eisopen; if(f->busy == 0) return Enotexist; mode = rhdr.mode; if(f->paq->qid.type & QTDIR){ if(mode != OREAD) return Eperm; thdr.qid = f->paq->qid; return 0; } if(mode & ORCLOSE) return Erdonly; trunc = mode & OTRUNC; mode &= OPERM; if(mode==OWRITE || mode==ORDWR || trunc) return Erdonly; if(mode==OREAD) if(!perm(f->paq->dir, f->user, Pread)) return Eperm; if(mode==OEXEC) if(!perm(f->paq->dir, f->user, Pexec)) return Eperm; thdr.qid = f->paq->qid; f->open = 1; return 0;}char *rcreate(Fid *f){ if(f->open) return Eisopen; if(f->busy == 0) return Enotexist; return Erdonly;}char *readdir(Fid *f){ PaqDir *pd; uchar *p, *ep; ulong off; int n, cnt, i; uchar *buf; Block *ptr, *b; buf = (uchar*)thdr.data; cnt = rhdr.count; if(rhdr.offset == 0) f->offset = 0; off = f->offset; if(rootfile && f->paq == root){ if(off != 0){ rhdr.count = 0; return nil; } n = packDir(rootfile->dir, buf, cnt); rhdr.count = n; return nil; } ptr = blockLoad(f->paq->dir->offset, PointerBlock); if(ptr == nil) return Ebadblock; i = off/blocksize; off -= i*blocksize; thdr.count = 0; b = blockLoad(getl(ptr->data + i*4), DirBlock); while(b != nil) { p = b->data + off; ep = b->data + blocksize; if(checkDirSize(p, ep)) { pd = getDir(p); n = packDir(pd, buf, cnt); paqDirFree(pd); if(n == 0) { blockFree(b); if(thdr.count == 0) { blockFree(ptr); return Edirtoobig; } break; } off += gets(p); cnt -= n; buf += n; thdr.count += n; } else { off = 0; i++; blockFree(b); b = blockLoad(getl(ptr->data + i*4), DataBlock); } } f->offset = i*blocksize + off; blockFree(ptr); return 0;}char*rread(Fid *f){ PaqDir *pd; uchar *buf; vlong off; ulong uoff; int n, cnt, i; Block *ptr, *b; if(f->busy == 0) return Enotexist; if(f->paq->qid.type & QTDIR) return readdir(f); pd = f->paq->dir; off = rhdr.offset; buf = (uchar*)thdr.data; cnt = rhdr.count; thdr.count = 0; if(off >= pd->length || cnt == 0) return 0; if(cnt > pd->length - off) cnt = pd->length - off; ptr = blockLoad(pd->offset, PointerBlock); if(ptr == nil) return Ebadblock; i = off/blocksize; uoff = off-i*blocksize; while(cnt > 0) { b = blockLoad(getl(ptr->data + i*4), DataBlock); if(b == nil) { blockFree(ptr); return Ebadblock; } n = blocksize - uoff; if(n > cnt) n = cnt; memmove(buf, b->data + uoff, n); cnt -= n; thdr.count += n; buf += n; uoff = 0; i++; blockFree(b); } blockFree(ptr); return 0;}char*rwrite(Fid *f){ if(f->busy == 0) return Enotexist; return Erdonly;}char *rclunk(Fid *f){ f->busy = 0; f->open = 0; free(f->user); paqFree(f->paq); return 0;}char *rremove(Fid *f){ rclunk(f); return Erdonly;}char *rstat(Fid *f){ if(f->busy == 0) return Enotexist; thdr.stat = (uchar*)thdr.data; thdr.nstat = packDir(f->paq->dir, thdr.stat, mesgsize); if(thdr.nstat == 0) return Edirtoobig; return 0;}char *rwstat(Fid *f){ if(f->busy == 0) return Enotexist; return Erdonly;}Paq*paqCpy(Paq *s){ s->ref++; return s;}voidpaqFree(Paq *p){ if(p == nil) return; p->ref--; if(p->ref > 0) return;assert(p != root); paqFree(p->up); paqDirFree(p->dir); free(p);}void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -