cdrdwr.c 12 KB

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