xref: /plan9/sys/src/cmd/dossrv/xfile.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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