cdrdwr.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  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 <libsec.h>
  13. #include "iso9660.h"
  14. static int readisodesc(Cdimg*, Voldesc*);
  15. static int readjolietdesc(Cdimg*, Voldesc*);
  16. /*
  17. * It's not strictly conforming; instead it's enough to
  18. * get us up and running; presumably the real CD writing
  19. * will take care of being conforming.
  20. *
  21. * Things not conforming include:
  22. * - no path table
  23. * - root directories are of length zero
  24. */
  25. Cdimg*
  26. createcd(char *file, Cdinfo info)
  27. {
  28. int fd, xfd;
  29. Cdimg *cd;
  30. if(access(file, AEXIST) == 0){
  31. werrstr("file already exists");
  32. return nil;
  33. }
  34. if((fd = create(file, ORDWR, 0666)) < 0)
  35. return nil;
  36. cd = emalloc(sizeof *cd);
  37. cd->file = atom(file);
  38. Binit(&cd->brd, fd, OREAD);
  39. if((xfd = open(file, ORDWR)) < 0)
  40. sysfatal("can't open file again: %r");
  41. Binit(&cd->bwr, xfd, OWRITE);
  42. Crepeat(cd, 0, 16*Blocksize);
  43. Cputisopvd(cd, info);
  44. if(info.flags & CDbootable){
  45. cd->bootimage = info.bootimage;
  46. cd->loader = info.loader;
  47. cd->flags |= info.flags & (CDbootable|CDbootnoemu);
  48. Cputbootvol(cd);
  49. }
  50. if(readisodesc(cd, &cd->iso) < 0)
  51. assert(0);
  52. if(info.flags & CDplan9)
  53. cd->flags |= CDplan9;
  54. else if(info.flags & CDrockridge)
  55. cd->flags |= CDrockridge;
  56. if(info.flags & CDjoliet) {
  57. Cputjolietsvd(cd, info);
  58. if(readjolietdesc(cd, &cd->joliet) < 0)
  59. assert(0);
  60. cd->flags |= CDjoliet;
  61. }
  62. Cputendvd(cd);
  63. if(info.flags & CDdump){
  64. cd->nulldump = Cputdumpblock(cd);
  65. cd->flags |= CDdump;
  66. }
  67. if(cd->flags & CDbootable){
  68. Cputbootcat(cd);
  69. Cupdatebootvol(cd);
  70. }
  71. if(info.flags & CDconform)
  72. cd->flags |= CDconform;
  73. cd->flags |= CDnew;
  74. cd->nextblock = Cwoffset(cd) / Blocksize;
  75. assert(cd->nextblock != 0);
  76. return cd;
  77. }
  78. Cdimg*
  79. opencd(char *file, Cdinfo info)
  80. {
  81. int fd, xfd;
  82. Cdimg *cd;
  83. Dir *d;
  84. if((fd = open(file, ORDWR)) < 0) {
  85. if(access(file, AEXIST) == 0)
  86. return nil;
  87. return createcd(file, info);
  88. }
  89. if((d = dirfstat(fd)) == nil) {
  90. close(fd);
  91. return nil;
  92. }
  93. if(d->length == 0 || d->length % Blocksize) {
  94. werrstr("bad length %lld", d->length);
  95. close(fd);
  96. free(d);
  97. return nil;
  98. }
  99. cd = emalloc(sizeof *cd);
  100. cd->file = atom(file);
  101. cd->nextblock = d->length / Blocksize;
  102. assert(cd->nextblock != 0);
  103. free(d);
  104. Binit(&cd->brd, fd, OREAD);
  105. if((xfd = open(file, ORDWR)) < 0)
  106. sysfatal("can't open file again: %r");
  107. Binit(&cd->bwr, xfd, OWRITE);
  108. if(readisodesc(cd, &cd->iso) < 0) {
  109. free(cd);
  110. close(fd);
  111. close(xfd);
  112. return nil;
  113. }
  114. /* lowercase because of isostring */
  115. if(strstr(cd->iso.systemid, "iso9660") == nil
  116. && strstr(cd->iso.systemid, "utf8") == nil) {
  117. werrstr("unknown systemid %s", cd->iso.systemid);
  118. free(cd);
  119. close(fd);
  120. close(xfd);
  121. return nil;
  122. }
  123. if(strstr(cd->iso.systemid, "plan 9"))
  124. cd->flags |= CDplan9;
  125. if(strstr(cd->iso.systemid, "iso9660"))
  126. cd->flags |= CDconform;
  127. if(strstr(cd->iso.systemid, "rrip"))
  128. cd->flags |= CDrockridge;
  129. if(strstr(cd->iso.systemid, "boot"))
  130. cd->flags |= CDbootable;
  131. if(readjolietdesc(cd, &cd->joliet) == 0)
  132. cd->flags |= CDjoliet;
  133. if(hasdump(cd))
  134. cd->flags |= CDdump;
  135. return cd;
  136. }
  137. uint32_t
  138. big(void *a, int n)
  139. {
  140. uint8_t *p;
  141. uint32_t v;
  142. int i;
  143. p = a;
  144. v = 0;
  145. for(i=0; i<n; i++)
  146. v = (v<<8) | *p++;
  147. return v;
  148. }
  149. uint32_t
  150. little(void *a, int n)
  151. {
  152. uint8_t *p;
  153. uint32_t v;
  154. int i;
  155. p = a;
  156. v = 0;
  157. for(i=0; i<n; i++)
  158. v |= (*p++<<(i*8));
  159. return v;
  160. }
  161. void
  162. Creadblock(Cdimg *cd, void *buf, uint32_t block, uint32_t len)
  163. {
  164. assert(block != 0); /* nothing useful there */
  165. Bflush(&cd->bwr);
  166. if(Bseek(&cd->brd, (int64_t)block * Blocksize, 0) !=
  167. (int64_t)block * Blocksize)
  168. sysfatal("error seeking to block %lu", block);
  169. if(Bread(&cd->brd, buf, len) != len)
  170. sysfatal("error reading %lu bytes at block %lu: %r %lld",
  171. len, block, Bseek(&cd->brd, 0, 2));
  172. }
  173. int
  174. parsedir(Cdimg *cd, Direc *d, uint8_t *buf, int len,
  175. char *(*cvtname)(uint8_t*, int))
  176. {
  177. enum { NAMELEN = 28 };
  178. char name[NAMELEN];
  179. uint8_t *p;
  180. Cdir *c;
  181. memset(d, 0, sizeof *d);
  182. c = (Cdir*)buf;
  183. if(c->len > len) {
  184. werrstr("buffer too small");
  185. return -1;
  186. }
  187. if(c->namelen == 1 && c->name[0] == '\0')
  188. d->name = atom(".");
  189. else if(c->namelen == 1 && c->name[0] == '\001')
  190. d->name = atom("..");
  191. else if(cvtname)
  192. d->name = cvtname(c->name, c->namelen);
  193. d->block = little(c->dloc, 4);
  194. d->length = little(c->dlen, 4);
  195. if(c->flags & 2)
  196. d->mode |= DMDIR;
  197. /*BUG: do we really need to parse the plan 9 fields? */
  198. /* plan 9 use fields */
  199. if((cd->flags & CDplan9) && cvtname == isostring
  200. && (c->namelen != 1 || c->name[0] > 1)) {
  201. p = buf+33+c->namelen;
  202. if((p-buf)&1)
  203. p++;
  204. assert(p < buf+c->len);
  205. assert(*p < NAMELEN);
  206. if(*p != 0) {
  207. memmove(name, p+1, *p);
  208. name[*p] = '\0';
  209. d->confname = d->name;
  210. d->name = atom(name);
  211. }
  212. p += *p+1;
  213. assert(*p < NAMELEN);
  214. memmove(name, p+1, *p);
  215. name[*p] = '\0';
  216. d->uid = atom(name);
  217. p += *p+1;
  218. assert(*p < NAMELEN);
  219. memmove(name, p+1, *p);
  220. name[*p] = '\0';
  221. d->gid = atom(name);
  222. p += *p+1;
  223. if((p-buf)&1)
  224. p++;
  225. d->mode = little(p, 4);
  226. }
  227. // BUG: rock ridge extensions
  228. return 0;
  229. }
  230. void
  231. setroot(Cdimg *cd, uint32_t block, uint32_t dloc, uint32_t dlen)
  232. {
  233. assert(block != 0);
  234. Cwseek(cd, (int64_t)block * Blocksize + offsetof(Cvoldesc, rootdir[0]) +
  235. offsetof(Cdir, dloc[0]));
  236. Cputn(cd, dloc, 4);
  237. Cputn(cd, dlen, 4);
  238. }
  239. void
  240. setvolsize(Cdimg *cd, uint64_t block, uint32_t size)
  241. {
  242. assert(block != 0);
  243. Cwseek(cd, block * Blocksize + offsetof(Cvoldesc, volsize[0]));
  244. Cputn(cd, size, 4); /* size in blocks */
  245. }
  246. void
  247. setpathtable(Cdimg *cd, uint32_t block, uint32_t sz, uint32_t lloc,
  248. uint32_t bloc)
  249. {
  250. assert(block != 0);
  251. Cwseek(cd,
  252. (int64_t)block * Blocksize + offsetof(Cvoldesc, pathsize[0]));
  253. Cputn(cd, sz, 4);
  254. Cputnl(cd, lloc, 4);
  255. Cputnl(cd, 0, 4);
  256. Cputnm(cd, bloc, 4);
  257. Cputnm(cd, 0, 4);
  258. assert(Cwoffset(cd) == (int64_t)block * Blocksize +
  259. offsetof(Cvoldesc, rootdir[0]));
  260. }
  261. static void
  262. parsedesc(Voldesc *v, Cvoldesc *cv, char *(*string)(uint8_t*, int))
  263. {
  264. v->systemid = string(cv->systemid, sizeof cv->systemid);
  265. v->pathsize = little(cv->pathsize, 4);
  266. v->lpathloc = little(cv->lpathloc, 4);
  267. v->mpathloc = little(cv->mpathloc, 4);
  268. v->volumeset = string(cv->volumeset, sizeof cv->volumeset);
  269. v->publisher = string(cv->publisher, sizeof cv->publisher);
  270. v->preparer = string(cv->preparer, sizeof cv->preparer);
  271. v->application = string(cv->application, sizeof cv->application);
  272. v->abstract = string(cv->abstract, sizeof cv->abstract);
  273. v->biblio = string(cv->biblio, sizeof cv->biblio);
  274. v->notice = string(cv->notice, sizeof cv->notice);
  275. }
  276. static int
  277. readisodesc(Cdimg *cd, Voldesc *v)
  278. {
  279. static uint8_t magic[] = { 0x01, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
  280. Cvoldesc cv;
  281. memset(v, 0, sizeof *v);
  282. Creadblock(cd, &cv, 16, sizeof cv);
  283. if(memcmp(cv.magic, magic, sizeof magic) != 0) {
  284. werrstr("bad pvd magic");
  285. return -1;
  286. }
  287. if(little(cv.blocksize, 2) != Blocksize) {
  288. werrstr("block size not %d", Blocksize);
  289. return -1;
  290. }
  291. cd->iso9660pvd = 16;
  292. parsedesc(v, &cv, isostring);
  293. return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, isostring);
  294. }
  295. static int
  296. readjolietdesc(Cdimg *cd, Voldesc *v)
  297. {
  298. int i;
  299. static uint8_t magic[] = { 0x02, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
  300. Cvoldesc cv;
  301. memset(v, 0, sizeof *v);
  302. for(i=16; i<24; i++) {
  303. Creadblock(cd, &cv, i, sizeof cv);
  304. if(memcmp(cv.magic, magic, sizeof magic) != 0)
  305. continue;
  306. if(cv.charset[0] != 0x25 || cv.charset[1] != 0x2F
  307. || (cv.charset[2] != 0x40 && cv.charset[2] != 0x43 && cv.charset[2] != 0x45))
  308. continue;
  309. break;
  310. }
  311. if(i==24) {
  312. werrstr("could not find Joliet SVD");
  313. return -1;
  314. }
  315. if(little(cv.blocksize, 2) != Blocksize) {
  316. werrstr("block size not %d", Blocksize);
  317. return -1;
  318. }
  319. cd->jolietsvd = i;
  320. parsedesc(v, &cv, jolietstring);
  321. return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, jolietstring);
  322. }
  323. /*
  324. * CD image buffering routines.
  325. */
  326. void
  327. Cputc(Cdimg *cd, int c)
  328. {
  329. assert(Boffset(&cd->bwr) >= 16*Blocksize || c == 0);
  330. if(Boffset(&cd->bwr) == 0x9962)
  331. if(c >= 256) abort();
  332. if(Bputc(&cd->bwr, c) < 0)
  333. sysfatal("Bputc: %r");
  334. Bflush(&cd->brd);
  335. }
  336. void
  337. Cputnl(Cdimg *cd, uint64_t val, int size)
  338. {
  339. switch(size) {
  340. default:
  341. sysfatal("bad size %d in Cputnl", size);
  342. case 2:
  343. if(val >= (1<<16))
  344. sysfatal("value %llu too big for size %d in Cputnl",
  345. val, size);
  346. Cputc(cd, val);
  347. Cputc(cd, val>>8);
  348. break;
  349. case 4:
  350. if(val >= (1ULL<<32))
  351. sysfatal("value %llu too big for size %d in Cputnl",
  352. val, size);
  353. Cputc(cd, val);
  354. Cputc(cd, val>>8);
  355. Cputc(cd, val>>16);
  356. Cputc(cd, val>>24);
  357. break;
  358. case 8:
  359. Cputc(cd, val);
  360. Cputc(cd, val>>8);
  361. Cputc(cd, val>>16);
  362. Cputc(cd, val>>24);
  363. Cputc(cd, val>>32);
  364. Cputc(cd, val>>40);
  365. Cputc(cd, val>>48);
  366. Cputc(cd, val>>56);
  367. break;
  368. }
  369. }
  370. void
  371. Cputnm(Cdimg *cd, uint64_t val, int size)
  372. {
  373. switch(size) {
  374. default:
  375. sysfatal("bad size %d in Cputnm", size);
  376. case 2:
  377. if(val >= (1<<16))
  378. sysfatal("value %llu too big for size %d in Cputnl",
  379. val, size);
  380. Cputc(cd, val>>8);
  381. Cputc(cd, val);
  382. break;
  383. case 4:
  384. if(val >= (1ULL<<32))
  385. sysfatal("value %llu too big for size %d in Cputnl",
  386. val, size);
  387. Cputc(cd, val>>24);
  388. Cputc(cd, val>>16);
  389. Cputc(cd, val>>8);
  390. Cputc(cd, val);
  391. break;
  392. case 8:
  393. Cputc(cd, val>>56);
  394. Cputc(cd, val>>48);
  395. Cputc(cd, val>>40);
  396. Cputc(cd, val>>32);
  397. Cputc(cd, val>>24);
  398. Cputc(cd, val>>16);
  399. Cputc(cd, val>>8);
  400. Cputc(cd, val);
  401. break;
  402. }
  403. }
  404. void
  405. Cputn(Cdimg *cd, uint64_t val, int size)
  406. {
  407. Cputnl(cd, val, size);
  408. Cputnm(cd, val, size);
  409. }
  410. /*
  411. * ASCII/UTF string writing
  412. */
  413. void
  414. Crepeat(Cdimg *cd, int c, int n)
  415. {
  416. while(n-- > 0)
  417. Cputc(cd, c);
  418. }
  419. void
  420. Cputs(Cdimg *cd, char *s, int size)
  421. {
  422. int n;
  423. if(s == nil) {
  424. Crepeat(cd, ' ', size);
  425. return;
  426. }
  427. for(n=0; n<size && *s; n++)
  428. Cputc(cd, *s++);
  429. if(n<size)
  430. Crepeat(cd, ' ', size-n);
  431. }
  432. void
  433. Cwrite(Cdimg *cd, void *buf, int n)
  434. {
  435. assert(Boffset(&cd->bwr) >= 16*Blocksize);
  436. if(Bwrite(&cd->bwr, buf, n) != n)
  437. sysfatal("Bwrite: %r");
  438. Bflush(&cd->brd);
  439. }
  440. void
  441. Cputr(Cdimg *cd, Rune r)
  442. {
  443. Cputc(cd, r>>8);
  444. Cputc(cd, r);
  445. }
  446. void
  447. Crepeatr(Cdimg *cd, Rune r, int n)
  448. {
  449. int i;
  450. for(i=0; i<n; i++)
  451. Cputr(cd, r);
  452. }
  453. void
  454. Cputrs(Cdimg *cd, Rune *s, int osize)
  455. {
  456. int n, size;
  457. size = osize/2;
  458. if(s == nil)
  459. Crepeatr(cd, (Rune)' ', size);
  460. else {
  461. for(n=0; *s && n<size; n++)
  462. Cputr(cd, *s++);
  463. if(n<size)
  464. Crepeatr(cd, ' ', size-n);
  465. }
  466. if(osize&1)
  467. Cputc(cd, 0); /* what else can we do? */
  468. }
  469. void
  470. Cputrscvt(Cdimg *cd, char *s, int size)
  471. {
  472. Rune r[256];
  473. strtorune(r, s);
  474. Cputrs(cd, strtorune(r, s), size);
  475. }
  476. void
  477. Cpadblock(Cdimg *cd)
  478. {
  479. int n;
  480. uint32_t nb;
  481. n = Blocksize - (Boffset(&cd->bwr) % Blocksize);
  482. if(n != Blocksize)
  483. Crepeat(cd, 0, n);
  484. nb = Boffset(&cd->bwr)/Blocksize;
  485. assert(nb != 0);
  486. if(nb > cd->nextblock)
  487. cd->nextblock = nb;
  488. }
  489. void
  490. Cputdate(Cdimg *cd, uint32_t ust)
  491. {
  492. Tm *tm;
  493. if(ust == 0) {
  494. Crepeat(cd, 0, 7);
  495. return;
  496. }
  497. tm = gmtime(ust);
  498. Cputc(cd, tm->year);
  499. Cputc(cd, tm->mon+1);
  500. Cputc(cd, tm->mday);
  501. Cputc(cd, tm->hour);
  502. Cputc(cd, tm->min);
  503. Cputc(cd, tm->sec);
  504. Cputc(cd, 0);
  505. }
  506. void
  507. Cputdate1(Cdimg *cd, uint32_t ust)
  508. {
  509. Tm *tm;
  510. char str[20];
  511. if(ust == 0) {
  512. Crepeat(cd, '0', 16);
  513. Cputc(cd, 0);
  514. return;
  515. }
  516. tm = gmtime(ust);
  517. sprint(str, "%.4d%.2d%.2d%.2d%.2d%.4d",
  518. tm->year+1900,
  519. tm->mon+1,
  520. tm->mday,
  521. tm->hour,
  522. tm->min,
  523. tm->sec*100);
  524. Cputs(cd, str, 16);
  525. Cputc(cd, 0);
  526. }
  527. void
  528. Cwseek(Cdimg *cd, int64_t offset)
  529. {
  530. Bseek(&cd->bwr, offset, 0);
  531. }
  532. uint64_t
  533. Cwoffset(Cdimg *cd)
  534. {
  535. return Boffset(&cd->bwr);
  536. }
  537. void
  538. Cwflush(Cdimg *cd)
  539. {
  540. Bflush(&cd->bwr);
  541. }
  542. uint64_t
  543. Croffset(Cdimg *cd)
  544. {
  545. return Boffset(&cd->brd);
  546. }
  547. void
  548. Crseek(Cdimg *cd, int64_t offset)
  549. {
  550. Bseek(&cd->brd, offset, 0);
  551. }
  552. int
  553. Cgetc(Cdimg *cd)
  554. {
  555. int c;
  556. Cwflush(cd);
  557. if((c = Bgetc(&cd->brd)) == Beof) {
  558. fprint(2, "getc at %llu\n", Croffset(cd));
  559. assert(0);
  560. //sysfatal("Bgetc: %r");
  561. }
  562. return c;
  563. }
  564. void
  565. Cread(Cdimg *cd, void *buf, int n)
  566. {
  567. Cwflush(cd);
  568. if(Bread(&cd->brd, buf, n) != n)
  569. sysfatal("Bread: %r");
  570. }
  571. char*
  572. Crdline(Cdimg *cd, int c)
  573. {
  574. Cwflush(cd);
  575. return Brdline(&cd->brd, c);
  576. }
  577. int
  578. Clinelen(Cdimg *cd)
  579. {
  580. return Blinelen(&cd->brd);
  581. }