xref: /plan9-contrib/sys/src/cmd/dossrv/dossubs.c (revision efb32250a8587c63ac66d9426ed42bf32cc94d53)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier #include <auth.h>
53e12c5d1SDavid du Colombier #include <fcall.h>
63e12c5d1SDavid du Colombier #include "iotrack.h"
73e12c5d1SDavid du Colombier #include "dat.h"
83e12c5d1SDavid du Colombier #include "fns.h"
93e12c5d1SDavid du Colombier 
107dd7cddfSDavid du Colombier static uchar	isdos[256];
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier int
isdosfs(uchar * buf)137dd7cddfSDavid du Colombier isdosfs(uchar *buf)
147dd7cddfSDavid du Colombier {
157dd7cddfSDavid du Colombier 	/*
167dd7cddfSDavid du Colombier 	 * When dynamic disc managers move the disc partition,
177dd7cddfSDavid du Colombier 	 * they make it start with 0xE9.
187dd7cddfSDavid du Colombier 	 */
197dd7cddfSDavid du Colombier 	if(buf[0] == 0xE9)
207dd7cddfSDavid du Colombier 		return 1;
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier 	/*
237dd7cddfSDavid du Colombier 	 * Check if the jump displacement (magic[1]) is too short for a FAT.
24*efb32250SDavid du Colombier 	 *
25*efb32250SDavid du Colombier 	 * check now omitted due to digital cameras that use a 0 jump.
26*efb32250SDavid du Colombier 	 * the ecma-107 standard says this is okay and that interoperable fat
27*efb32250SDavid du Colombier 	 * implementations shouldn't assume this:
28*efb32250SDavid du Colombier 	 * http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-107.pdf,
29*efb32250SDavid du Colombier 	 * page 11.
307dd7cddfSDavid du Colombier 	 */
31*efb32250SDavid du Colombier 	if(buf[0] == 0xEB && buf[2] == 0x90 /* && buf[1] >= 0x30 */)
327dd7cddfSDavid du Colombier 		return 1;
33*efb32250SDavid du Colombier 	if(chatty)
34*efb32250SDavid du Colombier 		fprint(2, "bad sig %.2ux %.2ux %.2uxn", buf[0], buf[1], buf[2]);
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier 	return 0;
377dd7cddfSDavid du Colombier }
387dd7cddfSDavid du Colombier 
393e12c5d1SDavid du Colombier int
dosfs(Xfs * xf)403e12c5d1SDavid du Colombier dosfs(Xfs *xf)
413e12c5d1SDavid du Colombier {
427dd7cddfSDavid du Colombier 	Iosect *p, *p1;
437dd7cddfSDavid du Colombier 	Dosboot *b;
447dd7cddfSDavid du Colombier 	Fatinfo *fi;
457dd7cddfSDavid du Colombier 	Dosboot32 *b32;
463e12c5d1SDavid du Colombier 	Dosbpb *bp;
477dd7cddfSDavid du Colombier 	long fisec, extflags;
489a747e4fSDavid du Colombier 	int i;
493e12c5d1SDavid du Colombier 
507dd7cddfSDavid du Colombier 	if(!isdos['a']){
517dd7cddfSDavid du Colombier 		for(i = 'a'; i <= 'z'; i++)
527dd7cddfSDavid du Colombier 			isdos[i] = 1;
537dd7cddfSDavid du Colombier 		for(i = 'A'; i <= 'Z'; i++)
547dd7cddfSDavid du Colombier 			isdos[i] = 1;
557dd7cddfSDavid du Colombier 		for(i = '0'; i <= '9'; i++)
567dd7cddfSDavid du Colombier 			isdos[i] = 1;
577dd7cddfSDavid du Colombier 		isdos['$'] = 1;
587dd7cddfSDavid du Colombier 		isdos['%'] = 1;
597dd7cddfSDavid du Colombier 		isdos['''] = 1;
607dd7cddfSDavid du Colombier 		isdos['-'] = 1;
617dd7cddfSDavid du Colombier 		isdos['_'] = 1;
627dd7cddfSDavid du Colombier 		isdos['@'] = 1;
637dd7cddfSDavid du Colombier 		isdos['~'] = 1;
647dd7cddfSDavid du Colombier 		isdos['`'] = 1;
657dd7cddfSDavid du Colombier 		isdos['!'] = 1;
667dd7cddfSDavid du Colombier 		isdos['('] = 1;
677dd7cddfSDavid du Colombier 		isdos[')'] = 1;
687dd7cddfSDavid du Colombier 		isdos['{'] = 1;
697dd7cddfSDavid du Colombier 		isdos['}'] = 1;
707dd7cddfSDavid du Colombier 		isdos['^'] = 1;
717dd7cddfSDavid du Colombier 		isdos['#'] = 1;
727dd7cddfSDavid du Colombier 		isdos['&'] = 1;
737dd7cddfSDavid du Colombier 	}
747dd7cddfSDavid du Colombier 
753e12c5d1SDavid du Colombier 	p = getsect(xf, 0);
763e12c5d1SDavid du Colombier 	if(p == 0)
773e12c5d1SDavid du Colombier 		return -1;
787dd7cddfSDavid du Colombier 
793e12c5d1SDavid du Colombier 	b = (Dosboot*)p->iobuf;
80d9306527SDavid du Colombier 	if(b->clustsize == 0 || isdosfs(p->iobuf) == 0){
81219b2ee8SDavid du Colombier 		putsect(p);
82219b2ee8SDavid du Colombier 		return -1;
83219b2ee8SDavid du Colombier 	}
843e12c5d1SDavid du Colombier 
853e12c5d1SDavid du Colombier 	bp = malloc(sizeof(Dosbpb));
867dd7cddfSDavid du Colombier 	memset(bp, 0, sizeof(Dosbpb));	/* clear lock */
873e12c5d1SDavid du Colombier 	xf->ptr = bp;
883e12c5d1SDavid du Colombier 	xf->fmt = 1;
893e12c5d1SDavid du Colombier 
903e12c5d1SDavid du Colombier 	bp->sectsize = GSHORT(b->sectsize);
913e12c5d1SDavid du Colombier 	bp->clustsize = b->clustsize;
923e12c5d1SDavid du Colombier 	bp->nresrv = GSHORT(b->nresrv);
933e12c5d1SDavid du Colombier 	bp->nfats = b->nfats;
943e12c5d1SDavid du Colombier 	bp->rootsize = GSHORT(b->rootsize);
953e12c5d1SDavid du Colombier 	bp->volsize = GSHORT(b->volsize);
963e12c5d1SDavid du Colombier 	if(bp->volsize == 0)
973e12c5d1SDavid du Colombier 		bp->volsize = GLONG(b->bigvolsize);
983e12c5d1SDavid du Colombier 	bp->mediadesc = b->mediadesc;
993e12c5d1SDavid du Colombier 	bp->fatsize = GSHORT(b->fatsize);
1007dd7cddfSDavid du Colombier 	bp->fataddr = GSHORT(b->nresrv);
1013e12c5d1SDavid du Colombier 
1027dd7cddfSDavid du Colombier 	bp->fatinfo = 0;
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier 	if(bp->fatsize == 0){	/* is FAT32 */
1057dd7cddfSDavid du Colombier 		if(chatty)
1067dd7cddfSDavid du Colombier 			bootsecdump32(2, xf, (Dosboot32*)b);
1077dd7cddfSDavid du Colombier 		xf->isfat32 = 1;
1087dd7cddfSDavid du Colombier 		b32 = (Dosboot32*)b;
1097dd7cddfSDavid du Colombier 		bp->fatsize = GLONG(b32->fatsize32);
1107dd7cddfSDavid du Colombier 		if(bp->fatsize == 0){
1117dd7cddfSDavid du Colombier 			putsect(p);
112*efb32250SDavid du Colombier 			if(chatty)
113*efb32250SDavid du Colombier 				fprint(2, "fatsize 0\n");
1147dd7cddfSDavid du Colombier 			return -1;
1157dd7cddfSDavid du Colombier 		}
1167dd7cddfSDavid du Colombier 		bp->dataaddr = bp->fataddr + bp->nfats*bp->fatsize;
1177dd7cddfSDavid du Colombier 		bp->rootaddr = 0;
1187dd7cddfSDavid du Colombier 		bp->rootstart = GLONG(b32->rootstart);
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier 		/*
1217dd7cddfSDavid du Colombier 		 * disable fat mirroring?
1227dd7cddfSDavid du Colombier 		 */
1237dd7cddfSDavid du Colombier 		extflags = GSHORT(b32->extflags);
1247dd7cddfSDavid du Colombier 		if(extflags & 0x0080){
1257dd7cddfSDavid du Colombier 			for(i = 0; i < 4; i++){
1267dd7cddfSDavid du Colombier 				if(extflags & (1 << i)){
1277dd7cddfSDavid du Colombier 					bp->fataddr += i * bp->fatsize;
1287dd7cddfSDavid du Colombier 					bp->nfats = 1;
1297dd7cddfSDavid du Colombier 					break;
1307dd7cddfSDavid du Colombier 				}
1317dd7cddfSDavid du Colombier 			}
1327dd7cddfSDavid du Colombier 		}
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier 		/*
1357dd7cddfSDavid du Colombier 		 * fat free list info
1367dd7cddfSDavid du Colombier 		 */
1377dd7cddfSDavid du Colombier 		bp->freeptr = FATRESRV;
1387dd7cddfSDavid du Colombier 		fisec = GSHORT(b32->infospec);
1397dd7cddfSDavid du Colombier 		if(fisec != 0 && fisec < GSHORT(b32->nresrv)){
1407dd7cddfSDavid du Colombier 			p1 = getsect(xf, fisec);
1417dd7cddfSDavid du Colombier 			if(p1 != nil){
1427dd7cddfSDavid du Colombier 				fi = (Fatinfo*)p1->iobuf;
1437dd7cddfSDavid du Colombier 				if(GLONG(fi->sig1) == FATINFOSIG1 && GLONG(fi->sig) == FATINFOSIG){
1447dd7cddfSDavid du Colombier 					bp->fatinfo = fisec;
1457dd7cddfSDavid du Colombier 					bp->freeptr = GLONG(fi->nextfree);
1467dd7cddfSDavid du Colombier 					bp->freeclusters = GLONG(fi->freeclust);
1477dd7cddfSDavid du Colombier 					chat("fat info: %ld free clusters, next free %ld\n", bp->freeclusters, bp->freeptr);
1487dd7cddfSDavid du Colombier 				}
1497dd7cddfSDavid du Colombier 				putsect(p1);
1507dd7cddfSDavid du Colombier 			}
1517dd7cddfSDavid du Colombier 		}
1527dd7cddfSDavid du Colombier 	}else{
1537dd7cddfSDavid du Colombier 		if(chatty)
1547dd7cddfSDavid du Colombier 			bootdump(2, b);
1553e12c5d1SDavid du Colombier 		bp->rootaddr = bp->fataddr + bp->nfats*bp->fatsize;
1567dd7cddfSDavid du Colombier 		bp->rootstart = 0;
1577dd7cddfSDavid du Colombier 		i = bp->rootsize*DOSDIRSIZE + bp->sectsize-1;
1583e12c5d1SDavid du Colombier 		i /= bp->sectsize;
1593e12c5d1SDavid du Colombier 		bp->dataaddr = bp->rootaddr + i;
1607dd7cddfSDavid du Colombier 		bp->freeptr = FATRESRV;
1617dd7cddfSDavid du Colombier 	}
1627dd7cddfSDavid du Colombier 	bp->fatclusters = FATRESRV+(bp->volsize - bp->dataaddr)/bp->clustsize;
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier 	if(xf->isfat32)
1657dd7cddfSDavid du Colombier 		bp->fatbits = 32;
1667dd7cddfSDavid du Colombier 	else if(bp->fatclusters < 4087)
1673e12c5d1SDavid du Colombier 		bp->fatbits = 12;
1683e12c5d1SDavid du Colombier 	else
1693e12c5d1SDavid du Colombier 		bp->fatbits = 16;
1707dd7cddfSDavid du Colombier 
1713e12c5d1SDavid du Colombier 	chat("fatbits=%d (%d clusters)...", bp->fatbits, bp->fatclusters);
1723e12c5d1SDavid du Colombier 	for(i=0; i<b->nfats; i++)
1739a747e4fSDavid du Colombier 		chat("fat %d: %ld...", i, bp->fataddr+i*bp->fatsize);
1749a747e4fSDavid du Colombier 	chat("root: %ld...", bp->rootaddr);
1759a747e4fSDavid du Colombier 	chat("data: %ld...", bp->dataaddr);
1763e12c5d1SDavid du Colombier 	putsect(p);
1773e12c5d1SDavid du Colombier 	return 0;
1783e12c5d1SDavid du Colombier }
1793e12c5d1SDavid du Colombier 
1807dd7cddfSDavid du Colombier /*
1817dd7cddfSDavid du Colombier  * initialize f to the root directory
1827dd7cddfSDavid du Colombier  * this file has no Dosdir entry,
1837dd7cddfSDavid du Colombier  * so we special case it all over.
1847dd7cddfSDavid du Colombier  */
1857dd7cddfSDavid du Colombier void
1867dd7cddfSDavid du Colombier rootfile(Xfile *f)
1877dd7cddfSDavid du Colombier {
1887dd7cddfSDavid du Colombier 	Dosptr *dp;
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier 	dp = f->ptr;
1917dd7cddfSDavid du Colombier 	memset(dp, 0, sizeof(Dosptr));
1927dd7cddfSDavid du Colombier 	dp->prevaddr = -1;
1937dd7cddfSDavid du Colombier }
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier int
1967dd7cddfSDavid du Colombier isroot(ulong addr)
1977dd7cddfSDavid du Colombier {
1987dd7cddfSDavid du Colombier 	return addr == 0;
1997dd7cddfSDavid du Colombier }
2007dd7cddfSDavid du Colombier 
2013e12c5d1SDavid du Colombier int
2023e12c5d1SDavid du Colombier getfile(Xfile *f)
2033e12c5d1SDavid du Colombier {
2047dd7cddfSDavid du Colombier 	Dosptr *dp;
2053e12c5d1SDavid du Colombier 	Iosect *p;
2063e12c5d1SDavid du Colombier 
2077dd7cddfSDavid du Colombier 	dp = f->ptr;
2083e12c5d1SDavid du Colombier 	if(dp->p)
2093e12c5d1SDavid du Colombier 		panic("getfile");
2103e12c5d1SDavid du Colombier 	p = getsect(f->xf, dp->addr);
2117dd7cddfSDavid du Colombier 	if(p == nil)
2123e12c5d1SDavid du Colombier 		return -1;
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 	/*
2157dd7cddfSDavid du Colombier 	 * we could also make up a Dosdir for the root
2167dd7cddfSDavid du Colombier 	 */
2177dd7cddfSDavid du Colombier 	dp->d = nil;
2187dd7cddfSDavid du Colombier 	if(!isroot(dp->addr)){
2199a747e4fSDavid du Colombier 		if(f->qid.path != QIDPATH(dp)){
2209a747e4fSDavid du Colombier 			chat("qid mismatch f=%#llux d=%#lux...", f->qid.path, QIDPATH(dp));
2213e12c5d1SDavid du Colombier 			putsect(p);
2223e12c5d1SDavid du Colombier 			errno = Enonexist;
2233e12c5d1SDavid du Colombier 			return -1;
2243e12c5d1SDavid du Colombier 		}
2257dd7cddfSDavid du Colombier 		dp->d = (Dosdir *)&p->iobuf[dp->offset];
2263e12c5d1SDavid du Colombier 	}
2273e12c5d1SDavid du Colombier 	dp->p = p;
2283e12c5d1SDavid du Colombier 	return 0;
2293e12c5d1SDavid du Colombier }
2303e12c5d1SDavid du Colombier 
2313e12c5d1SDavid du Colombier void
2323e12c5d1SDavid du Colombier putfile(Xfile *f)
2333e12c5d1SDavid du Colombier {
2347dd7cddfSDavid du Colombier 	Dosptr *dp;
2353e12c5d1SDavid du Colombier 
2367dd7cddfSDavid du Colombier 	dp = f->ptr;
2373e12c5d1SDavid du Colombier 	if(!dp->p)
2383e12c5d1SDavid du Colombier 		panic("putfile");
2393e12c5d1SDavid du Colombier 	putsect(dp->p);
2407dd7cddfSDavid du Colombier 	dp->p = nil;
2417dd7cddfSDavid du Colombier 	dp->d = nil;
2423e12c5d1SDavid du Colombier }
2433e12c5d1SDavid du Colombier 
2447dd7cddfSDavid du Colombier long
2457dd7cddfSDavid du Colombier getstart(Xfs *xf, Dosdir *d)
2463e12c5d1SDavid du Colombier {
2477dd7cddfSDavid du Colombier 	long start;
2483e12c5d1SDavid du Colombier 
2497dd7cddfSDavid du Colombier 	start = GSHORT(d->start);
2507dd7cddfSDavid du Colombier 	if(xf->isfat32)
2517dd7cddfSDavid du Colombier 		start |= GSHORT(d->hstart)<<16;
2527dd7cddfSDavid du Colombier 	return start;
2533e12c5d1SDavid du Colombier }
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier void
2567dd7cddfSDavid du Colombier putstart(Xfs *xf, Dosdir *d, long start)
2577dd7cddfSDavid du Colombier {
2589a747e4fSDavid du Colombier 	PSHORT(d->start, start);
2599a747e4fSDavid du Colombier 	if(xf->isfat32)
2609a747e4fSDavid du Colombier 		PSHORT(d->hstart, start>>16);
2617dd7cddfSDavid du Colombier }
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier /*
2647dd7cddfSDavid du Colombier  * return the disk cluster for the iclust cluster in f
2657dd7cddfSDavid du Colombier  */
2669a747e4fSDavid du Colombier long
2679a747e4fSDavid du Colombier fileclust(Xfile *f, long iclust, int cflag)
2687dd7cddfSDavid du Colombier {
2697dd7cddfSDavid du Colombier 	Dosbpb *bp;
2707dd7cddfSDavid du Colombier 	Dosptr *dp;
2717dd7cddfSDavid du Colombier 	Dosdir *d;
2729a747e4fSDavid du Colombier 	long start, clust, nskip, next;
2737dd7cddfSDavid du Colombier 
2747dd7cddfSDavid du Colombier 	bp = f->xf->ptr;
2757dd7cddfSDavid du Colombier 	dp = f->ptr;
2767dd7cddfSDavid du Colombier 	d = dp->d;
2777dd7cddfSDavid du Colombier 	next = 0;
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 	/*
2807dd7cddfSDavid du Colombier 	 * asking for the cluster of the root directory
2817dd7cddfSDavid du Colombier 	 * is not a well-formed question, since the root directory
2827dd7cddfSDavid du Colombier 	 * does not begin on a cluster boundary.
2837dd7cddfSDavid du Colombier 	 */
2847dd7cddfSDavid du Colombier 	if(!f->xf->isfat32 && isroot(dp->addr))
2857dd7cddfSDavid du Colombier 		return -1;
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier 	if(f->xf->isfat32 && isroot(dp->addr)){
2887dd7cddfSDavid du Colombier 		start = bp->rootstart;
2897dd7cddfSDavid du Colombier 	}else{
2907dd7cddfSDavid du Colombier 		start = getstart(f->xf, d);
2917dd7cddfSDavid du Colombier 		if(start == 0){
2927dd7cddfSDavid du Colombier 			if(!cflag)
2937dd7cddfSDavid du Colombier 				return -1;
2947dd7cddfSDavid du Colombier 			mlock(bp);
2957dd7cddfSDavid du Colombier 			start = falloc(f->xf);
2967dd7cddfSDavid du Colombier 			unmlock(bp);
2977dd7cddfSDavid du Colombier 			if(start <= 0)
2987dd7cddfSDavid du Colombier 				return -1;
2997dd7cddfSDavid du Colombier 			puttime(d, 0);
3007dd7cddfSDavid du Colombier 			putstart(f->xf, d, start);
3017dd7cddfSDavid du Colombier 			dp->p->flags |= BMOD;
3027dd7cddfSDavid du Colombier 			dp->clust = 0;
3037dd7cddfSDavid du Colombier 		}
3047dd7cddfSDavid du Colombier 	}
3053e12c5d1SDavid du Colombier 	if(dp->clust == 0 || iclust < dp->iclust){
3067dd7cddfSDavid du Colombier 		clust = start;
3073e12c5d1SDavid du Colombier 		nskip = iclust;
3083e12c5d1SDavid du Colombier 	}else{
3093e12c5d1SDavid du Colombier 		clust = dp->clust;
3103e12c5d1SDavid du Colombier 		nskip = iclust - dp->iclust;
3113e12c5d1SDavid du Colombier 	}
312219b2ee8SDavid du Colombier 	if(chatty > 1 && nskip > 0)
3139a747e4fSDavid du Colombier 		chat("clust %#lx, skip %ld...", clust, nskip);
3143e12c5d1SDavid du Colombier 	if(clust <= 0)
3153e12c5d1SDavid du Colombier 		return -1;
3163e12c5d1SDavid du Colombier 	if(nskip > 0){
3177dd7cddfSDavid du Colombier 		mlock(bp);
3183e12c5d1SDavid du Colombier 		while(--nskip >= 0){
3193e12c5d1SDavid du Colombier 			next = getfat(f->xf, clust);
320219b2ee8SDavid du Colombier 			if(chatty > 1)
3219a747e4fSDavid du Colombier 				chat("->%#lx", next);
3223e12c5d1SDavid du Colombier 			if(next > 0){
3233e12c5d1SDavid du Colombier 				clust = next;
3243e12c5d1SDavid du Colombier 				continue;
3253e12c5d1SDavid du Colombier 			}else if(!cflag)
3263e12c5d1SDavid du Colombier 				break;
3279a747e4fSDavid du Colombier 			if(d && (d->attr&DSYSTEM)){
3287dd7cddfSDavid du Colombier 				next = cfalloc(f);
3297dd7cddfSDavid du Colombier 				if(next < 0)
3307dd7cddfSDavid du Colombier 					break;
3317dd7cddfSDavid du Colombier 				/* cfalloc will call putfat for us, since clust may change */
3327dd7cddfSDavid du Colombier 			} else {
3333e12c5d1SDavid du Colombier 				next = falloc(f->xf);
3343e12c5d1SDavid du Colombier 				if(next < 0)
3353e12c5d1SDavid du Colombier 					break;
3363e12c5d1SDavid du Colombier 				putfat(f->xf, clust, next);
3377dd7cddfSDavid du Colombier 			}
3383e12c5d1SDavid du Colombier 			clust = next;
3393e12c5d1SDavid du Colombier 		}
3407dd7cddfSDavid du Colombier 		unmlock(bp);
3413e12c5d1SDavid du Colombier 		if(next <= 0)
3423e12c5d1SDavid du Colombier 			return -1;
3433e12c5d1SDavid du Colombier 		dp->clust = clust;
3443e12c5d1SDavid du Colombier 		dp->iclust = iclust;
3453e12c5d1SDavid du Colombier 	}
3463e12c5d1SDavid du Colombier 	if(chatty > 1)
3479a747e4fSDavid du Colombier 		chat(" clust(%#lx)=%#lx...", iclust, clust);
3487dd7cddfSDavid du Colombier 	return clust;
3493e12c5d1SDavid du Colombier }
3503e12c5d1SDavid du Colombier 
3517dd7cddfSDavid du Colombier /*
3527dd7cddfSDavid du Colombier  * return the disk sector for the isect disk sector in f
3537dd7cddfSDavid du Colombier  */
3549a747e4fSDavid du Colombier long
3559a747e4fSDavid du Colombier fileaddr(Xfile *f, long isect, int cflag)
3563e12c5d1SDavid du Colombier {
3577dd7cddfSDavid du Colombier 	Dosbpb *bp;
3587dd7cddfSDavid du Colombier 	Dosptr *dp;
3599a747e4fSDavid du Colombier 	long clust;
3603e12c5d1SDavid du Colombier 
3617dd7cddfSDavid du Colombier 	bp = f->xf->ptr;
3627dd7cddfSDavid du Colombier 	dp = f->ptr;
3637dd7cddfSDavid du Colombier 	if(!f->xf->isfat32 && isroot(dp->addr)){
3647dd7cddfSDavid du Colombier 		if(isect*bp->sectsize >= bp->rootsize*DOSDIRSIZE)
3657dd7cddfSDavid du Colombier 			return -1;
3667dd7cddfSDavid du Colombier 		return bp->rootaddr + isect;
3677dd7cddfSDavid du Colombier 	}
3687dd7cddfSDavid du Colombier 	clust = fileclust(f, isect/bp->clustsize, cflag);
3697dd7cddfSDavid du Colombier 	if(clust < 0)
3707dd7cddfSDavid du Colombier 		return -1;
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 	return clust2sect(bp, clust) + isect%bp->clustsize;
3737dd7cddfSDavid du Colombier }
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier /*
3769a747e4fSDavid du Colombier  * translate names
3777dd7cddfSDavid du Colombier  */
3789a747e4fSDavid du Colombier void
3797dd7cddfSDavid du Colombier fixname(char *buf)
3807dd7cddfSDavid du Colombier {
3819a747e4fSDavid du Colombier 	int c;
3827dd7cddfSDavid du Colombier 	char *p;
3837dd7cddfSDavid du Colombier 
3847dd7cddfSDavid du Colombier 	p = buf;
3857dd7cddfSDavid du Colombier 	while(c = *p){
3869a747e4fSDavid du Colombier 		if(c == ':' && trspaces)
3879a747e4fSDavid du Colombier 			*p = ' ';
3887dd7cddfSDavid du Colombier 		p++;
3897dd7cddfSDavid du Colombier 	}
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier /*
3939a747e4fSDavid du Colombier  * classify the file name as one of
3949a747e4fSDavid du Colombier  *	Invalid - contains a bad character
3959a747e4fSDavid du Colombier  *	Short - short valid 8.3 name, no lowercase letters
3969a747e4fSDavid du Colombier  *	ShortLower - short valid 8.3 name except for lowercase letters
3979a747e4fSDavid du Colombier  *	Long - long name
3987dd7cddfSDavid du Colombier  */
3999a747e4fSDavid du Colombier int
4009a747e4fSDavid du Colombier classifyname(char *buf)
4019a747e4fSDavid du Colombier {
4029a747e4fSDavid du Colombier 	char *p, *dot;
4039a747e4fSDavid du Colombier 	int c, isextended, is8dot3, islower, ndot;
4049a747e4fSDavid du Colombier 
4059a747e4fSDavid du Colombier 	p = buf;
4069a747e4fSDavid du Colombier 	isextended = 0;
4079a747e4fSDavid du Colombier 	islower = 0;
4089a747e4fSDavid du Colombier 	dot = nil;
4099a747e4fSDavid du Colombier 	ndot = 0;
4109a747e4fSDavid du Colombier 	while(c = (uchar)*p){
4119a747e4fSDavid du Colombier 		if(c&0x80)	/* UTF8 */
4129a747e4fSDavid du Colombier 			isextended = 1;
4139a747e4fSDavid du Colombier 		else if(c == '.'){
4149a747e4fSDavid du Colombier 			dot = p;
4159a747e4fSDavid du Colombier 			ndot++;
4169a747e4fSDavid du Colombier 		}else if(strchr("+,:;=[] ", c))
4179a747e4fSDavid du Colombier 			isextended = 1;
4189a747e4fSDavid du Colombier 		else if(!isdos[c])
4199a747e4fSDavid du Colombier 			return Invalid;
4209a747e4fSDavid du Colombier 		if('a' <= c && c <= 'z')
4219a747e4fSDavid du Colombier 			islower = 1;
4229a747e4fSDavid du Colombier 		p++;
4237dd7cddfSDavid du Colombier 	}
4247dd7cddfSDavid du Colombier 
4259a747e4fSDavid du Colombier 	is8dot3 = (ndot==0 && p-buf <= 8) || (ndot==1 && dot-buf <= 8 && p-(dot+1) <= 3);
4267dd7cddfSDavid du Colombier 
4279a747e4fSDavid du Colombier 	if(!isextended && is8dot3){
4289a747e4fSDavid du Colombier 		if(islower)
4299a747e4fSDavid du Colombier 			return ShortLower;
4309a747e4fSDavid du Colombier 		return Short;
4319a747e4fSDavid du Colombier 	}
4329a747e4fSDavid du Colombier 	return Long;
4337dd7cddfSDavid du Colombier }
4347dd7cddfSDavid du Colombier 
4357dd7cddfSDavid du Colombier /*
4367dd7cddfSDavid du Colombier  * make an alias for a valid long file name
4377dd7cddfSDavid du Colombier  */
4387dd7cddfSDavid du Colombier void
4397dd7cddfSDavid du Colombier mkalias(char *name, char *sname, int id)
4407dd7cddfSDavid du Colombier {
4417dd7cddfSDavid du Colombier 	Rune r;
4427dd7cddfSDavid du Colombier 	char *s, *e, sid[10];
4437dd7cddfSDavid du Colombier 	int i, esuf, v;
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier 	e = strrchr(name, '.');
4467dd7cddfSDavid du Colombier 	if(e == nil)
4477dd7cddfSDavid du Colombier 		e = strchr(name, '\0');
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier 	s = name;
4507dd7cddfSDavid du Colombier 	i = 0;
4517dd7cddfSDavid du Colombier 	while(s < e && i < 6){
4529a747e4fSDavid du Colombier 		if(isdos[(uchar)*s])
4537dd7cddfSDavid du Colombier 			sname[i++] = *s++;
4547dd7cddfSDavid du Colombier 		else
4557dd7cddfSDavid du Colombier 			s += chartorune(&r, s);
4567dd7cddfSDavid du Colombier 	}
4577dd7cddfSDavid du Colombier 
4587dd7cddfSDavid du Colombier 	v = snprint(sid, 10, "%d", id);
4597dd7cddfSDavid du Colombier 	if(i + 1 + v > 8)
4607dd7cddfSDavid du Colombier 		i = 8 - 1 - v;
4617dd7cddfSDavid du Colombier 	sname[i++] = '~';
4627dd7cddfSDavid du Colombier 	strcpy(&sname[i], sid);
4637dd7cddfSDavid du Colombier 	i += v;
4647dd7cddfSDavid du Colombier 
4657dd7cddfSDavid du Colombier 	sname[i++] = '.';
4667dd7cddfSDavid du Colombier 	esuf = i + 3;
4677dd7cddfSDavid du Colombier 	if(esuf > 12)
4687dd7cddfSDavid du Colombier 		panic("bad mkalias");
4697dd7cddfSDavid du Colombier 	while(*e && i < esuf){
4709a747e4fSDavid du Colombier 		if(isdos[(uchar)*e])
4717dd7cddfSDavid du Colombier 			sname[i++] = *e++;
4727dd7cddfSDavid du Colombier 		else
4737dd7cddfSDavid du Colombier 			e += chartorune(&r, e);
4747dd7cddfSDavid du Colombier 	}
4757dd7cddfSDavid du Colombier 	if(sname[i-1] == '.')
4767dd7cddfSDavid du Colombier 		i--;
4777dd7cddfSDavid du Colombier 	sname[i] = '\0';
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier /*
4817dd7cddfSDavid du Colombier  * check for valid plan 9 names,
4827dd7cddfSDavid du Colombier  * rewrite ' ' to ':'
4837dd7cddfSDavid du Colombier  */
4847dd7cddfSDavid du Colombier char isfrog[256]={
4857dd7cddfSDavid du Colombier 	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,
4867dd7cddfSDavid du Colombier 	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,
4877dd7cddfSDavid du Colombier 	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,
4887dd7cddfSDavid du Colombier 	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,
4899a747e4fSDavid du Colombier /*	[' ']	1,	let's try this -rsc */
4907dd7cddfSDavid du Colombier 	['/']	1,
4917dd7cddfSDavid du Colombier 	[0x7f]	1,
4927dd7cddfSDavid du Colombier };
4937dd7cddfSDavid du Colombier 
4947dd7cddfSDavid du Colombier int
4957dd7cddfSDavid du Colombier nameok(char *elem)
4967dd7cddfSDavid du Colombier {
4977dd7cddfSDavid du Colombier 	while(*elem) {
4989a747e4fSDavid du Colombier 		if(*elem == ' ' && trspaces)
4997dd7cddfSDavid du Colombier 			*elem = ':';
5007dd7cddfSDavid du Colombier 		if(isfrog[*(uchar*)elem])
5017dd7cddfSDavid du Colombier 			return 0;
5027dd7cddfSDavid du Colombier 		elem++;
5037dd7cddfSDavid du Colombier 	}
5047dd7cddfSDavid du Colombier 	return 1;
5057dd7cddfSDavid du Colombier }
5067dd7cddfSDavid du Colombier 
5077dd7cddfSDavid du Colombier /*
5087dd7cddfSDavid du Colombier  * look for a directory entry matching name
5097dd7cddfSDavid du Colombier  * always searches for long names which match a short name
5107dd7cddfSDavid du Colombier  */
5117dd7cddfSDavid du Colombier int
5129a747e4fSDavid du Colombier searchdir(Xfile *f, char *name, Dosptr *dp, int cflag, int longtype)
5137dd7cddfSDavid du Colombier {
5147dd7cddfSDavid du Colombier 	Xfs *xf;
5157dd7cddfSDavid du Colombier 	Iosect *p;
5167dd7cddfSDavid du Colombier 	Dosbpb *bp;
5177dd7cddfSDavid du Colombier 	Dosdir *d;
5187dd7cddfSDavid du Colombier 	char buf[261], *bname;
51959cc4ca5SDavid du Colombier 	int isect, addr, o, addr1, addr2, prevaddr, prevaddr1, o1, islong, have, need, sum;
5207dd7cddfSDavid du Colombier 
5217dd7cddfSDavid du Colombier 	xf = f->xf;
5227dd7cddfSDavid du Colombier 	bp = xf->ptr;
5237dd7cddfSDavid du Colombier 	addr1 = -1;
5247dd7cddfSDavid du Colombier 	addr2 = -1;
52559cc4ca5SDavid du Colombier 	prevaddr1 = -1;
5267dd7cddfSDavid du Colombier 	o1 = 0;
5277dd7cddfSDavid du Colombier 	islong = 0;
5287dd7cddfSDavid du Colombier 	sum = -1;
5297dd7cddfSDavid du Colombier 
5307dd7cddfSDavid du Colombier 	need = 1;
5319a747e4fSDavid du Colombier 	if(longtype!=Short && cflag)
5327dd7cddfSDavid du Colombier 		need += (utflen(name) + DOSRUNE-1) / DOSRUNE;
5337dd7cddfSDavid du Colombier 
5343e12c5d1SDavid du Colombier 	memset(dp, 0, sizeof(Dosptr));
5357dd7cddfSDavid du Colombier 	dp->prevaddr = -1;
5367dd7cddfSDavid du Colombier 	dp->naddr = -1;
5373e12c5d1SDavid du Colombier 	dp->paddr = ((Dosptr *)f->ptr)->addr;
5383e12c5d1SDavid du Colombier 	dp->poffset = ((Dosptr *)f->ptr)->offset;
5393e12c5d1SDavid du Colombier 
5407dd7cddfSDavid du Colombier 	have = 0;
5417dd7cddfSDavid du Colombier 	addr = -1;
5427dd7cddfSDavid du Colombier 	bname = nil;
5433e12c5d1SDavid du Colombier 	for(isect=0;; isect++){
54459cc4ca5SDavid du Colombier 		prevaddr = addr;
5453e12c5d1SDavid du Colombier 		addr = fileaddr(f, isect, cflag);
5463e12c5d1SDavid du Colombier 		if(addr < 0)
5473e12c5d1SDavid du Colombier 			break;
5483e12c5d1SDavid du Colombier 		p = getsect(xf, addr);
5493e12c5d1SDavid du Colombier 		if(p == 0)
5503e12c5d1SDavid du Colombier 			break;
5517dd7cddfSDavid du Colombier 		for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
5523e12c5d1SDavid du Colombier 			d = (Dosdir *)&p->iobuf[o];
5533e12c5d1SDavid du Colombier 			if(d->name[0] == 0x00){
5543e12c5d1SDavid du Colombier 				chat("end dir(0)...");
5553e12c5d1SDavid du Colombier 				putsect(p);
5563e12c5d1SDavid du Colombier 				if(!cflag)
5573e12c5d1SDavid du Colombier 					return -1;
5587dd7cddfSDavid du Colombier 
5597dd7cddfSDavid du Colombier 				/*
5607dd7cddfSDavid du Colombier 				 * addr1 & o1 are the start of the dirs
5617dd7cddfSDavid du Colombier 				 * addr2 is the optional second cluster used if the long name
5627dd7cddfSDavid du Colombier 				 * entry does not fit within the addr1 cluster
5637dd7cddfSDavid du Colombier 				 *
5647dd7cddfSDavid du Colombier 				 * have tells us the number of contiguous free dirs
5657dd7cddfSDavid du Colombier 				 * starting at addr1.o1; need are necessary to hold the long name.
5667dd7cddfSDavid du Colombier 				 */
5677dd7cddfSDavid du Colombier 				if(addr1 < 0){
5683e12c5d1SDavid du Colombier 					addr1 = addr;
56959cc4ca5SDavid du Colombier 					prevaddr1 = prevaddr;
5703e12c5d1SDavid du Colombier 					o1 = o;
5713e12c5d1SDavid du Colombier 				}
5727dd7cddfSDavid du Colombier 				if(addr2 < 0 && (bp->sectsize-o)/DOSDIRSIZE + have < need){
5737dd7cddfSDavid du Colombier 					addr2 = fileaddr(f, isect+1, cflag);
5747dd7cddfSDavid du Colombier 					if(addr2 < 0)
5757dd7cddfSDavid du Colombier 						goto breakout;
5767dd7cddfSDavid du Colombier 				}else if(addr2 < 0)
5777dd7cddfSDavid du Colombier 					addr2 = addr;
5787dd7cddfSDavid du Colombier 				if(addr2 == addr1)
5797dd7cddfSDavid du Colombier 					addr2 = -1;
5803e12c5d1SDavid du Colombier 				dp->addr = addr1;
5813e12c5d1SDavid du Colombier 				dp->offset = o1;
58259cc4ca5SDavid du Colombier 				dp->prevaddr = prevaddr1;
5837dd7cddfSDavid du Colombier 				dp->naddr = addr2;
5843e12c5d1SDavid du Colombier 				return 0;
5853e12c5d1SDavid du Colombier 			}
5867dd7cddfSDavid du Colombier 			if(d->name[0] == DOSEMPTY){
5877dd7cddfSDavid du Colombier 				if(chatty)
5887dd7cddfSDavid du Colombier 					fprint(2, "empty dir\n");
5897dd7cddfSDavid du Colombier 
5907dd7cddfSDavid du Colombier 				have++;
5917dd7cddfSDavid du Colombier 				if(addr1 == -1){
5923e12c5d1SDavid du Colombier 					addr1 = addr;
5933e12c5d1SDavid du Colombier 					o1 = o;
59459cc4ca5SDavid du Colombier 					prevaddr1 = prevaddr;
5953e12c5d1SDavid du Colombier 				}
5967dd7cddfSDavid du Colombier 				if(addr2 == -1 && have >= need)
5977dd7cddfSDavid du Colombier 					addr2 = addr;
5983e12c5d1SDavid du Colombier 				continue;
5993e12c5d1SDavid du Colombier 			}
6007dd7cddfSDavid du Colombier 			have = 0;
6017dd7cddfSDavid du Colombier 			if(addr2 == -1)
6027dd7cddfSDavid du Colombier 				addr1 = -1;
6037dd7cddfSDavid du Colombier 
6043e12c5d1SDavid du Colombier 			dirdump(d);
6057dd7cddfSDavid du Colombier 			if((d->attr & 0xf) == 0xf){
6067dd7cddfSDavid du Colombier 				bname = getnamesect(buf, bname, p->iobuf + o, &islong, &sum, 1);
6077dd7cddfSDavid du Colombier 				continue;
6087dd7cddfSDavid du Colombier 			}
6097dd7cddfSDavid du Colombier 			if(d->attr & DVLABEL){
6107dd7cddfSDavid du Colombier 				islong = 0;
6117dd7cddfSDavid du Colombier 				continue;
6127dd7cddfSDavid du Colombier 			}
6137dd7cddfSDavid du Colombier 			if(islong != 1 || sum != aliassum(d) || cistrcmp(bname, name) != 0){
6147dd7cddfSDavid du Colombier 				bname = buf;
6157dd7cddfSDavid du Colombier 				getname(buf, d);
6167dd7cddfSDavid du Colombier 			}
6177dd7cddfSDavid du Colombier 			islong = 0;
6187dd7cddfSDavid du Colombier 			if(cistrcmp(bname, name) != 0)
6197dd7cddfSDavid du Colombier 				continue;
6207dd7cddfSDavid du Colombier 			if(chatty)
6217dd7cddfSDavid du Colombier 				fprint(2, "found\n");
6223e12c5d1SDavid du Colombier 			if(cflag){
6233e12c5d1SDavid du Colombier 				putsect(p);
6243e12c5d1SDavid du Colombier 				return -1;
6253e12c5d1SDavid du Colombier 			}
6263e12c5d1SDavid du Colombier 			dp->addr = addr;
62759cc4ca5SDavid du Colombier 			dp->prevaddr = prevaddr;
6283e12c5d1SDavid du Colombier 			dp->offset = o;
6293e12c5d1SDavid du Colombier 			dp->p = p;
6303e12c5d1SDavid du Colombier 			dp->d = d;
6313e12c5d1SDavid du Colombier 			return 0;
6323e12c5d1SDavid du Colombier 		}
6333e12c5d1SDavid du Colombier 		putsect(p);
6343e12c5d1SDavid du Colombier 	}
6357dd7cddfSDavid du Colombier breakout:
6363e12c5d1SDavid du Colombier 	chat("end dir(1)...");
6373e12c5d1SDavid du Colombier 	return -1;
6383e12c5d1SDavid du Colombier }
6393e12c5d1SDavid du Colombier 
6403e12c5d1SDavid du Colombier int
6413e12c5d1SDavid du Colombier emptydir(Xfile *f)
6423e12c5d1SDavid du Colombier {
6433e12c5d1SDavid du Colombier 	Xfs *xf = f->xf;
6443e12c5d1SDavid du Colombier 	Dosbpb *bp = xf->ptr;
6453e12c5d1SDavid du Colombier 	int isect, addr, o;
6463e12c5d1SDavid du Colombier 	Iosect *p;
6473e12c5d1SDavid du Colombier 	Dosdir *d;
6483e12c5d1SDavid du Colombier 
6493e12c5d1SDavid du Colombier 	for(isect=0;; isect++){
6503e12c5d1SDavid du Colombier 		addr = fileaddr(f, isect, 0);
6513e12c5d1SDavid du Colombier 		if(addr < 0)
6523e12c5d1SDavid du Colombier 			break;
6533e12c5d1SDavid du Colombier 		p = getsect(xf, addr);
6543e12c5d1SDavid du Colombier 		if(p == 0)
6553e12c5d1SDavid du Colombier 			return -1;
6567dd7cddfSDavid du Colombier 		for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
6573e12c5d1SDavid du Colombier 			d = (Dosdir *)&p->iobuf[o];
6583e12c5d1SDavid du Colombier 			if(d->name[0] == 0x00){
6593e12c5d1SDavid du Colombier 				putsect(p);
6603e12c5d1SDavid du Colombier 				return 0;
6613e12c5d1SDavid du Colombier 			}
6627dd7cddfSDavid du Colombier 			if(d->name[0] == DOSEMPTY)
6633e12c5d1SDavid du Colombier 				continue;
6643e12c5d1SDavid du Colombier 			if(d->name[0] == '.')
6653e12c5d1SDavid du Colombier 				continue;
6663e12c5d1SDavid du Colombier 			if(d->attr&DVLABEL)
6673e12c5d1SDavid du Colombier 				continue;
6683e12c5d1SDavid du Colombier 			putsect(p);
6693e12c5d1SDavid du Colombier 			return -1;
6703e12c5d1SDavid du Colombier 		}
6713e12c5d1SDavid du Colombier 		putsect(p);
6723e12c5d1SDavid du Colombier 	}
6733e12c5d1SDavid du Colombier 	return 0;
6743e12c5d1SDavid du Colombier }
6753e12c5d1SDavid du Colombier 
6763e12c5d1SDavid du Colombier long
6777dd7cddfSDavid du Colombier readdir(Xfile *f, void *vbuf, long offset, long count)
6783e12c5d1SDavid du Colombier {
6797dd7cddfSDavid du Colombier 	Xfs *xf;
6807dd7cddfSDavid du Colombier 	Dosbpb *bp;
6813e12c5d1SDavid du Colombier 	Dir dir;
6827dd7cddfSDavid du Colombier 	int isect, addr, o, islong, sum;
6833e12c5d1SDavid du Colombier 	Iosect *p;
6843e12c5d1SDavid du Colombier 	Dosdir *d;
6859a747e4fSDavid du Colombier 	long rcnt, n;
6869a747e4fSDavid du Colombier 	char *name, snamebuf[8+1+3+1], namebuf[DOSNAMELEN];
6879a747e4fSDavid du Colombier 	uchar *buf;
6883e12c5d1SDavid du Colombier 
6897dd7cddfSDavid du Colombier 	buf = vbuf;
6907dd7cddfSDavid du Colombier 	rcnt = 0;
6917dd7cddfSDavid du Colombier 	xf = f->xf;
6927dd7cddfSDavid du Colombier 	bp = xf->ptr;
6933e12c5d1SDavid du Colombier 	if(count <= 0)
6943e12c5d1SDavid du Colombier 		return 0;
6957dd7cddfSDavid du Colombier 	islong = 0;
6967dd7cddfSDavid du Colombier 	sum = -1;
6977dd7cddfSDavid du Colombier 	name = nil;
6983e12c5d1SDavid du Colombier 	for(isect=0;; isect++){
6993e12c5d1SDavid du Colombier 		addr = fileaddr(f, isect, 0);
7003e12c5d1SDavid du Colombier 		if(addr < 0)
7013e12c5d1SDavid du Colombier 			break;
7023e12c5d1SDavid du Colombier 		p = getsect(xf, addr);
7033e12c5d1SDavid du Colombier 		if(p == 0)
7043e12c5d1SDavid du Colombier 			return -1;
7057dd7cddfSDavid du Colombier 		for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
7063e12c5d1SDavid du Colombier 			d = (Dosdir *)&p->iobuf[o];
7073e12c5d1SDavid du Colombier 			if(d->name[0] == 0x00){
7083e12c5d1SDavid du Colombier 				putsect(p);
7093e12c5d1SDavid du Colombier 				return rcnt;
7103e12c5d1SDavid du Colombier 			}
7117dd7cddfSDavid du Colombier 			if(d->name[0] == DOSEMPTY)
7123e12c5d1SDavid du Colombier 				continue;
7137dd7cddfSDavid du Colombier 			dirdump(d);
7143e12c5d1SDavid du Colombier 			if(d->name[0] == '.'){
7153e12c5d1SDavid du Colombier 				if(d->name[1] == ' ' || d->name[1] == 0)
7163e12c5d1SDavid du Colombier 					continue;
7173e12c5d1SDavid du Colombier 				if(d->name[1] == '.' &&
7183e12c5d1SDavid du Colombier 				  (d->name[2] == ' ' || d->name[2] == 0))
7193e12c5d1SDavid du Colombier 					continue;
7203e12c5d1SDavid du Colombier 			}
7217dd7cddfSDavid du Colombier 			if((d->attr & 0xf) == 0xf){
7227dd7cddfSDavid du Colombier 				name = getnamesect(namebuf, name, p->iobuf+o, &islong, &sum, 1);
7233e12c5d1SDavid du Colombier 				continue;
7243e12c5d1SDavid du Colombier 			}
7257dd7cddfSDavid du Colombier 			if(d->attr & DVLABEL){
7267dd7cddfSDavid du Colombier 				islong = 0;
7277dd7cddfSDavid du Colombier 				continue;
7287dd7cddfSDavid du Colombier 			}
7299a747e4fSDavid du Colombier 			dir.name = snamebuf;
7309a747e4fSDavid du Colombier 			getdir(xf, &dir, d, addr, o);
7319a747e4fSDavid du Colombier 			if(islong == 1 && nameok(name) && sum == aliassum(d))
7329a747e4fSDavid du Colombier 				dir.name = name;
7339a747e4fSDavid du Colombier 			islong = 0;
7349a747e4fSDavid du Colombier 			n = convD2M(&dir, &buf[rcnt], count - rcnt);
7359a747e4fSDavid du Colombier 			name = nil;
7369a747e4fSDavid du Colombier 			if(n <= BIT16SZ){	/* no room for next entry */
7379a747e4fSDavid du Colombier 				putsect(p);
7389a747e4fSDavid du Colombier 				return rcnt;
7399a747e4fSDavid du Colombier 			}
7409a747e4fSDavid du Colombier 			rcnt += n;
7417dd7cddfSDavid du Colombier 			if(offset > 0){
7429a747e4fSDavid du Colombier 				offset -= rcnt;
7439a747e4fSDavid du Colombier 				rcnt = 0;
7447dd7cddfSDavid du Colombier 				islong = 0;
7457dd7cddfSDavid du Colombier 				continue;
7467dd7cddfSDavid du Colombier 			}
7479a747e4fSDavid du Colombier 			if(rcnt == count){
7483e12c5d1SDavid du Colombier 				putsect(p);
7493e12c5d1SDavid du Colombier 				return rcnt;
7503e12c5d1SDavid du Colombier 			}
7513e12c5d1SDavid du Colombier 		}
7523e12c5d1SDavid du Colombier 		putsect(p);
7533e12c5d1SDavid du Colombier 	}
7543e12c5d1SDavid du Colombier 	return rcnt;
7553e12c5d1SDavid du Colombier }
7563e12c5d1SDavid du Colombier 
7577dd7cddfSDavid du Colombier /*
7587dd7cddfSDavid du Colombier  * set up ndp for a directory's parent
7597dd7cddfSDavid du Colombier  * the hardest part is setting up paddr
7607dd7cddfSDavid du Colombier  */
7613e12c5d1SDavid du Colombier int
7623e12c5d1SDavid du Colombier walkup(Xfile *f, Dosptr *ndp)
7633e12c5d1SDavid du Colombier {
7647dd7cddfSDavid du Colombier 	Dosbpb *bp;
7657dd7cddfSDavid du Colombier 	Dosptr *dp;
7663e12c5d1SDavid du Colombier 	Dosdir *xd;
7673e12c5d1SDavid du Colombier 	Iosect *p;
7687dd7cddfSDavid du Colombier 	long k, o, so, start, pstart, ppstart, st, ppclust;
7693e12c5d1SDavid du Colombier 
7707dd7cddfSDavid du Colombier 	bp = f->xf->ptr;
7717dd7cddfSDavid du Colombier 	dp = f->ptr;
7723e12c5d1SDavid du Colombier 	memset(ndp, 0, sizeof(Dosptr));
7737dd7cddfSDavid du Colombier 	ndp->prevaddr = -1;
7747dd7cddfSDavid du Colombier 	ndp->naddr = -1;
7753e12c5d1SDavid du Colombier 	ndp->addr = dp->paddr;
7763e12c5d1SDavid du Colombier 	ndp->offset = dp->poffset;
7777dd7cddfSDavid du Colombier 
7789a747e4fSDavid du Colombier 	chat("walkup: paddr=%#lx...", dp->paddr);
7797dd7cddfSDavid du Colombier 
7807dd7cddfSDavid du Colombier 	/*
7817dd7cddfSDavid du Colombier 	 * root's paddr is always itself
7827dd7cddfSDavid du Colombier 	 */
7837dd7cddfSDavid du Colombier 	if(isroot(dp->paddr))
7843e12c5d1SDavid du Colombier 		return 0;
7857dd7cddfSDavid du Colombier 
7867dd7cddfSDavid du Colombier 	/*
7877dd7cddfSDavid du Colombier 	 * find the start of our parent's directory
7887dd7cddfSDavid du Colombier 	 */
7893e12c5d1SDavid du Colombier 	p = getsect(f->xf, dp->paddr);
7907dd7cddfSDavid du Colombier 	if(p == nil)
7913e12c5d1SDavid du Colombier 		goto error;
7923e12c5d1SDavid du Colombier 	xd = (Dosdir *)&p->iobuf[dp->poffset];
7933e12c5d1SDavid du Colombier 	dirdump(xd);
7947dd7cddfSDavid du Colombier 	start = getstart(f->xf, xd);
7959a747e4fSDavid du Colombier 	chat("start=%#lx...", start);
7963e12c5d1SDavid du Colombier 	if(start == 0)
7973e12c5d1SDavid du Colombier 		goto error;
7983e12c5d1SDavid du Colombier 	putsect(p);
7997dd7cddfSDavid du Colombier 
8007dd7cddfSDavid du Colombier 	/*
8017dd7cddfSDavid du Colombier 	 * verify that parent's . points to itself
8027dd7cddfSDavid du Colombier 	 */
8037dd7cddfSDavid du Colombier 	p = getsect(f->xf, clust2sect(bp, start));
8047dd7cddfSDavid du Colombier 	if(p == nil)
8053e12c5d1SDavid du Colombier 		goto error;
8063e12c5d1SDavid du Colombier 	xd = (Dosdir *)p->iobuf;
8073e12c5d1SDavid du Colombier 	dirdump(xd);
8087dd7cddfSDavid du Colombier 	st = getstart(f->xf, xd);
8097dd7cddfSDavid du Colombier 	if(xd->name[0]!='.' || xd->name[1]!=' ' || start!=st)
8103e12c5d1SDavid du Colombier 		goto error;
8117dd7cddfSDavid du Colombier 
8127dd7cddfSDavid du Colombier 	/*
8137dd7cddfSDavid du Colombier 	 * parent's .. is the next entry, and has start of parent's parent
8147dd7cddfSDavid du Colombier 	 */
8153e12c5d1SDavid du Colombier 	xd++;
8163e12c5d1SDavid du Colombier 	dirdump(xd);
8173e12c5d1SDavid du Colombier 	if(xd->name[0] != '.' || xd->name[1] != '.')
8183e12c5d1SDavid du Colombier 		goto error;
8197dd7cddfSDavid du Colombier 	pstart = getstart(f->xf, xd);
8203e12c5d1SDavid du Colombier 	putsect(p);
8217dd7cddfSDavid du Colombier 
8227dd7cddfSDavid du Colombier 	/*
8237dd7cddfSDavid du Colombier 	 * we're done if parent is root
8247dd7cddfSDavid du Colombier 	 */
8257dd7cddfSDavid du Colombier 	if(pstart == 0 || f->xf->isfat32 && pstart == bp->rootstart)
8263e12c5d1SDavid du Colombier 		return 0;
8277dd7cddfSDavid du Colombier 
8287dd7cddfSDavid du Colombier 	/*
8297dd7cddfSDavid du Colombier 	 * verify that parent's . points to itself
8307dd7cddfSDavid du Colombier 	 */
8317dd7cddfSDavid du Colombier 	p = getsect(f->xf, clust2sect(bp, pstart));
832219b2ee8SDavid du Colombier 	if(p == 0){
8339a747e4fSDavid du Colombier 		chat("getsect %ld failed\n", pstart);
8343e12c5d1SDavid du Colombier 		goto error;
835219b2ee8SDavid du Colombier 	}
8363e12c5d1SDavid du Colombier 	xd = (Dosdir *)p->iobuf;
837219b2ee8SDavid du Colombier 	dirdump(xd);
8387dd7cddfSDavid du Colombier 	st = getstart(f->xf, xd);
8397dd7cddfSDavid du Colombier 	if(xd->name[0]!='.' || xd->name[1]!=' ' || pstart!=st)
8403e12c5d1SDavid du Colombier 		goto error;
8417dd7cddfSDavid du Colombier 
8427dd7cddfSDavid du Colombier 	/*
8437dd7cddfSDavid du Colombier 	 * parent's parent's .. is the next entry, and has start of parent's parent's parent
8447dd7cddfSDavid du Colombier 	 */
8453e12c5d1SDavid du Colombier 	xd++;
846219b2ee8SDavid du Colombier 	dirdump(xd);
8473e12c5d1SDavid du Colombier 	if(xd->name[0] != '.' || xd->name[1] != '.')
8483e12c5d1SDavid du Colombier 		goto error;
8497dd7cddfSDavid du Colombier 	ppstart = getstart(f->xf, xd);
8503e12c5d1SDavid du Colombier 	putsect(p);
8517dd7cddfSDavid du Colombier 
8527dd7cddfSDavid du Colombier 	/*
8537dd7cddfSDavid du Colombier 	 * open parent's parent's parent, and walk through it until parent's parent is found
8547dd7cddfSDavid du Colombier 	 * need this to find parent's parent's addr and offset
8557dd7cddfSDavid du Colombier 	 */
8567dd7cddfSDavid du Colombier 	ppclust = ppstart;
8577dd7cddfSDavid du Colombier 	if(f->xf->isfat32 && ppclust == 0){
8587dd7cddfSDavid du Colombier 		ppclust = bp->rootstart;
8597dd7cddfSDavid du Colombier 		chat("ppclust 0, resetting to rootstart\n");
8607dd7cddfSDavid du Colombier 	}
8617dd7cddfSDavid du Colombier 	k = ppclust ? clust2sect(bp, ppclust) : bp->rootaddr;
8623e12c5d1SDavid du Colombier 	p = getsect(f->xf, k);
8637dd7cddfSDavid du Colombier 	if(p == nil){
8649a747e4fSDavid du Colombier 		chat("getsect %ld failed\n", k);
8653e12c5d1SDavid du Colombier 		goto error;
866219b2ee8SDavid du Colombier 	}
8673e12c5d1SDavid du Colombier 	xd = (Dosdir *)p->iobuf;
868219b2ee8SDavid du Colombier 	dirdump(xd);
8697dd7cddfSDavid du Colombier 	if(ppstart){
8707dd7cddfSDavid du Colombier 		st = getstart(f->xf, xd);
8717dd7cddfSDavid du Colombier 		if(xd->name[0]!='.' || xd->name[1]!=' ' || ppstart!=st)
8723e12c5d1SDavid du Colombier 			goto error;
8737dd7cddfSDavid du Colombier 	}
8743e12c5d1SDavid du Colombier 	for(so=1;; so++){
8757dd7cddfSDavid du Colombier 		for(o=0; o<bp->sectsize; o+=DOSDIRSIZE){
8763e12c5d1SDavid du Colombier 			xd = (Dosdir *)&p->iobuf[o];
877219b2ee8SDavid du Colombier 			if(xd->name[0] == 0x00){
878219b2ee8SDavid du Colombier 				chat("end dir\n");
8793e12c5d1SDavid du Colombier 				goto error;
880219b2ee8SDavid du Colombier 			}
8817dd7cddfSDavid du Colombier 			if(xd->name[0] == DOSEMPTY)
8823e12c5d1SDavid du Colombier 				continue;
8837dd7cddfSDavid du Colombier 			st = getstart(f->xf, xd);
8847dd7cddfSDavid du Colombier 			if(st == pstart)
8853e12c5d1SDavid du Colombier 				goto out;
8863e12c5d1SDavid du Colombier 		}
8877dd7cddfSDavid du Colombier 		if(ppclust){
888219b2ee8SDavid du Colombier 			if(so%bp->clustsize == 0){
8897dd7cddfSDavid du Colombier 				mlock(bp);
8907dd7cddfSDavid du Colombier 				ppclust = getfat(f->xf, ppclust);
8917dd7cddfSDavid du Colombier 				unmlock(bp);
8927dd7cddfSDavid du Colombier 				if(ppclust < 0){
8939a747e4fSDavid du Colombier 					chat("getfat %ld failed\n", ppclust);
8943e12c5d1SDavid du Colombier 					goto error;
895219b2ee8SDavid du Colombier 				}
896219b2ee8SDavid du Colombier 			}
8977dd7cddfSDavid du Colombier 			k = clust2sect(bp, ppclust) +
898219b2ee8SDavid du Colombier 				so%bp->clustsize;
8993e12c5d1SDavid du Colombier 		}else{
9007dd7cddfSDavid du Colombier 			if(so*bp->sectsize >= bp->rootsize*DOSDIRSIZE)
9013e12c5d1SDavid du Colombier 				goto error;
9023e12c5d1SDavid du Colombier 			k = bp->rootaddr + so;
9033e12c5d1SDavid du Colombier 		}
9043e12c5d1SDavid du Colombier 		putsect(p);
9053e12c5d1SDavid du Colombier 		p = getsect(f->xf, k);
906219b2ee8SDavid du Colombier 		if(p == 0){
9079a747e4fSDavid du Colombier 			chat("getsect %ld failed\n", k);
9083e12c5d1SDavid du Colombier 			goto error;
9093e12c5d1SDavid du Colombier 		}
910219b2ee8SDavid du Colombier 	}
9113e12c5d1SDavid du Colombier out:
9123e12c5d1SDavid du Colombier 	putsect(p);
9133e12c5d1SDavid du Colombier 	ndp->paddr = k;
9143e12c5d1SDavid du Colombier 	ndp->poffset = o;
9153e12c5d1SDavid du Colombier 	return 0;
9163e12c5d1SDavid du Colombier 
9173e12c5d1SDavid du Colombier error:
9183e12c5d1SDavid du Colombier 	if(p)
9193e12c5d1SDavid du Colombier 		putsect(p);
9203e12c5d1SDavid du Colombier 	return -1;
9213e12c5d1SDavid du Colombier }
9223e12c5d1SDavid du Colombier 
9233e12c5d1SDavid du Colombier long
9247dd7cddfSDavid du Colombier readfile(Xfile *f, void *vbuf, long offset, long count)
9253e12c5d1SDavid du Colombier {
9263e12c5d1SDavid du Colombier 	Xfs *xf = f->xf;
9273e12c5d1SDavid du Colombier 	Dosbpb *bp = xf->ptr;
9283e12c5d1SDavid du Colombier 	Dosptr *dp = f->ptr;
9293e12c5d1SDavid du Colombier 	Dosdir *d = dp->d;
9303e12c5d1SDavid du Colombier 	int isect, addr, o, c;
9313e12c5d1SDavid du Colombier 	Iosect *p;
9327dd7cddfSDavid du Colombier 	uchar *buf;
9339a747e4fSDavid du Colombier 	long length, rcnt;
9343e12c5d1SDavid du Colombier 
9359a747e4fSDavid du Colombier 	rcnt = 0;
9369a747e4fSDavid du Colombier 	length = GLONG(d->length);
9377dd7cddfSDavid du Colombier 	buf = vbuf;
9383e12c5d1SDavid du Colombier 	if(offset >= length)
9393e12c5d1SDavid du Colombier 		return 0;
9403e12c5d1SDavid du Colombier 	if(offset+count >= length)
9413e12c5d1SDavid du Colombier 		count = length - offset;
9423e12c5d1SDavid du Colombier 	isect = offset/bp->sectsize;
9433e12c5d1SDavid du Colombier 	o = offset%bp->sectsize;
9443e12c5d1SDavid du Colombier 	while(count > 0){
9453e12c5d1SDavid du Colombier 		addr = fileaddr(f, isect++, 0);
9463e12c5d1SDavid du Colombier 		if(addr < 0)
9473e12c5d1SDavid du Colombier 			break;
9483e12c5d1SDavid du Colombier 		c = bp->sectsize - o;
9493e12c5d1SDavid du Colombier 		if(c > count)
9503e12c5d1SDavid du Colombier 			c = count;
9513e12c5d1SDavid du Colombier 		p = getsect(xf, addr);
9523e12c5d1SDavid du Colombier 		if(p == 0)
9533e12c5d1SDavid du Colombier 			return -1;
9543e12c5d1SDavid du Colombier 		memmove(&buf[rcnt], &p->iobuf[o], c);
9553e12c5d1SDavid du Colombier 		putsect(p);
9563e12c5d1SDavid du Colombier 		count -= c;
9573e12c5d1SDavid du Colombier 		rcnt += c;
9583e12c5d1SDavid du Colombier 		o = 0;
9593e12c5d1SDavid du Colombier 	}
9603e12c5d1SDavid du Colombier 	return rcnt;
9613e12c5d1SDavid du Colombier }
9623e12c5d1SDavid du Colombier 
9633e12c5d1SDavid du Colombier long
9647dd7cddfSDavid du Colombier writefile(Xfile *f, void *vbuf, long offset, long count)
9653e12c5d1SDavid du Colombier {
9663e12c5d1SDavid du Colombier 	Xfs *xf = f->xf;
9673e12c5d1SDavid du Colombier 	Dosbpb *bp = xf->ptr;
9683e12c5d1SDavid du Colombier 	Dosptr *dp = f->ptr;
9693e12c5d1SDavid du Colombier 	Dosdir *d = dp->d;
970219b2ee8SDavid du Colombier 	int isect, addr = 0, o, c;
9713e12c5d1SDavid du Colombier 	Iosect *p;
9727dd7cddfSDavid du Colombier 	uchar *buf;
973219b2ee8SDavid du Colombier 	long length, rcnt = 0, dlen;
9743e12c5d1SDavid du Colombier 
9757dd7cddfSDavid du Colombier 	buf = vbuf;
9763e12c5d1SDavid du Colombier 	isect = offset/bp->sectsize;
9773e12c5d1SDavid du Colombier 	o = offset%bp->sectsize;
9783e12c5d1SDavid du Colombier 	while(count > 0){
9793e12c5d1SDavid du Colombier 		addr = fileaddr(f, isect++, 1);
9803e12c5d1SDavid du Colombier 		if(addr < 0)
9813e12c5d1SDavid du Colombier 			break;
9823e12c5d1SDavid du Colombier 		c = bp->sectsize - o;
9833e12c5d1SDavid du Colombier 		if(c > count)
9843e12c5d1SDavid du Colombier 			c = count;
9853e12c5d1SDavid du Colombier 		if(c == bp->sectsize){
9863e12c5d1SDavid du Colombier 			p = getosect(xf, addr);
9873e12c5d1SDavid du Colombier 			p->flags = 0;
9883e12c5d1SDavid du Colombier 		}else{
9893e12c5d1SDavid du Colombier 			p = getsect(xf, addr);
9907dd7cddfSDavid du Colombier 			if(p == nil)
9913e12c5d1SDavid du Colombier 				return -1;
9923e12c5d1SDavid du Colombier 		}
9933e12c5d1SDavid du Colombier 		memmove(&p->iobuf[o], &buf[rcnt], c);
9943e12c5d1SDavid du Colombier 		p->flags |= BMOD;
9953e12c5d1SDavid du Colombier 		putsect(p);
9963e12c5d1SDavid du Colombier 		count -= c;
9973e12c5d1SDavid du Colombier 		rcnt += c;
9983e12c5d1SDavid du Colombier 		o = 0;
9993e12c5d1SDavid du Colombier 	}
1000219b2ee8SDavid du Colombier 	if(rcnt <= 0 && addr < 0)
1001219b2ee8SDavid du Colombier 		return -1;
1002219b2ee8SDavid du Colombier 	length = 0;
1003219b2ee8SDavid du Colombier 	dlen = GLONG(d->length);
1004219b2ee8SDavid du Colombier 	if(rcnt > 0)
10053e12c5d1SDavid du Colombier 		length = offset+rcnt;
1006219b2ee8SDavid du Colombier 	else if(dp->addr && dp->clust){
1007219b2ee8SDavid du Colombier 		c = bp->clustsize*bp->sectsize;
1008219b2ee8SDavid du Colombier 		if(dp->iclust > (dlen+c-1)/c)
1009219b2ee8SDavid du Colombier 			length = c*dp->iclust;
1010219b2ee8SDavid du Colombier 	}
10119a747e4fSDavid du Colombier 	if(length > dlen)
10129a747e4fSDavid du Colombier 		PLONG(d->length, length);
1013219b2ee8SDavid du Colombier 	puttime(d, 0);
10143e12c5d1SDavid du Colombier 	dp->p->flags |= BMOD;
10153e12c5d1SDavid du Colombier 	return rcnt;
10163e12c5d1SDavid du Colombier }
10173e12c5d1SDavid du Colombier 
10183e12c5d1SDavid du Colombier int
10199a747e4fSDavid du Colombier truncfile(Xfile *f, long length)
10203e12c5d1SDavid du Colombier {
10213e12c5d1SDavid du Colombier 	Xfs *xf = f->xf;
10223e12c5d1SDavid du Colombier 	Dosbpb *bp = xf->ptr;
10233e12c5d1SDavid du Colombier 	Dosptr *dp = f->ptr;
10243e12c5d1SDavid du Colombier 	Dosdir *d = dp->d;
10259a747e4fSDavid du Colombier 	long clust, next, n;
10263e12c5d1SDavid du Colombier 
10277dd7cddfSDavid du Colombier 	mlock(bp);
10287dd7cddfSDavid du Colombier 	clust = getstart(f->xf, d);
10299a747e4fSDavid du Colombier 	n = length;
10309a747e4fSDavid du Colombier 	if(n <= 0)
10317dd7cddfSDavid du Colombier 		putstart(f->xf, d, 0);
10329a747e4fSDavid du Colombier 	else
10339a747e4fSDavid du Colombier 		n -= bp->sectsize;
10347dd7cddfSDavid du Colombier 	while(clust > 0){
10353e12c5d1SDavid du Colombier 		next = getfat(xf, clust);
10369a747e4fSDavid du Colombier 		if(n <= 0)
10373e12c5d1SDavid du Colombier 			putfat(xf, clust, 0);
10389a747e4fSDavid du Colombier 		else
10399a747e4fSDavid du Colombier 			n -= bp->clustsize*bp->sectsize;
10403e12c5d1SDavid du Colombier 		clust = next;
10413e12c5d1SDavid du Colombier 	}
10427dd7cddfSDavid du Colombier 	unmlock(bp);
10439a747e4fSDavid du Colombier 	PLONG(d->length, length);
10443e12c5d1SDavid du Colombier 	dp->iclust = 0;
10453e12c5d1SDavid du Colombier 	dp->clust = 0;
10463e12c5d1SDavid du Colombier 	dp->p->flags |= BMOD;
10473e12c5d1SDavid du Colombier 	return 0;
10483e12c5d1SDavid du Colombier }
10493e12c5d1SDavid du Colombier 
10503e12c5d1SDavid du Colombier void
10517dd7cddfSDavid du Colombier putdir(Dosdir *d, Dir *dp)
10527dd7cddfSDavid du Colombier {
10539a747e4fSDavid du Colombier 	if(dp->mode != ~0){
10547dd7cddfSDavid du Colombier 		if(dp->mode & 2)
10557dd7cddfSDavid du Colombier 			d->attr &= ~DRONLY;
10567dd7cddfSDavid du Colombier 		else
10577dd7cddfSDavid du Colombier 			d->attr |= DRONLY;
10589a747e4fSDavid du Colombier 		if(dp->mode & DMEXCL)
10597dd7cddfSDavid du Colombier 			d->attr |= DSYSTEM;
10607dd7cddfSDavid du Colombier 		else
10617dd7cddfSDavid du Colombier 			d->attr &= ~DSYSTEM;
10629a747e4fSDavid du Colombier 	}
10639a747e4fSDavid du Colombier 	if(dp->mtime != ~0)
10647dd7cddfSDavid du Colombier 		puttime(d, dp->mtime);
10657dd7cddfSDavid du Colombier }
10667dd7cddfSDavid du Colombier 
10677dd7cddfSDavid du Colombier /*
10687dd7cddfSDavid du Colombier  * should extend this to deal with
10697dd7cddfSDavid du Colombier  * creation and access dates
10707dd7cddfSDavid du Colombier  */
10717dd7cddfSDavid du Colombier void
10727dd7cddfSDavid du Colombier getdir(Xfs *xfs, Dir *dp, Dosdir *d, int addr, int offset)
10733e12c5d1SDavid du Colombier {
10747dd7cddfSDavid du Colombier 	if(d == nil || addr == 0)
10757dd7cddfSDavid du Colombier 		panic("getdir on root");
10769a747e4fSDavid du Colombier 	dp->type = 0;
10779a747e4fSDavid du Colombier 	dp->dev = 0;
10783e12c5d1SDavid du Colombier 	getname(dp->name, d);
10797dd7cddfSDavid du Colombier 
10807dd7cddfSDavid du Colombier 	dp->qid.path = addr*(Sectorsize/DOSDIRSIZE) +
10817dd7cddfSDavid du Colombier 			offset/DOSDIRSIZE;
10829a747e4fSDavid du Colombier 	dp->qid.vers = 0;
10837dd7cddfSDavid du Colombier 
10843e12c5d1SDavid du Colombier 	if(d->attr & DRONLY)
10853e12c5d1SDavid du Colombier 		dp->mode = 0444;
10863e12c5d1SDavid du Colombier 	else
10873e12c5d1SDavid du Colombier 		dp->mode = 0666;
10883e12c5d1SDavid du Colombier 	dp->atime = gtime(d);
10893e12c5d1SDavid du Colombier 	dp->mtime = dp->atime;
10909a747e4fSDavid du Colombier 	dp->qid.type = QTFILE;
10913e12c5d1SDavid du Colombier 	if(d->attr & DDIR){
10929a747e4fSDavid du Colombier 		dp->qid.type = QTDIR;
10939a747e4fSDavid du Colombier 		dp->mode |= DMDIR|0111;
10949a747e4fSDavid du Colombier 		dp->length = 0;
10953e12c5d1SDavid du Colombier 	}else
10963e12c5d1SDavid du Colombier 		dp->length = GLONG(d->length);
10977dd7cddfSDavid du Colombier 	if(d->attr & DSYSTEM){
10989a747e4fSDavid du Colombier 		dp->mode |= DMEXCL;
10997dd7cddfSDavid du Colombier 		if(iscontig(xfs, d))
11009a747e4fSDavid du Colombier 			dp->mode |= DMAPPEND;
11013e12c5d1SDavid du Colombier 	}
11027dd7cddfSDavid du Colombier 
11039a747e4fSDavid du Colombier 	dp->uid = "bill";
11049a747e4fSDavid du Colombier 	dp->muid = "bill";
11059a747e4fSDavid du Colombier 	dp->gid = "trog";
11063e12c5d1SDavid du Colombier }
11073e12c5d1SDavid du Colombier 
11083e12c5d1SDavid du Colombier void
11093e12c5d1SDavid du Colombier getname(char *p, Dosdir *d)
11103e12c5d1SDavid du Colombier {
11113e12c5d1SDavid du Colombier 	int c, i;
11123e12c5d1SDavid du Colombier 
11133e12c5d1SDavid du Colombier 	for(i=0; i<8; i++){
11143e12c5d1SDavid du Colombier 		c = d->name[i];
11157dd7cddfSDavid du Colombier 		if(c == '\0' || c == ' ')
11163e12c5d1SDavid du Colombier 			break;
11173e12c5d1SDavid du Colombier 		if(i == 0 && c == 0x05)
11183e12c5d1SDavid du Colombier 			c = 0xe5;
11193e12c5d1SDavid du Colombier 		*p++ = c;
11203e12c5d1SDavid du Colombier 	}
11213e12c5d1SDavid du Colombier 	for(i=0; i<3; i++){
11223e12c5d1SDavid du Colombier 		c = d->ext[i];
11237dd7cddfSDavid du Colombier 		if(c == '\0' || c == ' ')
11243e12c5d1SDavid du Colombier 			break;
11253e12c5d1SDavid du Colombier 		if(i == 0)
11263e12c5d1SDavid du Colombier 			*p++ = '.';
11273e12c5d1SDavid du Colombier 		*p++ = c;
11283e12c5d1SDavid du Colombier 	}
11293e12c5d1SDavid du Colombier 	*p = 0;
11303e12c5d1SDavid du Colombier }
11313e12c5d1SDavid du Colombier 
11327dd7cddfSDavid du Colombier static char*
11337dd7cddfSDavid du Colombier getnamerunes(char *dst, uchar *buf, int step)
11347dd7cddfSDavid du Colombier {
11357dd7cddfSDavid du Colombier 	int i;
11367dd7cddfSDavid du Colombier 	Rune r;
11377dd7cddfSDavid du Colombier 	char dbuf[DOSRUNE * UTFmax + 1], *d;
11387dd7cddfSDavid du Colombier 
11397dd7cddfSDavid du Colombier 	d = dbuf;
11407dd7cddfSDavid du Colombier 	r = 1;
11417dd7cddfSDavid du Colombier 	for(i = 1; r && i < 11; i += 2){
11427dd7cddfSDavid du Colombier 		r = buf[i] | (buf[i+1] << 8);
11437dd7cddfSDavid du Colombier 		d += runetochar(d, &r);
11447dd7cddfSDavid du Colombier 	}
11457dd7cddfSDavid du Colombier 	for(i = 14; r && i < 26; i += 2){
11467dd7cddfSDavid du Colombier 		r = buf[i] | (buf[i+1] << 8);
11477dd7cddfSDavid du Colombier 		d += runetochar(d, &r);
11487dd7cddfSDavid du Colombier 	}
11497dd7cddfSDavid du Colombier 	for(i = 28; r && i < 32; i += 2){
11507dd7cddfSDavid du Colombier 		r = buf[i] | (buf[i+1] << 8);
11517dd7cddfSDavid du Colombier 		d += runetochar(d, &r);
11527dd7cddfSDavid du Colombier 	}
11537dd7cddfSDavid du Colombier 
11547dd7cddfSDavid du Colombier 	if(step == 1)
11557dd7cddfSDavid du Colombier 		dst -= d - dbuf;
11567dd7cddfSDavid du Colombier 
11577dd7cddfSDavid du Colombier 	memmove(dst, dbuf, d - dbuf);
11587dd7cddfSDavid du Colombier 
11597dd7cddfSDavid du Colombier 	if(step == -1){
11607dd7cddfSDavid du Colombier 		dst += d - dbuf;
11617dd7cddfSDavid du Colombier 		*dst = '\0';
11627dd7cddfSDavid du Colombier 	}
11637dd7cddfSDavid du Colombier 
11647dd7cddfSDavid du Colombier 	return dst;
11657dd7cddfSDavid du Colombier }
11667dd7cddfSDavid du Colombier 
11677dd7cddfSDavid du Colombier char*
11687dd7cddfSDavid du Colombier getnamesect(char *dbuf, char *d, uchar *buf, int *islong, int *sum, int step)
11697dd7cddfSDavid du Colombier {
11707dd7cddfSDavid du Colombier 	/*
11717dd7cddfSDavid du Colombier 	 * validation checks to make sure we're
11727dd7cddfSDavid du Colombier 	 * making up a consistent name
11737dd7cddfSDavid du Colombier 	 */
11747dd7cddfSDavid du Colombier 	if(buf[11] != 0xf || buf[12] != 0){
11757dd7cddfSDavid du Colombier 		*islong = 0;
11767dd7cddfSDavid du Colombier 		return nil;
11777dd7cddfSDavid du Colombier 	}
11787dd7cddfSDavid du Colombier 	if(step == 1){
11797dd7cddfSDavid du Colombier 		if((buf[0] & 0xc0) == 0x40){
11807dd7cddfSDavid du Colombier 			*islong = buf[0] & 0x3f;
11817dd7cddfSDavid du Colombier 			*sum = buf[13];
11827dd7cddfSDavid du Colombier 			d = dbuf + DOSNAMELEN;
11837dd7cddfSDavid du Colombier 			*--d = '\0';
11847dd7cddfSDavid du Colombier 		}else if(*islong && *islong == buf[0] + 1 && *sum == buf[13]){
11857dd7cddfSDavid du Colombier 			*islong = buf[0];
11867dd7cddfSDavid du Colombier 		}else{
11877dd7cddfSDavid du Colombier 			*islong = 0;
11887dd7cddfSDavid du Colombier 			return nil;
11897dd7cddfSDavid du Colombier 		}
11907dd7cddfSDavid du Colombier 	}else{
11917dd7cddfSDavid du Colombier 		if(*islong + 1 == (buf[0] & 0xbf) && *sum == buf[13]){
11927dd7cddfSDavid du Colombier 			*islong = buf[0] & 0x3f;
11937dd7cddfSDavid du Colombier 			if(buf[0] & 0x40)
11947dd7cddfSDavid du Colombier 				*sum = -1;
11957dd7cddfSDavid du Colombier 		}else{
11967dd7cddfSDavid du Colombier 			*islong = 0;
11977dd7cddfSDavid du Colombier 			*sum = -1;
11987dd7cddfSDavid du Colombier 			return nil;
11997dd7cddfSDavid du Colombier 		}
12007dd7cddfSDavid du Colombier 	}
12017dd7cddfSDavid du Colombier 	if(*islong > 20){
12027dd7cddfSDavid du Colombier 		*islong = 0;
12037dd7cddfSDavid du Colombier 		*sum = -1;
12047dd7cddfSDavid du Colombier 		return nil;
12057dd7cddfSDavid du Colombier 	}
12067dd7cddfSDavid du Colombier 
12077dd7cddfSDavid du Colombier 	return getnamerunes(d, buf, step);
12087dd7cddfSDavid du Colombier }
12097dd7cddfSDavid du Colombier 
12103e12c5d1SDavid du Colombier void
12113e12c5d1SDavid du Colombier putname(char *p, Dosdir *d)
12123e12c5d1SDavid du Colombier {
12133e12c5d1SDavid du Colombier 	int i;
12143e12c5d1SDavid du Colombier 
12153e12c5d1SDavid du Colombier 	memset(d->name, ' ', sizeof d->name+sizeof d->ext);
12163e12c5d1SDavid du Colombier 	for(i=0; i<sizeof d->name; i++){
12173e12c5d1SDavid du Colombier 		if(*p == 0 || *p == '.')
12183e12c5d1SDavid du Colombier 			break;
12193e12c5d1SDavid du Colombier 		d->name[i] = toupper(*p++);
12203e12c5d1SDavid du Colombier 	}
12213e12c5d1SDavid du Colombier 	p = strrchr(p, '.');
12223e12c5d1SDavid du Colombier 	if(p){
12233e12c5d1SDavid du Colombier 		for(i=0; i<sizeof d->ext; i++){
12243e12c5d1SDavid du Colombier 			if(*++p == 0)
12253e12c5d1SDavid du Colombier 				break;
12263e12c5d1SDavid du Colombier 			d->ext[i] = toupper(*p);
12273e12c5d1SDavid du Colombier 		}
12283e12c5d1SDavid du Colombier 	}
12293e12c5d1SDavid du Colombier }
12303e12c5d1SDavid du Colombier 
12317dd7cddfSDavid du Colombier static void
12327dd7cddfSDavid du Colombier putnamesect(uchar *slot, Rune *longname, int curslot, int first, int sum)
12337dd7cddfSDavid du Colombier {
12347dd7cddfSDavid du Colombier 	Rune r;
12357dd7cddfSDavid du Colombier 	Dosdir ds;
12367dd7cddfSDavid du Colombier 	int i, j;
12377dd7cddfSDavid du Colombier 
12387dd7cddfSDavid du Colombier 	memset(&ds, 0xff, sizeof ds);
12397dd7cddfSDavid du Colombier 	ds.attr = 0xf;
12407dd7cddfSDavid du Colombier 	ds.reserved[0] = 0;
12417dd7cddfSDavid du Colombier 	ds.reserved[1] = sum;
12427dd7cddfSDavid du Colombier 	ds.start[0] = 0;
12437dd7cddfSDavid du Colombier 	ds.start[1] = 0;
12447dd7cddfSDavid du Colombier 	if(first)
12457dd7cddfSDavid du Colombier 		ds.name[0] = 0x40 | curslot;
12467dd7cddfSDavid du Colombier 	else
12477dd7cddfSDavid du Colombier 		ds.name[0] = curslot;
12487dd7cddfSDavid du Colombier 	memmove(slot, &ds, sizeof ds);
12497dd7cddfSDavid du Colombier 
12507dd7cddfSDavid du Colombier 	j = (curslot-1) * DOSRUNE;
12517dd7cddfSDavid du Colombier 
12527dd7cddfSDavid du Colombier 	for(i = 1; i < 11; i += 2){
12537dd7cddfSDavid du Colombier 		r = longname[j++];
12547dd7cddfSDavid du Colombier 		slot[i] = r;
12557dd7cddfSDavid du Colombier 		slot[i+1] = r >> 8;
12567dd7cddfSDavid du Colombier 		if(r == 0)
12577dd7cddfSDavid du Colombier 			return;
12587dd7cddfSDavid du Colombier 	}
12597dd7cddfSDavid du Colombier 	for(i = 14; i < 26; i += 2){
12607dd7cddfSDavid du Colombier 		r = longname[j++];
12617dd7cddfSDavid du Colombier 		slot[i] = r;
12627dd7cddfSDavid du Colombier 		slot[i+1] = r >> 8;
12637dd7cddfSDavid du Colombier 		if(r == 0)
12647dd7cddfSDavid du Colombier 			return;
12657dd7cddfSDavid du Colombier 	}
12667dd7cddfSDavid du Colombier 	for(i = 28; i < 32; i += 2){
12677dd7cddfSDavid du Colombier 		r = longname[j++];
12687dd7cddfSDavid du Colombier 		slot[i] = r;
12697dd7cddfSDavid du Colombier 		slot[i+1] = r >> 8;
12707dd7cddfSDavid du Colombier 		if(r == 0)
12717dd7cddfSDavid du Colombier 			return;
12727dd7cddfSDavid du Colombier 	}
12737dd7cddfSDavid du Colombier }
12747dd7cddfSDavid du Colombier 
12757dd7cddfSDavid du Colombier int
12767dd7cddfSDavid du Colombier aliassum(Dosdir *d)
12777dd7cddfSDavid du Colombier {
12787dd7cddfSDavid du Colombier 	int i, sum;
12797dd7cddfSDavid du Colombier 
12807dd7cddfSDavid du Colombier 	if(d == nil)
12817dd7cddfSDavid du Colombier 		return -1;
12827dd7cddfSDavid du Colombier 	sum = 0;
12837dd7cddfSDavid du Colombier 	for(i = 0; i < 11; i++)
12847dd7cddfSDavid du Colombier 		sum = (((sum&1)<<7) | ((sum&0xfe)>>1)) + d->name[i];
12857dd7cddfSDavid du Colombier 	return sum & 0xff;
12867dd7cddfSDavid du Colombier }
12877dd7cddfSDavid du Colombier 
12887dd7cddfSDavid du Colombier int
12897dd7cddfSDavid du Colombier putlongname(Xfs *xf, Dosptr *ndp, char *name, char sname[13])
12907dd7cddfSDavid du Colombier {
12917dd7cddfSDavid du Colombier 	Dosbpb *bp;
12927dd7cddfSDavid du Colombier 	Dosdir tmpd;
12939a747e4fSDavid du Colombier 	Rune longname[DOSNAMELEN+1];
12949a747e4fSDavid du Colombier 	int i, first, sum, nds, len;
12957dd7cddfSDavid du Colombier 
12967dd7cddfSDavid du Colombier 	/* calculate checksum */
12977dd7cddfSDavid du Colombier 	putname(sname, &tmpd);
12987dd7cddfSDavid du Colombier 	sum = aliassum(&tmpd);
12997dd7cddfSDavid du Colombier 
13007dd7cddfSDavid du Colombier 	bp = xf->ptr;
13017dd7cddfSDavid du Colombier 	first = 1;
13029a747e4fSDavid du Colombier 	len = utftorunes(longname, name, DOSNAMELEN);
13039a747e4fSDavid du Colombier 	if(chatty){
13049a747e4fSDavid du Colombier 		chat("utftorunes %s =", name);
13059a747e4fSDavid du Colombier 		for(i=0; i<len; i++)
13069a747e4fSDavid du Colombier 			chat(" %.4X", longname[i]);
13079a747e4fSDavid du Colombier 		chat("\n");
13089a747e4fSDavid du Colombier 	}
13097dd7cddfSDavid du Colombier 	for(nds = (len + DOSRUNE-1) / DOSRUNE; nds > 0; nds--){
13107dd7cddfSDavid du Colombier 		putnamesect(&ndp->p->iobuf[ndp->offset], longname, nds, first, sum);
13117dd7cddfSDavid du Colombier 		first = 0;
13127dd7cddfSDavid du Colombier 		ndp->offset += 32;
13137dd7cddfSDavid du Colombier 		if(ndp->offset == bp->sectsize){
13147dd7cddfSDavid du Colombier 			chat("long name moving over sector boundary\n");
13157dd7cddfSDavid du Colombier 			ndp->p->flags |= BMOD;
13167dd7cddfSDavid du Colombier 			putsect(ndp->p);
13177dd7cddfSDavid du Colombier 			ndp->p = nil;
13187dd7cddfSDavid du Colombier 
13197dd7cddfSDavid du Colombier 			/*
13207dd7cddfSDavid du Colombier 			 * switch to the next cluster for a long entry
13217dd7cddfSDavid du Colombier 			 * naddr should be set up correctly by searchdir
13227dd7cddfSDavid du Colombier 			 */
13237dd7cddfSDavid du Colombier 			ndp->prevaddr = ndp->addr;
13247dd7cddfSDavid du Colombier 			ndp->addr = ndp->naddr;
13257dd7cddfSDavid du Colombier 			ndp->naddr = -1;
13267dd7cddfSDavid du Colombier 			if(ndp->addr == -1)
13277dd7cddfSDavid du Colombier 				return -1;
13287dd7cddfSDavid du Colombier 			ndp->p = getsect(xf, ndp->addr);
13297dd7cddfSDavid du Colombier 			if(ndp->p == nil)
13307dd7cddfSDavid du Colombier 				return -1;
13317dd7cddfSDavid du Colombier 			ndp->offset = 0;
13327dd7cddfSDavid du Colombier 			ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
13337dd7cddfSDavid du Colombier 		}
13347dd7cddfSDavid du Colombier 	}
13357dd7cddfSDavid du Colombier 	return 0;
13367dd7cddfSDavid du Colombier }
13377dd7cddfSDavid du Colombier 
13389a747e4fSDavid du Colombier long
13393e12c5d1SDavid du Colombier getfat(Xfs *xf, int n)
13403e12c5d1SDavid du Colombier {
13413e12c5d1SDavid du Colombier 	Dosbpb *bp = xf->ptr;
13427dd7cddfSDavid du Colombier 	Iosect *p;
13437dd7cddfSDavid du Colombier 	ulong k, sect;
13447dd7cddfSDavid du Colombier 	int o, fb;
13453e12c5d1SDavid du Colombier 
13467dd7cddfSDavid du Colombier 	if(n < FATRESRV || n >= bp->fatclusters)
13473e12c5d1SDavid du Colombier 		return -1;
13487dd7cddfSDavid du Colombier 	fb = bp->fatbits;
13497dd7cddfSDavid du Colombier 	k = (fb * n) >> 3;
13503e12c5d1SDavid du Colombier 	if(k >= bp->fatsize*bp->sectsize)
13513e12c5d1SDavid du Colombier 		panic("getfat");
13523e12c5d1SDavid du Colombier 	sect = k/bp->sectsize + bp->fataddr;
13533e12c5d1SDavid du Colombier 	o = k%bp->sectsize;
13543e12c5d1SDavid du Colombier 	p = getsect(xf, sect);
13557dd7cddfSDavid du Colombier 	if(p == nil)
13563e12c5d1SDavid du Colombier 		return -1;
13573e12c5d1SDavid du Colombier 	k = p->iobuf[o++];
13583e12c5d1SDavid du Colombier 	if(o >= bp->sectsize){
13593e12c5d1SDavid du Colombier 		putsect(p);
13603e12c5d1SDavid du Colombier 		p = getsect(xf, sect+1);
13617dd7cddfSDavid du Colombier 		if(p == nil)
13623e12c5d1SDavid du Colombier 			return -1;
13633e12c5d1SDavid du Colombier 		o = 0;
13643e12c5d1SDavid du Colombier 	}
13657dd7cddfSDavid du Colombier 	k |= p->iobuf[o++]<<8;
13667dd7cddfSDavid du Colombier 	if(fb == 32){
13677dd7cddfSDavid du Colombier 		/* fat32 is really fat28 */
13687dd7cddfSDavid du Colombier 		k |= p->iobuf[o++] << 16;
13697dd7cddfSDavid du Colombier 		k |= (p->iobuf[o] & 0x0f) << 24;
13707dd7cddfSDavid du Colombier 		fb = 28;
13717dd7cddfSDavid du Colombier 	}
13723e12c5d1SDavid du Colombier 	putsect(p);
13737dd7cddfSDavid du Colombier 	if(fb == 12){
13743e12c5d1SDavid du Colombier 		if(n&1)
13753e12c5d1SDavid du Colombier 			k >>= 4;
13763e12c5d1SDavid du Colombier 		else
13773e12c5d1SDavid du Colombier 			k &= 0xfff;
13783e12c5d1SDavid du Colombier 	}
13793e12c5d1SDavid du Colombier 	if(chatty > 1)
13809a747e4fSDavid du Colombier 		chat("fat(%#x)=%#lx...", n, k);
13817dd7cddfSDavid du Colombier 
13827dd7cddfSDavid du Colombier 	/*
13839a747e4fSDavid du Colombier 	 * This is a very strange check for out of range.
13849a747e4fSDavid du Colombier 	 * As a concrete example, for a 16-bit FAT,
13859a747e4fSDavid du Colombier 	 * FFF8 through FFFF all signify ``end of cluster chain.''
13869a747e4fSDavid du Colombier 	 * This generalizes to other-sized FATs.
13877dd7cddfSDavid du Colombier 	 */
13889a747e4fSDavid du Colombier 	if(k >= (1 << fb) - 8)
13897dd7cddfSDavid du Colombier 		return -1;
13907dd7cddfSDavid du Colombier 
13917dd7cddfSDavid du Colombier 	return k;
13923e12c5d1SDavid du Colombier }
13933e12c5d1SDavid du Colombier 
13943e12c5d1SDavid du Colombier void
13957dd7cddfSDavid du Colombier putfat(Xfs *xf, int n, ulong val)
13963e12c5d1SDavid du Colombier {
13977dd7cddfSDavid du Colombier 	Fatinfo *fi;
13987dd7cddfSDavid du Colombier 	Dosbpb *bp;
13997dd7cddfSDavid du Colombier 	Iosect *p;
14007dd7cddfSDavid du Colombier 	ulong k, sect, esect;
14013e12c5d1SDavid du Colombier 	int o;
14023e12c5d1SDavid du Colombier 
14037dd7cddfSDavid du Colombier 	bp = xf->ptr;
14047dd7cddfSDavid du Colombier 	if(n < FATRESRV || n >= bp->fatclusters)
14057dd7cddfSDavid du Colombier 		panic("putfat n=%d", n);
14067dd7cddfSDavid du Colombier 	k = (bp->fatbits * n) >> 3;
14073e12c5d1SDavid du Colombier 	if(k >= bp->fatsize*bp->sectsize)
14083e12c5d1SDavid du Colombier 		panic("putfat");
14093e12c5d1SDavid du Colombier 	sect = k/bp->sectsize + bp->fataddr;
14107dd7cddfSDavid du Colombier 	esect = sect + bp->nfats * bp->fatsize;
14117dd7cddfSDavid du Colombier 	for(; sect<esect; sect+=bp->fatsize){
14123e12c5d1SDavid du Colombier 		o = k%bp->sectsize;
14133e12c5d1SDavid du Colombier 		p = getsect(xf, sect);
14147dd7cddfSDavid du Colombier 		if(p == nil)
14153e12c5d1SDavid du Colombier 			continue;
14163e12c5d1SDavid du Colombier 		switch(bp->fatbits){
14173e12c5d1SDavid du Colombier 		case 12:
14183e12c5d1SDavid du Colombier 			if(n&1){
14193e12c5d1SDavid du Colombier 				p->iobuf[o] &= 0x0f;
14203e12c5d1SDavid du Colombier 				p->iobuf[o++] |= val<<4;
14213e12c5d1SDavid du Colombier 				if(o >= bp->sectsize){
14223e12c5d1SDavid du Colombier 					p->flags |= BMOD;
14233e12c5d1SDavid du Colombier 					putsect(p);
14243e12c5d1SDavid du Colombier 					p = getsect(xf, sect+1);
14257dd7cddfSDavid du Colombier 					if(p == nil)
14263e12c5d1SDavid du Colombier 						continue;
14273e12c5d1SDavid du Colombier 					o = 0;
14283e12c5d1SDavid du Colombier 				}
14293e12c5d1SDavid du Colombier 				p->iobuf[o] = val>>4;
14303e12c5d1SDavid du Colombier 			}else{
14313e12c5d1SDavid du Colombier 				p->iobuf[o++] = val;
14323e12c5d1SDavid du Colombier 				if(o >= bp->sectsize){
14333e12c5d1SDavid du Colombier 					p->flags |= BMOD;
14343e12c5d1SDavid du Colombier 					putsect(p);
14353e12c5d1SDavid du Colombier 					p = getsect(xf, sect+1);
14367dd7cddfSDavid du Colombier 					if(p == nil)
14373e12c5d1SDavid du Colombier 						continue;
14383e12c5d1SDavid du Colombier 					o = 0;
14393e12c5d1SDavid du Colombier 				}
14403e12c5d1SDavid du Colombier 				p->iobuf[o] &= 0xf0;
14413e12c5d1SDavid du Colombier 				p->iobuf[o] |= (val>>8) & 0x0f;
14423e12c5d1SDavid du Colombier 			}
14433e12c5d1SDavid du Colombier 			break;
14443e12c5d1SDavid du Colombier 		case 16:
14453e12c5d1SDavid du Colombier 			p->iobuf[o++] = val;
14463e12c5d1SDavid du Colombier 			p->iobuf[o] = val>>8;
14473e12c5d1SDavid du Colombier 			break;
14487dd7cddfSDavid du Colombier 		case 32:	/* fat32 is really fat28 */
14497dd7cddfSDavid du Colombier 			p->iobuf[o++] = val;
14507dd7cddfSDavid du Colombier 			p->iobuf[o++] = val>>8;
14517dd7cddfSDavid du Colombier 			p->iobuf[o++] = val>>16;
14527dd7cddfSDavid du Colombier 			p->iobuf[o] = (p->iobuf[o] & 0xf0) | ((val>>24) & 0x0f);
14537dd7cddfSDavid du Colombier 			break;
14547dd7cddfSDavid du Colombier 		default:
14557dd7cddfSDavid du Colombier 			panic("putfat fatbits");
14563e12c5d1SDavid du Colombier 		}
14573e12c5d1SDavid du Colombier 		p->flags |= BMOD;
14583e12c5d1SDavid du Colombier 		putsect(p);
14593e12c5d1SDavid du Colombier 	}
14607dd7cddfSDavid du Colombier 
14617dd7cddfSDavid du Colombier 	if(val == 0)
14627dd7cddfSDavid du Colombier 		bp->freeclusters++;
14637dd7cddfSDavid du Colombier 	else
14647dd7cddfSDavid du Colombier 		bp->freeclusters--;
14657dd7cddfSDavid du Colombier 
14667dd7cddfSDavid du Colombier 	if(bp->fatinfo){
14677dd7cddfSDavid du Colombier 		p = getsect(xf, bp->fatinfo);
14687dd7cddfSDavid du Colombier 		if(p != nil){
14697dd7cddfSDavid du Colombier 			fi = (Fatinfo*)p->iobuf;
14709a747e4fSDavid du Colombier 			PLONG(fi->nextfree, bp->freeptr);
14719a747e4fSDavid du Colombier 			PLONG(fi->freeclust, bp->freeclusters);
14727dd7cddfSDavid du Colombier 			p->flags |= BMOD;
14737dd7cddfSDavid du Colombier 			putsect(p);
14747dd7cddfSDavid du Colombier 		}
14757dd7cddfSDavid du Colombier 	}
14767dd7cddfSDavid du Colombier }
14777dd7cddfSDavid du Colombier 
14787dd7cddfSDavid du Colombier /*
14797dd7cddfSDavid du Colombier  * Contiguous falloc; if we can, use lastclust+1.
14807dd7cddfSDavid du Colombier  * Otherwise, move the file to get some space.
14817dd7cddfSDavid du Colombier  * If there just isn't enough contiguous space
14827dd7cddfSDavid du Colombier  * anywhere on disk, fail.
14837dd7cddfSDavid du Colombier  */
14847dd7cddfSDavid du Colombier int
14857dd7cddfSDavid du Colombier cfalloc(Xfile *f)
14867dd7cddfSDavid du Colombier {
14877dd7cddfSDavid du Colombier 	int l;
14887dd7cddfSDavid du Colombier 
14897dd7cddfSDavid du Colombier 	if((l=makecontig(f, 8)) >= 0)
14907dd7cddfSDavid du Colombier 		return l;
14917dd7cddfSDavid du Colombier 	return makecontig(f, 1);
14927dd7cddfSDavid du Colombier }
14937dd7cddfSDavid du Colombier 
14947dd7cddfSDavid du Colombier /*
14957dd7cddfSDavid du Colombier  * Check whether a file is contiguous.
14967dd7cddfSDavid du Colombier  */
14977dd7cddfSDavid du Colombier int
14987dd7cddfSDavid du Colombier iscontig(Xfs *xf, Dosdir *d)
14997dd7cddfSDavid du Colombier {
15007dd7cddfSDavid du Colombier 	long clust, next;
15017dd7cddfSDavid du Colombier 
15027dd7cddfSDavid du Colombier 	clust = getstart(xf, d);
15037dd7cddfSDavid du Colombier 	if(clust <= 0)
15047dd7cddfSDavid du Colombier 		return 1;
15057dd7cddfSDavid du Colombier 
15067dd7cddfSDavid du Colombier 	for(;;) {
15077dd7cddfSDavid du Colombier 		next = getfat(xf, clust);
15087dd7cddfSDavid du Colombier 		if(next < 0)
15097dd7cddfSDavid du Colombier 			return 1;
15107dd7cddfSDavid du Colombier 		if(next != clust+1)
15117dd7cddfSDavid du Colombier 			return 0;
15127dd7cddfSDavid du Colombier 		clust = next;
15137dd7cddfSDavid du Colombier 	}
15147dd7cddfSDavid du Colombier }
15157dd7cddfSDavid du Colombier 
15167dd7cddfSDavid du Colombier /*
15177dd7cddfSDavid du Colombier  * Make a file contiguous, with nextra clusters of
15187dd7cddfSDavid du Colombier  * free space after it for later expansion.
15197dd7cddfSDavid du Colombier  * Return the number of the first new cluster.
15207dd7cddfSDavid du Colombier  */
15217dd7cddfSDavid du Colombier int
15227dd7cddfSDavid du Colombier makecontig(Xfile *f, int nextra)
15237dd7cddfSDavid du Colombier {
15247dd7cddfSDavid du Colombier 	Dosbpb *bp;
15257dd7cddfSDavid du Colombier 	Dosdir *d;
15267dd7cddfSDavid du Colombier 	Dosptr *dp;
15277dd7cddfSDavid du Colombier 	Xfs *xf;
15287dd7cddfSDavid du Colombier 	Iosect *wp, *rp;
15297dd7cddfSDavid du Colombier 	long clust, next, last, start, rclust, wclust, eclust, ostart;
15309a747e4fSDavid du Colombier 	int isok, i, n, nclust, nrun, rs, ws;
15317dd7cddfSDavid du Colombier 
15327dd7cddfSDavid du Colombier 	xf = f->xf;
15337dd7cddfSDavid du Colombier 	bp = xf->ptr;
15347dd7cddfSDavid du Colombier 	dp = f->ptr;
15357dd7cddfSDavid du Colombier 	d = dp->d;
15367dd7cddfSDavid du Colombier 
15377dd7cddfSDavid du Colombier 	isok = 1;
15387dd7cddfSDavid du Colombier 	nclust = 0;
15397dd7cddfSDavid du Colombier 	clust = fileclust(f, 0, 0);
15409a747e4fSDavid du Colombier 	chat("clust %#lux", clust);
15417dd7cddfSDavid du Colombier 	if(clust != -1) {
15427dd7cddfSDavid du Colombier 		for(;;) {
15437dd7cddfSDavid du Colombier 			nclust++;
15447dd7cddfSDavid du Colombier 			chat(".");
15457dd7cddfSDavid du Colombier 			next = getfat(xf, clust);
15467dd7cddfSDavid du Colombier 			if(next <= 0)
15477dd7cddfSDavid du Colombier 				break;
15487dd7cddfSDavid du Colombier 			if(next != clust+1)
15497dd7cddfSDavid du Colombier 				isok = 0;
15507dd7cddfSDavid du Colombier 			clust = next;
15517dd7cddfSDavid du Colombier 		}
15527dd7cddfSDavid du Colombier 	}
15537dd7cddfSDavid du Colombier 	chat("nclust %d\n", nclust);
15547dd7cddfSDavid du Colombier 
15557dd7cddfSDavid du Colombier 	if(isok && clust != -1) {
15567dd7cddfSDavid du Colombier 		eclust = clust+1;	/* eclust = first cluster past file */
15577dd7cddfSDavid du Colombier 		assert(eclust == fileclust(f, 0, 0)+nclust);
15587dd7cddfSDavid du Colombier 		for(i=0; i<nextra; i++)
15597dd7cddfSDavid du Colombier 			if(getfat(xf, eclust+i) != 0)
15607dd7cddfSDavid du Colombier 				break;
15617dd7cddfSDavid du Colombier 		if(i == nextra) {	/* they were all free */
15629a747e4fSDavid du Colombier 			chat("eclust=%#lx, getfat eclust-1 = %#lux\n", eclust, getfat(xf, eclust-1));
15637dd7cddfSDavid du Colombier 			assert(getfat(xf, eclust-1) == 0xffffffff);
15647dd7cddfSDavid du Colombier 			putfat(xf, eclust-1, eclust);
15657dd7cddfSDavid du Colombier 			putfat(xf, eclust, 0xffffffff);
15667dd7cddfSDavid du Colombier 			bp->freeptr = clust+1;	/* to help keep the blocks free */
15677dd7cddfSDavid du Colombier 			return eclust;
15687dd7cddfSDavid du Colombier 		}
15697dd7cddfSDavid du Colombier 	}
15707dd7cddfSDavid du Colombier 
15717dd7cddfSDavid du Colombier 	/* need to search for nclust+nextra contiguous free blocks */
15727dd7cddfSDavid du Colombier 	last = -1;
15737dd7cddfSDavid du Colombier 	n = bp->freeptr;
15747dd7cddfSDavid du Colombier 	nrun = 0;
15757dd7cddfSDavid du Colombier 	for(;;){
15767dd7cddfSDavid du Colombier 		if(getfat(xf, n) == 0) {
15777dd7cddfSDavid du Colombier 			if(last+1 == n)
15787dd7cddfSDavid du Colombier 				nrun++;
15797dd7cddfSDavid du Colombier 			else
15807dd7cddfSDavid du Colombier 				nrun = 1;
15817dd7cddfSDavid du Colombier 			if(nrun >= nclust+nextra)
15827dd7cddfSDavid du Colombier 				break;
15837dd7cddfSDavid du Colombier 			last = n;
15847dd7cddfSDavid du Colombier 		}
15857dd7cddfSDavid du Colombier 		if(++n >= bp->fatclusters)
15867dd7cddfSDavid du Colombier 			n = FATRESRV;
15877dd7cddfSDavid du Colombier 		if(n == bp->freeptr) {
15887dd7cddfSDavid du Colombier 			errno = Econtig;
15897dd7cddfSDavid du Colombier 			return -1;
15907dd7cddfSDavid du Colombier 		}
15917dd7cddfSDavid du Colombier 	}
15927dd7cddfSDavid du Colombier 	bp->freeptr = n+1;
15937dd7cddfSDavid du Colombier 
15947dd7cddfSDavid du Colombier 	/* copy old data over */
15957dd7cddfSDavid du Colombier 	start = n+1 - nrun;
15967dd7cddfSDavid du Colombier 
15977dd7cddfSDavid du Colombier 	/* sanity check */
15987dd7cddfSDavid du Colombier 	for(i=0; i<nclust+nextra; i++)
15997dd7cddfSDavid du Colombier 		assert(getfat(xf, start+i) == 0);
16007dd7cddfSDavid du Colombier 
16019a747e4fSDavid du Colombier 	chat("relocate chain %lux -> 0x%lux len %d\n", fileclust(f, 0, 0), start, nclust);
16027dd7cddfSDavid du Colombier 
16037dd7cddfSDavid du Colombier 	wclust = start;
16047dd7cddfSDavid du Colombier 	for(rclust = fileclust(f, 0, 0); rclust > 0; rclust = next){
16057dd7cddfSDavid du Colombier 		rs = clust2sect(bp, rclust);
16067dd7cddfSDavid du Colombier 		ws = clust2sect(bp, wclust);
16077dd7cddfSDavid du Colombier 		for(i=0; i<bp->clustsize; i++, rs++, ws++){
16087dd7cddfSDavid du Colombier 			rp = getsect(xf, rs);
16097dd7cddfSDavid du Colombier 			if(rp == nil)
16107dd7cddfSDavid du Colombier 				return -1;
16117dd7cddfSDavid du Colombier 			wp = getosect(xf, ws);
16127dd7cddfSDavid du Colombier 			assert(wp != nil);
16137dd7cddfSDavid du Colombier 			memmove(wp->iobuf, rp->iobuf, bp->sectsize);
16147dd7cddfSDavid du Colombier 			wp->flags = BMOD;
16157dd7cddfSDavid du Colombier 			putsect(rp);
16167dd7cddfSDavid du Colombier 			putsect(wp);
16177dd7cddfSDavid du Colombier 		}
16189a747e4fSDavid du Colombier 		chat("move cluster %#lx -> %#lx...", rclust, wclust);
16197dd7cddfSDavid du Colombier 		next = getfat(xf, rclust);
16207dd7cddfSDavid du Colombier 		putfat(xf, wclust, wclust+1);
16217dd7cddfSDavid du Colombier 		wclust++;
16227dd7cddfSDavid du Colombier 	}
16237dd7cddfSDavid du Colombier 
16247dd7cddfSDavid du Colombier 	/* now wclust points at the first new cluster; chain it in */
16257dd7cddfSDavid du Colombier 	chat("wclust 0x%lux start 0x%lux (fat->0x%lux) nclust %d\n", wclust, start, getfat(xf, start), nclust);
16267dd7cddfSDavid du Colombier 	assert(wclust == start+nclust);
16277dd7cddfSDavid du Colombier 	putfat(xf, wclust, 0xffffffff);	/* end of file */
16287dd7cddfSDavid du Colombier 
16297dd7cddfSDavid du Colombier 	/* update directory entry to point at new start */
16307dd7cddfSDavid du Colombier 	ostart = fileclust(f, 0, 0);
16317dd7cddfSDavid du Colombier 	putstart(xf, d, start);
16327dd7cddfSDavid du Colombier 
16337dd7cddfSDavid du Colombier 	/* check our work */
16347dd7cddfSDavid du Colombier 	i = 0;
16357dd7cddfSDavid du Colombier 	clust = fileclust(f, 0, 0);
16367dd7cddfSDavid du Colombier 	if(clust != -1) {
16377dd7cddfSDavid du Colombier 		for(;;) {
16387dd7cddfSDavid du Colombier 			i++;
16397dd7cddfSDavid du Colombier 			next = getfat(xf, clust);
16407dd7cddfSDavid du Colombier 			if(next <= 0)
16417dd7cddfSDavid du Colombier 				break;
16427dd7cddfSDavid du Colombier 			assert(next == clust+1);
16437dd7cddfSDavid du Colombier 			clust = next;
16447dd7cddfSDavid du Colombier 		}
16457dd7cddfSDavid du Colombier 	}
16467dd7cddfSDavid du Colombier 	chat("chain check: len %d\n", i);
16477dd7cddfSDavid du Colombier 	assert(i == nclust+1);
16487dd7cddfSDavid du Colombier 
16497dd7cddfSDavid du Colombier 	/* succeeded; remove old chain. */
16507dd7cddfSDavid du Colombier 	for(rclust = ostart; rclust > 0; rclust = next){
16517dd7cddfSDavid du Colombier 		next = getfat(xf, rclust);
16527dd7cddfSDavid du Colombier 		putfat(xf, rclust, 0);	/* free cluster */
16537dd7cddfSDavid du Colombier 	}
16547dd7cddfSDavid du Colombier 
16557dd7cddfSDavid du Colombier 	return start+nclust;
16563e12c5d1SDavid du Colombier }
16573e12c5d1SDavid du Colombier 
16583e12c5d1SDavid du Colombier int
16593e12c5d1SDavid du Colombier falloc(Xfs *xf)
16603e12c5d1SDavid du Colombier {
16613e12c5d1SDavid du Colombier 	Dosbpb *bp = xf->ptr;
16623e12c5d1SDavid du Colombier 	Iosect *p;
16639a747e4fSDavid du Colombier 	int n, i, k;
16643e12c5d1SDavid du Colombier 
16653e12c5d1SDavid du Colombier 	n = bp->freeptr;
16663e12c5d1SDavid du Colombier 	for(;;){
16673e12c5d1SDavid du Colombier 		if(getfat(xf, n) == 0)
16683e12c5d1SDavid du Colombier 			break;
16693e12c5d1SDavid du Colombier 		if(++n >= bp->fatclusters)
16707dd7cddfSDavid du Colombier 			n = FATRESRV;
16713e12c5d1SDavid du Colombier 		if(n == bp->freeptr)
16723e12c5d1SDavid du Colombier 			return -1;
16733e12c5d1SDavid du Colombier 	}
16743e12c5d1SDavid du Colombier 	bp->freeptr = n+1;
16753e12c5d1SDavid du Colombier 	if(bp->freeptr >= bp->fatclusters)
16767dd7cddfSDavid du Colombier 		bp->freeptr = FATRESRV;
16777dd7cddfSDavid du Colombier 	putfat(xf, n, 0xffffffff);
16787dd7cddfSDavid du Colombier 	k = clust2sect(bp, n);
16793e12c5d1SDavid du Colombier 	for(i=0; i<bp->clustsize; i++){
16803e12c5d1SDavid du Colombier 		p = getosect(xf, k+i);
16813e12c5d1SDavid du Colombier 		memset(p->iobuf, 0, bp->sectsize);
16823e12c5d1SDavid du Colombier 		p->flags = BMOD;
16833e12c5d1SDavid du Colombier 		putsect(p);
16843e12c5d1SDavid du Colombier 	}
16853e12c5d1SDavid du Colombier 	return n;
16863e12c5d1SDavid du Colombier }
16873e12c5d1SDavid du Colombier 
16883e12c5d1SDavid du Colombier void
16897dd7cddfSDavid du Colombier ffree(Xfs *xf, long start)
16903e12c5d1SDavid du Colombier {
16917dd7cddfSDavid du Colombier 	putfat(xf, start, 0);
16927dd7cddfSDavid du Colombier }
16933e12c5d1SDavid du Colombier 
16947dd7cddfSDavid du Colombier long
16957dd7cddfSDavid du Colombier clust2sect(Dosbpb *bp, long clust)
16967dd7cddfSDavid du Colombier {
16977dd7cddfSDavid du Colombier 	return bp->dataaddr + (clust - FATRESRV) * bp->clustsize;
16987dd7cddfSDavid du Colombier }
16997dd7cddfSDavid du Colombier 
17007dd7cddfSDavid du Colombier long
17017dd7cddfSDavid du Colombier sect2clust(Dosbpb *bp, long sect)
17027dd7cddfSDavid du Colombier {
17037dd7cddfSDavid du Colombier 	long c;
17047dd7cddfSDavid du Colombier 
17057dd7cddfSDavid du Colombier 	c = (sect - bp->dataaddr) / bp->clustsize + FATRESRV;
17067dd7cddfSDavid du Colombier 	assert(sect == clust2sect(bp, c));
17077dd7cddfSDavid du Colombier 	return c;
17083e12c5d1SDavid du Colombier }
17093e12c5d1SDavid du Colombier 
17103e12c5d1SDavid du Colombier void
1711219b2ee8SDavid du Colombier puttime(Dosdir *d, long s)
17123e12c5d1SDavid du Colombier {
1713219b2ee8SDavid du Colombier 	Tm *t;
17143e12c5d1SDavid du Colombier 	ushort x;
17153e12c5d1SDavid du Colombier 
1716219b2ee8SDavid du Colombier 	if(s == 0)
1717219b2ee8SDavid du Colombier 		s = time(0);
1718219b2ee8SDavid du Colombier 	t = localtime(s);
1719219b2ee8SDavid du Colombier 
17203e12c5d1SDavid du Colombier 	x = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
17219a747e4fSDavid du Colombier 	PSHORT(d->time, x);
17223e12c5d1SDavid du Colombier 	x = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
17239a747e4fSDavid du Colombier 	PSHORT(d->date, x);
17243e12c5d1SDavid du Colombier }
17253e12c5d1SDavid du Colombier 
17263e12c5d1SDavid du Colombier long
17273e12c5d1SDavid du Colombier gtime(Dosdir *dp)
17283e12c5d1SDavid du Colombier {
17297dd7cddfSDavid du Colombier 	Tm tm;
17307dd7cddfSDavid du Colombier 	int i;
17313e12c5d1SDavid du Colombier 
17323e12c5d1SDavid du Colombier 	i = GSHORT(dp->time);
17337dd7cddfSDavid du Colombier 	tm.hour = i >> 11;
17347dd7cddfSDavid du Colombier 	tm.min = (i >> 5) & 63;
17357dd7cddfSDavid du Colombier 	tm.sec = (i & 31) << 1;
17363e12c5d1SDavid du Colombier 	i = GSHORT(dp->date);
17377dd7cddfSDavid du Colombier 	tm.year = 80 + (i >> 9);
17387dd7cddfSDavid du Colombier 	tm.mon = ((i >> 5) & 15) - 1;
17397dd7cddfSDavid du Colombier 	tm.mday = i & 31;
17407dd7cddfSDavid du Colombier 	tm.zone[0] = '\0';
17417dd7cddfSDavid du Colombier 	tm.tzoff = 0;
17426b6b9ac8SDavid du Colombier 	tm.yday = 0;
17433e12c5d1SDavid du Colombier 
17447dd7cddfSDavid du Colombier 	return tm2sec(&tm);
17457dd7cddfSDavid du Colombier }
17467dd7cddfSDavid du Colombier 
17477dd7cddfSDavid du Colombier /*
17487dd7cddfSDavid du Colombier  * structure dumps for debugging
17497dd7cddfSDavid du Colombier  */
17507dd7cddfSDavid du Colombier void
17517dd7cddfSDavid du Colombier bootdump(int fd, Dosboot *b)
17527dd7cddfSDavid du Colombier {
17537dd7cddfSDavid du Colombier 	Biobuf bp;
17547dd7cddfSDavid du Colombier 
17557dd7cddfSDavid du Colombier 	Binit(&bp, fd, OWRITE);
17567dd7cddfSDavid du Colombier 	Bprint(&bp, "magic: 0x%2.2x 0x%2.2x 0x%2.2x\n",
17577dd7cddfSDavid du Colombier 		b->magic[0], b->magic[1], b->magic[2]);
17587dd7cddfSDavid du Colombier 	Bprint(&bp, "version: \"%8.8s\"\n", (char*)b->version);
17597dd7cddfSDavid du Colombier 	Bprint(&bp, "sectsize: %d\n", GSHORT(b->sectsize));
17607dd7cddfSDavid du Colombier 	Bprint(&bp, "clustsize: %d\n", b->clustsize);
17617dd7cddfSDavid du Colombier 	Bprint(&bp, "nresrv: %d\n", GSHORT(b->nresrv));
17627dd7cddfSDavid du Colombier 	Bprint(&bp, "nfats: %d\n", b->nfats);
17637dd7cddfSDavid du Colombier 	Bprint(&bp, "rootsize: %d\n", GSHORT(b->rootsize));
17647dd7cddfSDavid du Colombier 	Bprint(&bp, "volsize: %d\n", GSHORT(b->volsize));
17657dd7cddfSDavid du Colombier 	Bprint(&bp, "mediadesc: 0x%2.2x\n", b->mediadesc);
17667dd7cddfSDavid du Colombier 	Bprint(&bp, "fatsize: %d\n", GSHORT(b->fatsize));
17677dd7cddfSDavid du Colombier 	Bprint(&bp, "trksize: %d\n", GSHORT(b->trksize));
17687dd7cddfSDavid du Colombier 	Bprint(&bp, "nheads: %d\n", GSHORT(b->nheads));
17697dd7cddfSDavid du Colombier 	Bprint(&bp, "nhidden: %ld\n", GLONG(b->nhidden));
17707dd7cddfSDavid du Colombier 	Bprint(&bp, "bigvolsize: %ld\n", GLONG(b->bigvolsize));
17717dd7cddfSDavid du Colombier 	Bprint(&bp, "driveno: %d\n", b->driveno);
17727dd7cddfSDavid du Colombier 	Bprint(&bp, "reserved0: 0x%2.2x\n", b->reserved0);
17737dd7cddfSDavid du Colombier 	Bprint(&bp, "bootsig: 0x%2.2x\n", b->bootsig);
17747dd7cddfSDavid du Colombier 	Bprint(&bp, "volid: 0x%8.8lux\n", GLONG(b->volid));
17757dd7cddfSDavid du Colombier 	Bprint(&bp, "label: \"%11.11s\"\n", (char*)b->label);
17767dd7cddfSDavid du Colombier 	Bterm(&bp);
17773e12c5d1SDavid du Colombier }
17783e12c5d1SDavid du Colombier 
17793e12c5d1SDavid du Colombier void
17807dd7cddfSDavid du Colombier bootdump32(int fd, Dosboot32 *b)
17817dd7cddfSDavid du Colombier {
17827dd7cddfSDavid du Colombier 	Biobuf bp;
17837dd7cddfSDavid du Colombier 
17847dd7cddfSDavid du Colombier 	Binit(&bp, fd, OWRITE);
17857dd7cddfSDavid du Colombier 	Bprint(&bp, "magic: 0x%2.2x 0x%2.2x 0x%2.2x\n",
17867dd7cddfSDavid du Colombier 		b->magic[0], b->magic[1], b->magic[2]);
17877dd7cddfSDavid du Colombier 	Bprint(&bp, "version: \"%8.8s\"\n", (char*)b->version);
17887dd7cddfSDavid du Colombier 	Bprint(&bp, "sectsize: %d\n", GSHORT(b->sectsize));
17897dd7cddfSDavid du Colombier 	Bprint(&bp, "clustsize: %d\n", b->clustsize);
17907dd7cddfSDavid du Colombier 	Bprint(&bp, "nresrv: %d\n", GSHORT(b->nresrv));
17917dd7cddfSDavid du Colombier 	Bprint(&bp, "nfats: %d\n", b->nfats);
17927dd7cddfSDavid du Colombier 	Bprint(&bp, "rootsize: %d\n", GSHORT(b->rootsize));
17937dd7cddfSDavid du Colombier 	Bprint(&bp, "volsize: %d\n", GSHORT(b->volsize));
17947dd7cddfSDavid du Colombier 	Bprint(&bp, "mediadesc: 0x%2.2x\n", b->mediadesc);
17957dd7cddfSDavid du Colombier 	Bprint(&bp, "fatsize: %d\n", GSHORT(b->fatsize));
17967dd7cddfSDavid du Colombier 	Bprint(&bp, "trksize: %d\n", GSHORT(b->trksize));
17977dd7cddfSDavid du Colombier 	Bprint(&bp, "nheads: %d\n", GSHORT(b->nheads));
17987dd7cddfSDavid du Colombier 	Bprint(&bp, "nhidden: %ld\n", GLONG(b->nhidden));
17997dd7cddfSDavid du Colombier 	Bprint(&bp, "bigvolsize: %ld\n", GLONG(b->bigvolsize));
18007dd7cddfSDavid du Colombier 	Bprint(&bp, "fatsize32: %ld\n", GLONG(b->fatsize32));
18017dd7cddfSDavid du Colombier 	Bprint(&bp, "extflags: %d\n", GSHORT(b->extflags));
18027dd7cddfSDavid du Colombier 	Bprint(&bp, "version: %d\n", GSHORT(b->version1));
18037dd7cddfSDavid du Colombier 	Bprint(&bp, "rootstart: %ld\n", GLONG(b->rootstart));
18047dd7cddfSDavid du Colombier 	Bprint(&bp, "infospec: %d\n", GSHORT(b->infospec));
18057dd7cddfSDavid du Colombier 	Bprint(&bp, "backupboot: %d\n", GSHORT(b->backupboot));
18067dd7cddfSDavid du Colombier 	Bprint(&bp, "reserved: %d %d %d %d %d %d %d %d %d %d %d %d\n",
18077dd7cddfSDavid du Colombier 		b->reserved[0], b->reserved[1], b->reserved[2], b->reserved[3],
18087dd7cddfSDavid du Colombier 		b->reserved[4], b->reserved[5], b->reserved[6], b->reserved[7],
18097dd7cddfSDavid du Colombier 		b->reserved[8], b->reserved[9], b->reserved[10], b->reserved[11]);
18107dd7cddfSDavid du Colombier 	Bterm(&bp);
18117dd7cddfSDavid du Colombier }
18127dd7cddfSDavid du Colombier 
18137dd7cddfSDavid du Colombier void
18147dd7cddfSDavid du Colombier bootsecdump32(int fd, Xfs *xf, Dosboot32 *b32)
18157dd7cddfSDavid du Colombier {
18167dd7cddfSDavid du Colombier 	Fatinfo *fi;
18177dd7cddfSDavid du Colombier 	Iosect *p1;
18187dd7cddfSDavid du Colombier 	int fisec, bsec, res;
18197dd7cddfSDavid du Colombier 
18207dd7cddfSDavid du Colombier 	fprint(fd, "\nfat32\n");
18217dd7cddfSDavid du Colombier 	bootdump32(fd, b32);
18227dd7cddfSDavid du Colombier 	res = GSHORT(b32->nresrv);
18237dd7cddfSDavid du Colombier 	bsec = GSHORT(b32->backupboot);
18247dd7cddfSDavid du Colombier 	if(bsec < res && bsec != 0){
18257dd7cddfSDavid du Colombier 		p1 = getsect(xf, bsec);
18267dd7cddfSDavid du Colombier 		if(p1 == nil)
18277dd7cddfSDavid du Colombier 			fprint(fd, "\ncouldn't get backup boot sector: %r\n");
18287dd7cddfSDavid du Colombier 		else{
18297dd7cddfSDavid du Colombier 			fprint(fd, "\nbackup boot\n");
18307dd7cddfSDavid du Colombier 			bootdump32(fd, (Dosboot32*)p1->iobuf);
18317dd7cddfSDavid du Colombier 			putsect(p1);
18327dd7cddfSDavid du Colombier 		}
18337dd7cddfSDavid du Colombier 	}else if(bsec != 0xffff)
18347dd7cddfSDavid du Colombier 		fprint(fd, "bad backup boot sector: %d reserved %d\n", bsec, res);
18357dd7cddfSDavid du Colombier 	fisec = GSHORT(b32->infospec);
18367dd7cddfSDavid du Colombier 	if(fisec < res && fisec != 0){
18377dd7cddfSDavid du Colombier 		p1 = getsect(xf, fisec);
18387dd7cddfSDavid du Colombier 		if(p1 == nil)
18397dd7cddfSDavid du Colombier 			fprint(fd, "\ncouldn't get fat info sector: %r\n");
18407dd7cddfSDavid du Colombier 		else{
18417dd7cddfSDavid du Colombier 			fprint(fd, "\nfat info %d\n", fisec);
18427dd7cddfSDavid du Colombier 			fi = (Fatinfo*)p1->iobuf;
18437dd7cddfSDavid du Colombier 			fprint(fd, "sig1: 0x%lux sb 0x%lux\n", GLONG(fi->sig1), FATINFOSIG1);
18447dd7cddfSDavid du Colombier 			fprint(fd, "sig: 0x%lux sb 0x%lux\n", GLONG(fi->sig), FATINFOSIG);
18457dd7cddfSDavid du Colombier 			fprint(fd, "freeclust: %lud\n", GLONG(fi->freeclust));
18467dd7cddfSDavid du Colombier 			fprint(fd, "nextfree: %lud\n", GLONG(fi->nextfree));
18477dd7cddfSDavid du Colombier 			fprint(fd, "reserved: %lud %lud %lud\n", GLONG(fi->resrv), GLONG(fi->resrv+4), GLONG(fi->resrv+8));
18487dd7cddfSDavid du Colombier 			putsect(p1);
18497dd7cddfSDavid du Colombier 		}
18507dd7cddfSDavid du Colombier 	}else if(fisec != 0xffff)
18517dd7cddfSDavid du Colombier 		fprint(2, "bad fat info sector: %d reserved %d\n", bsec, res);
18527dd7cddfSDavid du Colombier }
18537dd7cddfSDavid du Colombier 
18547dd7cddfSDavid du Colombier void
18557dd7cddfSDavid du Colombier dirdump(void *vdbuf)
18563e12c5d1SDavid du Colombier {
18573e12c5d1SDavid du Colombier 	static char attrchar[] = "rhsvda67";
18587dd7cddfSDavid du Colombier 	Dosdir *d;
18597dd7cddfSDavid du Colombier 	char *name, namebuf[DOSNAMELEN];
18607dd7cddfSDavid du Colombier 	char buf[128], *s, *ebuf;
18617dd7cddfSDavid du Colombier 	uchar *dbuf;
18627dd7cddfSDavid du Colombier 	int i;
18633e12c5d1SDavid du Colombier 
18643e12c5d1SDavid du Colombier 	if(!chatty)
18653e12c5d1SDavid du Colombier 		return;
18667dd7cddfSDavid du Colombier 
18677dd7cddfSDavid du Colombier 	d = vdbuf;
18687dd7cddfSDavid du Colombier 
18697dd7cddfSDavid du Colombier 	ebuf = buf + sizeof(buf);
18707dd7cddfSDavid du Colombier 	if(d->attr == 0xf){
18717dd7cddfSDavid du Colombier 		dbuf = vdbuf;
18727dd7cddfSDavid du Colombier 		name = namebuf + DOSNAMELEN;
18737dd7cddfSDavid du Colombier 		*--name = '\0';
18747dd7cddfSDavid du Colombier 		name = getnamerunes(name, dbuf, 1);
18757dd7cddfSDavid du Colombier 		seprint(buf, ebuf, "\"%s\" %2.2x %2.2ux %2.2ux %d", name, dbuf[0], dbuf[12], dbuf[13], GSHORT(d->start));
18767dd7cddfSDavid du Colombier 	}else{
18777dd7cddfSDavid du Colombier 		s = seprint(buf, ebuf, "\"%.8s.%.3s\" ", (char*)d->name, (char*)d->ext);
18787dd7cddfSDavid du Colombier 		for(i=7; i>=0; i--)
18797dd7cddfSDavid du Colombier 			*s++ = d->attr&(1<<i) ? attrchar[i] : '-';
18807dd7cddfSDavid du Colombier 
18813e12c5d1SDavid du Colombier 		i = GSHORT(d->time);
18827dd7cddfSDavid du Colombier 		s = seprint(s, ebuf, " %2.2d:%2.2d:%2.2d", i>>11, (i>>5)&63, (i&31)<<1);
18833e12c5d1SDavid du Colombier 		i = GSHORT(d->date);
18847dd7cddfSDavid du Colombier 		s = seprint(s, ebuf, " %2.2d.%2.2d.%2.2d", 80+(i>>9), (i>>5)&15, i&31);
18857dd7cddfSDavid du Colombier 
18867dd7cddfSDavid du Colombier 		i = GSHORT(d->ctime);
18877dd7cddfSDavid du Colombier 		s = seprint(s, ebuf, " %2.2d:%2.2d:%2.2d", i>>11, (i>>5)&63, (i&31)<<1);
18887dd7cddfSDavid du Colombier 		i = GSHORT(d->cdate);
18897dd7cddfSDavid du Colombier 		s = seprint(s, ebuf, " %2.2d.%2.2d.%2.2d", 80+(i>>9), (i>>5)&15, i&31);
18907dd7cddfSDavid du Colombier 
18917dd7cddfSDavid du Colombier 		i = GSHORT(d->adate);
18927dd7cddfSDavid du Colombier 		s = seprint(s, ebuf, " %2.2d.%2.2d.%2.2d", 80+(i>>9), (i>>5)&15, i&31);
18937dd7cddfSDavid du Colombier 
18947dd7cddfSDavid du Colombier 		seprint(s, ebuf, " %d %d", GSHORT(d->start), GSHORT(d->length));
18957dd7cddfSDavid du Colombier 	}
18963e12c5d1SDavid du Colombier 	chat("%s\n", buf);
18973e12c5d1SDavid du Colombier }
18987dd7cddfSDavid du Colombier 
18997dd7cddfSDavid du Colombier int
19007dd7cddfSDavid du Colombier cistrcmp(char *s1, char *s2)
19017dd7cddfSDavid du Colombier {
19027dd7cddfSDavid du Colombier 	int c1, c2;
19037dd7cddfSDavid du Colombier 
19047dd7cddfSDavid du Colombier 	while(*s1){
19057dd7cddfSDavid du Colombier 		c1 = *s1++;
19067dd7cddfSDavid du Colombier 		c2 = *s2++;
19077dd7cddfSDavid du Colombier 
19087dd7cddfSDavid du Colombier 		if(c1 >= 'A' && c1 <= 'Z')
19097dd7cddfSDavid du Colombier 			c1 -= 'A' - 'a';
19107dd7cddfSDavid du Colombier 
19117dd7cddfSDavid du Colombier 		if(c2 >= 'A' && c2 <= 'Z')
19127dd7cddfSDavid du Colombier 			c2 -= 'A' - 'a';
19137dd7cddfSDavid du Colombier 
19147dd7cddfSDavid du Colombier 		if(c1 != c2)
19157dd7cddfSDavid du Colombier 			return c1 - c2;
19167dd7cddfSDavid du Colombier 	}
19177dd7cddfSDavid du Colombier 	return -*s2;
19187dd7cddfSDavid du Colombier }
19197dd7cddfSDavid du Colombier 
19207dd7cddfSDavid du Colombier int
19219a747e4fSDavid du Colombier utftorunes(Rune *rr, char *s, int n)
19227dd7cddfSDavid du Colombier {
19239a747e4fSDavid du Colombier 	Rune *r, *re;
19247dd7cddfSDavid du Colombier 	int c;
19257dd7cddfSDavid du Colombier 
19267dd7cddfSDavid du Colombier 	r = rr;
19279a747e4fSDavid du Colombier 	re = r + n - 1;
19289a747e4fSDavid du Colombier 	while(c = (uchar)*s){
19297dd7cddfSDavid du Colombier 		if(c < Runeself){
19307dd7cddfSDavid du Colombier 			*r = c;
19317dd7cddfSDavid du Colombier 			s++;
19327dd7cddfSDavid du Colombier 		}else
19337dd7cddfSDavid du Colombier 			s += chartorune(r, s);
19347dd7cddfSDavid du Colombier 		r++;
19359a747e4fSDavid du Colombier 		if(r >= re)
19369a747e4fSDavid du Colombier 			break;
19377dd7cddfSDavid du Colombier 	}
19387dd7cddfSDavid du Colombier 	*r = 0;
19397dd7cddfSDavid du Colombier 	return r - rr;
19407dd7cddfSDavid du Colombier }
1941