flfmt9660.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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. /*
  10. * Initialize a fossil file system from an ISO9660 image already in the
  11. * file system. This is a fairly bizarre thing to do, but it lets us generate
  12. * installation CDs that double as valid Plan 9 disk partitions.
  13. * People having trouble booting the CD can just copy it into a disk
  14. * partition and you've got a working Plan 9 system.
  15. *
  16. * I've tried hard to keep all the associated cruft in this file.
  17. * If you deleted this file and cut out the three calls into it from flfmt.c,
  18. * no traces would remain.
  19. */
  20. #include "stdinc.h"
  21. #include "dat.h"
  22. #include "fns.h"
  23. #include "flfmt9660.h"
  24. #include <bio.h>
  25. #include <ctype.h>
  26. static Biobuf *b;
  27. enum{
  28. Tag = 0x96609660,
  29. Blocksize = 2048,
  30. };
  31. typedef struct Voldesc Voldesc;
  32. struct Voldesc {
  33. uint8_t magic[8]; /* 0x01, "CD001", 0x01, 0x00 */
  34. uint8_t systemid[32]; /* system identifier */
  35. uint8_t volumeid[32]; /* volume identifier */
  36. uint8_t unused[8]; /* character set in secondary desc */
  37. uint8_t volsize[8]; /* volume size */
  38. uint8_t charset[32];
  39. uint8_t volsetsize[4]; /* volume set size = 1 */
  40. uint8_t volseqnum[4]; /* volume sequence number = 1 */
  41. uint8_t blocksize[4]; /* logical block size */
  42. uint8_t pathsize[8]; /* path table size */
  43. uint8_t lpathloc[4]; /* Lpath */
  44. uint8_t olpathloc[4]; /* optional Lpath */
  45. uint8_t mpathloc[4]; /* Mpath */
  46. uint8_t ompathloc[4]; /* optional Mpath */
  47. uint8_t rootdir[34]; /* root directory */
  48. uint8_t volsetid[128]; /* volume set identifier */
  49. uint8_t publisher[128];
  50. uint8_t prepid[128]; /* data preparer identifier */
  51. uint8_t applid[128]; /* application identifier */
  52. uint8_t notice[37]; /* copyright notice file */
  53. uint8_t abstract[37]; /* abstract file */
  54. uint8_t biblio[37]; /* bibliographic file */
  55. uint8_t cdate[17]; /* creation date */
  56. uint8_t mdate[17]; /* modification date */
  57. uint8_t xdate[17]; /* expiration date */
  58. uint8_t edate[17]; /* effective date */
  59. uint8_t fsvers; /* file system version = 1 */
  60. };
  61. /* Not used?
  62. static void
  63. dumpbootvol(void *a)
  64. {
  65. Voldesc *v;
  66. v = a;
  67. print("magic %.2x %.5s %.2x %2ux\n",
  68. v->magic[0], v->magic+1, v->magic[6], v->magic[7]);
  69. if(v->magic[0] == 0xFF)
  70. return;
  71. print("system %.32T\n", v->systemid);
  72. print("volume %.32T\n", v->volumeid);
  73. print("volume size %.4N\n", v->volsize);
  74. print("charset %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
  75. v->charset[0], v->charset[1], v->charset[2], v->charset[3],
  76. v->charset[4], v->charset[5], v->charset[6], v->charset[7]);
  77. print("volume set size %.2N\n", v->volsetsize);
  78. print("volume sequence number %.2N\n", v->volseqnum);
  79. print("logical block size %.2N\n", v->blocksize);
  80. print("path size %.4L\n", v->pathsize);
  81. print("lpath loc %.4L\n", v->lpathloc);
  82. print("opt lpath loc %.4L\n", v->olpathloc);
  83. print("mpath loc %.4B\n", v->mpathloc);
  84. print("opt mpath loc %.4B\n", v->ompathloc);
  85. print("rootdir %D\n", v->rootdir);
  86. print("volume set identifier %.128T\n", v->volsetid);
  87. print("publisher %.128T\n", v->publisher);
  88. print("preparer %.128T\n", v->prepid);
  89. print("application %.128T\n", v->applid);
  90. print("notice %.37T\n", v->notice);
  91. print("abstract %.37T\n", v->abstract);
  92. print("biblio %.37T\n", v->biblio);
  93. print("creation date %.17s\n", v->cdate);
  94. print("modification date %.17s\n", v->mdate);
  95. print("expiration date %.17s\n", v->xdate);
  96. print("effective date %.17s\n", v->edate);
  97. print("fs version %d\n", v->fsvers);
  98. }
  99. */
  100. typedef struct Cdir Cdir;
  101. struct Cdir {
  102. uint8_t len;
  103. uint8_t xlen;
  104. uint8_t dloc[8];
  105. uint8_t dlen[8];
  106. uint8_t date[7];
  107. uint8_t flags;
  108. uint8_t unitsize;
  109. uint8_t gapsize;
  110. uint8_t volseqnum[4];
  111. uint8_t namelen;
  112. uint8_t name[1]; /* chumminess */
  113. };
  114. static int
  115. Dfmt(Fmt *fmt)
  116. {
  117. char buf[128];
  118. Cdir *c;
  119. c = va_arg(fmt->args, Cdir*);
  120. if(c->namelen == 1 && c->name[0] == '\0' || c->name[0] == '\001') {
  121. snprint(buf, sizeof buf, ".%s dloc %.4N dlen %.4N",
  122. c->name[0] ? "." : "", c->dloc, c->dlen);
  123. } else {
  124. snprint(buf, sizeof buf, "%.*T dloc %.4N dlen %.4N", c->namelen, c->name,
  125. c->dloc, c->dlen);
  126. }
  127. fmtstrcpy(fmt, buf);
  128. return 0;
  129. }
  130. char longc, shortc;
  131. /* Not used?
  132. static void
  133. bigend(void)
  134. {
  135. longc = 'B';
  136. }
  137. static void
  138. littleend(void)
  139. {
  140. longc = 'L';
  141. }
  142. */
  143. static uint32_t
  144. big(void *a, int n)
  145. {
  146. uint8_t *p;
  147. uint32_t v;
  148. int i;
  149. p = a;
  150. v = 0;
  151. for(i=0; i<n; i++)
  152. v = (v<<8) | *p++;
  153. return v;
  154. }
  155. static uint32_t
  156. little(void *a, int n)
  157. {
  158. uint8_t *p;
  159. uint32_t v;
  160. int i;
  161. p = a;
  162. v = 0;
  163. for(i=0; i<n; i++)
  164. v |= (*p++<<(i*8));
  165. return v;
  166. }
  167. /* numbers in big or little endian. */
  168. static int
  169. BLfmt(Fmt *fmt)
  170. {
  171. uint32_t v;
  172. uint8_t *p;
  173. char buf[20];
  174. p = va_arg(fmt->args, uint8_t*);
  175. if(!(fmt->flags&FmtPrec)) {
  176. fmtstrcpy(fmt, "*BL*");
  177. return 0;
  178. }
  179. if(fmt->r == 'B')
  180. v = big(p, fmt->prec);
  181. else
  182. v = little(p, fmt->prec);
  183. sprint(buf, "0x%.*lux", fmt->prec*2, v);
  184. fmt->flags &= ~FmtPrec;
  185. fmtstrcpy(fmt, buf);
  186. return 0;
  187. }
  188. /* numbers in both little and big endian */
  189. static int
  190. Nfmt(Fmt *fmt)
  191. {
  192. char buf[100];
  193. uint8_t *p;
  194. p = va_arg(fmt->args, uint8_t*);
  195. sprint(buf, "%.*L %.*B", fmt->prec, p, fmt->prec, p+fmt->prec);
  196. fmt->flags &= ~FmtPrec;
  197. fmtstrcpy(fmt, buf);
  198. return 0;
  199. }
  200. static int
  201. asciiTfmt(Fmt *fmt)
  202. {
  203. char *p, buf[256];
  204. int i;
  205. p = va_arg(fmt->args, char*);
  206. for(i=0; i<fmt->prec; i++)
  207. buf[i] = *p++;
  208. buf[i] = '\0';
  209. for(p=buf+strlen(buf); p>buf && p[-1]==' '; p--)
  210. ;
  211. p[0] = '\0';
  212. fmt->flags &= ~FmtPrec;
  213. fmtstrcpy(fmt, buf);
  214. return 0;
  215. }
  216. static void
  217. ascii(void)
  218. {
  219. fmtinstall('T', asciiTfmt);
  220. }
  221. /*Not used?
  222. static int
  223. runeTfmt(Fmt *fmt)
  224. {
  225. Rune buf[256], *r;
  226. int i;
  227. uint8_t *p;
  228. p = va_arg(fmt->args, uint8_t*);
  229. for(i=0; i*2+2<=fmt->prec; i++, p+=2)
  230. buf[i] = (p[0]<<8)|p[1];
  231. buf[i] = L'\0';
  232. for(r=buf+i; r>buf && r[-1]==L' '; r--)
  233. ;
  234. r[0] = L'\0';
  235. fmt->flags &= ~FmtPrec;
  236. return fmtprint(fmt, "%S", buf);
  237. }
  238. */
  239. static void
  240. getsect(uint8_t *buf, int n)
  241. {
  242. if(Bseek(b, n*2048, 0) != n*2048 || Bread(b, buf, 2048) != 2048)
  243. {
  244. abort();
  245. sysfatal("reading block at %,d: %r", n*2048);
  246. }
  247. }
  248. static Header *h;
  249. static int fd;
  250. static char *file9660;
  251. static int off9660;
  252. static uint32_t startoff;
  253. static uint32_t endoff;
  254. static uint32_t fsoff;
  255. static uint8_t root[2048];
  256. static Voldesc *v;
  257. static uint32_t iso9660start(Cdir*);
  258. static void iso9660copydir(Fs*, File*, Cdir*);
  259. static void iso9660copyfile(Fs*, File*, Cdir*);
  260. void
  261. iso9660init(int xfd, Header *xh, char *xfile9660, int xoff9660)
  262. {
  263. uint8_t sect[2048], sect2[2048];
  264. fmtinstall('L', BLfmt);
  265. fmtinstall('B', BLfmt);
  266. fmtinstall('N', Nfmt);
  267. fmtinstall('D', Dfmt);
  268. fd = xfd;
  269. h = xh;
  270. file9660 = xfile9660;
  271. off9660 = xoff9660;
  272. if((b = Bopen(file9660, OREAD)) == nil)
  273. vtFatal("Bopen %s: %r", file9660);
  274. getsect(root, 16);
  275. ascii();
  276. v = (Voldesc*)root;
  277. if(memcmp(v->magic, "\001CD001\001\000", 8) != 0)
  278. vtFatal("%s not a cd image", file9660);
  279. startoff = iso9660start((Cdir*)v->rootdir)*Blocksize;
  280. endoff = little(v->volsize, 4); /* already in bytes */
  281. fsoff = off9660 + h->data*h->blockSize;
  282. if(fsoff > startoff)
  283. vtFatal("fossil data starts after cd data");
  284. if(off9660 + (int64_t)h->end*h->blockSize < endoff)
  285. vtFatal("fossil data ends before cd data");
  286. if(fsoff%h->blockSize)
  287. vtFatal("cd offset not a multiple of fossil block size");
  288. /* Read "same" block via CD image and via Fossil image */
  289. getsect(sect, startoff/Blocksize);
  290. if(seek(fd, startoff-off9660, 0) < 0)
  291. vtFatal("cannot seek to first data sector on cd via fossil");
  292. fprint(2, "look for %lu at %lu\n", startoff, startoff-off9660);
  293. if(readn(fd, sect2, Blocksize) != Blocksize)
  294. vtFatal("cannot read first data sector on cd via fossil");
  295. if(memcmp(sect, sect2, Blocksize) != 0)
  296. vtFatal("iso9660 offset is a lie %08ux %08ux",
  297. *(int32_t*)sect, *(int32_t*)sect2);
  298. }
  299. void
  300. iso9660labels(Disk *disk, uint8_t *buf, void (*write)(int, uint32_t))
  301. {
  302. uint32_t sb, eb, bn, lb, llb;
  303. Label l;
  304. int lpb;
  305. uint8_t sect[Blocksize];
  306. if(!diskReadRaw(disk, PartData, (startoff-fsoff)/h->blockSize, buf))
  307. vtFatal("disk read failed: %r");
  308. getsect(sect, startoff/Blocksize);
  309. if(memcmp(buf, sect, Blocksize) != 0)
  310. vtFatal("fsoff is wrong");
  311. sb = (startoff-fsoff)/h->blockSize;
  312. eb = (endoff-fsoff+h->blockSize-1)/h->blockSize;
  313. lpb = h->blockSize/LabelSize;
  314. /* for each reserved block, mark label */
  315. llb = ~0;
  316. l.type = BtData;
  317. l.state = BsAlloc;
  318. l.tag = Tag;
  319. l.epoch = 1;
  320. l.epochClose = ~(uint32_t)0;
  321. for(bn=sb; bn<eb; bn++){
  322. lb = bn/lpb;
  323. if(lb != llb){
  324. if(llb != ~0)
  325. (*write)(PartLabel, llb);
  326. memset(buf, 0, h->blockSize);
  327. }
  328. llb = lb;
  329. labelPack(&l, buf, bn%lpb);
  330. }
  331. if(llb != ~0)
  332. (*write)(PartLabel, llb);
  333. }
  334. void
  335. iso9660copy(Fs *fs)
  336. {
  337. File *root;
  338. root = fileOpen(fs, "/active");
  339. iso9660copydir(fs, root, (Cdir*)v->rootdir);
  340. fileDecRef(root);
  341. vtRUnlock(fs->elk);
  342. if(!fsSnapshot(fs, nil, nil, 0))
  343. vtFatal("snapshot failed: %R");
  344. vtRLock(fs->elk);
  345. }
  346. /*
  347. * The first block used is the first data block of the leftmost file in the tree.
  348. * (Just an artifact of how mk9660 works.)
  349. */
  350. static uint32_t
  351. iso9660start(Cdir *c)
  352. {
  353. uint8_t sect[Blocksize];
  354. while(c->flags&2){
  355. getsect(sect, little(c->dloc, 4));
  356. c = (Cdir*)sect;
  357. c = (Cdir*)((uint8_t*)c+c->len); /* skip dot */
  358. c = (Cdir*)((uint8_t*)c+c->len); /* skip dotdot */
  359. /* oops: might happen if leftmost directory is empty or leftmost file is zero length! */
  360. if(little(c->dloc, 4) == 0)
  361. vtFatal("error parsing cd image or unfortunate cd image");
  362. }
  363. return little(c->dloc, 4);
  364. }
  365. static void
  366. iso9660copydir(Fs *fs, File *dir, Cdir *cd)
  367. {
  368. uint32_t off, end, len;
  369. uint8_t sect[Blocksize], *esect, *p;
  370. Cdir *c;
  371. len = little(cd->dlen, 4);
  372. off = little(cd->dloc, 4)*Blocksize;
  373. end = off+len;
  374. esect = sect+Blocksize;
  375. for(; off<end; off+=Blocksize){
  376. getsect(sect, off/Blocksize);
  377. p = sect;
  378. while(p < esect){
  379. c = (Cdir*)p;
  380. if(c->len <= 0)
  381. break;
  382. if(c->namelen!=1 || c->name[0]>1)
  383. iso9660copyfile(fs, dir, c);
  384. p += c->len;
  385. }
  386. }
  387. }
  388. static char*
  389. getname(uint8_t **pp)
  390. {
  391. uint8_t *p;
  392. int l;
  393. p = *pp;
  394. l = *p;
  395. *pp = p+1+l;
  396. if(l == 0)
  397. return "";
  398. memmove(p, p+1, l);
  399. p[l] = 0;
  400. return (char*)p;
  401. }
  402. static char*
  403. getcname(Cdir *c)
  404. {
  405. uint8_t *up;
  406. char *p, *q;
  407. up = &c->namelen;
  408. p = getname(&up);
  409. for(q=p; *q; q++)
  410. *q = tolower(*q);
  411. return p;
  412. }
  413. static char
  414. dmsize[12] =
  415. {
  416. 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  417. };
  418. static uint32_t
  419. getcdate(uint8_t *p) /* yMdhmsz */
  420. {
  421. Tm tm;
  422. int y, M, d, h, m, s, tz;
  423. y=p[0]; M=p[1]; d=p[2];
  424. h=p[3]; m=p[4]; s=p[5]; tz=p[6];
  425. USED(tz);
  426. if (y < 70)
  427. return 0;
  428. if (M < 1 || M > 12)
  429. return 0;
  430. if (d < 1 || d > dmsize[M-1])
  431. return 0;
  432. if (h > 23)
  433. return 0;
  434. if (m > 59)
  435. return 0;
  436. if (s > 59)
  437. return 0;
  438. memset(&tm, 0, sizeof tm);
  439. tm.sec = s;
  440. tm.min = m;
  441. tm.hour = h;
  442. tm.mday = d;
  443. tm.mon = M-1;
  444. tm.year = 1900+y;
  445. tm.zone[0] = 0;
  446. return tm2sec(&tm);
  447. }
  448. static int ind;
  449. static void
  450. iso9660copyfile(Fs *fs, File *dir, Cdir *c)
  451. {
  452. Dir d;
  453. DirEntry de;
  454. int sysl;
  455. uint8_t score[VtScoreSize];
  456. uint32_t off, foff, len, mode;
  457. uint8_t *p;
  458. File *f;
  459. ind++;
  460. memset(&d, 0, sizeof d);
  461. p = c->name + c->namelen;
  462. if(((uintptr)p) & 1)
  463. p++;
  464. sysl = (uint8_t*)c + c->len - p;
  465. if(sysl <= 0)
  466. vtFatal("missing plan9 directory entry on %d/%d/%.*s", c->namelen, c->name[0], c->namelen, c->name);
  467. d.name = getname(&p);
  468. d.uid = getname(&p);
  469. d.gid = getname(&p);
  470. if((uintptr)p & 1)
  471. p++;
  472. d.mode = little(p, 4);
  473. if(d.name[0] == 0)
  474. d.name = getcname(c);
  475. d.mtime = getcdate(c->date);
  476. d.atime = d.mtime;
  477. if(d.mode&DMDIR) print("%*scopy %s %s %s %luo\n", ind*2, "", d.name, d.uid, d.gid, d.mode);
  478. mode = d.mode&0777;
  479. if(d.mode&DMDIR)
  480. mode |= ModeDir;
  481. if((f = fileCreate(dir, d.name, mode, d.uid)) == nil)
  482. vtFatal("could not create file '%s': %r", d.name);
  483. if(d.mode&DMDIR)
  484. iso9660copydir(fs, f, c);
  485. else{
  486. len = little(c->dlen, 4);
  487. off = little(c->dloc, 4)*Blocksize;
  488. for(foff=0; foff<len; foff+=h->blockSize){
  489. localToGlobal((off+foff-fsoff)/h->blockSize, score);
  490. if(!fileMapBlock(f, foff/h->blockSize, score, Tag))
  491. vtFatal("fileMapBlock: %R");
  492. }
  493. if(!fileSetSize(f, len))
  494. vtFatal("fileSetSize: %R");
  495. }
  496. if(!fileGetDir(f, &de))
  497. vtFatal("fileGetDir: %R");
  498. de.uid = d.uid;
  499. de.gid = d.gid;
  500. de.mtime = d.mtime;
  501. de.atime = d.atime;
  502. de.mode = d.mode&0777;
  503. if(!fileSetDir(f, &de, "sys"))
  504. vtFatal("fileSetDir: %R");
  505. fileDecRef(f);
  506. ind--;
  507. }