123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600 |
- #include <u.h>
- #include <libc.h>
- #include <authsrv.h>
- #include <fcall.h>
- #include <tapefs.h>
- Fid *fids;
- Ram *ram;
- int mfd[2];
- char *user;
- uchar mdata[Maxbuf+IOHDRSZ];
- int messagesize = Maxbuf+IOHDRSZ;
- Fcall rhdr;
- Fcall thdr;
- ulong path;
- Idmap *uidmap;
- Idmap *gidmap;
- int replete;
- int verbose;
- int newtap; /* tap with time in sec */
- Fid * newfid(int);
- int ramstat(Ram*, uchar*, int);
- void io(void);
- void usage(void);
- int perm(int);
- 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,
- [Tauth] rauth,
- [Tattach] rattach,
- [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[] = "tapefs: 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";
- void
- notifyf(void *a, char *s)
- {
- USED(a);
- if(strncmp(s, "interrupt", 9) == 0)
- noted(NCONT);
- noted(NDFLT);
- }
- void
- main(int argc, char *argv[])
- {
- Ram *r;
- char *defmnt;
- int p[2];
- char buf[TICKREQLEN];
- fmtinstall('F', fcallfmt);
- defmnt = "/n/tapefs";
- ARGBEGIN{
- case 'm':
- defmnt = ARGF();
- break;
- case 'p': /* password file */
- uidmap = getpass(ARGF());
- break;
- case 'g': /* group file */
- gidmap = getpass(ARGF());
- break;
- case 'v':
- verbose++;
- case 'n':
- newtap++;
- break;
- default:
- usage();
- }ARGEND
- if (argc==0)
- error("no file to mount");
- user = getuser();
- if(user == nil)
- user = "dmr";
- ram = r = (Ram *)emalloc(sizeof(Ram));
- r->busy = 1;
- r->data = 0;
- r->ndata = 0;
- r->perm = DMDIR | 0775;
- r->qid.path = 0;
- r->qid.vers = 0;
- r->qid.type = QTDIR;
- r->parent = 0;
- r->child = 0;
- r->next = 0;
- r->user = user;
- r->group = user;
- r->atime = time(0);
- r->mtime = r->atime;
- r->replete = 0;
- r->name = estrdup(".");
- populate(argv[0]);
- r->replete |= replete;
- if(pipe(p) < 0)
- error("pipe failed");
- mfd[0] = mfd[1] = p[0];
- notify(notifyf);
- switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
- case -1:
- error("fork");
- case 0:
- close(p[1]);
- notify(notifyf);
- io();
- break;
- default:
- close(p[0]); /* don't deadlock if child fails */
- if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0) {
- sprint(buf, "mount on `%s' failed", defmnt);
- error(buf);
- }
- }
- exits(0);
- }
- char*
- rversion(Fid *unused)
- {
- Fid *f;
- USED(unused);
- if(rhdr.msize < 256)
- return "version: message too small";
- if(rhdr.msize > messagesize)
- rhdr.msize = messagesize;
- else
- messagesize = rhdr.msize;
- thdr.msize = messagesize;
- if(strncmp(rhdr.version, "9P2000", 6) != 0)
- return "unrecognized 9P version";
- thdr.version = "9P2000";
- for(f = fids; f; f = f->next)
- if(f->busy)
- rclunk(f);
- return 0;
- }
- char*
- rauth(Fid *unused)
- {
- USED(unused);
- return Enoauth;
- }
- char*
- rflush(Fid *f)
- {
- USED(f);
- return 0;
- }
- char*
- rattach(Fid *f)
- {
- /* no authentication! */
- f->busy = 1;
- f->rclose = 0;
- f->ram = ram;
- thdr.qid = f->ram->qid;
- if(rhdr.uname[0])
- f->user = strdup(rhdr.uname);
- else
- f->user = "none";
- return 0;
- }
- char*
- rwalk(Fid *f)
- {
- Fid *nf;
- Ram *r;
- char *err;
- char *name;
- Ram *dir;
- int i;
- nf = nil;
- if(f->ram->busy == 0)
- return Enotexist;
- if(f->open)
- return Eisopen;
- if(rhdr.newfid != rhdr.fid){
- nf = newfid(rhdr.newfid);
- nf->busy = 1;
- nf->open = 0;
- nf->rclose = 0;
- nf->ram = f->ram;
- nf->user = f->user; /* no ref count; the leakage is minor */
- f = nf;
- }
- thdr.nwqid = 0;
- err = nil;
- r = f->ram;
- if(rhdr.nwname > 0){
- for(i=0; i<rhdr.nwname; i++){
- if((r->qid.type & QTDIR) == 0){
- err = Enotdir;
- break;
- }
- if(r->busy == 0){
- err = Enotexist;
- break;
- }
- r->atime = time(0);
- name = rhdr.wname[i];
- dir = r;
- if(!perm(Pexec)){
- err = Eperm;
- break;
- }
- if(strcmp(name, "..") == 0){
- r = dir->parent;
- Accept:
- if(i == MAXWELEM){
- err = "name too long";
- break;
- }
- thdr.wqid[thdr.nwqid++] = r->qid;
- continue;
- }
- if (!dir->replete)
- popdir(dir);
- for(r=dir->child; r; r=r->next)
- if(r->busy && strcmp(name, r->name)==0)
- goto Accept;
- break; /* file not found */
- }
- if(i==0 && err == nil)
- err = Enotexist;
- }
- if(err!=nil || thdr.nwqid<rhdr.nwname){
- if(nf){
- nf->busy = 0;
- nf->open = 0;
- nf->ram = 0;
- }
- }else if(thdr.nwqid == rhdr.nwname)
- f->ram = r;
- return err;
- }
- char *
- ropen(Fid *f)
- {
- Ram *r;
- int mode, trunc;
- if(f->open)
- return Eisopen;
- r = f->ram;
- if(r->busy == 0)
- return Enotexist;
- if(r->perm & DMEXCL)
- if(r->open)
- return Excl;
- mode = rhdr.mode;
- if(r->qid.type & QTDIR){
- if(mode != OREAD)
- return Eperm;
- thdr.qid = r->qid;
- return 0;
- }
- if(mode & ORCLOSE)
- return Eperm;
- trunc = mode & OTRUNC;
- mode &= OPERM;
- if(mode==OWRITE || mode==ORDWR || trunc)
- if(!perm(Pwrite))
- return Eperm;
- if(mode==OREAD || mode==ORDWR)
- if(!perm(Pread))
- return Eperm;
- if(mode==OEXEC)
- if(!perm(Pexec))
- return Eperm;
- if(trunc && (r->perm&DMAPPEND)==0){
- r->ndata = 0;
- dotrunc(r);
- r->qid.vers++;
- }
- thdr.qid = r->qid;
- thdr.iounit = messagesize-IOHDRSZ;
- f->open = 1;
- r->open++;
- return 0;
- }
- char *
- rcreate(Fid *f)
- {
- USED(f);
- return Eperm;
- }
- char*
- rread(Fid *f)
- {
- int i, len;
- Ram *r;
- char *buf;
- uvlong off, end;
- int n, cnt;
- if(f->ram->busy == 0)
- return Enotexist;
- n = 0;
- thdr.count = 0;
- off = rhdr.offset;
- end = rhdr.offset + rhdr.count;
- cnt = rhdr.count;
- if(cnt > messagesize-IOHDRSZ)
- cnt = messagesize-IOHDRSZ;
- buf = thdr.data;
- if(f->ram->qid.type & QTDIR){
- if (!f->ram->replete)
- popdir(f->ram);
- for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){
- if(!r->busy)
- continue;
- len = ramstat(r, (uchar*)buf+n, cnt-n);
- if(len <= BIT16SZ)
- break;
- if(i >= off)
- n += len;
- i += len;
- }
- thdr.count = n;
- return 0;
- }
- r = f->ram;
- if(off >= r->ndata)
- return 0;
- r->atime = time(0);
- n = cnt;
- if(off+n > r->ndata)
- n = r->ndata - off;
- thdr.data = doread(r, off, n);
- thdr.count = n;
- return 0;
- }
- char*
- rwrite(Fid *f)
- {
- Ram *r;
- ulong off;
- int cnt;
- r = f->ram;
- if (dopermw(f->ram)==0)
- return Eperm;
- if(r->busy == 0)
- return Enotexist;
- off = rhdr.offset;
- if(r->perm & DMAPPEND)
- off = r->ndata;
- cnt = rhdr.count;
- if(r->qid.type & QTDIR)
- return "file is a directory";
- if(off > 100*1024*1024) /* sanity check */
- return "write too big";
- dowrite(r, rhdr.data, off, cnt);
- r->qid.vers++;
- r->mtime = time(0);
- thdr.count = cnt;
- return 0;
- }
- char *
- rclunk(Fid *f)
- {
- if(f->open)
- f->ram->open--;
- f->busy = 0;
- f->open = 0;
- f->ram = 0;
- return 0;
- }
- char *
- rremove(Fid *f)
- {
- USED(f);
- return Eperm;
- }
- char *
- rstat(Fid *f)
- {
- if(f->ram->busy == 0)
- return Enotexist;
- thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);
- return 0;
- }
- char *
- rwstat(Fid *f)
- {
- if(f->ram->busy == 0)
- return Enotexist;
- return Eperm;
- }
- int
- ramstat(Ram *r, uchar *buf, int nbuf)
- {
- Dir dir;
- dir.name = r->name;
- dir.qid = r->qid;
- dir.mode = r->perm;
- dir.length = r->ndata;
- dir.uid = r->user;
- dir.gid = r->group;
- dir.muid = r->user;
- dir.atime = r->atime;
- dir.mtime = r->mtime;
- return convD2M(&dir, buf, nbuf);
- }
- 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;
- ff->open = 0;
- ff->busy = 1;
- }
- f = emalloc(sizeof *f);
- f->ram = 0;
- f->fid = fid;
- f->busy = 1;
- f->open = 0;
- f->next = fids;
- fids = f;
- return f;
- }
- void
- io(void)
- {
- char *err;
- int n, nerr;
- char buf[ERRMAX];
- errstr(buf, sizeof buf);
- for(nerr=0, buf[0]='\0'; nerr<100; nerr++){
- /*
- * 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){
- if (buf[0]=='\0')
- errstr(buf, sizeof buf);
- continue;
- }
- nerr = 0;
- buf[0] = '\0';
- if(convM2S(mdata, n, &rhdr) != n)
- error("convert error in convM2S");
- if(verbose)
- fprint(2, "tapefs: <=%F\n", &rhdr);/**/
- thdr.data = (char*)mdata + IOHDRSZ;
- thdr.stat = 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;
- n = convS2M(&thdr, mdata, messagesize);
- if(n <= 0)
- error("convert error in convS2M");
- if(verbose)
- fprint(2, "tapefs: =>%F\n", &thdr);/**/
- if(write(mfd[1], mdata, n) != n)
- error("mount write");
- }
- if (buf[0]=='\0' || strncmp(buf, "write to hung", 13)==0)
- exits("");
- fprint(2, "%s: mount read: %s\n", argv0, buf);
- exits(buf);
- }
- int
- perm(int p)
- {
- if (p==Pwrite)
- return 0;
- return 1;
- }
- void
- error(char *s)
- {
- fprint(2, "%s: %s: ", argv0, s);
- perror("");
- exits(s);
- }
- char*
- estrdup(char *s)
- {
- char *t;
- t = emalloc(strlen(s)+1);
- strcpy(t, s);
- return t;
- }
- void *
- emalloc(ulong n)
- {
- void *p;
- p = mallocz(n, 1);
- if(!p)
- error("out of memory");
- return p;
- }
- void *
- erealloc(void *p, ulong n)
- {
- p = realloc(p, n);
- if(!p)
- error("out of memory");
- return p;
- }
- void
- usage(void)
- {
- fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);
- exits("usage");
- }
|