xref: /plan9/sys/src/cmd/9660srv/9660srv.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #include "dat.h"
63e12c5d1SDavid du Colombier #include "fns.h"
73e12c5d1SDavid du Colombier #include "iso9660.h"
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier static void	ireset(void);
103e12c5d1SDavid du Colombier static int	iattach(Xfile*);
113e12c5d1SDavid du Colombier static void	iclone(Xfile*, Xfile*);
123e12c5d1SDavid du Colombier static void	iwalkup(Xfile*);
133e12c5d1SDavid du Colombier static void	iwalk(Xfile*, char*);
143e12c5d1SDavid du Colombier static void	iopen(Xfile*, int);
153e12c5d1SDavid du Colombier static void	icreate(Xfile*, char*, long, int);
163e12c5d1SDavid du Colombier static long	ireaddir(Xfile*, void*, long, long);
173e12c5d1SDavid du Colombier static long	iread(Xfile*, void*, long, long);
183e12c5d1SDavid du Colombier static long	iwrite(Xfile*, void*, long, long);
193e12c5d1SDavid du Colombier static void	iclunk(Xfile*);
203e12c5d1SDavid du Colombier static void	iremove(Xfile*);
213e12c5d1SDavid du Colombier static void	istat(Xfile*, Dir*);
223e12c5d1SDavid du Colombier static void	iwstat(Xfile*, Dir*);
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier static char*	nstr(void*, int);
253e12c5d1SDavid du Colombier static char*	rdate(void*, int);
263e12c5d1SDavid du Colombier static int	getdrec(Xfile*, void*);
273e12c5d1SDavid du Colombier static int	opendotdot(Xfile*, Xfile*);
283e12c5d1SDavid du Colombier static int	showdrec(int, int, void*);
293e12c5d1SDavid du Colombier static long	gtime(void*);
303e12c5d1SDavid du Colombier static long	l16(void*);
313e12c5d1SDavid du Colombier static long	l32(void*);
323e12c5d1SDavid du Colombier static void	newdrec(Xfile*, Drec*);
33bd389b36SDavid du Colombier static int	rzdir(int, Dir*, int, Drec*);
343e12c5d1SDavid du Colombier 
35bd389b36SDavid du Colombier Xfsub	isosub =
36bd389b36SDavid du Colombier {
373e12c5d1SDavid du Colombier 	ireset, iattach, iclone, iwalkup, iwalk, iopen, icreate,
383e12c5d1SDavid du Colombier 	ireaddir, iread, iwrite, iclunk, iremove, istat, iwstat
393e12c5d1SDavid du Colombier };
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier static void
423e12c5d1SDavid du Colombier ireset(void)
433e12c5d1SDavid du Colombier {}
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier static int
463e12c5d1SDavid du Colombier iattach(Xfile *root)
473e12c5d1SDavid du Colombier {
483e12c5d1SDavid du Colombier 	Xfs *cd = root->xf;
493e12c5d1SDavid du Colombier 	Iobuf *p; Voldesc *v; Isofile *fp; Drec *dp;
503e12c5d1SDavid du Colombier 	int fmt, blksize;
513e12c5d1SDavid du Colombier 
523e12c5d1SDavid du Colombier 	p = getbuf(cd->d, VOLDESC);
533e12c5d1SDavid du Colombier 	v = (Voldesc*)(p->iobuf);
543e12c5d1SDavid du Colombier 	if(memcmp(v->byte, "\01CD001\01", 7) == 0){		/* iso */
553e12c5d1SDavid du Colombier 		fmt = 'z';
563e12c5d1SDavid du Colombier 		dp = (Drec*)v->z.desc.rootdir;
573e12c5d1SDavid du Colombier 		blksize = l16(v->z.desc.blksize);
583e12c5d1SDavid du Colombier 		chat("iso, blksize=%d...", blksize);
593e12c5d1SDavid du Colombier 	}else if(memcmp(&v->byte[8], "\01CDROM\01", 7) == 0){	/* high sierra */
603e12c5d1SDavid du Colombier 		fmt = 'r';
613e12c5d1SDavid du Colombier 		dp = (Drec*)v->r.desc.rootdir;
623e12c5d1SDavid du Colombier 		blksize = l16(v->r.desc.blksize);
633e12c5d1SDavid du Colombier 		chat("high sierra, blksize=%d...", blksize);
643e12c5d1SDavid du Colombier 	}else{
653e12c5d1SDavid du Colombier 		putbuf(p);
663e12c5d1SDavid du Colombier 		return -1;
673e12c5d1SDavid du Colombier 	}
683e12c5d1SDavid du Colombier 	if(chatty)
693e12c5d1SDavid du Colombier 		showdrec(2, fmt, dp);
703e12c5d1SDavid du Colombier 	if(blksize > Sectorsize){
713e12c5d1SDavid du Colombier 		chat("blksize too big...");
723e12c5d1SDavid du Colombier 		putbuf(p);
733e12c5d1SDavid du Colombier 		return -1;
743e12c5d1SDavid du Colombier 	}
753e12c5d1SDavid du Colombier 	if(waserror()){
763e12c5d1SDavid du Colombier 		putbuf(p);
773e12c5d1SDavid du Colombier 		nexterror();
783e12c5d1SDavid du Colombier 	}
793e12c5d1SDavid du Colombier 	root->len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
803e12c5d1SDavid du Colombier 	root->ptr = fp = ealloc(root->len);
813e12c5d1SDavid du Colombier 	root->xf->isplan9 = (strncmp((char*)v->z.boot.sysid, "PLAN 9", 6)==0);
823e12c5d1SDavid du Colombier 	fp->fmt = fmt;
833e12c5d1SDavid du Colombier 	fp->blksize = blksize;
843e12c5d1SDavid du Colombier 	fp->offset = 0;
853e12c5d1SDavid du Colombier 	fp->doffset = 0;
863e12c5d1SDavid du Colombier 	memmove(&fp->d, dp, dp->reclen);
873e12c5d1SDavid du Colombier 	root->qid.path = CHDIR|l32(dp->addr);
883e12c5d1SDavid du Colombier 	putbuf(p);
893e12c5d1SDavid du Colombier 	poperror();
903e12c5d1SDavid du Colombier 	return 0;
913e12c5d1SDavid du Colombier }
923e12c5d1SDavid du Colombier 
933e12c5d1SDavid du Colombier static void
943e12c5d1SDavid du Colombier iclone(Xfile *of, Xfile *nf)
953e12c5d1SDavid du Colombier {
963e12c5d1SDavid du Colombier 	USED(of, nf);
973e12c5d1SDavid du Colombier }
983e12c5d1SDavid du Colombier 
993e12c5d1SDavid du Colombier static void
1003e12c5d1SDavid du Colombier iwalkup(Xfile *f)
1013e12c5d1SDavid du Colombier {
1023e12c5d1SDavid du Colombier 	long paddr;
1033e12c5d1SDavid du Colombier 	uchar dbuf[256];
1043e12c5d1SDavid du Colombier 	Drec *d = (Drec *)dbuf;
1053e12c5d1SDavid du Colombier 	Xfile pf, ppf;
1063e12c5d1SDavid du Colombier 	Isofile piso, ppiso;
1073e12c5d1SDavid du Colombier 
1083e12c5d1SDavid du Colombier 	memset(&pf, 0, sizeof pf);
1093e12c5d1SDavid du Colombier 	memset(&ppf, 0, sizeof ppf);
1103e12c5d1SDavid du Colombier 	pf.ptr = &piso;
1113e12c5d1SDavid du Colombier 	ppf.ptr = &ppiso;
1123e12c5d1SDavid du Colombier 	if(opendotdot(f, &pf) < 0)
1133e12c5d1SDavid du Colombier 		error("can't open pf");
1143e12c5d1SDavid du Colombier 	paddr = l32(((Isofile *)pf.ptr)->d.addr);
1153e12c5d1SDavid du Colombier 	if(l32(((Isofile *)f->ptr)->d.addr) == paddr)
1163e12c5d1SDavid du Colombier 		return;
1173e12c5d1SDavid du Colombier 	if(opendotdot(&pf, &ppf) < 0)
1183e12c5d1SDavid du Colombier 		error("can't open ppf");
1193e12c5d1SDavid du Colombier 	while(getdrec(&ppf, d) >= 0){
1203e12c5d1SDavid du Colombier 		if(l32(d->addr) == paddr){
1213e12c5d1SDavid du Colombier 			newdrec(f, d);
1223e12c5d1SDavid du Colombier 			f->qid.path = paddr|CHDIR;
1233e12c5d1SDavid du Colombier 			return;
1243e12c5d1SDavid du Colombier 		}
1253e12c5d1SDavid du Colombier 	}
1263e12c5d1SDavid du Colombier 	error("can't find addr of ..");
1273e12c5d1SDavid du Colombier }
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier static void
1303e12c5d1SDavid du Colombier iwalk(Xfile *f, char *name)
1313e12c5d1SDavid du Colombier {
1323e12c5d1SDavid du Colombier 	Isofile *ip = f->ptr;
1333e12c5d1SDavid du Colombier 	uchar dbuf[256];
134bd389b36SDavid du Colombier 	char nbuf[NAMELEN];
1353e12c5d1SDavid du Colombier 	Drec *d = (Drec*)dbuf;
1363e12c5d1SDavid du Colombier 	Dir dir;
1373e12c5d1SDavid du Colombier 	char *p;
138bd389b36SDavid du Colombier 	int len, vers, dvers;
1393e12c5d1SDavid du Colombier 
140bd389b36SDavid du Colombier 	vers = -1;
141bd389b36SDavid du Colombier 	if(p = strchr(name, ';')) {	/* assign = */
142bd389b36SDavid du Colombier 		len = p-name;
1433e12c5d1SDavid du Colombier 		if(len >= NAMELEN)
144bd389b36SDavid du Colombier 			len = NAMELEN-1;
145bd389b36SDavid du Colombier 		memmove(nbuf, name, len);
146bd389b36SDavid du Colombier 		vers = strtoul(p+1, 0, 10);
1473e12c5d1SDavid du Colombier 		name = nbuf;
1483e12c5d1SDavid du Colombier 	}
149bd389b36SDavid du Colombier 	len = strlen(name);
150bd389b36SDavid du Colombier 	if(len >= NAMELEN)
151bd389b36SDavid du Colombier 		len = NAMELEN-1;
152bd389b36SDavid du Colombier 	name[len] = 0;
153bd389b36SDavid du Colombier 
1543e12c5d1SDavid du Colombier 	chat("%d \"%s\"...", len, name);
1553e12c5d1SDavid du Colombier 	ip->offset = 0;
156bd389b36SDavid du Colombier 	while(getdrec(f, d) >= 0) {
157bd389b36SDavid du Colombier 		dvers = rzdir(f->xf->isplan9, &dir, 'z', d);
1583e12c5d1SDavid du Colombier 		if(strcmp(name, dir.name) != 0)
1593e12c5d1SDavid du Colombier 			continue;
1603e12c5d1SDavid du Colombier 		newdrec(f, d);
1613e12c5d1SDavid du Colombier 		f->qid.path = dir.qid.path;
162bd389b36SDavid du Colombier 		USED(dvers);
1633e12c5d1SDavid du Colombier 		return;
1643e12c5d1SDavid du Colombier 	}
165bd389b36SDavid du Colombier 	USED(vers);
1663e12c5d1SDavid du Colombier 	error(Enonexist);
1673e12c5d1SDavid du Colombier }
1683e12c5d1SDavid du Colombier 
1693e12c5d1SDavid du Colombier static void
1703e12c5d1SDavid du Colombier iopen(Xfile *f, int mode)
1713e12c5d1SDavid du Colombier {
1723e12c5d1SDavid du Colombier 	mode &= ~OCEXEC;
1733e12c5d1SDavid du Colombier 	if(mode != OREAD && mode != OEXEC)
1743e12c5d1SDavid du Colombier 		error(Eperm);
1753e12c5d1SDavid du Colombier 	((Isofile*)f->ptr)->offset = 0;
1763e12c5d1SDavid du Colombier 	((Isofile*)f->ptr)->doffset = 0;
1773e12c5d1SDavid du Colombier }
1783e12c5d1SDavid du Colombier 
1793e12c5d1SDavid du Colombier static void
1803e12c5d1SDavid du Colombier icreate(Xfile *f, char *name, long perm, int mode)
1813e12c5d1SDavid du Colombier {
1823e12c5d1SDavid du Colombier 	USED(f, name, perm, mode);
1833e12c5d1SDavid du Colombier 	error(Eperm);
1843e12c5d1SDavid du Colombier }
1853e12c5d1SDavid du Colombier 
1863e12c5d1SDavid du Colombier static long
1873e12c5d1SDavid du Colombier ireaddir(Xfile *f, char *buf, long offset, long count)
1883e12c5d1SDavid du Colombier {
1893e12c5d1SDavid du Colombier 	Isofile *ip = f->ptr;
1903e12c5d1SDavid du Colombier 	Dir d;
1913e12c5d1SDavid du Colombier 	uchar dbuf[256];
1923e12c5d1SDavid du Colombier 	Drec *drec = (Drec *)dbuf;
1933e12c5d1SDavid du Colombier 	int rcnt = 0;
1943e12c5d1SDavid du Colombier 
1953e12c5d1SDavid du Colombier 	if(offset < ip->doffset){
1963e12c5d1SDavid du Colombier 		ip->offset = 0;
1973e12c5d1SDavid du Colombier 		ip->doffset = 0;
1983e12c5d1SDavid du Colombier 	}
1993e12c5d1SDavid du Colombier 	while(rcnt < count && getdrec(f, drec) >= 0){
2003e12c5d1SDavid du Colombier 		if(drec->namelen == 1){
2013e12c5d1SDavid du Colombier 			if(drec->name[0] == 0)
2023e12c5d1SDavid du Colombier 				continue;
2033e12c5d1SDavid du Colombier 			if(drec->name[0] == 1)
2043e12c5d1SDavid du Colombier 				continue;
2053e12c5d1SDavid du Colombier 		}
2063e12c5d1SDavid du Colombier 		if(ip->doffset < offset){
2073e12c5d1SDavid du Colombier 			ip->doffset += DIRLEN;
2083e12c5d1SDavid du Colombier 			continue;
2093e12c5d1SDavid du Colombier 		}
2103e12c5d1SDavid du Colombier 		rzdir(f->xf->isplan9, &d, ip->fmt, drec);
2113e12c5d1SDavid du Colombier 		d.qid.vers = f->qid.vers;
2123e12c5d1SDavid du Colombier 		rcnt += convD2M(&d, &buf[rcnt]);
2133e12c5d1SDavid du Colombier 	}
2143e12c5d1SDavid du Colombier 	ip->doffset += rcnt;
2153e12c5d1SDavid du Colombier 	return rcnt;
2163e12c5d1SDavid du Colombier }
2173e12c5d1SDavid du Colombier 
2183e12c5d1SDavid du Colombier static long
2193e12c5d1SDavid du Colombier iread(Xfile *f, char *buf, long offset, long count)
2203e12c5d1SDavid du Colombier {
2213e12c5d1SDavid du Colombier 	Isofile *ip = f->ptr;
2223e12c5d1SDavid du Colombier 	long size, addr, o, n;
2233e12c5d1SDavid du Colombier 	int rcnt = 0;
2243e12c5d1SDavid du Colombier 	Iobuf *p;
2253e12c5d1SDavid du Colombier 
2263e12c5d1SDavid du Colombier 	size = l32(ip->d.size);
2273e12c5d1SDavid du Colombier 	if(offset >= size)
2283e12c5d1SDavid du Colombier 		return 0;
2293e12c5d1SDavid du Colombier 	if(offset+count > size)
2303e12c5d1SDavid du Colombier 		count = size - offset;
2313e12c5d1SDavid du Colombier 	addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + offset;
2323e12c5d1SDavid du Colombier 	o = addr % Sectorsize;
2333e12c5d1SDavid du Colombier 	addr /= Sectorsize;
2343e12c5d1SDavid du Colombier 	/*chat("d.addr=0x%x, addr=0x%x, o=0x%x...", l32(ip->d.addr), addr, o);*/
2353e12c5d1SDavid du Colombier 	n = Sectorsize - o;
2363e12c5d1SDavid du Colombier 
2373e12c5d1SDavid du Colombier 	while(count > 0){
2383e12c5d1SDavid du Colombier 		if(n > count)
2393e12c5d1SDavid du Colombier 			n = count;
2403e12c5d1SDavid du Colombier 		p = getbuf(f->xf->d, addr);
2413e12c5d1SDavid du Colombier 		memmove(&buf[rcnt], &p->iobuf[o], n);
2423e12c5d1SDavid du Colombier 		putbuf(p);
2433e12c5d1SDavid du Colombier 		count -= n;
2443e12c5d1SDavid du Colombier 		rcnt += n;
2453e12c5d1SDavid du Colombier 		++addr;
2463e12c5d1SDavid du Colombier 		o = 0;
2473e12c5d1SDavid du Colombier 		n = Sectorsize;
2483e12c5d1SDavid du Colombier 	}
2493e12c5d1SDavid du Colombier 	return rcnt;
2503e12c5d1SDavid du Colombier }
2513e12c5d1SDavid du Colombier 
2523e12c5d1SDavid du Colombier static long
2533e12c5d1SDavid du Colombier iwrite(Xfile *f, uchar *buf, long offset, long count)
2543e12c5d1SDavid du Colombier {
2553e12c5d1SDavid du Colombier 	USED(f, buf, offset, count);
2563e12c5d1SDavid du Colombier 	error(Eperm);
2573e12c5d1SDavid du Colombier 	return 0;
2583e12c5d1SDavid du Colombier }
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier static void
2613e12c5d1SDavid du Colombier iclunk(Xfile *f)
2623e12c5d1SDavid du Colombier {
2633e12c5d1SDavid du Colombier 	USED(f);
2643e12c5d1SDavid du Colombier }
2653e12c5d1SDavid du Colombier 
2663e12c5d1SDavid du Colombier static void
2673e12c5d1SDavid du Colombier iremove(Xfile *f)
2683e12c5d1SDavid du Colombier {
2693e12c5d1SDavid du Colombier 	USED(f);
2703e12c5d1SDavid du Colombier 	error(Eperm);
2713e12c5d1SDavid du Colombier }
2723e12c5d1SDavid du Colombier 
2733e12c5d1SDavid du Colombier static void
2743e12c5d1SDavid du Colombier istat(Xfile *f, Dir *d)
2753e12c5d1SDavid du Colombier {
2763e12c5d1SDavid du Colombier 	Isofile *ip = f->ptr;
2773e12c5d1SDavid du Colombier 
2783e12c5d1SDavid du Colombier 	rzdir(f->xf->isplan9, d, ip->fmt, &ip->d);
2793e12c5d1SDavid du Colombier 	d->qid.vers = f->qid.vers;
2803e12c5d1SDavid du Colombier 	if(d->qid.path==f->xf->rootqid.path)
2813e12c5d1SDavid du Colombier 		d->qid.path = CHDIR;
2823e12c5d1SDavid du Colombier }
2833e12c5d1SDavid du Colombier 
2843e12c5d1SDavid du Colombier static void
2853e12c5d1SDavid du Colombier iwstat(Xfile *f, Dir *d)
2863e12c5d1SDavid du Colombier {
2873e12c5d1SDavid du Colombier 	USED(f, d);
2883e12c5d1SDavid du Colombier 	error(Eperm);
2893e12c5d1SDavid du Colombier }
2903e12c5d1SDavid du Colombier 
2913e12c5d1SDavid du Colombier static int
2923e12c5d1SDavid du Colombier showdrec(int fd, int fmt, void *x)
2933e12c5d1SDavid du Colombier {
2943e12c5d1SDavid du Colombier 	Drec *d = (Drec *)x;
2953e12c5d1SDavid du Colombier 	int namelen, syslen;
2963e12c5d1SDavid du Colombier 
2973e12c5d1SDavid du Colombier 	if(d->reclen == 0)
2983e12c5d1SDavid du Colombier 		return 0;
2993e12c5d1SDavid du Colombier 	fprint(fd, "%d %d %d %d ",
3003e12c5d1SDavid du Colombier 		d->reclen, d->attrlen, l32(d->addr), l32(d->size));
3013e12c5d1SDavid du Colombier 	fprint(fd, "%s 0x%2.2x %d %d %d ",
3023e12c5d1SDavid du Colombier 		rdate(d->date, fmt), (fmt=='z' ? d->flags : d->r_flags),
3033e12c5d1SDavid du Colombier 		d->unitsize, d->gapsize, l16(d->vseqno));
3043e12c5d1SDavid du Colombier 	fprint(fd, "%d %s", d->namelen, nstr(d->name, d->namelen));
3053e12c5d1SDavid du Colombier 	namelen = d->namelen + (1-(d->namelen&1));
3063e12c5d1SDavid du Colombier 	syslen = d->reclen - 33 - namelen;
3073e12c5d1SDavid du Colombier 	if(syslen != 0)
3083e12c5d1SDavid du Colombier 		fprint(fd, " %s", nstr(&d->name[namelen], syslen));
3093e12c5d1SDavid du Colombier 	fprint(fd, "\n");
3103e12c5d1SDavid du Colombier 	return d->reclen + (d->reclen&1);
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier 
3133e12c5d1SDavid du Colombier static void
3143e12c5d1SDavid du Colombier newdrec(Xfile *f, Drec *dp)
3153e12c5d1SDavid du Colombier {
3163e12c5d1SDavid du Colombier 	Isofile *x = f->ptr;
3173e12c5d1SDavid du Colombier 	Isofile *n;
3183e12c5d1SDavid du Colombier 	int len;
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier 	len = sizeof(Isofile) - sizeof(Drec) + dp->reclen;
3213e12c5d1SDavid du Colombier 	n = ealloc(len);
3223e12c5d1SDavid du Colombier 	n->fmt = x->fmt;
3233e12c5d1SDavid du Colombier 	n->blksize = x->blksize;
3243e12c5d1SDavid du Colombier 	n->offset = 0;
3253e12c5d1SDavid du Colombier 	n->doffset = 0;
3263e12c5d1SDavid du Colombier 	memmove(&n->d, dp, dp->reclen);
3273e12c5d1SDavid du Colombier 	free(x);
3283e12c5d1SDavid du Colombier 	f->ptr = n;
3293e12c5d1SDavid du Colombier 	f->len = len;
3303e12c5d1SDavid du Colombier }
3313e12c5d1SDavid du Colombier 
3323e12c5d1SDavid du Colombier static int
3333e12c5d1SDavid du Colombier getdrec(Xfile *f, void *buf)
3343e12c5d1SDavid du Colombier {
3353e12c5d1SDavid du Colombier 	Isofile *ip = f->ptr;
3363e12c5d1SDavid du Colombier 	int len = 0, boff = 0;
3373e12c5d1SDavid du Colombier 	long size, addr;
3383e12c5d1SDavid du Colombier 	Iobuf *p = 0;
3393e12c5d1SDavid du Colombier 
3403e12c5d1SDavid du Colombier 	if(!ip)
3413e12c5d1SDavid du Colombier 		return -1;
3423e12c5d1SDavid du Colombier 	size = l32(ip->d.size);
3433e12c5d1SDavid du Colombier 	while(ip->offset<size){
3443e12c5d1SDavid du Colombier 		addr = (l32(ip->d.addr)+ip->d.attrlen)*ip->blksize + ip->offset;
3453e12c5d1SDavid du Colombier 		boff = addr % Sectorsize;
3463e12c5d1SDavid du Colombier 		if(boff > Sectorsize-34){
3473e12c5d1SDavid du Colombier 			ip->offset += Sectorsize-boff;
3483e12c5d1SDavid du Colombier 			continue;
3493e12c5d1SDavid du Colombier 		}
3503e12c5d1SDavid du Colombier 		p = getbuf(f->xf->d, addr/Sectorsize);
3513e12c5d1SDavid du Colombier 		len = p->iobuf[boff];
3523e12c5d1SDavid du Colombier 		if(len >= 34)
3533e12c5d1SDavid du Colombier 			break;
3543e12c5d1SDavid du Colombier 		putbuf(p);
3553e12c5d1SDavid du Colombier 		p = 0;
3563e12c5d1SDavid du Colombier 		ip->offset += Sectorsize-boff;
3573e12c5d1SDavid du Colombier 	}
3583e12c5d1SDavid du Colombier 	if(p) {
3593e12c5d1SDavid du Colombier 		memmove(buf, &p->iobuf[boff], len);
3603e12c5d1SDavid du Colombier 		putbuf(p);
3613e12c5d1SDavid du Colombier 		ip->offset += len + (len&1);
3623e12c5d1SDavid du Colombier 	}
363bd389b36SDavid du Colombier 	if(p)
364bd389b36SDavid du Colombier 		return 0;
365bd389b36SDavid du Colombier 	return -1;
3663e12c5d1SDavid du Colombier }
3673e12c5d1SDavid du Colombier 
3683e12c5d1SDavid du Colombier static int
3693e12c5d1SDavid du Colombier opendotdot(Xfile *f, Xfile *pf)
3703e12c5d1SDavid du Colombier {
3713e12c5d1SDavid du Colombier 	uchar dbuf[256];
3723e12c5d1SDavid du Colombier 	Drec *d = (Drec *)dbuf;
3733e12c5d1SDavid du Colombier 	Isofile *ip = f->ptr, *pip = pf->ptr;
3743e12c5d1SDavid du Colombier 
3753e12c5d1SDavid du Colombier 	ip->offset = 0;
3763e12c5d1SDavid du Colombier 	if(getdrec(f, d) < 0){
3773e12c5d1SDavid du Colombier 		chat("opendotdot: getdrec(.) failed...");
3783e12c5d1SDavid du Colombier 		return -1;
3793e12c5d1SDavid du Colombier 	}
3803e12c5d1SDavid du Colombier 	if(d->namelen != 1 || d->name[0] != 0){
3813e12c5d1SDavid du Colombier 		chat("opendotdot: no . entry...");
3823e12c5d1SDavid du Colombier 		return -1;
3833e12c5d1SDavid du Colombier 	}
3843e12c5d1SDavid du Colombier 	if(l32(d->addr) != l32(ip->d.addr)){
3853e12c5d1SDavid du Colombier 		chat("opendotdot: bad . address...");
3863e12c5d1SDavid du Colombier 		return -1;
3873e12c5d1SDavid du Colombier 	}
3883e12c5d1SDavid du Colombier 	if(getdrec(f, d) < 0){
3893e12c5d1SDavid du Colombier 		chat("opendotdot: getdrec(..) failed...");
3903e12c5d1SDavid du Colombier 		return -1;
3913e12c5d1SDavid du Colombier 	}
3923e12c5d1SDavid du Colombier 	if(d->namelen != 1 || d->name[0] != 1){
3933e12c5d1SDavid du Colombier 		chat("opendotdot: no .. entry...");
3943e12c5d1SDavid du Colombier 		return -1;
3953e12c5d1SDavid du Colombier 	}
3963e12c5d1SDavid du Colombier 
3973e12c5d1SDavid du Colombier 	pf->xf = f->xf;
3983e12c5d1SDavid du Colombier 	pip->fmt = ip->fmt;
3993e12c5d1SDavid du Colombier 	pip->blksize = ip->blksize;
4003e12c5d1SDavid du Colombier 	pip->offset = 0;
4013e12c5d1SDavid du Colombier 	pip->doffset = 0;
4023e12c5d1SDavid du Colombier 	pip->d = *d;
4033e12c5d1SDavid du Colombier 	return 0;
4043e12c5d1SDavid du Colombier }
4053e12c5d1SDavid du Colombier 
406bd389b36SDavid du Colombier static int
4073e12c5d1SDavid du Colombier rzdir(int isplan9, Dir *d, int fmt, Drec *dp)
4083e12c5d1SDavid du Colombier {
409bd389b36SDavid du Colombier 	int n, flags, i, nl, vers;
4103e12c5d1SDavid du Colombier 	uchar *s;
411bd389b36SDavid du Colombier 	char *p;
4123e12c5d1SDavid du Colombier 
413bd389b36SDavid du Colombier 	flags = 0;
414bd389b36SDavid du Colombier 	vers = -1;
4153e12c5d1SDavid du Colombier 	d->qid.path = l32(dp->addr);
4163e12c5d1SDavid du Colombier 	d->qid.vers = 0;
417bd389b36SDavid du Colombier 	n = dp->namelen;
418bd389b36SDavid du Colombier 	if(n >= NAMELEN)
4193e12c5d1SDavid du Colombier 		n = NAMELEN-1;
4203e12c5d1SDavid du Colombier 	memset(d->name, 0, NAMELEN);
4213e12c5d1SDavid du Colombier 	if(n == 1) {
4223e12c5d1SDavid du Colombier 		switch(dp->name[0]){
4233e12c5d1SDavid du Colombier 		case 1:
4243e12c5d1SDavid du Colombier 			d->name[1] = '.';
4253e12c5d1SDavid du Colombier 			/* fall through */
4263e12c5d1SDavid du Colombier 		case 0:
4273e12c5d1SDavid du Colombier 			d->name[0] = '.';
4283e12c5d1SDavid du Colombier 			break;
4293e12c5d1SDavid du Colombier 		default:
4303e12c5d1SDavid du Colombier 			d->name[0] = tolower(dp->name[0]);
4313e12c5d1SDavid du Colombier 		}
4323e12c5d1SDavid du Colombier 	} else {
4333e12c5d1SDavid du Colombier 		for(i=0; i<n; i++)
4343e12c5d1SDavid du Colombier 			d->name[i] = tolower(dp->name[i]);
4353e12c5d1SDavid du Colombier 	}
4363e12c5d1SDavid du Colombier 
437bd389b36SDavid du Colombier 	if(isplan9 && dp->reclen>34+dp->namelen) {
438bd389b36SDavid du Colombier 		/*
439bd389b36SDavid du Colombier 		 * get gid, uid, mode and possibly name
440bd389b36SDavid du Colombier 		 * from plan9 directory extension
441bd389b36SDavid du Colombier 		 */
4423e12c5d1SDavid du Colombier 		s = (uchar*)dp->name + dp->namelen;
4433e12c5d1SDavid du Colombier 		if(((ulong)s) & 1)
4443e12c5d1SDavid du Colombier 			s++;
4453e12c5d1SDavid du Colombier 		nl = *s;
4463e12c5d1SDavid du Colombier 		if(nl >= NAMELEN)
4473e12c5d1SDavid du Colombier 			nl = NAMELEN-1;
4483e12c5d1SDavid du Colombier 		if(nl) {
4493e12c5d1SDavid du Colombier 			memset(d->name, 0, NAMELEN);
4503e12c5d1SDavid du Colombier 			memmove(d->name, s+1, nl);
4513e12c5d1SDavid du Colombier 		}
4523e12c5d1SDavid du Colombier 		s += 1 + *s;
4533e12c5d1SDavid du Colombier 		nl = *s;
4543e12c5d1SDavid du Colombier 		if(nl >= NAMELEN)
4553e12c5d1SDavid du Colombier 			nl = NAMELEN-1;
4563e12c5d1SDavid du Colombier 		memset(d->uid, 0, NAMELEN);
4573e12c5d1SDavid du Colombier 		memmove(d->uid, s+1, nl);
4583e12c5d1SDavid du Colombier 		s += 1 + *s;
4593e12c5d1SDavid du Colombier 		nl = *s;
4603e12c5d1SDavid du Colombier 		if(nl >= NAMELEN)
4613e12c5d1SDavid du Colombier 			nl = NAMELEN-1;
4623e12c5d1SDavid du Colombier 		memset(d->gid, 0, NAMELEN);
4633e12c5d1SDavid du Colombier 		memmove(d->gid, s+1, nl);
4643e12c5d1SDavid du Colombier 		s += 1 + *s;
4653e12c5d1SDavid du Colombier 		if(((ulong)s) & 1)
4663e12c5d1SDavid du Colombier 			s++;
4673e12c5d1SDavid du Colombier 		d->mode = l32(s);
4683e12c5d1SDavid du Colombier 		if(d->mode & CHDIR)
4693e12c5d1SDavid du Colombier 			d->qid.path |= CHDIR;
4703e12c5d1SDavid du Colombier 	} else {
4713e12c5d1SDavid du Colombier 		d->mode = 0444;
4723e12c5d1SDavid du Colombier 		switch(fmt) {
4733e12c5d1SDavid du Colombier 		case 'z':
4743e12c5d1SDavid du Colombier 			strcpy(d->gid, "iso");
4753e12c5d1SDavid du Colombier 			flags = dp->flags;
4763e12c5d1SDavid du Colombier 			break;
4773e12c5d1SDavid du Colombier 		case 'r':
4783e12c5d1SDavid du Colombier 			strcpy(d->gid, "sierra");
4793e12c5d1SDavid du Colombier 			flags = dp->r_flags;
4803e12c5d1SDavid du Colombier 			break;
4813e12c5d1SDavid du Colombier 		}
4823e12c5d1SDavid du Colombier 		if(flags & 0x02){
4833e12c5d1SDavid du Colombier 			d->qid.path |= CHDIR;
4843e12c5d1SDavid du Colombier 			d->mode |= CHDIR|0111;
4853e12c5d1SDavid du Colombier 		}
4863e12c5d1SDavid du Colombier 		strcpy(d->uid, "cdrom");
487bd389b36SDavid du Colombier 		p = strchr(d->name, ';');
488bd389b36SDavid du Colombier 		if(p != 0) {
489bd389b36SDavid du Colombier 			vers = strtoul(p+1, 0, 10);
490bd389b36SDavid du Colombier 			memset(p, 0, NAMELEN-(p-d->name));
491bd389b36SDavid du Colombier 		}
4923e12c5d1SDavid du Colombier 	}
4933e12c5d1SDavid du Colombier 	d->length = 0;
4943e12c5d1SDavid du Colombier 	if((d->mode & CHDIR) == 0)
4953e12c5d1SDavid du Colombier 		d->length = l32(dp->size);
4963e12c5d1SDavid du Colombier 	d->type = 0;
4973e12c5d1SDavid du Colombier 	d->dev = 0;
4983e12c5d1SDavid du Colombier 	d->atime = gtime(dp->date);
4993e12c5d1SDavid du Colombier 	d->mtime = d->atime;
500bd389b36SDavid du Colombier 	return vers;
5013e12c5d1SDavid du Colombier }
5023e12c5d1SDavid du Colombier 
5033e12c5d1SDavid du Colombier static char *
5043e12c5d1SDavid du Colombier nstr(uchar *p, int n)
5053e12c5d1SDavid du Colombier {
5063e12c5d1SDavid du Colombier 	static char buf[132];
5073e12c5d1SDavid du Colombier 	char *q = buf;
508bd389b36SDavid du Colombier 
5093e12c5d1SDavid du Colombier 	while(--n >= 0){
5103e12c5d1SDavid du Colombier 		if(*p == '\\')
5113e12c5d1SDavid du Colombier 			*q++ = '\\';
5123e12c5d1SDavid du Colombier 		if(' ' <= *p && *p <= '~')
5133e12c5d1SDavid du Colombier 			*q++ = *p++;
5143e12c5d1SDavid du Colombier 		else
5153e12c5d1SDavid du Colombier 			q += sprint(q, "\\%2.2ux", *p++);
5163e12c5d1SDavid du Colombier 	}
5173e12c5d1SDavid du Colombier 	*q = 0;
5183e12c5d1SDavid du Colombier 	return buf;
5193e12c5d1SDavid du Colombier }
5203e12c5d1SDavid du Colombier 
5213e12c5d1SDavid du Colombier static char *
5223e12c5d1SDavid du Colombier rdate(uchar *p, int fmt)
5233e12c5d1SDavid du Colombier {
5243e12c5d1SDavid du Colombier 	static char buf[64];
5253e12c5d1SDavid du Colombier 	int htz, s, n;
5263e12c5d1SDavid du Colombier 
5273e12c5d1SDavid du Colombier 	n = sprint(buf, "%2.2d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d",
5283e12c5d1SDavid du Colombier 		p[0], p[1], p[2], p[3], p[4], p[5]);
5293e12c5d1SDavid du Colombier 	if(fmt == 'z'){
5303e12c5d1SDavid du Colombier 		htz = p[6];
5313e12c5d1SDavid du Colombier 		if(htz >= 128){
5323e12c5d1SDavid du Colombier 			htz = 256-htz;
5333e12c5d1SDavid du Colombier 			s = '-';
5343e12c5d1SDavid du Colombier 		}else
5353e12c5d1SDavid du Colombier 			s = '+';
5363e12c5d1SDavid du Colombier 		sprint(&buf[n], " (%c%.1f)", s, (float)htz/2);
5373e12c5d1SDavid du Colombier 	}
5383e12c5d1SDavid du Colombier 	return buf;
5393e12c5d1SDavid du Colombier }
5403e12c5d1SDavid du Colombier 
541bd389b36SDavid du Colombier static char
542bd389b36SDavid du Colombier dmsize[12] =
543bd389b36SDavid du Colombier {
5443e12c5d1SDavid du Colombier 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
5453e12c5d1SDavid du Colombier };
546bd389b36SDavid du Colombier 
5473e12c5d1SDavid du Colombier static int
5483e12c5d1SDavid du Colombier dysize(int y)
5493e12c5d1SDavid du Colombier {
5503e12c5d1SDavid du Colombier 
5513e12c5d1SDavid du Colombier 	if((y%4) == 0)
5523e12c5d1SDavid du Colombier 		return 366;
5533e12c5d1SDavid du Colombier 	return 365;
5543e12c5d1SDavid du Colombier }
555bd389b36SDavid du Colombier 
5563e12c5d1SDavid du Colombier static long
5573e12c5d1SDavid du Colombier gtime(uchar *p)	/* yMdhmsz */
5583e12c5d1SDavid du Colombier {
5593e12c5d1SDavid du Colombier 	long t;
5603e12c5d1SDavid du Colombier 	int i, y, M, d, h, m, s, tz;
5613e12c5d1SDavid du Colombier 	y=p[0]; M=p[1]; d=p[2];
5623e12c5d1SDavid du Colombier 	h=p[3]; m=p[4]; s=p[5]; tz=p[6];
5633e12c5d1SDavid du Colombier 	USED(tz);
5643e12c5d1SDavid du Colombier 	if (y < 70)
5653e12c5d1SDavid du Colombier 		return 0;
5663e12c5d1SDavid du Colombier 	if (M < 1 || M > 12)
5673e12c5d1SDavid du Colombier 		return 0;
5683e12c5d1SDavid du Colombier 	if (d < 1 || d > dmsize[M-1])
5693e12c5d1SDavid du Colombier 		return 0;
5703e12c5d1SDavid du Colombier 	if (h > 23)
5713e12c5d1SDavid du Colombier 		return 0;
5723e12c5d1SDavid du Colombier 	if (m > 59)
5733e12c5d1SDavid du Colombier 		return 0;
5743e12c5d1SDavid du Colombier 	if (s > 59)
5753e12c5d1SDavid du Colombier 		return 0;
5763e12c5d1SDavid du Colombier 	y += 1900;
5773e12c5d1SDavid du Colombier 	t = 0;
5783e12c5d1SDavid du Colombier 	for(i=1970; i<y; i++)
5793e12c5d1SDavid du Colombier 		t += dysize(i);
5803e12c5d1SDavid du Colombier 	if (dysize(y)==366 && M >= 3)
5813e12c5d1SDavid du Colombier 		t++;
5823e12c5d1SDavid du Colombier 	while(--M)
5833e12c5d1SDavid du Colombier 		t += dmsize[M-1];
5843e12c5d1SDavid du Colombier 	t += d-1;
5853e12c5d1SDavid du Colombier 	t = 24*t + h;
5863e12c5d1SDavid du Colombier 	t = 60*t + m;
5873e12c5d1SDavid du Colombier 	t = 60*t + s;
5883e12c5d1SDavid du Colombier 	return t;
5893e12c5d1SDavid du Colombier }
5903e12c5d1SDavid du Colombier 
5913e12c5d1SDavid du Colombier #define	p	((uchar*)arg)
5923e12c5d1SDavid du Colombier 
5933e12c5d1SDavid du Colombier static long
5943e12c5d1SDavid du Colombier l16(void *arg)
5953e12c5d1SDavid du Colombier {
5963e12c5d1SDavid du Colombier 	long v;
5973e12c5d1SDavid du Colombier 
5983e12c5d1SDavid du Colombier 	v = ((long)p[1]<<8)|p[0];
5993e12c5d1SDavid du Colombier 	if (v >= 0x8000L)
6003e12c5d1SDavid du Colombier 		v -= 0x10000L;
6013e12c5d1SDavid du Colombier 	return v;
6023e12c5d1SDavid du Colombier }
6033e12c5d1SDavid du Colombier 
6043e12c5d1SDavid du Colombier static long
6053e12c5d1SDavid du Colombier l32(void *arg)
6063e12c5d1SDavid du Colombier {
6073e12c5d1SDavid du Colombier 	return ((((((long)p[3]<<8)|p[2])<<8)|p[1])<<8)|p[0];
6083e12c5d1SDavid du Colombier }
6093e12c5d1SDavid du Colombier 
6103e12c5d1SDavid du Colombier #undef	p
611