9 md5cd(Cdimg *cd, ulong block, ulong length, uchar *digest)
15 s = md5(nil, 0, nil, nil);
21 Creadblock(cd, buf, block, n);
28 md5(nil, 0, digest, s);
32 mkdumpdir(char *name, uchar *md5, ulong block, ulong length)
38 d = emalloc(sizeof *d);
40 memmove(d->md5, md5, sizeof d->md5);
48 ltreewalkmd5(Dumpdir **l, uchar *md5)
53 i = memcmp(md5, (*l)->md5, MD5dlen);
65 ltreewalkblock(Dumpdir **l, ulong block)
68 if(block < (*l)->block)
70 else if(block == (*l)->block)
73 l = &(*l)->blockright;
79 * Add a particular file to our binary tree.
82 addfile(Cdimg *cd, Dump *d, char *name, Direc *dir)
87 assert((dir->mode & DMDIR) == 0);
92 lblock = ltreewalkblock(&d->blockroot, dir->block);
94 if((*lblock)->length == dir->length)
96 fprint(2, "block %lud length %lud %s %lud %s\n", dir->block, (*lblock)->length, (*lblock)->name,
97 dir->length, dir->name);
101 md5cd(cd, dir->block, dir->length, md5);
103 fprint(2, "note file %.16H %lud (%s)\n", md5, dir->length, dir->name);
104 insertmd5(d, name, md5, dir->block, dir->length);
108 insertmd5(Dump *d, char *name, uchar *md5, ulong block, ulong length)
113 lblock = ltreewalkblock(&d->blockroot, block);
115 if((*lblock)->length == length)
117 fprint(2, "block %lud length %lud %lud\n", block, (*lblock)->length, length);
122 *lblock = mkdumpdir(name, md5, block, length);
124 lmd5 = ltreewalkmd5(&d->md5root, md5);
126 fprint(2, "warning: data duplicated on CD\n");
132 * Fill all the children entries for a particular directory;
133 * all we care about is block, length, and whether it is a directory.
136 readkids(Cdimg *cd, Direc *dir, char *(*cvt)(uchar*, int))
140 uchar buf[Blocksize], *ebuf, *p;
145 assert(dir->mode & DMDIR);
149 ebuf = buf+Blocksize;
150 nb = (dir->length+Blocksize-1) / Blocksize;
153 for(b=0; b<nb; b++) {
154 Creadblock(cd, buf, dir->block + b, Blocksize);
162 if(parsedir(cd, &dx, p, ebuf-p, cvt) == 0 && dx.name != dot && dx.name != dotdot)
168 m = (n+Ndirblock-1)/Ndirblock * Ndirblock;
169 dir->child = emalloc(m*sizeof dir->child[0]);
173 for(b=0; b<nb; b++) {
174 assert(n <= dir->nchild);
175 Creadblock(cd, buf, dir->block + b, Blocksize);
183 if(parsedir(cd, &dx, p, ebuf-p, cvt) == 0 && dx.name != dot && dx.name != dotdot) {
184 assert(n < dir->nchild);
185 dir->child[n++] = dx;
193 * Free the children. Make sure their children are free too.
200 for(i=0; i<dir->nchild; i++)
201 assert(dir->child[i].nchild == 0);
209 * Add a whole directory and all its children to our binary tree.
212 adddir(Cdimg *cd, Dump *d, Direc *dir)
216 readkids(cd, dir, isostring);
217 for(i=0; i<dir->nchild; i++) {
218 if(dir->child[i].mode & DMDIR)
219 adddir(cd, d, &dir->child[i]);
221 addfile(cd, d, atom(dir->name), &dir->child[i]);
227 lookupmd5(Dump *d, uchar *md5)
229 return *ltreewalkmd5(&d->md5root, md5);
233 adddirx(Cdimg *cd, Dump *d, Direc *dir, int lev)
243 for(i=0; i<dir->nchild; i++)
244 adddirx(cd, d, &dir->child[i], lev+1);
248 dumpcd(Cdimg *cd, Direc *dir)
252 d = emalloc(sizeof *d);
254 adddirx(cd, d, dir, 0);
260 minblock(Direc *root, int lev)
266 for(i=0; i<root->nchild; i++) {
267 n = minblock(&root->child[i], lev-1);
276 copybutname(Direc *d, Direc *s)
283 d->confname = x.confname;
287 createdumpdir(Direc *root, XDir *dir, char *utfname)
293 sysfatal("bad dump name '%s'", utfname);
294 p = strchr(utfname, '/');
295 if(p == nil || strchr(p+1, '/'))
296 sysfatal("bad dump name '%s'", utfname);
298 if((d = walkdirec(root, utfname)) == nil)
299 d = adddirec(root, utfname, dir);
301 sysfatal("duplicate dump name '%s/%s'", utfname, p);
302 d = adddirec(d, p, dir);
307 rmdirec(Direc *d, Direc *kid)
311 ekid = d->child+d->nchild;
312 assert(d->child <= kid && kid < ekid);
314 memmove(kid, kid+1, (ekid-(kid+1))*sizeof(*kid));
319 rmdumpdir(Direc *root, char *utfname)
325 sysfatal("bad dump name '%s'", utfname);
326 p = strchr(utfname, '/');
327 if(p == nil || strchr(p+1, '/'))
328 sysfatal("bad dump name '%s'", utfname);
330 if((d = walkdirec(root, utfname)) == nil)
331 sysfatal("cannot remove %s/%s: %s does not exist", utfname, p, utfname);
334 if((dd = walkdirec(d, p)) == nil)
335 sysfatal("cannot remove %s: does not exist", utfname);
343 adddumpdir(Direc *root, ulong now, XDir *dir)
350 tm = *localtime(now);
352 sprint(buf, "%d", tm.year+1900);
353 if((dyear = walkdirec(root, buf)) == nil) {
354 dyear = adddirec(root, buf, dir);
355 assert(dyear != nil);
359 sprint(buf, "%.2d%.2d", tm.mon+1, tm.mday);
361 while(walkdirec(dyear, buf))
362 sprint(p, "%d", ++n);
364 dday = adddirec(dyear, buf, dir);
367 sprint(buf, "%s/%s", dyear->name, dday->name);
368 assert(walkdirec(root, buf)==dday);
373 * The dump directory tree is inferred from a linked list of special blocks.
374 * One block is written at the end of each dump.
375 * The blocks have the form
378 * <dump-name> <dump-time> <next-block> <conform-block> <conform-length> \
379 * <iroot-block> <iroot-length> <jroot-block> <jroot-length>
381 * If only the first line is present, this is the end of the chain.
383 static char magic[] = "plan 9 dump cd\n";
385 Cputdumpblock(Cdimg *cd)
389 Cwseek(cd, cd->nextblock*Blocksize);
391 Cwrite(cd, magic, sizeof(magic)-1);
402 for(i=16; i<24; i++) {
403 Creadblock(cd, buf, i, sizeof buf);
404 if(memcmp(buf, magic, sizeof(magic)-1) == 0)
411 readdumpdirs(Cdimg *cd, XDir *dir, char *(*cvt)(uchar*, int))
425 sysfatal("error in dump blocks");
427 Creadblock(cd, buf, db, sizeof buf);
428 if(memcmp(buf, magic, sizeof(magic)-1) != 0)
430 p = buf+sizeof(magic)-1;
433 if((q = strchr(p, '\n')) != nil)
436 nf = tokenize(p, f, nelem(f));
438 if(nf < i || (cvt==jolietstring && nf < i+2))
439 sysfatal("error in dump block %lud: nf=%d; p='%s'", db, nf, p);
440 nr = createdumpdir(&root, &xd, f[0]);
441 t = strtoul(f[1], 0, 0);
442 xd.mtime = xd.ctime = xd.atime = t;
443 db = strtoul(f[2], 0, 0);
444 if(cvt == jolietstring)
446 nr->block = strtoul(f[i], 0, 0);
447 nr->length = strtoul(f[i+1], 0, 0);
453 extern void addtx(char*, char*);
459 if(!isdigit((uchar)*s++))
465 readdumpconform(Cdimg *cd)
473 assert(map==nil || map->nt == 0);
477 sysfatal("error0 in dump blocks");
479 Creadblock(cd, buf, db, sizeof buf);
480 if(memcmp(buf, magic, sizeof(magic)-1) != 0)
482 p = buf+sizeof(magic)-1;
485 if((q = strchr(p, '\n')) != nil)
488 nf = tokenize(p, f, nelem(f));
490 sysfatal("error0 in dump block %lud", db);
492 db = strtoul(f[2], 0, 0);
493 cb = strtoul(f[3], 0, 0);
494 nc = strtoul(f[4], 0, 0);
496 Crseek(cd, cb*Blocksize);
498 while(Croffset(cd) < m && (p = Crdline(cd, '\n')) != nil){
499 p[Clinelen(cd)-1] = '\0';
500 if(tokenize(p, f, 2) != 2 || (f[0][0] != 'D' && f[0][0] != 'F')
501 || strlen(f[0]) != 7 || !isalldigit(f[0]+1))
504 addtx(atom(f[1]), atom(f[0]));
508 cd->nconform = map->nt;