Dump9660 (and mk9660). Until we either do something
intelligent with symlinks or put in a switch for things like dump9660, this is of rather limited utility under Unix.
This commit is contained in:
parent
e1dddc0532
commit
7285a491c1
20 changed files with 4375 additions and 0 deletions
511
src/cmd/9660/dump.c
Normal file
511
src/cmd/9660/dump.c
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <libsec.h>
|
||||
#include <ctype.h>
|
||||
#include "iso9660.h"
|
||||
|
||||
static void
|
||||
md5cd(Cdimg *cd, ulong block, ulong length, uchar *digest)
|
||||
{
|
||||
int n;
|
||||
uchar buf[Blocksize];
|
||||
DigestState *s;
|
||||
|
||||
s = md5(nil, 0, nil, nil);
|
||||
while(length > 0) {
|
||||
n = length;
|
||||
if(n > Blocksize)
|
||||
n = Blocksize;
|
||||
|
||||
Creadblock(cd, buf, block, n);
|
||||
|
||||
md5(buf, n, nil, s);
|
||||
|
||||
block++;
|
||||
length -= n;
|
||||
}
|
||||
md5(nil, 0, digest, s);
|
||||
}
|
||||
|
||||
static Dumpdir*
|
||||
mkdumpdir(char *name, uchar *md5, ulong block, ulong length)
|
||||
{
|
||||
Dumpdir *d;
|
||||
|
||||
assert(block != 0);
|
||||
|
||||
d = emalloc(sizeof *d);
|
||||
d->name = name;
|
||||
memmove(d->md5, md5, sizeof d->md5);
|
||||
d->block = block;
|
||||
d->length = length;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static Dumpdir**
|
||||
ltreewalkmd5(Dumpdir **l, uchar *md5)
|
||||
{
|
||||
int i;
|
||||
|
||||
while(*l) {
|
||||
i = memcmp(md5, (*l)->md5, MD5dlen);
|
||||
if(i < 0)
|
||||
l = &(*l)->md5left;
|
||||
else if(i == 0)
|
||||
return l;
|
||||
else
|
||||
l = &(*l)->md5right;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
static Dumpdir**
|
||||
ltreewalkblock(Dumpdir **l, ulong block)
|
||||
{
|
||||
while(*l) {
|
||||
if(block < (*l)->block)
|
||||
l = &(*l)->blockleft;
|
||||
else if(block == (*l)->block)
|
||||
return l;
|
||||
else
|
||||
l = &(*l)->blockright;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a particular file to our binary tree.
|
||||
*/
|
||||
static void
|
||||
addfile(Cdimg *cd, Dump *d, char *name, Direc *dir)
|
||||
{
|
||||
uchar md5[MD5dlen];
|
||||
Dumpdir **lblock;
|
||||
|
||||
assert((dir->mode & DMDIR) == 0);
|
||||
|
||||
if(dir->length == 0)
|
||||
return;
|
||||
|
||||
lblock = ltreewalkblock(&d->blockroot, dir->block);
|
||||
if(*lblock != nil) {
|
||||
if((*lblock)->length == dir->length)
|
||||
return;
|
||||
fprint(2, "block %lud length %lud %s %lud %s\n", dir->block, (*lblock)->length, (*lblock)->name,
|
||||
dir->length, dir->name);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
md5cd(cd, dir->block, dir->length, md5);
|
||||
if(chatty > 1)
|
||||
fprint(2, "note file %.16H %lud (%s)\n", md5, dir->length, dir->name);
|
||||
insertmd5(d, name, md5, dir->block, dir->length);
|
||||
}
|
||||
|
||||
void
|
||||
insertmd5(Dump *d, char *name, uchar *md5, ulong block, ulong length)
|
||||
{
|
||||
Dumpdir **lmd5;
|
||||
Dumpdir **lblock;
|
||||
|
||||
lblock = ltreewalkblock(&d->blockroot, block);
|
||||
if(*lblock != nil) {
|
||||
if((*lblock)->length == length)
|
||||
return;
|
||||
fprint(2, "block %lud length %lud %lud\n", block, (*lblock)->length, length);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
assert(length != 0);
|
||||
*lblock = mkdumpdir(name, md5, block, length);
|
||||
|
||||
lmd5 = ltreewalkmd5(&d->md5root, md5);
|
||||
if(*lmd5 != nil)
|
||||
fprint(2, "warning: data duplicated on CD\n");
|
||||
else
|
||||
*lmd5 = *lblock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill all the children entries for a particular directory;
|
||||
* all we care about is block, length, and whether it is a directory.
|
||||
*/
|
||||
void
|
||||
readkids(Cdimg *cd, Direc *dir, char *(*cvt)(uchar*, int))
|
||||
{
|
||||
char *dot, *dotdot;
|
||||
int m, n;
|
||||
uchar buf[Blocksize], *ebuf, *p;
|
||||
ulong b, nb;
|
||||
Cdir *c;
|
||||
Direc dx;
|
||||
|
||||
assert(dir->mode & DMDIR);
|
||||
|
||||
dot = atom(".");
|
||||
dotdot = atom("..");
|
||||
ebuf = buf+Blocksize;
|
||||
nb = (dir->length+Blocksize-1) / Blocksize;
|
||||
|
||||
n = 0;
|
||||
for(b=0; b<nb; b++) {
|
||||
Creadblock(cd, buf, dir->block + b, Blocksize);
|
||||
p = buf;
|
||||
while(p < ebuf) {
|
||||
c = (Cdir*)p;
|
||||
if(c->len == 0)
|
||||
break;
|
||||
if(p+c->len > ebuf)
|
||||
break;
|
||||
if(parsedir(cd, &dx, p, ebuf-p, cvt) == 0 && dx.name != dot && dx.name != dotdot)
|
||||
n++;
|
||||
p += c->len;
|
||||
}
|
||||
}
|
||||
|
||||
m = (n+Ndirblock-1)/Ndirblock * Ndirblock;
|
||||
dir->child = emalloc(m*sizeof dir->child[0]);
|
||||
dir->nchild = n;
|
||||
|
||||
n = 0;
|
||||
for(b=0; b<nb; b++) {
|
||||
assert(n <= dir->nchild);
|
||||
Creadblock(cd, buf, dir->block + b, Blocksize);
|
||||
p = buf;
|
||||
while(p < ebuf) {
|
||||
c = (Cdir*)p;
|
||||
if(c->len == 0)
|
||||
break;
|
||||
if(p+c->len > ebuf)
|
||||
break;
|
||||
if(parsedir(cd, &dx, p, ebuf-p, cvt) == 0 && dx.name != dot && dx.name != dotdot) {
|
||||
assert(n < dir->nchild);
|
||||
dir->child[n++] = dx;
|
||||
}
|
||||
p += c->len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the children. Make sure their children are free too.
|
||||
*/
|
||||
void
|
||||
freekids(Direc *dir)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<dir->nchild; i++)
|
||||
assert(dir->child[i].nchild == 0);
|
||||
|
||||
free(dir->child);
|
||||
dir->child = nil;
|
||||
dir->nchild = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a whole directory and all its children to our binary tree.
|
||||
*/
|
||||
static void
|
||||
adddir(Cdimg *cd, Dump *d, Direc *dir)
|
||||
{
|
||||
int i;
|
||||
|
||||
readkids(cd, dir, isostring);
|
||||
for(i=0; i<dir->nchild; i++) {
|
||||
if(dir->child[i].mode & DMDIR)
|
||||
adddir(cd, d, &dir->child[i]);
|
||||
else
|
||||
addfile(cd, d, atom(dir->name), &dir->child[i]);
|
||||
}
|
||||
freekids(dir);
|
||||
}
|
||||
|
||||
Dumpdir*
|
||||
lookupmd5(Dump *d, uchar *md5)
|
||||
{
|
||||
return *ltreewalkmd5(&d->md5root, md5);
|
||||
}
|
||||
|
||||
void
|
||||
adddirx(Cdimg *cd, Dump *d, Direc *dir, int lev)
|
||||
{
|
||||
int i;
|
||||
Direc dd;
|
||||
|
||||
if(lev == 2){
|
||||
dd = *dir;
|
||||
adddir(cd, d, &dd);
|
||||
return;
|
||||
}
|
||||
for(i=0; i<dir->nchild; i++)
|
||||
adddirx(cd, d, &dir->child[i], lev+1);
|
||||
}
|
||||
|
||||
Dump*
|
||||
dumpcd(Cdimg *cd, Direc *dir)
|
||||
{
|
||||
Dump *d;
|
||||
|
||||
d = emalloc(sizeof *d);
|
||||
d->cd = cd;
|
||||
adddirx(cd, d, dir, 0);
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
static ulong
|
||||
minblock(Direc *root, int lev)
|
||||
{
|
||||
int i;
|
||||
ulong m, n;
|
||||
|
||||
m = root->block;
|
||||
for(i=0; i<root->nchild; i++) {
|
||||
n = minblock(&root->child[i], lev-1);
|
||||
if(m > n)
|
||||
m = n;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
*/
|
||||
|
||||
void
|
||||
copybutname(Direc *d, Direc *s)
|
||||
{
|
||||
Direc x;
|
||||
|
||||
x = *d;
|
||||
*d = *s;
|
||||
d->name = x.name;
|
||||
d->confname = x.confname;
|
||||
}
|
||||
|
||||
Direc*
|
||||
createdumpdir(Direc *root, XDir *dir, char *utfname)
|
||||
{
|
||||
char *p;
|
||||
Direc *d;
|
||||
|
||||
if(utfname[0]=='/')
|
||||
sysfatal("bad dump name '%s'", utfname);
|
||||
p = strchr(utfname, '/');
|
||||
if(p == nil || strchr(p+1, '/'))
|
||||
sysfatal("bad dump name '%s'", utfname);
|
||||
*p++ = '\0';
|
||||
if((d = walkdirec(root, utfname)) == nil)
|
||||
d = adddirec(root, utfname, dir);
|
||||
if(walkdirec(d, p))
|
||||
sysfatal("duplicate dump name '%s/%s'", utfname, p);
|
||||
d = adddirec(d, p, dir);
|
||||
return d;
|
||||
}
|
||||
|
||||
static void
|
||||
rmdirec(Direc *d, Direc *kid)
|
||||
{
|
||||
Direc *ekid;
|
||||
|
||||
ekid = d->child+d->nchild;
|
||||
assert(d->child <= kid && kid < ekid);
|
||||
if(ekid != kid+1)
|
||||
memmove(kid, kid+1, (ekid-(kid+1))*sizeof(*kid));
|
||||
d->nchild--;
|
||||
}
|
||||
|
||||
void
|
||||
rmdumpdir(Direc *root, char *utfname)
|
||||
{
|
||||
char *p;
|
||||
Direc *d, *dd;
|
||||
|
||||
if(utfname[0]=='/')
|
||||
sysfatal("bad dump name '%s'", utfname);
|
||||
p = strchr(utfname, '/');
|
||||
if(p == nil || strchr(p+1, '/'))
|
||||
sysfatal("bad dump name '%s'", utfname);
|
||||
*p++ = '\0';
|
||||
if((d = walkdirec(root, utfname)) == nil)
|
||||
sysfatal("cannot remove %s/%s: %s does not exist", utfname, p, utfname);
|
||||
p[-1] = '/';
|
||||
|
||||
if((dd = walkdirec(d, p)) == nil)
|
||||
sysfatal("cannot remove %s: does not exist", utfname);
|
||||
|
||||
rmdirec(d, dd);
|
||||
if(d->nchild == 0)
|
||||
rmdirec(root, d);
|
||||
}
|
||||
|
||||
char*
|
||||
adddumpdir(Direc *root, ulong now, XDir *dir)
|
||||
{
|
||||
char buf[40], *p;
|
||||
int n;
|
||||
Direc *dday, *dyear;
|
||||
Tm tm;
|
||||
|
||||
tm = *localtime(now);
|
||||
|
||||
sprint(buf, "%d", tm.year+1900);
|
||||
if((dyear = walkdirec(root, buf)) == nil) {
|
||||
dyear = adddirec(root, buf, dir);
|
||||
assert(dyear != nil);
|
||||
}
|
||||
|
||||
n = 0;
|
||||
sprint(buf, "%.2d%.2d", tm.mon+1, tm.mday);
|
||||
p = buf+strlen(buf);
|
||||
while(walkdirec(dyear, buf))
|
||||
sprint(p, "%d", ++n);
|
||||
|
||||
dday = adddirec(dyear, buf, dir);
|
||||
assert(dday != nil);
|
||||
|
||||
sprint(buf, "%s/%s", dyear->name, dday->name);
|
||||
assert(walkdirec(root, buf)==dday);
|
||||
return atom(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* The dump directory tree is inferred from a linked list of special blocks.
|
||||
* One block is written at the end of each dump.
|
||||
* The blocks have the form
|
||||
*
|
||||
* plan 9 dump cd
|
||||
* <dump-name> <dump-time> <next-block> <conform-block> <conform-length> \
|
||||
* <iroot-block> <iroot-length> <jroot-block> <jroot-length>
|
||||
*
|
||||
* If only the first line is present, this is the end of the chain.
|
||||
*/
|
||||
static char magic[] = "plan 9 dump cd\n";
|
||||
ulong
|
||||
Cputdumpblock(Cdimg *cd)
|
||||
{
|
||||
ulong x;
|
||||
|
||||
Cwseek(cd, cd->nextblock*Blocksize);
|
||||
x = Cwoffset(cd);
|
||||
Cwrite(cd, magic, sizeof(magic)-1);
|
||||
Cpadblock(cd);
|
||||
return x/Blocksize;
|
||||
}
|
||||
|
||||
int
|
||||
hasdump(Cdimg *cd)
|
||||
{
|
||||
int i;
|
||||
char buf[128];
|
||||
|
||||
for(i=16; i<24; i++) {
|
||||
Creadblock(cd, buf, i, sizeof buf);
|
||||
if(memcmp(buf, magic, sizeof(magic)-1) == 0)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Direc
|
||||
readdumpdirs(Cdimg *cd, XDir *dir, char *(*cvt)(uchar*, int))
|
||||
{
|
||||
char buf[Blocksize];
|
||||
char *p, *q, *f[16];
|
||||
int i, nf;
|
||||
ulong db, t;
|
||||
Direc *nr, root;
|
||||
XDir xd;
|
||||
|
||||
mkdirec(&root, dir);
|
||||
db = hasdump(cd);
|
||||
xd = *dir;
|
||||
for(;;){
|
||||
if(db == 0)
|
||||
sysfatal("error in dump blocks");
|
||||
|
||||
Creadblock(cd, buf, db, sizeof buf);
|
||||
if(memcmp(buf, magic, sizeof(magic)-1) != 0)
|
||||
break;
|
||||
p = buf+sizeof(magic)-1;
|
||||
if(p[0] == '\0')
|
||||
break;
|
||||
if((q = strchr(p, '\n')) != nil)
|
||||
*q = '\0';
|
||||
|
||||
nf = tokenize(p, f, nelem(f));
|
||||
i = 5;
|
||||
if(nf < i || (cvt==jolietstring && nf < i+2))
|
||||
sysfatal("error in dump block %lud: nf=%d; p='%s'", db, nf, p);
|
||||
nr = createdumpdir(&root, &xd, f[0]);
|
||||
t = strtoul(f[1], 0, 0);
|
||||
xd.mtime = xd.ctime = xd.atime = t;
|
||||
db = strtoul(f[2], 0, 0);
|
||||
if(cvt == jolietstring)
|
||||
i += 2;
|
||||
nr->block = strtoul(f[i], 0, 0);
|
||||
nr->length = strtoul(f[i+1], 0, 0);
|
||||
}
|
||||
cd->nulldump = db;
|
||||
return root;
|
||||
}
|
||||
|
||||
extern void addtx(char*, char*);
|
||||
|
||||
static int
|
||||
isalldigit(char *s)
|
||||
{
|
||||
while(*s)
|
||||
if(!isdigit(*s++))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
readdumpconform(Cdimg *cd)
|
||||
{
|
||||
char buf[Blocksize];
|
||||
char *p, *q, *f[10];
|
||||
ulong cb, nc, m, db;
|
||||
int nf;
|
||||
|
||||
db = hasdump(cd);
|
||||
assert(map==nil || map->nt == 0);
|
||||
|
||||
for(;;){
|
||||
if(db == 0)
|
||||
sysfatal("error0 in dump blocks");
|
||||
|
||||
Creadblock(cd, buf, db, sizeof buf);
|
||||
if(memcmp(buf, magic, sizeof(magic)-1) != 0)
|
||||
break;
|
||||
p = buf+sizeof(magic)-1;
|
||||
if(p[0] == '\0')
|
||||
break;
|
||||
if((q = strchr(p, '\n')) != nil)
|
||||
*q = '\0';
|
||||
|
||||
nf = tokenize(p, f, nelem(f));
|
||||
if(nf < 5)
|
||||
sysfatal("error0 in dump block %lud", db);
|
||||
|
||||
db = strtoul(f[2], 0, 0);
|
||||
cb = strtoul(f[3], 0, 0);
|
||||
nc = strtoul(f[4], 0, 0);
|
||||
|
||||
Crseek(cd, cb*Blocksize);
|
||||
m = cb*Blocksize+nc;
|
||||
while(Croffset(cd) < m && (p = Crdline(cd, '\n')) != nil){
|
||||
p[Clinelen(cd)-1] = '\0';
|
||||
if(tokenize(p, f, 2) != 2 || (f[0][0] != 'D' && f[0][0] != 'F')
|
||||
|| strlen(f[0]) != 7 || !isalldigit(f[0]+1))
|
||||
break;
|
||||
|
||||
addtx(atom(f[1]), atom(f[0]));
|
||||
}
|
||||
}
|
||||
if(map)
|
||||
cd->nconform = map->nt;
|
||||
else
|
||||
cd->nconform = 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue