cdrdwr.c 11 KB

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