| tdump9660.c - plan9port - [fork] Plan 9 from user space | |
| git clone git://src.adamsgaard.dk/plan9port | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| tdump9660.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… | |
| 25 else | |
| 26 fprint(2, "usage: dump9660 [-D:] [-9cjr] [-m maxsize] [-… | |
| 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, … | |
| 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… | |
| 174 if(cd->flags & CDjoliet) { | |
| 175 s = adddumpdir(&jdumproot, now, &dir); | |
| 176 if(s != dumpname) | |
| 177 sysfatal("dumpnames don't match %s %s\n"… | |
| 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 w… | |
| 243 * overwritten at the next dump. Because of this, it ne… | |
| 244 * reconstructable. We reconstruct the _conform.map and… | |
| 245 * from the header blocks in dump.c, and we reconstruct … | |
| 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 upperca… | |
| 269 if((iconform = walkdirec(&idumproot, "_conform.m… | |
| 270 iconform = adddirec(&idumproot, "_confor… | |
| 271 jconform = nil; | |
| 272 if(cd->flags & CDjoliet) { | |
| 273 if((jconform = walkdirec(&jdumproot, "_c… | |
| 274 jconform = adddirec(&jdumproot, … | |
| 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.le… | |
| 297 setvolsize(cd, cd->jolietsvd, cd->nextblock*Bloc… | |
| 298 } | |
| 299 }else{ | |
| 300 /* | |
| 301 * Write dump tree at end. We assume the name characters | |
| 302 * are all conforming, so everything is already sorted p… | |
| 303 */ | |
| 304 convertnames(&idumproot, (info.flags & CDconform) ? stru… | |
| 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*… | |
| 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.l… | |
| 327 setvolsize(cd, cd->iso9660pvd, cd->nextblock*Blocksize); | |
| 328 if(cd->flags & CDjoliet){ | |
| 329 setroot(cd, cd->jolietsvd, jdumproot.block, jdum… | |
| 330 setvolsize(cd, cd->jolietsvd, cd->nextblock*Bloc… | |
| 331 } | |
| 332 } | |
| 333 writepathtables(cd); | |
| 334 | |
| 335 if(!mk9660){ | |
| 336 /* | |
| 337 * If we've gotten too big, truncate back to what we sta… | |
| 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 cha… | |
| 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 … | |
| 361 dumpname, now, newnull, cblock, clength,… | |
| 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 } |