Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <disk.h>
5 #include <libsec.h>
6 #include "iso9660.h"
8 ulong now;
9 int chatty;
10 int doabort;
11 int docolon;
12 int mk9660;
13 Conform *map;
15 static void addprotofile(char *new, char *old, Dir *d, void *a);
16 void usage(void);
18 char *argv0;
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 }
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;
42 fix = 0;
43 status = nil;
44 memset(&info, 0, sizeof info);
45 proto = unsharp("#9/proto/allproto");
46 src = "./";
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);
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
113 if(mk9660 && (fix || now || maxsize))
114 usage();
116 if(argc != 1)
117 usage();
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");
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;
143 mkdirec(&iroot, &dir);
144 iroot.srcfile = src;
146 /*
147 * Read new files into memory
148 */
149 if(rdproto(proto, src, addprotofile, 0, &iroot) < 0)
150 sysfatal("rdproto: %r");
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);
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;
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);
179 dump = dumpcd(cd, &idumproot);
180 cd->nextblock = cd->nulldump+1;
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);
191 if(cd->bootimage){
192 findbootimage(cd, &iroot);
193 Cupdatebootcat(cd);
196 /* create Joliet tree */
197 if(cd->flags & CDjoliet)
198 copydirec(&jroot, &iroot);
200 if(info.flags & CDconform) {
201 checknames(&iroot, isbadiso9660);
202 convertnames(&iroot, struprcpy);
203 } else
204 convertnames(&iroot, (char* (*)(char*, char*))strcpy);
206 /* isoabstract = findconform(&iroot, abstract); */
207 /* isobiblio = findconform(&iroot, biblio); */
208 /* isonotice = findconform(&iroot, notice); */
210 dsort(&iroot, isocmp);
212 if(cd->flags & CDjoliet) {
213 /* jabstract = findconform(&jroot, abstract); */
214 /* jbiblio = findconform(&jroot, biblio); */
215 /* jnotice = findconform(&jroot, notice); */
217 checknames(&jroot, isbadjoliet);
218 convertnames(&jroot, (char* (*)(char*, char*))strcpy);
219 dsort(&jroot, jolietcmp);
222 /*
223 * Write directories.
224 */
225 writedirs(cd, &iroot, Cputisodir);
226 if(cd->flags & CDjoliet)
227 writedirs(cd, &jroot, Cputjolietdir);
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);
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);
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);
262 if(mk9660)
264 idumproot = iroot;
265 jdumproot = jroot;
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);
276 iconform->block = block;
277 iconform->length = length;
278 if(cd->flags & CDjoliet) {
279 jconform->block = block;
280 jconform->length = length;
283 if(mk9660) {
284 iroot = idumproot;
285 jroot = jdumproot;
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);
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);
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);
319 writedumpdirs(cd, &idumproot, Cputisodir);
320 if(cd->flags & CDjoliet)
321 writedumpdirs(cd, &jdumproot, Cputjolietdir);
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);
333 writepathtables(cd);
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";
345 rmdumpdir(&idumproot, dumpname);
346 rmdumpdir(&jdumproot, dumpname);
348 cd->nextblock = cd->nulldump+1;
349 cd->nulldump = 0;
350 Cwseek(cd, cd->nextblock*Blocksize);
351 goto Dofix;
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);
372 fdtruncate(cd->fd, cd->nextblock*Blocksize);
373 exits(status);
374 return 0;
377 static void
378 addprotofile(char *new, char *old, Dir *d, void *a)
380 char *name, *p;
381 Direc *direc;
382 XDir xd;
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;
393 if((direc = adddirec((Direc*)a, new, &xd))) {
394 direc->srcfile = atom(old);
396 /* BUG: abstract, biblio, notice */
398 if(name)
399 free(name);