olefs.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <auth.h>
  13. #include <fcall.h>
  14. #include <thread.h>
  15. #include <9p.h>
  16. /* little endian */
  17. #define SHORT(p) (((uint8_t*)(p))[0] | (((uint8_t*)(p))[1] << 8))
  18. #define LONG(p) ((uint32_t)SHORT(p) |(((uint32_t)SHORT((p)+2)) << 16))
  19. typedef struct Ofile Ofile;
  20. typedef struct Odir Odir;
  21. enum {
  22. /* special block map entries */
  23. Bspecial = 0xFFFFFFFD,
  24. Bendchain = 0xFFFFFFFE,
  25. Bunused = 0xFFFFFFFF,
  26. Blocksize = 0x200,
  27. Odirsize = 0x80,
  28. /* Odir types */
  29. Tstorage = 1,
  30. Tstream = 2,
  31. Troot = 5,
  32. };
  33. /*
  34. * the file consists of chains of blocks of size 0x200.
  35. * to find what block follows block n, you look at
  36. * blockmap[n]. that block follows it unless it is Bspecial
  37. * or Bendchain.
  38. *
  39. * it's like the MS-DOS file system allocation tables.
  40. */
  41. struct Ofile {
  42. Biobuf *b;
  43. uint32_t nblock;
  44. uint32_t *blockmap;
  45. uint32_t rootblock;
  46. uint32_t smapblock;
  47. uint32_t *smallmap;
  48. };
  49. /* Odir headers are found in directory listings in the Olefile */
  50. /* prev and next form a binary tree of directory entries */
  51. struct Odir {
  52. Ofile *f;
  53. Rune name[32+1];
  54. uint8_t type;
  55. uint8_t isroot;
  56. uint32_t left;
  57. uint32_t right;
  58. uint32_t dir;
  59. uint32_t start;
  60. uint32_t size;
  61. };
  62. void*
  63. emalloc(uint32_t sz)
  64. {
  65. void *v;
  66. v = malloc(sz);
  67. assert(v != nil);
  68. return v;
  69. }
  70. int
  71. convM2OD(Odir *f, void *buf, int nbuf)
  72. {
  73. int i;
  74. char *p;
  75. int len;
  76. if(nbuf < Odirsize)
  77. return -1;
  78. /*
  79. * the short at 0x40 is the length of the name.
  80. * when zero, it means there is no Odir here.
  81. */
  82. p = buf;
  83. len = SHORT(p+0x40);
  84. if(len == 0)
  85. return 0;
  86. if(len > 32) /* shouldn't happen */
  87. len = 32;
  88. for(i=0; i<len; i++)
  89. f->name[i] = SHORT(p+i*2);
  90. f->name[len] = 0;
  91. f->type = p[0x42];
  92. f->left = LONG(p+0x44);
  93. f->right = LONG(p+0x48);
  94. f->dir = LONG(p+0x4C);
  95. f->start = LONG(p+0x74);
  96. f->size = LONG(p+0x78);
  97. /* BUG: grab time in ms format from here */
  98. return 1;
  99. }
  100. int
  101. oreadblock(Ofile *f, int block, uint32_t off, char *buf, int nbuf)
  102. {
  103. int n;
  104. if(block < 0 || block >= f->nblock) {
  105. werrstr("attempt to read %x/%lx\n", block, f->nblock);
  106. return -1;
  107. }
  108. if(off >= Blocksize){
  109. print("offset too far into block\n");
  110. return 0;
  111. }
  112. if(off+nbuf > Blocksize)
  113. nbuf = Blocksize-off;
  114. /* blocks start numbering at -1 [sic] */
  115. off += (block+1)*Blocksize;
  116. if(Bseek(f->b, off, 0) != off){
  117. print("seek failed\n");
  118. return -1;
  119. }
  120. n = Bread(f->b, buf, nbuf);
  121. if(n < 0)
  122. print("Bread failed: %r");
  123. return n;
  124. }
  125. int
  126. chainlen(Ofile *f, uint32_t start)
  127. {
  128. int i;
  129. for(i=0; start < 0xFFFF0000; i++)
  130. start = f->blockmap[start];
  131. return i;
  132. }
  133. /*
  134. * read nbuf bytes starting at offset off from the
  135. * chain whose first block is block. the chain is linked
  136. * together via the blockmap as described above,
  137. * like the MS-DOS file allocation tables.
  138. */
  139. int
  140. oreadchain(Ofile *f, uint32_t block, int off, char *buf, int nbuf)
  141. {
  142. int i;
  143. int offblock;
  144. offblock = off/Blocksize;
  145. for(i=0; i<offblock && block < 0xFFFF0000; i++)
  146. block = f->blockmap[block];
  147. return oreadblock(f, block, off%Blocksize, buf, nbuf);
  148. }
  149. int
  150. oreadfile(Odir *d, int off, char *buf, int nbuf)
  151. {
  152. /*
  153. * if d->size < 0x1000 then d->start refers
  154. * to a small depot block, else a big one.
  155. * if this is the root entry, it's a big one
  156. * no matter what.
  157. */
  158. if(off >= d->size)
  159. return 0;
  160. if(off+nbuf > d->size)
  161. nbuf = d->size-off;
  162. if(d->size >= 0x1000
  163. || memcmp(d->name, L"Root Entry", 11*sizeof(Rune)) == 0)
  164. return oreadchain(d->f, d->start, off, buf, nbuf);
  165. else { /* small block */
  166. off += d->start*64;
  167. return oreadchain(d->f, d->f->smapblock, off, buf, nbuf);
  168. }
  169. }
  170. int
  171. oreaddir(Ofile *f, int entry, Odir *d)
  172. {
  173. char buf[Odirsize];
  174. if(oreadchain(f, f->rootblock, entry*Odirsize, buf, Odirsize) != Odirsize)
  175. return -1;
  176. d->f = f;
  177. return convM2OD(d, buf, Odirsize);
  178. }
  179. void
  180. dumpdir(Ofile *f, uint32_t dnum)
  181. {
  182. Odir d;
  183. if(oreaddir(f, dnum, &d) != 1) {
  184. fprint(2, "dumpdir %lx failed\n", dnum);
  185. return;
  186. }
  187. fprint(2, "%.8lux type %d size %lu l %.8lux r %.8lux d %.8lux (%S)\n", dnum, d.type, d.size, d.left, d.right, d.dir, d.name);
  188. if(d.left != (uint32_t)-1)
  189. dumpdir(f, d.left);
  190. if(d.right != (uint32_t)-1)
  191. dumpdir(f, d.right);
  192. if(d.dir != (uint32_t)-1)
  193. dumpdir(f, d.dir);
  194. }
  195. Ofile*
  196. oleopen(char *fn)
  197. {
  198. int i, j, k, block;
  199. int ndepot;
  200. uint32_t u;
  201. Odir rootdir;
  202. uint32_t extrablock;
  203. uint8_t buf[Blocksize];
  204. Ofile *f;
  205. Biobuf *b;
  206. static char magic[] = {
  207. 0xD0, 0xCF, 0x11, 0xE0,
  208. 0xA1, 0xB1, 0x1A, 0xE1
  209. };
  210. b = Bopen(fn, OREAD);
  211. if(b == nil)
  212. return nil;
  213. /* the first bytes are magic */
  214. if(Bread(b, buf, sizeof magic) != sizeof magic
  215. || memcmp(buf, magic, sizeof magic) != 0) {
  216. Bterm(b);
  217. werrstr("bad magic: not OLE file");
  218. return nil;
  219. }
  220. f = emalloc(sizeof *f);
  221. f->b = b;
  222. /*
  223. * the header contains a list of depots, which are
  224. * block maps. we assimilate them into one large map,
  225. * kept in main memory.
  226. */
  227. Bseek(b, 0, 0);
  228. if(Bread(b, buf, Blocksize) != Blocksize) {
  229. Bterm(b);
  230. free(f);
  231. print("short read\n");
  232. return nil;
  233. }
  234. ndepot = LONG(buf+0x2C);
  235. f->nblock = ndepot*(Blocksize/4);
  236. // fprint(2, "ndepot = %d f->nblock = %lu\n", ndepot, f->nblock);
  237. f->rootblock = LONG(buf+0x30);
  238. f->smapblock = LONG(buf+0x3C);
  239. f->blockmap = emalloc(sizeof(f->blockmap[0])*f->nblock);
  240. extrablock = LONG(buf+0x44);
  241. u = 0;
  242. /* the big block map fills to the end of the first 512-byte block */
  243. for(i=0; i<ndepot && i<(0x200-0x4C)/4; i++) {
  244. if(Bseek(b, 0x4C+4*i, 0) != 0x4C+4*i
  245. || Bread(b, buf, 4) != 4) {
  246. print("bseek %d fail\n", 0x4C+4*i);
  247. goto Die;
  248. }
  249. block = LONG(buf);
  250. if((uint32_t)block == Bendchain) {
  251. ndepot = i;
  252. f->nblock = ndepot*(Blocksize/4);
  253. break;
  254. }
  255. if(Bseek(b, (block+1)*Blocksize, 0) != (block+1)*Blocksize) {
  256. print("Xbseek %d fail\n", (block+1)*Blocksize);
  257. goto Die;
  258. }
  259. for(j=0; j<Blocksize/4; j++) {
  260. if(Bread(b, buf, 4) != 4) {
  261. print("Bread fail seek block %x, %d i %d ndepot %d\n", block, (block+1)*Blocksize, i, ndepot);
  262. goto Die;
  263. }
  264. f->blockmap[u++] = LONG(buf);
  265. }
  266. }
  267. /*
  268. * if the first block can't hold it, it continues in the block at LONG(hdr+0x44).
  269. * if that in turn is not big enough, there's a next block number at the end of
  270. * each block.
  271. */
  272. while(i < ndepot) {
  273. for(k=0; k<(0x200-4)/4 && i<ndepot; i++, k++) {
  274. if(Bseek(b, 0x200+extrablock*Blocksize+4*i, 0) != 0x200+extrablock*0x200+4*i
  275. || Bread(b, buf, 4) != 4) {
  276. print("bseek %d fail\n", 0x4C+4*i);
  277. goto Die;
  278. }
  279. block = LONG(buf);
  280. if((uint32_t)block == Bendchain) {
  281. ndepot = i;
  282. f->nblock = ndepot*(Blocksize/4);
  283. goto Break2;
  284. }
  285. if(Bseek(b, (block+1)*Blocksize, 0) != (block+1)*Blocksize) {
  286. print("Xbseek %d fail\n", (block+1)*Blocksize);
  287. goto Die;
  288. }
  289. for(j=0; j<Blocksize/4; j++) {
  290. if(Bread(b, buf, 4) != 4) {
  291. print("Bread fail seek block %x, %d i %d ndepot %d\n", block, (block+1)*Blocksize, i, ndepot);
  292. goto Die;
  293. }
  294. f->blockmap[u++] = LONG(buf);
  295. }
  296. }
  297. if(Bseek(b, 0x200+extrablock*Blocksize+Blocksize-4, 0) != 0x200+extrablock*Blocksize+Blocksize-4
  298. || Bread(b, buf, 4) != 4) {
  299. print("bseek %d fail\n", 0x4C+4*i);
  300. goto Die;
  301. }
  302. extrablock = LONG(buf);
  303. }
  304. Break2:;
  305. if(oreaddir(f, 0, &rootdir) <= 0){
  306. print("oreaddir could not read root\n");
  307. goto Die;
  308. }
  309. f->smapblock = rootdir.start;
  310. return f;
  311. Die:
  312. Bterm(b);
  313. free(f->blockmap);
  314. free(f);
  315. return nil;
  316. }
  317. void
  318. oleread(Req *r)
  319. {
  320. Odir *d;
  321. char *p;
  322. int e, n;
  323. int32_t c;
  324. int64_t o;
  325. o = r->ifcall.offset;
  326. d = r->fid->file->aux;
  327. if(d == nil) {
  328. respond(r, "cannot happen");
  329. return;
  330. }
  331. c = r->ifcall.count;
  332. if(o >= d->size) {
  333. r->ofcall.count = 0;
  334. respond(r, nil);
  335. return;
  336. }
  337. if(o+c > d->size)
  338. c = d->size-o;
  339. /*
  340. * oreadfile returns so little data, it will
  341. * help to read as much as we can.
  342. */
  343. e = c+o;
  344. n = 0;
  345. for(p=r->ofcall.data; o<e; o+=n, p+=n) {
  346. n = oreadfile(d, o, p, e-o);
  347. if(n <= 0)
  348. break;
  349. }
  350. if(n == -1 && o == r->ifcall.offset)
  351. respond(r, "error reading word file");
  352. else {
  353. r->ofcall.count = o - r->ifcall.offset;
  354. respond(r, nil);
  355. }
  356. }
  357. Odir*
  358. copydir(Odir *d)
  359. {
  360. Odir *e;
  361. e = emalloc(sizeof(*d));
  362. *e = *d;
  363. return e;
  364. }
  365. void
  366. filldir(File *t, Ofile *f, int dnum, int nrecur)
  367. {
  368. Odir d;
  369. int i;
  370. Rune rbuf[40];
  371. char buf[UTFmax*nelem(rbuf)];
  372. File *nt;
  373. if(dnum == 0xFFFFFFFF || oreaddir(f, dnum, &d) != 1)
  374. return;
  375. /*
  376. * i hope there are no broken files with
  377. * circular trees. i hate infinite loops.
  378. */
  379. if(nrecur > 100)
  380. sysfatal("tree too large in office file: probably circular");
  381. filldir(t, f, d.left, nrecur+1);
  382. /* add current tree entry */
  383. runestrecpy(rbuf, rbuf+sizeof rbuf, d.name);
  384. for(i=0; rbuf[i]; i++)
  385. if(rbuf[i] == L' ')
  386. rbuf[i] = L'␣';
  387. else if(rbuf[i] <= 0x20 || rbuf[i] == L'/'
  388. || (0x80 <= rbuf[i] && rbuf[i] <= 0x9F))
  389. rbuf[i] = ':';
  390. snprint(buf, sizeof buf, "%S", rbuf);
  391. if(d.dir == 0xFFFFFFFF) {
  392. /* make file */
  393. nt = createfile(t, buf, nil, 0444, nil);
  394. if(nt == nil)
  395. sysfatal("nt nil: create %s: %r", buf);
  396. nt->aux = copydir(&d);
  397. nt->Dir.length = d.size;
  398. } else /* make directory */
  399. nt = createfile(t, buf, nil, DMDIR|0777, nil);
  400. filldir(t, f, d.right, nrecur+1);
  401. if(d.dir != 0xFFFFFFFF)
  402. filldir(nt, f, d.dir, nrecur+1);
  403. closefile(nt);
  404. }
  405. Srv olesrv = {
  406. .read= oleread,
  407. };
  408. void
  409. main(int argc, char **argv)
  410. {
  411. char *mtpt;
  412. Ofile *f;
  413. Odir d;
  414. mtpt = "/mnt/doc";
  415. ARGBEGIN{
  416. case 'm':
  417. mtpt = ARGF();
  418. break;
  419. default:
  420. goto Usage;
  421. }ARGEND
  422. if(argc != 1) {
  423. Usage:
  424. fprint(2, "usage: olefs file\n");
  425. exits("usage");
  426. }
  427. f = oleopen(argv[0]);
  428. if(f == nil) {
  429. print("error opening %s: %r\n", argv[0]);
  430. exits("open");
  431. }
  432. // dumpdir(f, 0);
  433. if(oreaddir(f, 0, &d) != 1) {
  434. fprint(2, "oreaddir error: %r\n");
  435. exits("oreaddir");
  436. }
  437. olesrv.tree = alloctree(nil, nil, DMDIR|0777, nil);
  438. filldir(olesrv.tree->root, f, d.dir, 0);
  439. postmountsrv(&olesrv, nil, mtpt, MREPL);
  440. exits(0);
  441. }