dump9660.c 9.2 KB

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