123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861 |
- #include "stdinc.h"
- #include <auth.h>
- #include <fcall.h>
- #include "vac.h"
- typedef struct Fid Fid;
- typedef struct DirBuf DirBuf;
- enum
- {
- OPERM = 0x3, /* mask of all permission types in open mode */
- };
- enum
- {
- DirBufSize = 20,
- };
- struct Fid
- {
- short busy;
- short open;
- int fid;
- char *user;
- Qid qid;
- VacFile *file;
- DirBuf *db;
- Fid *next;
- };
- struct DirBuf
- {
- VacDirEnum *vde;
- VacDir buf[DirBufSize];
- int i, n;
- int eof;
- };
- enum
- {
- Pexec = 1,
- Pwrite = 2,
- Pread = 4,
- Pother = 1,
- Pgroup = 8,
- Powner = 64,
- };
- Fid *fids;
- uchar *data;
- int mfd[2];
- char *user;
- uchar mdata[8192+IOHDRSZ];
- int messagesize = sizeof mdata;
- Fcall rhdr;
- Fcall thdr;
- VacFS *fs;
- VtSession *session;
- int noperm;
- Fid * newfid(int);
- void error(char*);
- void io(void);
- void shutdown(void);
- void usage(void);
- int perm(Fid*, int);
- int permf(VacFile*, char*, int);
- ulong getl(void *p);
- void init(char*, char*, long, int);
- DirBuf *dirBufAlloc(VacFile*);
- VacDir *dirBufGet(DirBuf*);
- int dirBufUnget(DirBuf*);
- void dirBufFree(DirBuf*);
- int vacdirread(Fid *f, char *p, long off, long cnt);
- int vdStat(VacDir *vd, uchar *p, int np);
- 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 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 Eio[] = "i/o error";
- char Eempty[] = "directory is not empty";
- char Emode[] = "illegal mode";
- int dflag;
- void
- notifyf(void *a, char *s)
- {
- USED(a);
- if(strncmp(s, "interrupt", 9) == 0)
- noted(NCONT);
- noted(NDFLT);
- }
- void
- main(int argc, char *argv[])
- {
- char *defmnt, *defsrv, *srv;
- int p[2];
- char buf[12];
- int fd;
- int stdio = 0;
- char *host = nil;
- long ncache = 1000;
- int readOnly = 1;
- defmnt = "/n/vac";
- defsrv = "vacfs";
- ARGBEGIN{
- case 'd':
- fmtinstall('F', fcallfmt);
- dflag = 1;
- break;
- case 'c':
- ncache = atoi(ARGF());
- break;
- case 'i':
- defmnt = nil;
- stdio = 1;
- mfd[0] = 0;
- mfd[1] = 1;
- break;
- case 'h':
- host = ARGF();
- break;
- case 'S':
- defsrv = ARGF();
- /*FALLTHROUGH*/
- case 's':
- defmnt = nil;
- break;
- case 'p':
- noperm = 1;
- break;
- case 'm':
- defmnt = ARGF();
- break;
- default:
- usage();
- }ARGEND
- if(argc != 1)
- usage();
- vtAttach();
- init(argv[0], host, ncache, readOnly);
- if(pipe(p) < 0)
- sysfatal("pipe failed: %r");
- if(!stdio){
- mfd[0] = p[0];
- mfd[1] = p[0];
- if(defmnt == 0){
- srv = smprint("/srv/%s", defsrv);
- fd = create(srv, OWRITE, 0666);
- if(fd < 0)
- sysfatal("create of %s failed: %r", srv);
- sprint(buf, "%d", p[1]);
- if(write(fd, buf, strlen(buf)) < 0)
- sysfatal("writing %s: %r", srv);
- free(srv);
- }
- }
- switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
- case -1:
- sysfatal("fork: %r");
- case 0:
- vtAttach();
- close(p[1]);
- io();
- shutdown();
- break;
- default:
- close(p[0]); /* don't deadlock if child fails */
- if(defmnt && mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0)
- sysfatal("mount failed: %r");
- }
- vtDetach();
- exits(0);
- }
- void
- usage(void)
- {
- fprint(2, "usage: %s [-dips]"
- " [-c ncache]"
- " [-h host]"
- " [-m mountpoint]"
- " [-S srvname]"
- " vacfile\n", argv0);
- exits("usage");
- }
- char*
- rversion(Fid *unused)
- {
- Fid *f;
- USED(unused);
- for(f = fids; f; f = f->next)
- if(f->busy)
- rclunk(f);
- if(rhdr.msize < 256)
- return "version: message size too small";
- messagesize = rhdr.msize;
- if(messagesize > sizeof mdata)
- messagesize = sizeof mdata;
- thdr.msize = messagesize;
- if(strncmp(rhdr.version, "9P2000", 6) != 0)
- return "unrecognized 9P version";
- thdr.version = "9P2000";
- return nil;
- }
- char*
- rflush(Fid *f)
- {
- USED(f);
- return 0;
- }
- char*
- rauth(Fid *f)
- {
- USED(f);
- return "vacfs: authentication not required";
- }
- char*
- rattach(Fid *f)
- {
- /* no authentication for the momment */
- VacFile *file;
- file = vfsGetRoot(fs);
- if(file == nil)
- return vtGetError();
- f->busy = 1;
- f->file = file;
- f->qid = (Qid){vfGetId(f->file), 0, QTDIR};
- thdr.qid = f->qid;
- if(rhdr.uname[0])
- f->user = vtStrDup(rhdr.uname);
- else
- f->user = "none";
- return 0;
- }
- VacFile*
- _vfWalk(VacFile *file, char *name)
- {
- VacFile *n;
- n = vfWalk(file, name);
- if(n)
- return n;
- if(strcmp(name, "SLASH") == 0)
- return vfWalk(file, "/");
- return nil;
- }
- char*
- rwalk(Fid *f)
- {
- VacFile *file, *nfile;
- Fid *nf;
- int nqid, nwname;
- Qid qid;
- if(f->busy == 0)
- return Enotexist;
- nf = nil;
- if(rhdr.fid != rhdr.newfid){
- if(f->open)
- return Eisopen;
- if(f->busy == 0)
- return Enotexist;
- nf = newfid(rhdr.newfid);
- if(nf->busy)
- return Eisopen;
- nf->busy = 1;
- nf->open = 0;
- nf->qid = f->qid;
- nf->file = vfIncRef(f->file);
- nf->user = vtStrDup(f->user);
- f = nf;
- }
- nwname = rhdr.nwname;
- /* easy case */
- if(nwname == 0) {
- thdr.nwqid = 0;
- return 0;
- }
- file = f->file;
- vfIncRef(file);
- qid = f->qid;
- for(nqid = 0; nqid < nwname; nqid++){
- if((qid.type & QTDIR) == 0){
- vtSetError(Enotdir);
- break;
- }
- if(!permf(file, f->user, Pexec)) {
- vtSetError(Eperm);
- break;
- }
- nfile = _vfWalk(file, rhdr.wname[nqid]);
- if(nfile == nil)
- break;
- vfDecRef(file);
- file = nfile;
- qid.type = QTFILE;
- if(vfIsDir(file))
- qid.type = QTDIR;
- qid.vers = vfGetMcount(file);
- qid.path = vfGetId(file);
- thdr.wqid[nqid] = qid;
- }
- thdr.nwqid = nqid;
- if(nqid == nwname){
- /* success */
- f->qid = thdr.wqid[nqid-1];
- vfDecRef(f->file);
- f->file = file;
- return 0;
- }
- vfDecRef(file);
- if(nf != nil)
- rclunk(nf);
- /* only error on the first element */
- if(nqid == 0)
- return vtGetError();
- return 0;
- }
- char *
- ropen(Fid *f)
- {
- int mode, trunc;
- if(f->open)
- return Eisopen;
- if(!f->busy)
- return Enotexist;
- mode = rhdr.mode;
- thdr.iounit = messagesize - IOHDRSZ;
- if(f->qid.type & QTDIR){
- if(mode != OREAD)
- return Eperm;
- if(!perm(f, Pread))
- return Eperm;
- thdr.qid = f->qid;
- f->db = nil;
- f->open = 1;
- return 0;
- }
- if(mode & ORCLOSE)
- return Erdonly;
- trunc = mode & OTRUNC;
- mode &= OPERM;
- if(mode==OWRITE || mode==ORDWR || trunc)
- if(!perm(f, Pwrite))
- return Eperm;
- if(mode==OREAD || mode==ORDWR)
- if(!perm(f, Pread))
- return Eperm;
- if(mode==OEXEC)
- if(!perm(f, Pexec))
- return Eperm;
- thdr.qid = f->qid;
- thdr.iounit = messagesize - IOHDRSZ;
- f->open = 1;
- return 0;
- }
- char*
- rcreate(Fid* fid)
- {
- VacFile *vf;
- ulong mode;
- if(fid->open)
- return Eisopen;
- if(!fid->busy)
- return Enotexist;
- if(vfsIsReadOnly(fs))
- return Erdonly;
- vf = fid->file;
- if(!vfIsDir(vf))
- return Enotdir;
- if(!permf(vf, fid->user, Pwrite))
- return Eperm;
- mode = rhdr.perm & 0777;
- if(rhdr.perm & DMDIR){
- if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
- return Emode;
- switch(rhdr.mode & OPERM){
- default:
- return Emode;
- case OEXEC:
- case OREAD:
- break;
- case OWRITE:
- case ORDWR:
- return Eperm;
- }
- mode |= ModeDir;
- }
- vf = vfCreate(vf, rhdr.name, mode, "none");
- if(vf == nil)
- return vtGetError();
- vfDecRef(fid->file);
- fid->file = vf;
- fid->qid.type = QTFILE;
- if(vfIsDir(vf))
- fid->qid.type = QTDIR;
- fid->qid.vers = vfGetMcount(vf);
- fid->qid.path = vfGetId(vf);
- thdr.qid = fid->qid;
- thdr.iounit = messagesize - IOHDRSZ;
- return 0;
- }
- char*
- rread(Fid *f)
- {
- char *buf;
- vlong off;
- int cnt;
- VacFile *vf;
- char *err;
- int n;
- if(!f->busy)
- return Enotexist;
- vf = f->file;
- thdr.count = 0;
- off = rhdr.offset;
- buf = thdr.data;
- cnt = rhdr.count;
- if(f->qid.type & QTDIR)
- n = vacdirread(f, buf, off, cnt);
- else
- n = vfRead(vf, buf, cnt, off);
- if(n < 0) {
- err = vtGetError();
- if(err == nil)
- err = "unknown error!";
- return err;
- }
- thdr.count = n;
- return 0;
- }
- char*
- rwrite(Fid *f)
- {
- char *buf;
- vlong off;
- int cnt;
- VacFile *vf;
- if(!f->busy)
- return Enotexist;
- vf = f->file;
- thdr.count = 0;
- off = rhdr.offset;
- buf = rhdr.data;
- cnt = rhdr.count;
- if(f->qid.type & QTDIR)
- return "file is a directory";
- cnt = vfWrite(vf, buf, cnt, off, "none");
- if(cnt < 0) {
- fprint(2, "write failed: %s\n", vtGetError());
- return vtGetError();
- }
- thdr.count = cnt;
- return 0;
- }
- char *
- rclunk(Fid *f)
- {
- f->busy = 0;
- f->open = 0;
- vtMemFree(f->user);
- f->user = nil;
- vfDecRef(f->file);
- f->file = nil;
- dirBufFree(f->db);
- f->db = nil;
- return 0;
- }
- char *
- rremove(Fid *f)
- {
- VacFile *vf, *vfp;
- char *err = nil;
- if(!f->busy)
- return Enotexist;
- vf = f->file;
- vfp = vfGetParent(vf);
- if(!permf(vfp, f->user, Pwrite)) {
- err = Eperm;
- goto Exit;
- }
- if(!vfRemove(vf, "none")) {
- print("vfRemove failed\n");
- err = vtGetError();
- }
- Exit:
- vfDecRef(vfp);
- rclunk(f);
- return err;
- }
- char *
- rstat(Fid *f)
- {
- VacDir dir;
- static uchar statbuf[1024];
- if(!f->busy)
- return Enotexist;
- vfGetDir(f->file, &dir);
- thdr.stat = statbuf;
- thdr.nstat = vdStat(&dir, thdr.stat, sizeof statbuf);
- vdCleanup(&dir);
- return 0;
- }
- char *
- rwstat(Fid *f)
- {
- if(!f->busy)
- return Enotexist;
- return Erdonly;
- }
- int
- vdStat(VacDir *vd, uchar *p, int np)
- {
- Dir dir;
- memset(&dir, 0, sizeof(dir));
- /*
- * Where do path and version come from
- */
- dir.qid.path = vd->qid;
- dir.qid.vers = vd->mcount;
- dir.mode = vd->mode & 0777;
- if(vd->mode & ModeAppend){
- dir.qid.type |= QTAPPEND;
- dir.mode |= DMAPPEND;
- }
- if(vd->mode & ModeExclusive){
- dir.qid.type |= QTEXCL;
- dir.mode |= DMEXCL;
- }
- if(vd->mode & ModeDir){
- dir.qid.type |= QTDIR;
- dir.mode |= DMDIR;
- }
- dir.atime = vd->atime;
- dir.mtime = vd->mtime;
- dir.length = vd->size;
- dir.name = vd->elem;
- dir.uid = vd->uid;
- dir.gid = vd->gid;
- dir.muid = vd->mid;
- return convD2M(&dir, p, np);
- }
- DirBuf*
- dirBufAlloc(VacFile *vf)
- {
- DirBuf *db;
- db = vtMemAllocZ(sizeof(DirBuf));
- db->vde = vfDirEnum(vf);
- return db;
- }
- VacDir *
- dirBufGet(DirBuf *db)
- {
- VacDir *vd;
- int n;
- if(db->eof)
- return nil;
- if(db->i >= db->n) {
- n = vdeRead(db->vde, db->buf, DirBufSize);
- if(n < 0)
- return nil;
- db->i = 0;
- db->n = n;
- if(n == 0) {
- db->eof = 1;
- return nil;
- }
- }
- vd = db->buf + db->i;
- db->i++;
- return vd;
- }
- int
- dirBufUnget(DirBuf *db)
- {
- assert(db->i > 0);
- db->i--;
- return 1;
- }
- void
- dirBufFree(DirBuf *db)
- {
- int i;
- if(db == nil)
- return;
- for(i=db->i; i<db->n; i++)
- vdCleanup(db->buf + i);
- vdeFree(db->vde);
- vtMemFree(db);
- }
- int
- vacdirread(Fid *f, char *p, long off, long cnt)
- {
- int n, nb;
- VacDir *vd;
- /*
- * special case of rewinding a directory
- * otherwise ignore the offset
- */
- if(off == 0 && f->db) {
- dirBufFree(f->db);
- f->db = nil;
- }
- if(f->db == nil)
- f->db = dirBufAlloc(f->file);
- for(nb = 0; nb < cnt; nb += n) {
- vd = dirBufGet(f->db);
- if(vd == nil) {
- if(!f->db->eof)
- return -1;
- break;
- }
- n = vdStat(vd, (uchar*)p, cnt-nb);
- if(n <= BIT16SZ) {
- dirBufUnget(f->db);
- break;
- }
- vdCleanup(vd);
- p += n;
- }
- return nb;
- }
- Fid *
- newfid(int fid)
- {
- Fid *f, *ff;
- ff = 0;
- for(f = fids; f; f = f->next)
- if(f->fid == fid)
- return f;
- else if(!ff && !f->busy)
- ff = f;
- if(ff){
- ff->fid = fid;
- return ff;
- }
- f = vtMemAllocZ(sizeof *f);
- f->fid = fid;
- f->next = fids;
- fids = f;
- return f;
- }
- void
- io(void)
- {
- char *err;
- int n;
- for(;;){
- /*
- * reading from a pipe or a network device
- * will give an error after a few eof reads
- * however, we cannot tell the difference
- * between a zero-length read and an interrupt
- * on the processes writing to us,
- * so we wait for the error
- */
- n = read9pmsg(mfd[0], mdata, sizeof mdata);
- if(n == 0)
- continue;
- if(n < 0)
- break;
- if(convM2S(mdata, n, &rhdr) != n)
- sysfatal("convM2S conversion error");
- if(dflag)
- fprint(2, "vacfs:<-%F\n", &rhdr);
- thdr.data = (char*)mdata + IOHDRSZ;
- if(!fcalls[rhdr.type])
- err = "bad fcall type";
- else
- err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
- if(err){
- thdr.type = Rerror;
- thdr.ename = err;
- }else{
- thdr.type = rhdr.type + 1;
- thdr.fid = rhdr.fid;
- }
- thdr.tag = rhdr.tag;
- if(dflag)
- fprint(2, "vacfs:->%F\n", &thdr);
- n = convS2M(&thdr, mdata, messagesize);
- if(write(mfd[1], mdata, n) != n)
- sysfatal("mount write: %r");
- }
- }
- int
- permf(VacFile *vf, char *user, int p)
- {
- int ok = 1;
- VacDir dir;
- ulong perm;
- if(!vfGetDir(vf, &dir))
- return 0;
- perm = dir.mode & 0777;
- if(noperm)
- goto Good;
- if((p*Pother) & perm)
- goto Good;
- if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
- goto Good;
- if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
- goto Good;
- ok = 0;
- Good:
- vdCleanup(&dir);
- return ok;
- }
- int
- perm(Fid *f, int p)
- {
- return permf(f->file, f->user, p);
- }
- void
- init(char *file, char *host, long ncache, int readOnly)
- {
- notify(notifyf);
- user = getuser();
- fmtinstall('V', vtScoreFmt);
- fmtinstall('R', vtErrFmt);
- session = vtDial(host, 0);
- if(session == nil)
- vtFatal("could not connect to server: %s", vtGetError());
- if(!vtConnect(session, 0))
- vtFatal("vtConnect: %s", vtGetError());
- fs = vfsOpen(session, file, readOnly, ncache);
- if(fs == nil)
- vtFatal("vfsOpen: %s", vtGetError());
- }
- void
- shutdown(void)
- {
- Fid *f;
- for(f = fids; f; f = f->next) {
- if(!f->busy)
- continue;
- fprint(2, "open fid: %d\n", f->fid);
- rclunk(f);
- }
- vfsClose(fs);
- vtClose(session);
- }
|