123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- #include <u.h>
- #include <libc.h>
- #include "iotrack.h"
- #include "dat.h"
- #include "fns.h"
- #define FIDMOD 127 /* prime */
- static Xfs *xhead;
- static Xfile *xfiles[FIDMOD], *freelist;
- static MLock xlock, xlocks[FIDMOD], freelock;
- static int
- okmode(int omode, int fmode)
- {
- if(omode == OREAD)
- return fmode & 4;
- /* else ORDWR */
- return (fmode & 6) == 6;
- }
- Xfs *
- getxfs(char *user, char *name)
- {
- Xfs *xf, *fxf;
- Dir *dir;
- Qid dqid;
- char *p, *q;
- long offset;
- int fd, omode;
- USED(user);
- if(name==nil || name[0]==0)
- name = deffile;
- if(name == nil){
- errno = Enofilsys;
- return 0;
- }
- /*
- * If the name passed is of the form 'name:offset' then
- * offset is used to prime xf->offset. This allows accessing
- * a FAT-based filesystem anywhere within a partition.
- * Typical use would be to mount a filesystem in the presence
- * of a boot manager programme at the beginning of the disc.
- */
- offset = 0;
- if(p = strrchr(name, ':')){
- *p++ = 0;
- offset = strtol(p, &q, 0);
- chat("name %s, offset %ld\n", p, offset);
- if(offset < 0 || p == q){
- errno = Enofilsys;
- return 0;
- }
- offset *= Sectorsize;
- }
- if(readonly)
- omode = OREAD;
- else
- omode = ORDWR;
- fd = open(name, omode);
- if(fd < 0 && omode==ORDWR){
- omode = OREAD;
- fd = open(name, omode);
- }
- if(fd < 0){
- chat("can't open %s: %r\n", name);
- errno = Eerrstr;
- return 0;
- }
- dir = dirfstat(fd);
- if(dir == nil){
- errno = Eio;
- close(fd);
- return 0;
- }
- dqid = dir->qid;
- free(dir);
- mlock(&xlock);
- for(fxf=0,xf=xhead; xf; xf=xf->next){
- if(xf->ref == 0){
- if(fxf == 0)
- fxf = xf;
- continue;
- }
- if(!eqqid(xf->qid, dqid))
- continue;
- if(strcmp(xf->name, name) != 0 || xf->dev < 0)
- continue;
- if(devcheck(xf) < 0) /* look for media change */
- continue;
- if(offset && xf->offset != offset)
- continue;
- chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
- ++xf->ref;
- unmlock(&xlock);
- close(fd);
- return xf;
- }
- if(fxf == nil){
- fxf = malloc(sizeof(Xfs));
- if(fxf == nil){
- unmlock(&xlock);
- close(fd);
- errno = Enomem;
- return nil;
- }
- fxf->next = xhead;
- xhead = fxf;
- }
- chat("alloc \"%s\", dev=%d...", name, fd);
- fxf->name = strdup(name);
- fxf->ref = 1;
- fxf->qid = dqid;
- fxf->dev = fd;
- fxf->fmt = 0;
- fxf->offset = offset;
- fxf->ptr = nil;
- fxf->isfat32 = 0;
- fxf->omode = omode;
- unmlock(&xlock);
- return fxf;
- }
- void
- refxfs(Xfs *xf, int delta)
- {
- mlock(&xlock);
- xf->ref += delta;
- if(xf->ref == 0){
- chat("free \"%s\", dev=%d...", xf->name, xf->dev);
- free(xf->name);
- free(xf->ptr);
- purgebuf(xf);
- if(xf->dev >= 0){
- close(xf->dev);
- xf->dev = -1;
- }
- }
- unmlock(&xlock);
- }
- Xfile *
- xfile(int fid, int flag)
- {
- Xfile **hp, *f, *pf;
- int k;
- k = ((ulong)fid) % FIDMOD;
- hp = &xfiles[k];
- mlock(&xlocks[k]);
- pf = nil;
- for(f=*hp; f; f=f->next){
- if(f->fid == fid)
- break;
- pf = f;
- }
- if(f && pf){
- pf->next = f->next;
- f->next = *hp;
- *hp = f;
- }
- switch(flag){
- default:
- panic("xfile");
- case Asis:
- unmlock(&xlocks[k]);
- return (f && f->xf && f->xf->dev < 0) ? nil : f;
- case Clean:
- break;
- case Clunk:
- if(f){
- *hp = f->next;
- unmlock(&xlocks[k]);
- clean(f);
- mlock(&freelock);
- f->next = freelist;
- freelist = f;
- unmlock(&freelock);
- } else
- unmlock(&xlocks[k]);
- return nil;
- }
- unmlock(&xlocks[k]);
- if(f)
- return clean(f);
- mlock(&freelock);
- if(f = freelist){ /* assign = */
- freelist = f->next;
- unmlock(&freelock);
- } else {
- unmlock(&freelock);
- f = malloc(sizeof(Xfile));
- if(f == nil){
- errno = Enomem;
- return nil;
- }
- }
- mlock(&xlocks[k]);
- f->next = *hp;
- *hp = f;
- unmlock(&xlocks[k]);
- f->fid = fid;
- f->flags = 0;
- f->qid = (Qid){0,0,0};
- f->xf = nil;
- f->ptr = nil;
- return f;
- }
- Xfile *
- clean(Xfile *f)
- {
- if(f->ptr){
- free(f->ptr);
- f->ptr = nil;
- }
- if(f->xf){
- refxfs(f->xf, -1);
- f->xf = nil;
- }
- f->flags = 0;
- f->qid = (Qid){0,0,0};
- return f;
- }
- /*
- * the file at <addr, offset> has moved
- * relocate the dos entries of all fids in the same file
- */
- void
- dosptrreloc(Xfile *f, Dosptr *dp, ulong addr, ulong offset)
- {
- int i;
- Xfile *p;
- Dosptr *xdp;
- for(i=0; i < FIDMOD; i++){
- for(p = xfiles[i]; p != nil; p = p->next){
- xdp = p->ptr;
- if(p != f && p->xf == f->xf
- && xdp != nil && xdp->addr == addr && xdp->offset == offset){
- memmove(xdp, dp, sizeof(Dosptr));
- xdp->p = nil;
- xdp->d = nil;
- p->qid.path = QIDPATH(xdp);
- }
- }
- }
- }
|