Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <libsec.h>
6 #include "iso9660.h"
8 static void
9 writelittlebig4(uchar *buf, ulong x)
10 {
11 buf[0] = buf[7] = x;
12 buf[1] = buf[6] = x>>8;
13 buf[2] = buf[5] = x>>16;
14 buf[3] = buf[4] = x>>24;
15 }
17 void
18 rewritedot(Cdimg *cd, Direc *d)
19 {
20 uchar buf[Blocksize];
21 Cdir *c;
23 Creadblock(cd, buf, d->block, Blocksize);
24 c = (Cdir*)buf;
25 assert(c->len != 0);
26 assert(c->namelen == 1 && c->name[0] == '\0'); /* dot */
27 writelittlebig4(c->dloc, d->block);
28 writelittlebig4(c->dlen, d->length);
30 Cwseek(cd, d->block*Blocksize);
31 Cwrite(cd, buf, Blocksize);
32 }
34 void
35 rewritedotdot(Cdimg *cd, Direc *d, Direc *dparent)
36 {
37 uchar buf[Blocksize];
38 Cdir *c;
40 Creadblock(cd, buf, d->block, Blocksize);
41 c = (Cdir*)buf;
42 assert(c->len != 0);
43 assert(c->namelen == 1 && c->name[0] == '\0'); /* dot */
45 c = (Cdir*)(buf+c->len);
46 assert(c->len != 0);
47 assert(c->namelen == 1 && c->name[0] == '\001'); /* dotdot*/
49 writelittlebig4(c->dloc, dparent->block);
50 writelittlebig4(c->dlen, dparent->length);
52 Cwseek(cd, d->block*Blocksize);
53 Cwrite(cd, buf, Blocksize);
54 }
56 /*
57 * Write each non-directory file. We copy the file to
58 * the cd image, and then if it turns out that we've
59 * seen this stream of bits before, we push the next block
60 * pointer back. This ensures consistency between the MD5s
61 * and the data on the CD image. MD5 summing on one pass
62 * and copying on another would not ensure this.
63 */
64 void
65 writefiles(Dump *d, Cdimg *cd, Direc *direc)
66 {
67 int i;
68 uchar buf[8192], digest[MD5dlen];
69 ulong length, n, start;
70 Biobuf *b;
71 DigestState *s;
72 Dumpdir *dd;
74 if(direc->mode & DMDIR) {
75 for(i=0; i<direc->nchild; i++)
76 writefiles(d, cd, &direc->child[i]);
77 return;
78 }
80 assert(direc->block == 0);
82 if((b = Bopen(direc->srcfile, OREAD)) == nil){
83 fprint(2, "warning: cannot open '%s': %r\n", direc->srcfile);
84 direc->block = 0;
85 direc->length = 0;
86 return;
87 }
89 start = cd->nextblock;
90 assert(start != 0);
92 Cwseek(cd, start*Blocksize);
94 s = md5(nil, 0, nil, nil);
95 length = 0;
96 while((n = Bread(b, buf, sizeof buf)) > 0) {
97 md5(buf, n, nil, s);
98 Cwrite(cd, buf, n);
99 length += n;
101 md5(nil, 0, digest, s);
102 Bterm(b);
103 Cpadblock(cd);
105 if(length != direc->length) {
106 fprint(2, "warning: %s changed size underfoot\n", direc->srcfile);
107 direc->length = length;
110 if(length == 0)
111 direc->block = 0;
112 else if((dd = lookupmd5(d, digest))) {
113 assert(dd->length == length);
114 assert(dd->block != 0);
115 direc->block = dd->block;
116 cd->nextblock = start;
117 } else {
118 direc->block = start;
119 if(chatty > 1)
120 fprint(2, "lookup %.16H %lud (%s) failed\n", digest, length, direc->name);
121 insertmd5(d, atom(direc->name), digest, start, length);
125 /*
126 * Write a directory tree. We work from the leaves,
127 * and patch the dotdot pointers afterward.
128 */
129 static void
130 _writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
132 int i, l, ll;
133 ulong start, next;
135 if((d->mode & DMDIR) == 0)
136 return;
138 if(chatty)
139 fprint(2, "%*s%s\n", 4*level, "", d->name);
141 for(i=0; i<d->nchild; i++)
142 _writedirs(cd, &d->child[i], put, level+1);
144 l = 0;
145 l += put(cd, d, (level == 0) ? DTrootdot : DTdot, 0, l);
146 l += put(cd, nil, DTdotdot, 0, l);
147 for(i=0; i<d->nchild; i++)
148 l += put(cd, &d->child[i], DTiden, 0, l);
150 start = cd->nextblock;
151 cd->nextblock += (l+Blocksize-1)/Blocksize;
152 next = cd->nextblock;
154 Cwseek(cd, start*Blocksize);
155 ll = 0;
156 ll += put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, ll);
157 ll += put(cd, nil, DTdotdot, 1, ll);
158 for(i=0; i<d->nchild; i++)
159 ll += put(cd, &d->child[i], DTiden, 1, ll);
160 assert(ll == l);
161 Cpadblock(cd);
162 assert(Cwoffset(cd) == next*Blocksize);
164 d->block = start;
165 d->length = (next - start) * Blocksize;
166 rewritedot(cd, d);
167 rewritedotdot(cd, d, d);
169 for(i=0; i<d->nchild; i++)
170 if(d->child[i].mode & DMDIR)
171 rewritedotdot(cd, &d->child[i], d);
174 void
175 writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
177 /*
178 * If we're writing a mk9660 image, then the root really
179 * is the root, so start at level 0. If we're writing a dump image,
180 * then the "root" is really going to be two levels down once
181 * we patch in the dump hierarchy above it, so start at level non-zero.
182 */
183 if(chatty)
184 fprint(2, ">>> writedirs\n");
185 _writedirs(cd, d, put, mk9660 ? 0 : 1);
189 /*
190 * Write the dump tree. This is like writedirs but once we get to
191 * the roots of the individual days we just patch the parent dotdot blocks.
192 */
193 static void
194 _writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
196 int i;
197 ulong start;
199 switch(level) {
200 case 0:
201 /* write root, list of years, also conform.map */
202 for(i=0; i<d->nchild; i++)
203 if(d->child[i].mode & DMDIR)
204 _writedumpdirs(cd, &d->child[i], put, level+1);
205 chat("write dump root dir at %lud\n", cd->nextblock);
206 goto Writedir;
208 case 1: /* write year, list of days */
209 for(i=0; i<d->nchild; i++)
210 _writedumpdirs(cd, &d->child[i], put, level+1);
211 chat("write dump %s dir at %lud\n", d->name, cd->nextblock);
212 goto Writedir;
214 Writedir:
215 start = cd->nextblock;
216 Cwseek(cd, start*Blocksize);
218 put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, Cwoffset(cd));
219 put(cd, nil, DTdotdot, 1, Cwoffset(cd));
220 for(i=0; i<d->nchild; i++)
221 put(cd, &d->child[i], DTiden, 1, Cwoffset(cd));
222 Cpadblock(cd);
224 d->block = start;
225 d->length = (cd->nextblock - start) * Blocksize;
227 rewritedot(cd, d);
228 rewritedotdot(cd, d, d);
230 for(i=0; i<d->nchild; i++)
231 if(d->child[i].mode & DMDIR)
232 rewritedotdot(cd, &d->child[i], d);
233 break;
235 case 2: /* write day: already written, do nothing */
236 break;
238 default:
239 assert(0);
243 void
244 writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
246 _writedumpdirs(cd, d, put, 0);
249 static int
250 Cputplan9(Cdimg *cd, Direc *d, int dot, int dowrite)
252 int l, n;
254 if(dot != DTiden)
255 return 0;
257 l = 0;
258 if(d->flags & Dbadname) {
259 n = strlen(d->name);
260 l += 1+n;
261 if(dowrite) {
262 Cputc(cd, n);
263 Cputs(cd, d->name, n);
265 } else {
266 l++;
267 if(dowrite)
268 Cputc(cd, 0);
271 n = strlen(d->uid);
272 l += 1+n;
273 if(dowrite) {
274 Cputc(cd, n);
275 Cputs(cd, d->uid, n);
278 n = strlen(d->gid);
279 l += 1+n;
280 if(dowrite) {
281 Cputc(cd, n);
282 Cputs(cd, d->gid, n);
285 if(l & 1) {
286 l++;
287 if(dowrite)
288 Cputc(cd, 0);
290 l += 8;
291 if(dowrite)
292 Cputn(cd, d->mode, 4);
294 return l;
297 /*
298 * Write a directory entry.
299 */
300 static int
301 genputdir(Cdimg *cd, Direc *d, int dot, int joliet, int dowrite, int offset)
303 int f, n, l, lp;
304 long o;
306 f = 0;
307 if(dot != DTiden || (d->mode & DMDIR))
308 f |= 2;
310 n = 1;
311 if(dot == DTiden) {
312 if(joliet)
313 n = 2*utflen(d->confname);
314 else
315 n = strlen(d->confname);
318 l = 33+n;
319 if(l & 1)
320 l++;
321 assert(l <= 255);
323 if(joliet == 0) {
324 if(cd->flags & CDplan9)
325 l += Cputplan9(cd, d, dot, 0);
326 else if(cd->flags & CDrockridge)
327 l += Cputsysuse(cd, d, dot, 0, l);
328 assert(l <= 255);
331 if(dowrite == 0) {
332 if(Blocksize - offset%Blocksize < l)
333 l += Blocksize - offset%Blocksize;
334 return l;
337 assert(offset%Blocksize == Cwoffset(cd)%Blocksize);
339 o = Cwoffset(cd);
340 lp = 0;
341 if(Blocksize - Cwoffset(cd)%Blocksize < l) {
342 lp = Blocksize - Cwoffset(cd)%Blocksize;
343 Cpadblock(cd);
346 Cputc(cd, l); /* length of directory record */
347 Cputc(cd, 0); /* extended attribute record length */
348 if(d) {
349 if((d->mode & DMDIR) == 0)
350 assert(d->length == 0 || d->block >= 18);
352 Cputn(cd, d->block, 4); /* location of extent */
353 Cputn(cd, d->length, 4); /* data length */
354 } else {
355 Cputn(cd, 0, 4);
356 Cputn(cd, 0, 4);
358 Cputdate(cd, d ? d->mtime : now); /* recorded date */
359 Cputc(cd, f); /* file flags */
360 Cputc(cd, 0); /* file unit size */
361 Cputc(cd, 0); /* interleave gap size */
362 Cputn(cd, 1, 2); /* volume sequence number */
363 Cputc(cd, n); /* length of file identifier */
365 if(dot == DTiden) { /* identifier */
366 if(joliet)
367 Cputrscvt(cd, d->confname, n);
368 else
369 Cputs(cd, d->confname, n);
370 }else
371 if(dot == DTdotdot)
372 Cputc(cd, 1);
373 else
374 Cputc(cd, 0);
376 if(Cwoffset(cd) & 1) /* pad */
377 Cputc(cd, 0);
379 if(joliet == 0) {
380 if(cd->flags & CDplan9)
381 Cputplan9(cd, d, dot, 1);
382 else if(cd->flags & CDrockridge)
383 Cputsysuse(cd, d, dot, 1, Cwoffset(cd)-(o+lp));
386 assert(o+lp+l == Cwoffset(cd));
387 return lp+l;
390 int
391 Cputisodir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
393 return genputdir(cd, d, dot, 0, dowrite, offset);
396 int
397 Cputjolietdir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
399 return genputdir(cd, d, dot, 1, dowrite, offset);
402 void
403 Cputendvd(Cdimg *cd)
405 Cputc(cd, 255); /* volume descriptor set terminator */
406 Cputs(cd, "CD001", 5); /* standard identifier */
407 Cputc(cd, 1); /* volume descriptor version */
408 Cpadblock(cd);