13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include "iotrack.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier
73e12c5d1SDavid du Colombier #define FIDMOD 127 /* prime */
83e12c5d1SDavid du Colombier
93e12c5d1SDavid du Colombier static Xfs *xhead;
103e12c5d1SDavid du Colombier static Xfile *xfiles[FIDMOD], *freelist;
117dd7cddfSDavid du Colombier static MLock xlock, xlocks[FIDMOD], freelock;
123e12c5d1SDavid du Colombier
13*9a747e4fSDavid du Colombier static int
okmode(int omode,int fmode)14*9a747e4fSDavid du Colombier okmode(int omode, int fmode)
153e12c5d1SDavid du Colombier {
16*9a747e4fSDavid du Colombier if(omode == OREAD)
17*9a747e4fSDavid du Colombier return fmode & 4;
18*9a747e4fSDavid du Colombier /* else ORDWR */
19*9a747e4fSDavid du Colombier return (fmode & 6) == 6;
20*9a747e4fSDavid du Colombier }
21*9a747e4fSDavid du Colombier
22*9a747e4fSDavid du Colombier Xfs *
getxfs(char * user,char * name)23*9a747e4fSDavid du Colombier getxfs(char *user, char *name)
24*9a747e4fSDavid du Colombier {
25*9a747e4fSDavid du Colombier Xfs *xf, *fxf;
26*9a747e4fSDavid du Colombier Dir *dir;
27*9a747e4fSDavid du Colombier Qid dqid;
287dd7cddfSDavid du Colombier char *p, *q;
297dd7cddfSDavid du Colombier long offset;
30*9a747e4fSDavid du Colombier int fd, omode;
313e12c5d1SDavid du Colombier
32*9a747e4fSDavid du Colombier USED(user);
337dd7cddfSDavid du Colombier if(name==nil || name[0]==0)
343e12c5d1SDavid du Colombier name = deffile;
357dd7cddfSDavid du Colombier if(name == nil){
363e12c5d1SDavid du Colombier errno = Enofilsys;
373e12c5d1SDavid du Colombier return 0;
383e12c5d1SDavid du Colombier }
397dd7cddfSDavid du Colombier
407dd7cddfSDavid du Colombier /*
417dd7cddfSDavid du Colombier * If the name passed is of the form 'name:offset' then
427dd7cddfSDavid du Colombier * offset is used to prime xf->offset. This allows accessing
437dd7cddfSDavid du Colombier * a FAT-based filesystem anywhere within a partition.
447dd7cddfSDavid du Colombier * Typical use would be to mount a filesystem in the presence
457dd7cddfSDavid du Colombier * of a boot manager programme at the beginning of the disc.
467dd7cddfSDavid du Colombier */
477dd7cddfSDavid du Colombier offset = 0;
487dd7cddfSDavid du Colombier if(p = strrchr(name, ':')){
497dd7cddfSDavid du Colombier *p++ = 0;
507dd7cddfSDavid du Colombier offset = strtol(p, &q, 0);
517dd7cddfSDavid du Colombier chat("name %s, offset %ld\n", p, offset);
527dd7cddfSDavid du Colombier if(offset < 0 || p == q){
537dd7cddfSDavid du Colombier errno = Enofilsys;
547dd7cddfSDavid du Colombier return 0;
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier offset *= Sectorsize;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier
59*9a747e4fSDavid du Colombier if(readonly)
60*9a747e4fSDavid du Colombier omode = OREAD;
61*9a747e4fSDavid du Colombier else
62*9a747e4fSDavid du Colombier omode = ORDWR;
63*9a747e4fSDavid du Colombier fd = open(name, omode);
64*9a747e4fSDavid du Colombier
65*9a747e4fSDavid du Colombier if(fd < 0 && omode==ORDWR){
66*9a747e4fSDavid du Colombier omode = OREAD;
67*9a747e4fSDavid du Colombier fd = open(name, omode);
68*9a747e4fSDavid du Colombier }
69*9a747e4fSDavid du Colombier
703e12c5d1SDavid du Colombier if(fd < 0){
71*9a747e4fSDavid du Colombier chat("can't open %s: %r\n", name);
72*9a747e4fSDavid du Colombier errno = Eerrstr;
733e12c5d1SDavid du Colombier return 0;
743e12c5d1SDavid du Colombier }
75*9a747e4fSDavid du Colombier dir = dirfstat(fd);
76*9a747e4fSDavid du Colombier if(dir == nil){
773e12c5d1SDavid du Colombier errno = Eio;
783e12c5d1SDavid du Colombier close(fd);
793e12c5d1SDavid du Colombier return 0;
803e12c5d1SDavid du Colombier }
81*9a747e4fSDavid du Colombier
82*9a747e4fSDavid du Colombier dqid = dir->qid;
83*9a747e4fSDavid du Colombier free(dir);
847dd7cddfSDavid du Colombier mlock(&xlock);
853e12c5d1SDavid du Colombier for(fxf=0,xf=xhead; xf; xf=xf->next){
863e12c5d1SDavid du Colombier if(xf->ref == 0){
873e12c5d1SDavid du Colombier if(fxf == 0)
883e12c5d1SDavid du Colombier fxf = xf;
893e12c5d1SDavid du Colombier continue;
903e12c5d1SDavid du Colombier }
91*9a747e4fSDavid du Colombier if(!eqqid(xf->qid, dqid))
923e12c5d1SDavid du Colombier continue;
933e12c5d1SDavid du Colombier if(strcmp(xf->name, name) != 0 || xf->dev < 0)
943e12c5d1SDavid du Colombier continue;
95219b2ee8SDavid du Colombier if(devcheck(xf) < 0) /* look for media change */
96219b2ee8SDavid du Colombier continue;
977dd7cddfSDavid du Colombier if(offset && xf->offset != offset)
987dd7cddfSDavid du Colombier continue;
993e12c5d1SDavid du Colombier chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
1003e12c5d1SDavid du Colombier ++xf->ref;
1017dd7cddfSDavid du Colombier unmlock(&xlock);
1023e12c5d1SDavid du Colombier close(fd);
1033e12c5d1SDavid du Colombier return xf;
1043e12c5d1SDavid du Colombier }
1057dd7cddfSDavid du Colombier if(fxf == nil){
1063e12c5d1SDavid du Colombier fxf = malloc(sizeof(Xfs));
1077dd7cddfSDavid du Colombier if(fxf == nil){
1087dd7cddfSDavid du Colombier unmlock(&xlock);
1093e12c5d1SDavid du Colombier close(fd);
1103e12c5d1SDavid du Colombier errno = Enomem;
1117dd7cddfSDavid du Colombier return nil;
1123e12c5d1SDavid du Colombier }
1133e12c5d1SDavid du Colombier fxf->next = xhead;
1143e12c5d1SDavid du Colombier xhead = fxf;
1153e12c5d1SDavid du Colombier }
1163e12c5d1SDavid du Colombier chat("alloc \"%s\", dev=%d...", name, fd);
1173e12c5d1SDavid du Colombier fxf->name = strdup(name);
1183e12c5d1SDavid du Colombier fxf->ref = 1;
119*9a747e4fSDavid du Colombier fxf->qid = dqid;
1203e12c5d1SDavid du Colombier fxf->dev = fd;
1213e12c5d1SDavid du Colombier fxf->fmt = 0;
1227dd7cddfSDavid du Colombier fxf->offset = offset;
1237dd7cddfSDavid du Colombier fxf->ptr = nil;
1247dd7cddfSDavid du Colombier fxf->isfat32 = 0;
125*9a747e4fSDavid du Colombier fxf->omode = omode;
1267dd7cddfSDavid du Colombier unmlock(&xlock);
1273e12c5d1SDavid du Colombier return fxf;
1283e12c5d1SDavid du Colombier }
1293e12c5d1SDavid du Colombier
1303e12c5d1SDavid du Colombier void
refxfs(Xfs * xf,int delta)1313e12c5d1SDavid du Colombier refxfs(Xfs *xf, int delta)
1323e12c5d1SDavid du Colombier {
1337dd7cddfSDavid du Colombier mlock(&xlock);
1343e12c5d1SDavid du Colombier xf->ref += delta;
1353e12c5d1SDavid du Colombier if(xf->ref == 0){
1363e12c5d1SDavid du Colombier chat("free \"%s\", dev=%d...", xf->name, xf->dev);
1373e12c5d1SDavid du Colombier free(xf->name);
1383e12c5d1SDavid du Colombier free(xf->ptr);
1393e12c5d1SDavid du Colombier purgebuf(xf);
1403e12c5d1SDavid du Colombier if(xf->dev >= 0){
1413e12c5d1SDavid du Colombier close(xf->dev);
1423e12c5d1SDavid du Colombier xf->dev = -1;
1433e12c5d1SDavid du Colombier }
1443e12c5d1SDavid du Colombier }
1457dd7cddfSDavid du Colombier unmlock(&xlock);
1463e12c5d1SDavid du Colombier }
1473e12c5d1SDavid du Colombier
1483e12c5d1SDavid du Colombier Xfile *
xfile(int fid,int flag)1493e12c5d1SDavid du Colombier xfile(int fid, int flag)
1503e12c5d1SDavid du Colombier {
1517dd7cddfSDavid du Colombier Xfile **hp, *f, *pf;
1527dd7cddfSDavid du Colombier int k;
1533e12c5d1SDavid du Colombier
1547dd7cddfSDavid du Colombier k = ((ulong)fid) % FIDMOD;
1557dd7cddfSDavid du Colombier hp = &xfiles[k];
1567dd7cddfSDavid du Colombier mlock(&xlocks[k]);
1577dd7cddfSDavid du Colombier pf = nil;
1587dd7cddfSDavid du Colombier for(f=*hp; f; f=f->next){
1597dd7cddfSDavid du Colombier if(f->fid == fid)
1603e12c5d1SDavid du Colombier break;
1617dd7cddfSDavid du Colombier pf = f;
1627dd7cddfSDavid du Colombier }
1633e12c5d1SDavid du Colombier if(f && pf){
1643e12c5d1SDavid du Colombier pf->next = f->next;
1653e12c5d1SDavid du Colombier f->next = *hp;
1663e12c5d1SDavid du Colombier *hp = f;
1673e12c5d1SDavid du Colombier }
1683e12c5d1SDavid du Colombier switch(flag){
1693e12c5d1SDavid du Colombier default:
1703e12c5d1SDavid du Colombier panic("xfile");
1713e12c5d1SDavid du Colombier case Asis:
1727dd7cddfSDavid du Colombier unmlock(&xlocks[k]);
1737dd7cddfSDavid du Colombier return (f && f->xf && f->xf->dev < 0) ? nil : f;
1743e12c5d1SDavid du Colombier case Clean:
1753e12c5d1SDavid du Colombier break;
1763e12c5d1SDavid du Colombier case Clunk:
1773e12c5d1SDavid du Colombier if(f){
1783e12c5d1SDavid du Colombier *hp = f->next;
1797dd7cddfSDavid du Colombier unmlock(&xlocks[k]);
1803e12c5d1SDavid du Colombier clean(f);
1817dd7cddfSDavid du Colombier mlock(&freelock);
1823e12c5d1SDavid du Colombier f->next = freelist;
1833e12c5d1SDavid du Colombier freelist = f;
1847dd7cddfSDavid du Colombier unmlock(&freelock);
1853e12c5d1SDavid du Colombier } else
1867dd7cddfSDavid du Colombier unmlock(&xlocks[k]);
1877dd7cddfSDavid du Colombier return nil;
1883e12c5d1SDavid du Colombier }
1897dd7cddfSDavid du Colombier unmlock(&xlocks[k]);
1903e12c5d1SDavid du Colombier if(f)
1913e12c5d1SDavid du Colombier return clean(f);
1927dd7cddfSDavid du Colombier mlock(&freelock);
1933e12c5d1SDavid du Colombier if(f = freelist){ /* assign = */
1943e12c5d1SDavid du Colombier freelist = f->next;
1957dd7cddfSDavid du Colombier unmlock(&freelock);
1963e12c5d1SDavid du Colombier } else {
1977dd7cddfSDavid du Colombier unmlock(&freelock);
1983e12c5d1SDavid du Colombier f = malloc(sizeof(Xfile));
1997dd7cddfSDavid du Colombier if(f == nil){
2007dd7cddfSDavid du Colombier errno = Enomem;
2017dd7cddfSDavid du Colombier return nil;
2023e12c5d1SDavid du Colombier }
2037dd7cddfSDavid du Colombier }
2047dd7cddfSDavid du Colombier mlock(&xlocks[k]);
2053e12c5d1SDavid du Colombier f->next = *hp;
2063e12c5d1SDavid du Colombier *hp = f;
2077dd7cddfSDavid du Colombier unmlock(&xlocks[k]);
2083e12c5d1SDavid du Colombier f->fid = fid;
2093e12c5d1SDavid du Colombier f->flags = 0;
210*9a747e4fSDavid du Colombier f->qid = (Qid){0,0,0};
2117dd7cddfSDavid du Colombier f->xf = nil;
2127dd7cddfSDavid du Colombier f->ptr = nil;
2133e12c5d1SDavid du Colombier return f;
2143e12c5d1SDavid du Colombier }
2153e12c5d1SDavid du Colombier
2163e12c5d1SDavid du Colombier Xfile *
clean(Xfile * f)2173e12c5d1SDavid du Colombier clean(Xfile *f)
2183e12c5d1SDavid du Colombier {
2193e12c5d1SDavid du Colombier if(f->ptr){
2203e12c5d1SDavid du Colombier free(f->ptr);
2217dd7cddfSDavid du Colombier f->ptr = nil;
2223e12c5d1SDavid du Colombier }
2233e12c5d1SDavid du Colombier if(f->xf){
2243e12c5d1SDavid du Colombier refxfs(f->xf, -1);
2257dd7cddfSDavid du Colombier f->xf = nil;
2263e12c5d1SDavid du Colombier }
2273e12c5d1SDavid du Colombier f->flags = 0;
228*9a747e4fSDavid du Colombier f->qid = (Qid){0,0,0};
2293e12c5d1SDavid du Colombier return f;
2303e12c5d1SDavid du Colombier }
2313e12c5d1SDavid du Colombier
2327dd7cddfSDavid du Colombier /*
2337dd7cddfSDavid du Colombier * the file at <addr, offset> has moved
2347dd7cddfSDavid du Colombier * relocate the dos entries of all fids in the same file
2357dd7cddfSDavid du Colombier */
2367dd7cddfSDavid du Colombier void
dosptrreloc(Xfile * f,Dosptr * dp,ulong addr,ulong offset)2377dd7cddfSDavid du Colombier dosptrreloc(Xfile *f, Dosptr *dp, ulong addr, ulong offset)
2383e12c5d1SDavid du Colombier {
2397dd7cddfSDavid du Colombier int i;
2407dd7cddfSDavid du Colombier Xfile *p;
2417dd7cddfSDavid du Colombier Dosptr *xdp;
2423e12c5d1SDavid du Colombier
2437dd7cddfSDavid du Colombier for(i=0; i < FIDMOD; i++){
2447dd7cddfSDavid du Colombier for(p = xfiles[i]; p != nil; p = p->next){
2457dd7cddfSDavid du Colombier xdp = p->ptr;
2467dd7cddfSDavid du Colombier if(p != f && p->xf == f->xf
2477dd7cddfSDavid du Colombier && xdp != nil && xdp->addr == addr && xdp->offset == offset){
2487dd7cddfSDavid du Colombier memmove(xdp, dp, sizeof(Dosptr));
2497dd7cddfSDavid du Colombier xdp->p = nil;
2507dd7cddfSDavid du Colombier xdp->d = nil;
2517dd7cddfSDavid du Colombier p->qid.path = QIDPATH(xdp);
2523e12c5d1SDavid du Colombier }
2533e12c5d1SDavid du Colombier }
2543e12c5d1SDavid du Colombier }
2553e12c5d1SDavid du Colombier }
256