9 writelittlebig4(uchar *buf, ulong x)
12 buf[1] = buf[6] = x>>8;
13 buf[2] = buf[5] = x>>16;
14 buf[3] = buf[4] = x>>24;
18 rewritedot(Cdimg *cd, Direc *d)
23 Creadblock(cd, buf, d->block, Blocksize);
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, (vlong)d->block * Blocksize);
31 Cwrite(cd, buf, Blocksize);
35 rewritedotdot(Cdimg *cd, Direc *d, Direc *dparent)
40 Creadblock(cd, buf, d->block, Blocksize);
43 assert(c->namelen == 1 && c->name[0] == '\0'); /* dot */
45 c = (Cdir*)(buf+c->len);
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, (vlong)d->block * Blocksize);
53 Cwrite(cd, buf, Blocksize);
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.
65 writefiles(Dump *d, Cdimg *cd, Direc *direc)
68 uchar buf[8192], digest[MD5dlen];
69 ulong length, n, start;
74 if(direc->mode & DMDIR) {
75 for(i=0; i<direc->nchild; i++)
76 writefiles(d, cd, &direc->child[i]);
80 assert(direc->block == 0);
82 if((b = Bopen(direc->srcfile, OREAD)) == nil){
83 fprint(2, "warning: cannot open '%s': %r\n", direc->srcfile);
89 start = cd->nextblock;
91 if(blocksize && start%blocksize)
92 start += blocksize-start%blocksize;
94 Cwseek(cd, (vlong)start * Blocksize);
96 s = md5(nil, 0, nil, nil);
98 while((n = Bread(b, buf, sizeof buf)) > 0) {
103 md5(nil, 0, digest, s);
107 if(length != direc->length) {
108 fprint(2, "warning: %s changed size underfoot\n", direc->srcfile);
109 direc->length = length;
114 else if((dd = lookupmd5(d, digest))) {
115 assert(dd->length == length);
116 assert(dd->block != 0);
117 direc->block = dd->block;
118 cd->nextblock = start;
120 direc->block = start;
122 fprint(2, "lookup %.16H %lud (%s) failed\n", digest, length, direc->name);
123 insertmd5(d, atom(direc->name), digest, start, length);
128 * Write a directory tree. We work from the leaves,
129 * and patch the dotdot pointers afterward.
132 _writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
137 if((d->mode & DMDIR) == 0)
141 fprint(2, "%*s%s\n", 4*level, "", d->name);
143 for(i=0; i<d->nchild; i++)
144 _writedirs(cd, &d->child[i], put, level+1);
147 l += put(cd, d, (level == 0) ? DTrootdot : DTdot, 0, l);
148 l += put(cd, nil, DTdotdot, 0, l);
149 for(i=0; i<d->nchild; i++)
150 l += put(cd, &d->child[i], DTiden, 0, l);
152 start = cd->nextblock;
153 cd->nextblock += (l+Blocksize-1)/Blocksize;
154 next = cd->nextblock;
156 Cwseek(cd, (vlong)start * Blocksize);
158 ll += put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, ll);
159 ll += put(cd, nil, DTdotdot, 1, ll);
160 for(i=0; i<d->nchild; i++)
161 ll += put(cd, &d->child[i], DTiden, 1, ll);
164 assert(Cwoffset(cd) == (vlong)next * Blocksize);
167 d->length = (vlong)(next - start) * Blocksize;
169 rewritedotdot(cd, d, d);
171 for(i=0; i<d->nchild; i++)
172 if(d->child[i].mode & DMDIR)
173 rewritedotdot(cd, &d->child[i], d);
177 writedirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
180 * If we're writing a mk9660 image, then the root really
181 * is the root, so start at level 0. If we're writing a dump image,
182 * then the "root" is really going to be two levels down once
183 * we patch in the dump hierarchy above it, so start at level non-zero.
186 fprint(2, ">>> writedirs\n");
187 _writedirs(cd, d, put, mk9660 ? 0 : 1);
192 * Write the dump tree. This is like writedirs but once we get to
193 * the roots of the individual days we just patch the parent dotdot blocks.
196 _writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int), int level)
203 /* write root, list of years, also conform.map */
204 for(i=0; i<d->nchild; i++)
205 if(d->child[i].mode & DMDIR)
206 _writedumpdirs(cd, &d->child[i], put, level+1);
207 chat("write dump root dir at %lud\n", cd->nextblock);
210 case 1: /* write year, list of days */
211 for(i=0; i<d->nchild; i++)
212 _writedumpdirs(cd, &d->child[i], put, level+1);
213 chat("write dump %s dir at %lud\n", d->name, cd->nextblock);
217 start = cd->nextblock;
218 Cwseek(cd, (vlong)start * Blocksize);
220 put(cd, d, (level == 0) ? DTrootdot : DTdot, 1, Cwoffset(cd));
221 put(cd, nil, DTdotdot, 1, Cwoffset(cd));
222 for(i=0; i<d->nchild; i++)
223 put(cd, &d->child[i], DTiden, 1, Cwoffset(cd));
227 d->length = (vlong)(cd->nextblock - start) * Blocksize;
230 rewritedotdot(cd, d, d);
232 for(i=0; i<d->nchild; i++)
233 if(d->child[i].mode & DMDIR)
234 rewritedotdot(cd, &d->child[i], d);
237 case 2: /* write day: already written, do nothing */
246 writedumpdirs(Cdimg *cd, Direc *d, int (*put)(Cdimg*, Direc*, int, int, int))
248 _writedumpdirs(cd, d, put, 0);
252 Cputplan9(Cdimg *cd, Direc *d, int dot, int dowrite)
260 if(d->flags & Dbadname) {
265 Cputs(cd, d->name, n);
277 Cputs(cd, d->uid, n);
284 Cputs(cd, d->gid, n);
294 Cputn(cd, d->mode, 4);
300 * Write a directory entry.
303 genputdir(Cdimg *cd, Direc *d, int dot, int joliet, int dowrite, int offset)
309 if(dot != DTiden || (d->mode & DMDIR))
315 n = 2*utflen(d->confname);
317 n = strlen(d->confname);
326 if(cd->flags & CDplan9)
327 l += Cputplan9(cd, d, dot, 0);
328 else if(cd->flags & CDrockridge)
329 l += Cputsysuse(cd, d, dot, 0, l);
334 if(Blocksize - offset%Blocksize < l)
335 l += Blocksize - offset%Blocksize;
339 assert(offset%Blocksize == Cwoffset(cd)%Blocksize);
343 if(Blocksize - Cwoffset(cd)%Blocksize < l) {
344 lp = Blocksize - Cwoffset(cd)%Blocksize;
348 Cputc(cd, l); /* length of directory record */
349 Cputc(cd, 0); /* extended attribute record length */
351 if((d->mode & DMDIR) == 0)
352 assert(d->length == 0 || d->block >= 18);
354 Cputn(cd, d->block, 4); /* location of extent */
355 Cputn(cd, d->length, 4); /* data length */
360 Cputdate(cd, d ? d->mtime : now); /* recorded date */
361 Cputc(cd, f); /* file flags */
362 Cputc(cd, 0); /* file unit size */
363 Cputc(cd, 0); /* interleave gap size */
364 Cputn(cd, 1, 2); /* volume sequence number */
365 Cputc(cd, n); /* length of file identifier */
367 if(dot == DTiden) { /* identifier */
369 Cputrscvt(cd, d->confname, n);
371 Cputs(cd, d->confname, n);
378 if(Cwoffset(cd) & 1) /* pad */
382 if(cd->flags & CDplan9)
383 Cputplan9(cd, d, dot, 1);
384 else if(cd->flags & CDrockridge)
385 Cputsysuse(cd, d, dot, 1, Cwoffset(cd)-(o+lp));
388 assert(o+lp+l == Cwoffset(cd));
393 Cputisodir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
395 return genputdir(cd, d, dot, 0, dowrite, offset);
399 Cputjolietdir(Cdimg *cd, Direc *d, int dot, int dowrite, int offset)
401 return genputdir(cd, d, dot, 1, dowrite, offset);
407 Cputc(cd, 255); /* volume descriptor set terminator */
408 Cputs(cd, "CD001", 5); /* standard identifier */
409 Cputc(cd, 1); /* volume descriptor version */