xref: /plan9/sys/src/cmd/aux/olefs.c (revision 59c21d95eabd8f0704c9b4a4cb647ed908ae2da6)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include <fcall.h>
67dd7cddfSDavid du Colombier #include <thread.h>
77dd7cddfSDavid du Colombier #include <9p.h>
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier /* little endian */
107dd7cddfSDavid du Colombier #define SHORT(p)	(((uchar*)(p))[0] | (((uchar*)(p))[1] << 8))
117dd7cddfSDavid du Colombier #define LONG(p)	((ulong)SHORT(p) |(((ulong)SHORT((p)+2)) << 16))
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier typedef struct Ofile	Ofile;
147dd7cddfSDavid du Colombier typedef struct Odir	Odir;
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier enum {
177dd7cddfSDavid du Colombier 	/* special block map entries */
187dd7cddfSDavid du Colombier 	Bspecial = 0xFFFFFFFD,
197dd7cddfSDavid du Colombier 	Bendchain = 0xFFFFFFFE,
207dd7cddfSDavid du Colombier 	Bunused = 0xFFFFFFFF,
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier 	Blocksize = 0x200,
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier 	Odirsize = 0x80,
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier 	/* Odir types */
277dd7cddfSDavid du Colombier 	Tstorage = 1,
287dd7cddfSDavid du Colombier 	Tstream = 2,
297dd7cddfSDavid du Colombier 	Troot = 5,
307dd7cddfSDavid du Colombier };
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier /*
337dd7cddfSDavid du Colombier  * the file consists of chains of blocks of size 0x200.
347dd7cddfSDavid du Colombier  * to find what block follows block n, you look at
357dd7cddfSDavid du Colombier  * blockmap[n].  that block follows it unless it is Bspecial
367dd7cddfSDavid du Colombier  * or Bendchain.
377dd7cddfSDavid du Colombier  *
387dd7cddfSDavid du Colombier  * it's like the MS-DOS file system allocation tables.
397dd7cddfSDavid du Colombier  */
407dd7cddfSDavid du Colombier struct Ofile {
417dd7cddfSDavid du Colombier 	Biobuf *b;
427dd7cddfSDavid du Colombier 	ulong nblock;
437dd7cddfSDavid du Colombier 	ulong *blockmap;
447dd7cddfSDavid du Colombier 	ulong rootblock;
457dd7cddfSDavid du Colombier 	ulong smapblock;
467dd7cddfSDavid du Colombier 	ulong *smallmap;
477dd7cddfSDavid du Colombier };
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier /* Odir headers are found in directory listings in the Olefile */
507dd7cddfSDavid du Colombier /* prev and next form a binary tree of directory entries */
517dd7cddfSDavid du Colombier struct Odir {
527dd7cddfSDavid du Colombier 	Ofile *f;
537dd7cddfSDavid du Colombier 	Rune name[32+1];
547dd7cddfSDavid du Colombier 	uchar type;
557dd7cddfSDavid du Colombier 	uchar isroot;
567dd7cddfSDavid du Colombier 	ulong left;
577dd7cddfSDavid du Colombier 	ulong right;
587dd7cddfSDavid du Colombier 	ulong dir;
597dd7cddfSDavid du Colombier 	ulong start;
607dd7cddfSDavid du Colombier 	ulong size;
617dd7cddfSDavid du Colombier };
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier void*
emalloc(ulong sz)647dd7cddfSDavid du Colombier emalloc(ulong sz)
657dd7cddfSDavid du Colombier {
667dd7cddfSDavid du Colombier 	void *v;
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier 	v = malloc(sz);
697dd7cddfSDavid du Colombier 	assert(v != nil);
707dd7cddfSDavid du Colombier 	return v;
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier 
737dd7cddfSDavid du Colombier int
convM2OD(Odir * f,void * buf,int nbuf)747dd7cddfSDavid du Colombier convM2OD(Odir *f, void *buf, int nbuf)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	int i;
777dd7cddfSDavid du Colombier 	char *p;
787dd7cddfSDavid du Colombier 	int len;
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier 	if(nbuf < Odirsize)
817dd7cddfSDavid du Colombier 		return -1;
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier 	/*
847dd7cddfSDavid du Colombier 	 * the short at 0x40 is the length of the name.
857dd7cddfSDavid du Colombier 	 * when zero, it means there is no Odir here.
867dd7cddfSDavid du Colombier 	 */
877dd7cddfSDavid du Colombier 	p = buf;
887dd7cddfSDavid du Colombier 	len = SHORT(p+0x40);
897dd7cddfSDavid du Colombier 	if(len == 0)
907dd7cddfSDavid du Colombier 		return 0;
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	if(len > 32)	/* shouldn't happen */
937dd7cddfSDavid du Colombier 		len = 32;
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 	for(i=0; i<len; i++)
967dd7cddfSDavid du Colombier 		f->name[i] = SHORT(p+i*2);
977dd7cddfSDavid du Colombier 	f->name[len] = 0;
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier 	f->type = p[0x42];
1007dd7cddfSDavid du Colombier 	f->left = LONG(p+0x44);
1017dd7cddfSDavid du Colombier 	f->right = LONG(p+0x48);
1027dd7cddfSDavid du Colombier 	f->dir = LONG(p+0x4C);
1037dd7cddfSDavid du Colombier 	f->start = LONG(p+0x74);
1047dd7cddfSDavid du Colombier 	f->size = LONG(p+0x78);
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier 	/* BUG: grab time in ms format from here */
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier 	return 1;
1097dd7cddfSDavid du Colombier }
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier int
oreadblock(Ofile * f,int block,ulong off,char * buf,int nbuf)1127dd7cddfSDavid du Colombier oreadblock(Ofile *f, int block, ulong off, char *buf, int nbuf)
1137dd7cddfSDavid du Colombier {
114*59c21d95SDavid du Colombier 	int n;
115*59c21d95SDavid du Colombier 
1167dd7cddfSDavid du Colombier 	if(block < 0 || block >= f->nblock) {
1177dd7cddfSDavid du Colombier 		werrstr("attempt to read %x/%lux\n", block, f->nblock);
1187dd7cddfSDavid du Colombier 		return -1;
1197dd7cddfSDavid du Colombier 	}
1207dd7cddfSDavid du Colombier 
121*59c21d95SDavid du Colombier 	if(off >= Blocksize){
122*59c21d95SDavid du Colombier 		print("offset too far into block\n");
1237dd7cddfSDavid du Colombier 		return 0;
124*59c21d95SDavid du Colombier 	}
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier 	if(off+nbuf > Blocksize)
1277dd7cddfSDavid du Colombier 		nbuf = Blocksize-off;
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier 	/* blocks start numbering at -1 [sic] */
1307dd7cddfSDavid du Colombier 	off += (block+1)*Blocksize;
1317dd7cddfSDavid du Colombier 
132*59c21d95SDavid du Colombier 	if(Bseek(f->b, off, 0) != off){
133*59c21d95SDavid du Colombier 		print("seek failed\n");
1347dd7cddfSDavid du Colombier 		return -1;
135*59c21d95SDavid du Colombier 	}
1367dd7cddfSDavid du Colombier 
137*59c21d95SDavid du Colombier 	n = Bread(f->b, buf, nbuf);
138*59c21d95SDavid du Colombier 	if(n < 0)
139*59c21d95SDavid du Colombier 		print("Bread failed: %r");
140*59c21d95SDavid du Colombier 	return n;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier int
chainlen(Ofile * f,ulong start)1447dd7cddfSDavid du Colombier chainlen(Ofile *f, ulong start)
1457dd7cddfSDavid du Colombier {
1467dd7cddfSDavid du Colombier 	int i;
1477dd7cddfSDavid du Colombier 	for(i=0; start < 0xFFFF0000; i++)
1487dd7cddfSDavid du Colombier 		start = f->blockmap[start];
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier 	return i;
1517dd7cddfSDavid du Colombier }
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier /*
1547dd7cddfSDavid du Colombier  * read nbuf bytes starting at offset off from the
1557dd7cddfSDavid du Colombier  * chain whose first block is block.  the chain is linked
1567dd7cddfSDavid du Colombier  * together via the blockmap as described above,
1577dd7cddfSDavid du Colombier  * like the MS-DOS file allocation tables.
1587dd7cddfSDavid du Colombier  */
1597dd7cddfSDavid du Colombier int
oreadchain(Ofile * f,ulong block,int off,char * buf,int nbuf)1607dd7cddfSDavid du Colombier oreadchain(Ofile *f, ulong block, int off, char *buf, int nbuf)
1617dd7cddfSDavid du Colombier {
1627dd7cddfSDavid du Colombier 	int i;
1637dd7cddfSDavid du Colombier 	int offblock;
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier 	offblock = off/Blocksize;
1667dd7cddfSDavid du Colombier 	for(i=0; i<offblock && block < 0xFFFF0000; i++)
1677dd7cddfSDavid du Colombier 		block = f->blockmap[block];
1687dd7cddfSDavid du Colombier 	return oreadblock(f, block, off%Blocksize, buf, nbuf);
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier int
oreadfile(Odir * d,int off,char * buf,int nbuf)1727dd7cddfSDavid du Colombier oreadfile(Odir *d, int off, char *buf, int nbuf)
1737dd7cddfSDavid du Colombier {
1747dd7cddfSDavid du Colombier 	/*
1757dd7cddfSDavid du Colombier 	 * if d->size < 0x1000 then d->start refers
1767dd7cddfSDavid du Colombier 	 * to a small depot block, else a big one.
1777dd7cddfSDavid du Colombier 	 * if this is the root entry, it's a big one
1787dd7cddfSDavid du Colombier 	 * no matter what.
1797dd7cddfSDavid du Colombier 	 */
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 	if(off >= d->size)
1827dd7cddfSDavid du Colombier 		return 0;
1837dd7cddfSDavid du Colombier 	if(off+nbuf > d->size)
1847dd7cddfSDavid du Colombier 		nbuf = d->size-off;
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier 	if(d->size >= 0x1000
1877dd7cddfSDavid du Colombier 	|| memcmp(d->name, L"Root Entry", 11*sizeof(Rune)) == 0)
1887dd7cddfSDavid du Colombier 		return oreadchain(d->f, d->start, off, buf, nbuf);
1897dd7cddfSDavid du Colombier 	else {	/* small block */
1907dd7cddfSDavid du Colombier 		off += d->start*64;
1917dd7cddfSDavid du Colombier 		return oreadchain(d->f, d->f->smapblock, off, buf, nbuf);
1927dd7cddfSDavid du Colombier 	}
1937dd7cddfSDavid du Colombier }
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier int
oreaddir(Ofile * f,int entry,Odir * d)1967dd7cddfSDavid du Colombier oreaddir(Ofile *f, int entry, Odir *d)
1977dd7cddfSDavid du Colombier {
1987dd7cddfSDavid du Colombier 	char buf[Odirsize];
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 	if(oreadchain(f, f->rootblock, entry*Odirsize, buf, Odirsize) != Odirsize)
2017dd7cddfSDavid du Colombier 		return -1;
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier 	d->f = f;
2047dd7cddfSDavid du Colombier 	return convM2OD(d, buf, Odirsize);
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier void
dumpdir(Ofile * f,ulong dnum)2087dd7cddfSDavid du Colombier dumpdir(Ofile *f, ulong dnum)
2097dd7cddfSDavid du Colombier {
2107dd7cddfSDavid du Colombier 	Odir d;
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier 	if(oreaddir(f, dnum, &d) != 1) {
2137dd7cddfSDavid du Colombier 		fprint(2, "dumpdir %lux failed\n", dnum);
2147dd7cddfSDavid du Colombier 		return;
2157dd7cddfSDavid du Colombier 	}
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier 	fprint(2, "%.8lux type %d size %lud l %.8lux r %.8lux d %.8lux (%S)\n", dnum, d.type, d.size, d.left, d.right, d.dir, d.name);
2187dd7cddfSDavid du Colombier 	if(d.left != (ulong)-1)
2197dd7cddfSDavid du Colombier 		dumpdir(f, d.left);
2207dd7cddfSDavid du Colombier 	if(d.right != (ulong)-1)
2217dd7cddfSDavid du Colombier 		dumpdir(f, d.right);
2227dd7cddfSDavid du Colombier 	if(d.dir != (ulong)-1)
2237dd7cddfSDavid du Colombier 		dumpdir(f, d.dir);
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier Ofile*
oleopen(char * fn)2277dd7cddfSDavid du Colombier oleopen(char *fn)
2287dd7cddfSDavid du Colombier {
2297dd7cddfSDavid du Colombier 	int i, j, k, block;
2307dd7cddfSDavid du Colombier 	int ndepot;
2317dd7cddfSDavid du Colombier 	ulong u;
2327dd7cddfSDavid du Colombier 	Odir rootdir;
2337dd7cddfSDavid du Colombier 	ulong extrablock;
2347dd7cddfSDavid du Colombier 	uchar buf[Blocksize];
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier 	Ofile *f;
2377dd7cddfSDavid du Colombier 	Biobuf *b;
2387dd7cddfSDavid du Colombier 	static char magic[] = {
2397dd7cddfSDavid du Colombier 		0xD0, 0xCF, 0x11, 0xE0,
2407dd7cddfSDavid du Colombier 		0xA1, 0xB1, 0x1A, 0xE1
2417dd7cddfSDavid du Colombier 	};
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier 	b = Bopen(fn, OREAD);
2447dd7cddfSDavid du Colombier 	if(b == nil)
2457dd7cddfSDavid du Colombier 		return nil;
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier 	/* the first bytes are magic */
2487dd7cddfSDavid du Colombier 	if(Bread(b, buf, sizeof magic) != sizeof magic
2497dd7cddfSDavid du Colombier 	|| memcmp(buf, magic, sizeof magic) != 0) {
2507dd7cddfSDavid du Colombier 		Bterm(b);
251*59c21d95SDavid du Colombier 		werrstr("bad magic: not OLE file");
2527dd7cddfSDavid du Colombier 		return nil;
2537dd7cddfSDavid du Colombier 	}
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier 	f = emalloc(sizeof *f);
2567dd7cddfSDavid du Colombier 	f->b = b;
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	/*
2597dd7cddfSDavid du Colombier 	 * the header contains a list of depots, which are
2607dd7cddfSDavid du Colombier 	 * block maps.  we assimilate them into one large map,
2617dd7cddfSDavid du Colombier 	 * kept in main memory.
2627dd7cddfSDavid du Colombier 	 */
2637dd7cddfSDavid du Colombier 	Bseek(b, 0, 0);
2647dd7cddfSDavid du Colombier 	if(Bread(b, buf, Blocksize) != Blocksize) {
2657dd7cddfSDavid du Colombier 		Bterm(b);
2667dd7cddfSDavid du Colombier 		free(f);
267*59c21d95SDavid du Colombier 		print("short read\n");
2687dd7cddfSDavid du Colombier 		return nil;
2697dd7cddfSDavid du Colombier 	}
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	ndepot = LONG(buf+0x2C);
2727dd7cddfSDavid du Colombier 	f->nblock = ndepot*(Blocksize/4);
2737dd7cddfSDavid du Colombier //	fprint(2, "ndepot = %d f->nblock = %lud\n", ndepot, f->nblock);
2747dd7cddfSDavid du Colombier 	f->rootblock = LONG(buf+0x30);
2757dd7cddfSDavid du Colombier 	f->smapblock = LONG(buf+0x3C);
2767dd7cddfSDavid du Colombier 	f->blockmap = emalloc(sizeof(f->blockmap[0])*f->nblock);
2777dd7cddfSDavid du Colombier 	extrablock = LONG(buf+0x44);
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 	u = 0;
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 	/* the big block map fills to the end of the first 512-byte block */
2827dd7cddfSDavid du Colombier 	for(i=0; i<ndepot && i<(0x200-0x4C)/4; i++) {
2837dd7cddfSDavid du Colombier 		if(Bseek(b, 0x4C+4*i, 0) != 0x4C+4*i
2847dd7cddfSDavid du Colombier 		|| Bread(b, buf, 4) != 4) {
2857dd7cddfSDavid du Colombier 			print("bseek %d fail\n", 0x4C+4*i);
2867dd7cddfSDavid du Colombier 			goto Die;
2877dd7cddfSDavid du Colombier 		}
2887dd7cddfSDavid du Colombier 		block = LONG(buf);
2897dd7cddfSDavid du Colombier 		if((ulong)block == Bendchain) {
2907dd7cddfSDavid du Colombier 			ndepot = i;
2917dd7cddfSDavid du Colombier 			f->nblock = ndepot*(Blocksize/4);
2927dd7cddfSDavid du Colombier 			break;
2937dd7cddfSDavid du Colombier 		}
2947dd7cddfSDavid du Colombier 
2957dd7cddfSDavid du Colombier 		if(Bseek(b, (block+1)*Blocksize, 0) != (block+1)*Blocksize) {
2967dd7cddfSDavid du Colombier 			print("Xbseek %d fail\n", (block+1)*Blocksize);
2977dd7cddfSDavid du Colombier 			goto Die;
2987dd7cddfSDavid du Colombier 		}
2997dd7cddfSDavid du Colombier 		for(j=0; j<Blocksize/4; j++) {
3007dd7cddfSDavid du Colombier 			if(Bread(b, buf, 4) != 4) {
3017dd7cddfSDavid du Colombier 				print("Bread fail seek block %x, %d i %d ndepot %d\n", block, (block+1)*Blocksize, i, ndepot);
3027dd7cddfSDavid du Colombier 				goto Die;
3037dd7cddfSDavid du Colombier 			}
3047dd7cddfSDavid du Colombier 			f->blockmap[u++] = LONG(buf);
3057dd7cddfSDavid du Colombier 		}
3067dd7cddfSDavid du Colombier 	}
3077dd7cddfSDavid du Colombier 	/*
3087dd7cddfSDavid du Colombier 	 * if the first block can't hold it, it continues in the block at LONG(hdr+0x44).
3097dd7cddfSDavid du Colombier 	 * if that in turn is not big enough, there's a next block number at the end of
3107dd7cddfSDavid du Colombier 	 * each block.
3117dd7cddfSDavid du Colombier 	 */
3127dd7cddfSDavid du Colombier 	while(i < ndepot) {
3137dd7cddfSDavid du Colombier 		for(k=0; k<(0x200-4)/4 && i<ndepot; i++, k++) {
3147dd7cddfSDavid du Colombier 			if(Bseek(b, 0x200+extrablock*Blocksize+4*i, 0) != 0x200+extrablock*0x200+4*i
3157dd7cddfSDavid du Colombier 			|| Bread(b, buf, 4) != 4) {
3167dd7cddfSDavid du Colombier 				print("bseek %d fail\n", 0x4C+4*i);
3177dd7cddfSDavid du Colombier 				goto Die;
3187dd7cddfSDavid du Colombier 			}
3197dd7cddfSDavid du Colombier 			block = LONG(buf);
3207dd7cddfSDavid du Colombier 			if((ulong)block == Bendchain) {
3217dd7cddfSDavid du Colombier 				ndepot = i;
3227dd7cddfSDavid du Colombier 				f->nblock = ndepot*(Blocksize/4);
3237dd7cddfSDavid du Colombier 				goto Break2;
3247dd7cddfSDavid du Colombier 			}
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 			if(Bseek(b, (block+1)*Blocksize, 0) != (block+1)*Blocksize) {
3277dd7cddfSDavid du Colombier 				print("Xbseek %d fail\n", (block+1)*Blocksize);
3287dd7cddfSDavid du Colombier 				goto Die;
3297dd7cddfSDavid du Colombier 			}
3307dd7cddfSDavid du Colombier 			for(j=0; j<Blocksize/4; j++) {
3317dd7cddfSDavid du Colombier 				if(Bread(b, buf, 4) != 4) {
3327dd7cddfSDavid du Colombier 					print("Bread fail seek block %x, %d i %d ndepot %d\n", block, (block+1)*Blocksize, i, ndepot);
3337dd7cddfSDavid du Colombier 					goto Die;
3347dd7cddfSDavid du Colombier 				}
3357dd7cddfSDavid du Colombier 				f->blockmap[u++] = LONG(buf);
3367dd7cddfSDavid du Colombier 			}
3377dd7cddfSDavid du Colombier 		}
3387dd7cddfSDavid du Colombier 		if(Bseek(b, 0x200+extrablock*Blocksize+Blocksize-4, 0) != 0x200+extrablock*Blocksize+Blocksize-4
3397dd7cddfSDavid du Colombier 		|| Bread(b, buf, 4) != 4) {
3407dd7cddfSDavid du Colombier 			print("bseek %d fail\n", 0x4C+4*i);
3417dd7cddfSDavid du Colombier 			goto Die;
3427dd7cddfSDavid du Colombier 		}
3437dd7cddfSDavid du Colombier 		extrablock = LONG(buf);
3447dd7cddfSDavid du Colombier 	}
3457dd7cddfSDavid du Colombier Break2:;
3467dd7cddfSDavid du Colombier 
347*59c21d95SDavid du Colombier 	if(oreaddir(f, 0, &rootdir) <= 0){
348*59c21d95SDavid du Colombier 		print("oreaddir could not read root\n");
3497dd7cddfSDavid du Colombier 		goto Die;
350*59c21d95SDavid du Colombier 	}
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	f->smapblock = rootdir.start;
3537dd7cddfSDavid du Colombier 	return f;
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier Die:
3567dd7cddfSDavid du Colombier 	Bterm(b);
3577dd7cddfSDavid du Colombier 	free(f->blockmap);
3587dd7cddfSDavid du Colombier 	free(f);
3597dd7cddfSDavid du Colombier 	return nil;
3607dd7cddfSDavid du Colombier }
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier void
oleread(Req * r)3639a747e4fSDavid du Colombier oleread(Req *r)
3647dd7cddfSDavid du Colombier {
3657dd7cddfSDavid du Colombier 	Odir *d;
3667dd7cddfSDavid du Colombier 	char *p;
3677dd7cddfSDavid du Colombier 	int e, n;
3687dd7cddfSDavid du Colombier 	long c;
3697dd7cddfSDavid du Colombier 	vlong o;
3707dd7cddfSDavid du Colombier 
3719a747e4fSDavid du Colombier 	o = r->ifcall.offset;
3729a747e4fSDavid du Colombier 	d = r->fid->file->aux;
3737dd7cddfSDavid du Colombier 	if(d == nil) {
3747dd7cddfSDavid du Colombier 		respond(r, "cannot happen");
3757dd7cddfSDavid du Colombier 		return;
3767dd7cddfSDavid du Colombier 	}
3777dd7cddfSDavid du Colombier 
3789a747e4fSDavid du Colombier 	c = r->ifcall.count;
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier 	if(o >= d->size) {
3819a747e4fSDavid du Colombier 		r->ofcall.count = 0;
3827dd7cddfSDavid du Colombier 		respond(r, nil);
3837dd7cddfSDavid du Colombier 		return;
3847dd7cddfSDavid du Colombier 	}
3857dd7cddfSDavid du Colombier 
3867dd7cddfSDavid du Colombier 	if(o+c > d->size)
3877dd7cddfSDavid du Colombier 		c = d->size-o;
3887dd7cddfSDavid du Colombier 
3897dd7cddfSDavid du Colombier 	/*
3907dd7cddfSDavid du Colombier 	 * oreadfile returns so little data, it will
3917dd7cddfSDavid du Colombier 	 * help to read as much as we can.
3927dd7cddfSDavid du Colombier 	 */
3937dd7cddfSDavid du Colombier 	e = c+o;
3947dd7cddfSDavid du Colombier 	n = 0;
3959a747e4fSDavid du Colombier 	for(p=r->ofcall.data; o<e; o+=n, p+=n) {
3967dd7cddfSDavid du Colombier 		n = oreadfile(d, o, p, e-o);
3977dd7cddfSDavid du Colombier 		if(n <= 0)
3987dd7cddfSDavid du Colombier 			break;
3997dd7cddfSDavid du Colombier 	}
4007dd7cddfSDavid du Colombier 
4019a747e4fSDavid du Colombier 	if(n == -1 && o == r->ifcall.offset)
4027dd7cddfSDavid du Colombier 		respond(r, "error reading word file");
4037dd7cddfSDavid du Colombier 	else {
4049a747e4fSDavid du Colombier 		r->ofcall.count = o - r->ifcall.offset;
4057dd7cddfSDavid du Colombier 		respond(r, nil);
4067dd7cddfSDavid du Colombier 	}
4077dd7cddfSDavid du Colombier }
4087dd7cddfSDavid du Colombier 
4097dd7cddfSDavid du Colombier Odir*
copydir(Odir * d)4107dd7cddfSDavid du Colombier copydir(Odir *d)
4117dd7cddfSDavid du Colombier {
4127dd7cddfSDavid du Colombier 	Odir *e;
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier 	e = emalloc(sizeof(*d));
4157dd7cddfSDavid du Colombier 	*e = *d;
4167dd7cddfSDavid du Colombier 	return e;
4177dd7cddfSDavid du Colombier }
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier void
filldir(File * t,Ofile * f,int dnum,int nrecur)4207dd7cddfSDavid du Colombier filldir(File *t, Ofile *f, int dnum, int nrecur)
4217dd7cddfSDavid du Colombier {
4227dd7cddfSDavid du Colombier 	Odir d;
4237dd7cddfSDavid du Colombier 	int i;
4249a747e4fSDavid du Colombier 	Rune rbuf[40];
4259a747e4fSDavid du Colombier 	char buf[UTFmax*nelem(rbuf)];
4267dd7cddfSDavid du Colombier 	File *nt;
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier 	if(dnum == 0xFFFFFFFF || oreaddir(f, dnum, &d) != 1)
4297dd7cddfSDavid du Colombier 		return;
4307dd7cddfSDavid du Colombier 
4317dd7cddfSDavid du Colombier 	/*
4327dd7cddfSDavid du Colombier 	 * i hope there are no broken files with
4337dd7cddfSDavid du Colombier 	 * circular trees.  i hate infinite loops.
4347dd7cddfSDavid du Colombier 	 */
4357dd7cddfSDavid du Colombier 	if(nrecur > 100)
4367dd7cddfSDavid du Colombier 		sysfatal("tree too large in office file: probably circular");
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier 	filldir(t, f, d.left, nrecur+1);
4397dd7cddfSDavid du Colombier 
4407dd7cddfSDavid du Colombier 	/* add current tree entry */
4419a747e4fSDavid du Colombier 	runestrecpy(rbuf, rbuf+sizeof rbuf, d.name);
4429a747e4fSDavid du Colombier 	for(i=0; rbuf[i]; i++)
4437dd7cddfSDavid du Colombier 		if(rbuf[i] == L' ')
4447dd7cddfSDavid du Colombier 			rbuf[i] = L'␣';
4457dd7cddfSDavid du Colombier 		else if(rbuf[i] <= 0x20 || rbuf[i] == L'/'
4467dd7cddfSDavid du Colombier 			|| (0x80 <= rbuf[i] && rbuf[i] <= 0x9F))
4477dd7cddfSDavid du Colombier 				rbuf[i] = ':';
4487dd7cddfSDavid du Colombier 
4499a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%S", rbuf);
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 	if(d.dir == 0xFFFFFFFF) {
4527dd7cddfSDavid du Colombier 		/* make file */
4539a747e4fSDavid du Colombier 		nt = createfile(t, buf, nil, 0444, nil);
4549a747e4fSDavid du Colombier 		if(nt == nil)
4554fc7c356SDavid du Colombier 			sysfatal("nt nil: create %s: %r", buf);
4567dd7cddfSDavid du Colombier 		nt->aux = copydir(&d);
4577dd7cddfSDavid du Colombier 		nt->length = d.size;
4587dd7cddfSDavid du Colombier 	} else /* make directory */
4599a747e4fSDavid du Colombier 		nt = createfile(t, buf, nil, DMDIR|0777, nil);
4607dd7cddfSDavid du Colombier 
4617dd7cddfSDavid du Colombier 	filldir(t, f, d.right, nrecur+1);
4627dd7cddfSDavid du Colombier 
4637dd7cddfSDavid du Colombier 	if(d.dir != 0xFFFFFFFF)
4647dd7cddfSDavid du Colombier 		filldir(nt, f, d.dir, nrecur+1);
4657dd7cddfSDavid du Colombier 
4669a747e4fSDavid du Colombier 	closefile(nt);
4677dd7cddfSDavid du Colombier }
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier Srv olesrv = {
4707dd7cddfSDavid du Colombier 	.read=	oleread,
4717dd7cddfSDavid du Colombier };
4727dd7cddfSDavid du Colombier 
4737dd7cddfSDavid du Colombier void
main(int argc,char ** argv)4747dd7cddfSDavid du Colombier main(int argc, char **argv)
4757dd7cddfSDavid du Colombier {
4767dd7cddfSDavid du Colombier 	char *mtpt;
4777dd7cddfSDavid du Colombier 	Ofile *f;
4787dd7cddfSDavid du Colombier 	Odir d;
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier 	mtpt = "/mnt/doc";
4817dd7cddfSDavid du Colombier 	ARGBEGIN{
4827dd7cddfSDavid du Colombier 	case 'm':
4837dd7cddfSDavid du Colombier 		mtpt = ARGF();
4847dd7cddfSDavid du Colombier 		break;
4857dd7cddfSDavid du Colombier 
4867dd7cddfSDavid du Colombier 	default:
4877dd7cddfSDavid du Colombier 		goto Usage;
4887dd7cddfSDavid du Colombier 	}ARGEND
4897dd7cddfSDavid du Colombier 
4907dd7cddfSDavid du Colombier 	if(argc != 1) {
4917dd7cddfSDavid du Colombier 	Usage:
4927dd7cddfSDavid du Colombier 		fprint(2, "usage: olefs file\n");
4937dd7cddfSDavid du Colombier 		exits("usage");
4947dd7cddfSDavid du Colombier 	}
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier 	f = oleopen(argv[0]);
4977dd7cddfSDavid du Colombier 	if(f == nil) {
498*59c21d95SDavid du Colombier 		print("error opening %s: %r\n", argv[0]);
4997dd7cddfSDavid du Colombier 		exits("open");
5007dd7cddfSDavid du Colombier 	}
5017dd7cddfSDavid du Colombier 
5027dd7cddfSDavid du Colombier //	dumpdir(f, 0);
5037dd7cddfSDavid du Colombier 
5047dd7cddfSDavid du Colombier 	if(oreaddir(f, 0, &d) != 1) {
5057dd7cddfSDavid du Colombier 		fprint(2, "oreaddir error: %r\n");
5067dd7cddfSDavid du Colombier 		exits("oreaddir");
5077dd7cddfSDavid du Colombier 	}
5087dd7cddfSDavid du Colombier 
5099a747e4fSDavid du Colombier 	olesrv.tree = alloctree(nil, nil, DMDIR|0777, nil);
5107dd7cddfSDavid du Colombier 	filldir(olesrv.tree->root, f, d.dir, 0);
5117dd7cddfSDavid du Colombier 	postmountsrv(&olesrv, nil, mtpt, MREPL);
5127dd7cddfSDavid du Colombier 	exits(0);
5137dd7cddfSDavid du Colombier }
514