dump9660.c (9081B)
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 8 ulong now; 9 int chatty; 10 int doabort; 11 int docolon; 12 int mk9660; 13 Conform *map; 14 15 static void addprotofile(char *new, char *old, Dir *d, void *a); 16 void usage(void); 17 18 char *argv0; 19 20 void 21 usage(void) 22 { 23 if(mk9660) 24 fprint(2, "usage: mk9660 [-D:] [-9cjr] [-b bootfile] [-p proto] [-s src] cdimage\n"); 25 else 26 fprint(2, "usage: dump9660 [-D:] [-9cjr] [-m maxsize] [-n now] [-p proto] [-s src] cdimage\n"); 27 exits("usage"); 28 } 29 30 int 31 main(int argc, char **argv) 32 { 33 int fix; 34 char buf[256], *dumpname, *proto, *s, *src, *status; 35 ulong block, length, newnull, cblock, clength, maxsize; 36 Cdimg *cd; 37 Cdinfo info; 38 XDir dir; 39 Direc *iconform, idumproot, iroot, *jconform, jdumproot, jroot, *r; 40 Dump *dump; 41 42 fix = 0; 43 status = nil; 44 memset(&info, 0, sizeof info); 45 proto = unsharp("#9/proto/allproto"); 46 src = "./"; 47 48 info.volumename = atom("9CD"); 49 info.volumeset = atom("9VolumeSet"); 50 info.publisher = atom("9Publisher"); 51 info.preparer = atom("dump9660"); 52 info.application = atom("dump9660"); 53 info.flags = CDdump; 54 maxsize = 0; 55 mk9660 = 0; 56 fmtinstall('H', encodefmt); 57 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 if(!mk9660) 78 usage(); 79 info.flags |= CDbootable; 80 info.bootimage = EARGF(usage()); 81 break; 82 case 'c': 83 info.flags |= CDconform; 84 break; 85 case 'f': 86 fix = 1; 87 break; 88 case 'j': 89 info.flags |= CDjoliet; 90 break; 91 case 'n': 92 now = atoi(EARGF(usage())); 93 break; 94 case 'm': 95 maxsize = strtoul(EARGF(usage()), 0, 0); 96 break; 97 case 'p': 98 proto = EARGF(usage()); 99 break; 100 case 'r': 101 info.flags |= CDrockridge; 102 break; 103 case 's': 104 src = EARGF(usage()); 105 break; 106 case 'v': 107 info.volumename = atom(EARGF(usage())); 108 break; 109 default: 110 usage(); 111 }ARGEND 112 113 if(mk9660 && (fix || now || maxsize)) 114 usage(); 115 116 if(argc != 1) 117 usage(); 118 119 if(now == 0) 120 now = (ulong)time(0); 121 if(mk9660){ 122 if((cd = createcd(argv[0], info)) == nil) 123 sysfatal("cannot create '%s': %r", argv[0]); 124 }else{ 125 if((cd = opencd(argv[0], info)) == nil) 126 sysfatal("cannot open '%s': %r", argv[0]); 127 if(!(cd->flags & CDdump)) 128 sysfatal("not a dump cd"); 129 } 130 131 /* create ISO9660/Plan 9 tree in memory */ 132 memset(&dir, 0, sizeof dir); 133 dir.name = atom(""); 134 dir.uid = atom("sys"); 135 dir.gid = atom("sys"); 136 dir.uidno = 0; 137 dir.gidno = 0; 138 dir.mode = DMDIR | 0755; 139 dir.mtime = now; 140 dir.atime = now; 141 dir.ctime = now; 142 143 mkdirec(&iroot, &dir); 144 iroot.srcfile = src; 145 146 /* 147 * Read new files into memory 148 */ 149 if(rdproto(proto, src, addprotofile, 0, &iroot) < 0) 150 sysfatal("rdproto: %r"); 151 152 if(mk9660){ 153 dump = emalloc(sizeof *dump); 154 dumpname = nil; 155 }else{ 156 /* 157 * Read current dump tree and _conform.map. 158 */ 159 idumproot = readdumpdirs(cd, &dir, isostring); 160 readdumpconform(cd); 161 if(cd->flags & CDjoliet) 162 jdumproot = readdumpdirs(cd, &dir, jolietstring); 163 164 if(fix){ 165 dumpname = nil; 166 cd->nextblock = cd->nulldump+1; 167 cd->nulldump = 0; 168 Cwseek(cd, cd->nextblock*Blocksize); 169 goto Dofix; 170 } 171 172 dumpname = adddumpdir(&idumproot, now, &dir); 173 /* note that we assume all names are conforming and thus sorted */ 174 if(cd->flags & CDjoliet) { 175 s = adddumpdir(&jdumproot, now, &dir); 176 if(s != dumpname) 177 sysfatal("dumpnames don't match %s %s\n", dumpname, s); 178 } 179 dump = dumpcd(cd, &idumproot); 180 cd->nextblock = cd->nulldump+1; 181 } 182 183 /* 184 * Write new files, starting where the dump tree was. 185 * Must be done before creation of the Joliet tree so that 186 * blocks and lengths are correct. 187 */ 188 Cwseek(cd, cd->nextblock*Blocksize); 189 writefiles(dump, cd, &iroot); 190 191 if(cd->bootimage){ 192 findbootimage(cd, &iroot); 193 Cupdatebootcat(cd); 194 } 195 196 /* create Joliet tree */ 197 if(cd->flags & CDjoliet) 198 copydirec(&jroot, &iroot); 199 200 if(info.flags & CDconform) { 201 checknames(&iroot, isbadiso9660); 202 convertnames(&iroot, struprcpy); 203 } else 204 convertnames(&iroot, (char* (*)(char*, char*))strcpy); 205 206 /* isoabstract = findconform(&iroot, abstract); */ 207 /* isobiblio = findconform(&iroot, biblio); */ 208 /* isonotice = findconform(&iroot, notice); */ 209 210 dsort(&iroot, isocmp); 211 212 if(cd->flags & CDjoliet) { 213 /* jabstract = findconform(&jroot, abstract); */ 214 /* jbiblio = findconform(&jroot, biblio); */ 215 /* jnotice = findconform(&jroot, notice); */ 216 217 checknames(&jroot, isbadjoliet); 218 convertnames(&jroot, (char* (*)(char*, char*))strcpy); 219 dsort(&jroot, jolietcmp); 220 } 221 222 /* 223 * Write directories. 224 */ 225 writedirs(cd, &iroot, Cputisodir); 226 if(cd->flags & CDjoliet) 227 writedirs(cd, &jroot, Cputjolietdir); 228 229 if(mk9660){ 230 cblock = 0; 231 clength = 0; 232 newnull = 0; 233 }else{ 234 /* 235 * Write incremental _conform.map block. 236 */ 237 wrconform(cd, cd->nconform, &cblock, &clength); 238 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 251 /* 252 * Write _conform.map. 253 */ 254 dir.mode = 0444; 255 if(cd->flags & (CDconform|CDjoliet)) { 256 if(!mk9660 && cd->nconform == 0){ 257 block = cblock; 258 length = clength; 259 }else 260 wrconform(cd, 0, &block, &length); 261 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 289 if(mk9660){ 290 /* 291 * Patch in root directories. 292 */ 293 setroot(cd, cd->iso9660pvd, iroot.block, iroot.length); 294 setvolsize(cd, cd->iso9660pvd, cd->nextblock*Blocksize); 295 if(cd->flags & CDjoliet){ 296 setroot(cd, cd->jolietsvd, jroot.block, jroot.length); 297 setvolsize(cd, cd->jolietsvd, 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) ? struprcpy : (char* (*)(char*, char*)) 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, (char* (*)(char*, char*))strcpy); 312 if(cd->nulldump) { 313 r = walkdirec(&jdumproot, dumpname); 314 assert(r != nil); 315 copybutname(r, &jroot); 316 } 317 } 318 319 writedumpdirs(cd, &idumproot, Cputisodir); 320 if(cd->flags & CDjoliet) 321 writedumpdirs(cd, &jdumproot, Cputjolietdir); 322 323 /* 324 * Patch in new root directory entry. 325 */ 326 setroot(cd, cd->iso9660pvd, idumproot.block, idumproot.length); 327 setvolsize(cd, cd->iso9660pvd, cd->nextblock*Blocksize); 328 if(cd->flags & CDjoliet){ 329 setroot(cd, cd->jolietsvd, jdumproot.block, jdumproot.length); 330 setvolsize(cd, cd->jolietsvd, cd->nextblock*Blocksize); 331 } 332 } 333 writepathtables(cd); 334 335 if(!mk9660){ 336 /* 337 * If we've gotten too big, truncate back to what we started with, 338 * fix up the cd, and exit with a non-zero status. 339 */ 340 Cwflush(cd); 341 if(cd->nulldump && maxsize && Cwoffset(cd) > maxsize){ 342 fprint(2, "too big; writing old tree back\n"); 343 status = "cd too big; aborted"; 344 345 rmdumpdir(&idumproot, dumpname); 346 rmdumpdir(&jdumproot, dumpname); 347 348 cd->nextblock = cd->nulldump+1; 349 cd->nulldump = 0; 350 Cwseek(cd, cd->nextblock*Blocksize); 351 goto Dofix; 352 } 353 354 /* 355 * Write old null header block; this commits all our changes. 356 */ 357 if(cd->nulldump){ 358 Cwseek(cd, cd->nulldump*Blocksize); 359 sprint(buf, "plan 9 dump cd\n"); 360 sprint(buf+strlen(buf), "%s %lud %lud %lud %lud %lud %lud", 361 dumpname, now, newnull, cblock, clength, iroot.block, 362 iroot.length); 363 if(cd->flags & CDjoliet) 364 sprint(buf+strlen(buf), " %lud %lud", 365 jroot.block, jroot.length); 366 strcat(buf, "\n"); 367 Cwrite(cd, buf, strlen(buf)); 368 Cpadblock(cd); 369 Cwflush(cd); 370 } 371 } 372 fdtruncate(cd->fd, cd->nextblock*Blocksize); 373 exits(status); 374 return 0; 375 } 376 377 static void 378 addprotofile(char *new, char *old, Dir *d, void *a) 379 { 380 char *name, *p; 381 Direc *direc; 382 XDir xd; 383 384 dirtoxdir(&xd, d); 385 name = nil; 386 if(docolon && strchr(new, ':')) { 387 name = emalloc(strlen(new)+1); 388 strcpy(name, new); 389 while((p=strchr(name, ':'))) 390 *p=' '; 391 new = name; 392 } 393 if((direc = adddirec((Direc*)a, new, &xd))) { 394 direc->srcfile = atom(old); 395 396 /* BUG: abstract, biblio, notice */ 397 } 398 if(name) 399 free(name); 400 401 }