dump9660.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <disk.h>
  5. #include <libsec.h>
  6. #include "iso9660.h"
  7. ulong now;
  8. int chatty;
  9. int doabort;
  10. int docolon;
  11. int mk9660;
  12. vlong dataoffset;
  13. int blocksize;
  14. Conform *map;
  15. static void addprotofile(char *new, char *old, Dir *d, void *a);
  16. void usage(void);
  17. char *argv0;
  18. void
  19. usage(void)
  20. {
  21. if(mk9660)
  22. fprint(2, "usage: disk/mk9660 [-D:] [-9cjr] "
  23. "[-[bB] bootfile] [-o offset blocksize] "
  24. "[-p proto] [-s src] cdimage\n");
  25. else
  26. fprint(2, "usage: disk/dump9660 [-D:] [-9cjr] "
  27. "[-m maxsize] [-n now] "
  28. "[-p proto] [-s src] cdimage\n");
  29. exits("usage");
  30. }
  31. void
  32. main(int argc, char **argv)
  33. {
  34. int fix;
  35. ulong block, newnull, cblock;
  36. vlong maxsize;
  37. uvlong length, clength;
  38. char buf[256], *dumpname, *proto, *s, *src, *status;
  39. Cdimg *cd;
  40. Cdinfo info;
  41. XDir dir;
  42. Direc *iconform, idumproot, iroot, *jconform, jdumproot, jroot, *r;
  43. Dump *dump;
  44. fix = 0;
  45. status = nil;
  46. memset(&info, 0, sizeof info);
  47. proto = "/sys/lib/sysconfig/proto/allproto";
  48. src = "./";
  49. info.volumename = atom("9CD");
  50. info.volumeset = atom("9VolumeSet");
  51. info.publisher = atom("9Publisher");
  52. info.preparer = atom("dump9660");
  53. info.application = atom("dump9660");
  54. info.flags = CDdump;
  55. maxsize = 0;
  56. mk9660 = 0;
  57. fmtinstall('H', encodefmt);
  58. ARGBEGIN{
  59. case 'D':
  60. chatty++;
  61. break;
  62. case 'M':
  63. mk9660 = 1;
  64. argv0 = "disk/mk9660";
  65. info.flags &= ~CDdump;
  66. break;
  67. case '9':
  68. info.flags |= CDplan9;
  69. break;
  70. case ':':
  71. docolon = 1;
  72. break;
  73. case 'a':
  74. doabort = 1;
  75. break;
  76. case 'B':
  77. info.flags |= CDbootnoemu;
  78. /* fall through */
  79. case 'b':
  80. if(!mk9660)
  81. usage();
  82. info.flags |= CDbootable;
  83. info.bootimage = EARGF(usage());
  84. break;
  85. case 'c':
  86. info.flags |= CDconform;
  87. break;
  88. case 'f':
  89. fix = 1;
  90. break;
  91. case 'j':
  92. info.flags |= CDjoliet;
  93. break;
  94. case 'n':
  95. now = atoi(EARGF(usage()));
  96. break;
  97. case 'm':
  98. maxsize = strtoull(EARGF(usage()), 0, 0);
  99. break;
  100. case 'o':
  101. dataoffset = atoll(EARGF(usage()));
  102. blocksize = atoi(EARGF(usage()));
  103. if(blocksize%Blocksize)
  104. sysfatal("bad block size %d -- must be multiple of 2048", blocksize);
  105. blocksize /= Blocksize;
  106. break;
  107. case 'p':
  108. proto = EARGF(usage());
  109. break;
  110. case 'r':
  111. info.flags |= CDrockridge;
  112. break;
  113. case 's':
  114. src = EARGF(usage());
  115. break;
  116. case 'v':
  117. info.volumename = atom(EARGF(usage()));
  118. break;
  119. case 'x':
  120. info.flags |= CDpbs;
  121. info.loader = EARGF(usage());
  122. break;
  123. default:
  124. usage();
  125. }ARGEND
  126. if(info.flags & CDpbs && !(info.flags & CDbootnoemu))
  127. usage();
  128. if(mk9660 && (fix || now || maxsize))
  129. usage();
  130. if(argc != 1)
  131. usage();
  132. if(now == 0)
  133. now = (ulong)time(0);
  134. if(mk9660){
  135. if((cd = createcd(argv[0], info)) == nil)
  136. sysfatal("cannot create '%s': %r", argv[0]);
  137. }else{
  138. if((cd = opencd(argv[0], info)) == nil)
  139. sysfatal("cannot open '%s': %r", argv[0]);
  140. if(!(cd->flags & CDdump))
  141. sysfatal("not a dump cd");
  142. }
  143. /* create ISO9660/Plan 9 tree in memory */
  144. memset(&dir, 0, sizeof dir);
  145. dir.name = atom("");
  146. dir.uid = atom("sys");
  147. dir.gid = atom("sys");
  148. dir.uidno = 0;
  149. dir.gidno = 0;
  150. dir.mode = DMDIR | 0755;
  151. dir.mtime = now;
  152. dir.atime = now;
  153. dir.ctime = now;
  154. mkdirec(&iroot, &dir);
  155. iroot.srcfile = src;
  156. /*
  157. * Read new files into memory
  158. */
  159. if(rdproto(proto, src, addprotofile, nil, &iroot) < 0)
  160. sysfatal("rdproto: %r");
  161. if(mk9660){
  162. dump = emalloc(sizeof *dump);
  163. dumpname = nil;
  164. }else{
  165. /*
  166. * Read current dump tree and _conform.map.
  167. */
  168. idumproot = readdumpdirs(cd, &dir, isostring);
  169. readdumpconform(cd);
  170. if(cd->flags & CDjoliet)
  171. jdumproot = readdumpdirs(cd, &dir, jolietstring);
  172. if(fix){
  173. dumpname = nil;
  174. cd->nextblock = cd->nulldump+1;
  175. cd->nulldump = 0;
  176. Cwseek(cd, (vlong)cd->nextblock * Blocksize);
  177. goto Dofix;
  178. }
  179. dumpname = adddumpdir(&idumproot, now, &dir);
  180. /* note that we assume all names are conforming and thus sorted */
  181. if(cd->flags & CDjoliet) {
  182. s = adddumpdir(&jdumproot, now, &dir);
  183. if(s != dumpname)
  184. sysfatal("dumpnames don't match %s %s", dumpname, s);
  185. }
  186. dump = dumpcd(cd, &idumproot);
  187. cd->nextblock = cd->nulldump+1;
  188. }
  189. /*
  190. * Write new files, starting where the dump tree was.
  191. * Must be done before creation of the Joliet tree so that
  192. * blocks and lengths are correct.
  193. */
  194. if(dataoffset > (vlong)cd->nextblock * Blocksize)
  195. cd->nextblock = (dataoffset+Blocksize-1)/Blocksize;
  196. Cwseek(cd, (vlong)cd->nextblock * Blocksize);
  197. writefiles(dump, cd, &iroot);
  198. if(cd->bootimage){
  199. findbootimage(cd, &iroot);
  200. if(cd->loader)
  201. findloader(cd, &iroot);
  202. Cupdatebootcat(cd);
  203. }
  204. /* create Joliet tree */
  205. if(cd->flags & CDjoliet)
  206. copydirec(&jroot, &iroot);
  207. if(info.flags & CDconform) {
  208. checknames(&iroot, isbadiso9660);
  209. convertnames(&iroot, struprcpy);
  210. } else
  211. convertnames(&iroot, (void *) strcpy);
  212. // isoabstract = findconform(&iroot, abstract);
  213. // isobiblio = findconform(&iroot, biblio);
  214. // isonotice = findconform(&iroot, notice);
  215. dsort(&iroot, isocmp);
  216. if(cd->flags & CDjoliet) {
  217. // jabstract = findconform(&jroot, abstract);
  218. // jbiblio = findconform(&jroot, biblio);
  219. // jnotice = findconform(&jroot, notice);
  220. checknames(&jroot, isbadjoliet);
  221. convertnames(&jroot, (void *) strcpy);
  222. dsort(&jroot, jolietcmp);
  223. }
  224. /*
  225. * Write directories.
  226. */
  227. writedirs(cd, &iroot, Cputisodir);
  228. if(cd->flags & CDjoliet)
  229. writedirs(cd, &jroot, Cputjolietdir);
  230. if(mk9660){
  231. cblock = 0;
  232. clength = 0;
  233. newnull = 0;
  234. }else{
  235. /*
  236. * Write incremental _conform.map block.
  237. */
  238. wrconform(cd, cd->nconform, &cblock, &clength);
  239. /* jump here if we're just fixing up the cd */
  240. Dofix:
  241. /*
  242. * Write null dump header block; everything after this will be
  243. * overwritten at the next dump. Because of this, it needs to be
  244. * reconstructable. We reconstruct the _conform.map and dump trees
  245. * from the header blocks in dump.c, and we reconstruct the path
  246. * tables by walking the cd.
  247. */
  248. newnull = Cputdumpblock(cd);
  249. }
  250. if(info.flags & CDpbs)
  251. Cfillpbs(cd);
  252. /*
  253. * Write _conform.map.
  254. */
  255. dir.mode = 0444;
  256. if(cd->flags & (CDconform|CDjoliet)) {
  257. if(!mk9660 && cd->nconform == 0){
  258. block = cblock;
  259. length = clength;
  260. }else
  261. wrconform(cd, 0, &block, &length);
  262. if(mk9660)
  263. {
  264. idumproot = iroot;
  265. jdumproot = jroot;
  266. }
  267. if(length) {
  268. /* The ISO9660 name will get turned into uppercase when written. */
  269. if((iconform = walkdirec(&idumproot, "_conform.map")) == nil)
  270. iconform = adddirec(&idumproot, "_conform.map", &dir);
  271. jconform = nil;
  272. if(cd->flags & CDjoliet) {
  273. if((jconform = walkdirec(&jdumproot, "_conform.map")) == nil)
  274. jconform = adddirec(&jdumproot, "_conform.map", &dir);
  275. }
  276. iconform->block = block;
  277. iconform->length = length;
  278. if(cd->flags & CDjoliet) {
  279. jconform->block = block;
  280. jconform->length = length;
  281. }
  282. }
  283. if(mk9660) {
  284. iroot = idumproot;
  285. jroot = jdumproot;
  286. }
  287. }
  288. if(mk9660){
  289. /*
  290. * Patch in root directories.
  291. */
  292. setroot(cd, cd->iso9660pvd, iroot.block, iroot.length);
  293. setvolsize(cd, cd->iso9660pvd, (vlong)cd->nextblock * Blocksize);
  294. if(cd->flags & CDjoliet){
  295. setroot(cd, cd->jolietsvd, jroot.block, jroot.length);
  296. setvolsize(cd, cd->jolietsvd,
  297. (vlong)cd->nextblock * Blocksize);
  298. }
  299. }else{
  300. /*
  301. * Write dump tree at end. We assume the name characters
  302. * are all conforming, so everything is already sorted properly.
  303. */
  304. convertnames(&idumproot, (info.flags & CDconform) ? (void *) struprcpy : (void *) strcpy);
  305. if(cd->nulldump) {
  306. r = walkdirec(&idumproot, dumpname);
  307. assert(r != nil);
  308. copybutname(r, &iroot);
  309. }
  310. if(cd->flags & CDjoliet) {
  311. convertnames(&jdumproot, (void *) strcpy);
  312. if(cd->nulldump) {
  313. r = walkdirec(&jdumproot, dumpname);
  314. assert(r != nil);
  315. copybutname(r, &jroot);
  316. }
  317. }
  318. writedumpdirs(cd, &idumproot, Cputisodir);
  319. if(cd->flags & CDjoliet)
  320. writedumpdirs(cd, &jdumproot, Cputjolietdir);
  321. /*
  322. * Patch in new root directory entry.
  323. */
  324. setroot(cd, cd->iso9660pvd, idumproot.block, idumproot.length);
  325. setvolsize(cd, cd->iso9660pvd, (vlong)cd->nextblock * Blocksize);
  326. if(cd->flags & CDjoliet){
  327. setroot(cd, cd->jolietsvd, jdumproot.block, jdumproot.length);
  328. setvolsize(cd, cd->jolietsvd,
  329. (vlong)cd->nextblock * Blocksize);
  330. }
  331. }
  332. writepathtables(cd);
  333. if(!mk9660){
  334. /*
  335. * If we've gotten too big, truncate back to what we started with,
  336. * fix up the cd, and exit with a non-zero status.
  337. */
  338. Cwflush(cd);
  339. if(cd->nulldump && maxsize && Cwoffset(cd) > maxsize){
  340. fprint(2, "too big; writing old tree back\n");
  341. status = "cd too big; aborted";
  342. rmdumpdir(&idumproot, dumpname);
  343. rmdumpdir(&jdumproot, dumpname);
  344. cd->nextblock = cd->nulldump+1;
  345. cd->nulldump = 0;
  346. Cwseek(cd, (vlong)cd->nextblock * Blocksize);
  347. goto Dofix;
  348. }
  349. /*
  350. * Write old null header block; this commits all our changes.
  351. */
  352. if(cd->nulldump){
  353. Cwseek(cd, (vlong)cd->nulldump * Blocksize);
  354. sprint(buf, "plan 9 dump cd\n");
  355. sprint(buf+strlen(buf), "%s %lud %lud %lud %llud %lud %lud",
  356. dumpname, now, newnull, cblock, clength,
  357. iroot.block, iroot.length);
  358. if(cd->flags & CDjoliet)
  359. sprint(buf+strlen(buf), " %lud %lud",
  360. jroot.block, jroot.length);
  361. strcat(buf, "\n");
  362. Cwrite(cd, buf, strlen(buf));
  363. Cpadblock(cd);
  364. Cwflush(cd);
  365. }
  366. }
  367. fdtruncate(cd->fd, (vlong)cd->nextblock * Blocksize);
  368. exits(status);
  369. }
  370. static void
  371. addprotofile(char *new, char *old, Dir *d, void *a)
  372. {
  373. char *name, *p;
  374. Direc *direc;
  375. XDir xd;
  376. dirtoxdir(&xd, d);
  377. name = nil;
  378. if(docolon && strchr(new, ':')) {
  379. name = emalloc(strlen(new)+1);
  380. strcpy(name, new);
  381. while((p=strchr(name, ':')))
  382. *p=' ';
  383. new = name;
  384. }
  385. if((direc = adddirec((Direc*)a, new, &xd))) {
  386. direc->srcfile = atom(old);
  387. // BUG: abstract, biblio, notice
  388. }
  389. if(name)
  390. free(name);
  391. }