diff options
author | wkj <devnull@localhost> | 2004-06-17 01:47:21 +0000 |
---|---|---|
committer | wkj <devnull@localhost> | 2004-06-17 01:47:21 +0000 |
commit | 7285a491c1ce1e630a0751b1011fd33e6b17234b (patch) | |
tree | b2b2e24e333fa4660325a35f6c0f1d333e50e797 /src/cmd/9660/direc.c | |
parent | e1dddc053287874e82e2b67f95ccee7d7bc63e22 (diff) | |
download | plan9port-7285a491c1ce1e630a0751b1011fd33e6b17234b.tar.gz plan9port-7285a491c1ce1e630a0751b1011fd33e6b17234b.tar.bz2 plan9port-7285a491c1ce1e630a0751b1011fd33e6b17234b.zip |
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.
Diffstat (limited to 'src/cmd/9660/direc.c')
-rw-r--r-- | src/cmd/9660/direc.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/cmd/9660/direc.c b/src/cmd/9660/direc.c new file mode 100644 index 00000000..8185f680 --- /dev/null +++ b/src/cmd/9660/direc.c @@ -0,0 +1,222 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <libsec.h> + +#include "iso9660.h" + +void +mkdirec(Direc *direc, XDir *d) +{ + memset(direc, 0, sizeof(Direc)); + direc->name = atom(d->name); + direc->uid = atom(d->uid); + direc->gid = atom(d->gid); + direc->uidno = d->uidno; + direc->gidno = d->gidno; + direc->mode = d->mode; + direc->length = d->length; + direc->mtime = d->mtime; + direc->atime = d->atime; + direc->ctime = d->ctime; + direc->symlink = d->symlink; +} + +static int +strecmp(char *a, char *ea, char *b) +{ + int r; + + if((r = strncmp(a, b, ea-a)) != 0) + return r; + + if(b[ea-a] == '\0') + return 0; + return 1; +} + +/* + * Binary search a list of directories for the + * entry with name name. + * If no entry is found, return a pointer to + * where a new such entry would go. + */ +static Direc* +dbsearch(char *name, int nname, Direc *d, int n) +{ + int i; + + while(n > 0) { + i = strecmp(name, name+nname, d[n/2].name); + if(i < 0) + n = n/2; + else if(i > 0) { + d += n/2+1; + n -= (n/2+1); + } else + return &d[n/2]; + } + return d; +} + +/* + * Walk to name, starting at d. + */ +Direc* +walkdirec(Direc *d, char *name) +{ + char *p, *nextp, *slashp; + Direc *nd; + + for(p=name; p && *p; p=nextp) { + if((slashp = strchr(p, '/')) != nil) + nextp = slashp+1; + else + nextp = slashp = p+strlen(p); + + nd = dbsearch(p, slashp-p, d->child, d->nchild); + if(nd >= d->child+d->nchild || strecmp(p, slashp, nd->name) != 0) + return nil; + d = nd; + } + return d; +} + +/* + * Add the file ``name'' with attributes d to the + * directory ``root''. Name may contain multiple + * elements; all but the last must exist already. + * + * The child lists are kept sorted by utfname. + */ +Direc* +adddirec(Direc *root, char *name, XDir *d) +{ + char *p; + Direc *nd; + int off; + + if(name[0] == '/') + name++; + if((p = strrchr(name, '/')) != nil) { + *p = '\0'; + root = walkdirec(root, name); + if(root == nil) { + sysfatal("error in proto file: no entry for /%s but /%s/%s\n", name, name, p+1); + return nil; + } + *p = '/'; + p++; + } else + p = name; + + nd = dbsearch(p, strlen(p), root->child, root->nchild); + off = nd - root->child; + if(off < root->nchild && strcmp(nd->name, p) == 0) { + if ((d->mode & DMDIR) == 0) + fprint(2, "warning: proto lists %s twice\n", name); + return nil; + } + + if(root->nchild%Ndirblock == 0) { + root->child = erealloc(root->child, (root->nchild+Ndirblock)*sizeof(Direc)); + nd = root->child + off; + } + + memmove(nd+1, nd, (root->nchild - off)*sizeof(Direc)); + mkdirec(nd, d); + nd->name = atom(p); + root->nchild++; + return nd; +} + +/* + * Copy the tree src into dst. + */ +void +copydirec(Direc *dst, Direc *src) +{ + int i, n; + + *dst = *src; + + if((src->mode & DMDIR) == 0) + return; + + n = (src->nchild + Ndirblock - 1); + n -= n%Ndirblock; + dst->child = emalloc(n*sizeof(Direc)); + + n = dst->nchild; + for(i=0; i<n; i++) + copydirec(&dst->child[i], &src->child[i]); +} + +/* + * Turn the Dbadname flag on for any entries + * that have non-conforming names. + */ +static void +_checknames(Direc *d, int (*isbadname)(char*), int isroot) +{ + int i; + + if(!isroot && isbadname(d->name)) + d->flags |= Dbadname; + + if(strcmp(d->name, "_conform.map") == 0) + d->flags |= Dbadname; + + for(i=0; i<d->nchild; i++) + _checknames(&d->child[i], isbadname, 0); +} + +void +checknames(Direc *d, int (*isbadname)(char*)) +{ + _checknames(d, isbadname, 1); +} + +/* + * Set the names to conform to 8.3 + * by changing them to numbers. + * Plan 9 gets the right names from its + * own directory entry. + * + * We used to write a _conform.map file to translate + * names. Joliet should take care of most of the + * interoperability with other systems now. + */ +void +convertnames(Direc *d, char* (*cvt)(char*, char*)) +{ + int i; + char new[1024]; + + if(d->flags & Dbadname) + cvt(new, conform(d->name, d->mode & DMDIR)); + else + cvt(new, d->name); + d->confname = atom(new); + + for(i=0; i<d->nchild; i++) + convertnames(&d->child[i], cvt); +} + +/* + * Sort a directory with a given comparison function. + * After this is called on a tree, adddirec should not be, + * since the entries may no longer be sorted as adddirec expects. + */ +void +dsort(Direc *d, int (*cmp)(const void*, const void*)) +{ + int i, n; + + n = d->nchild; + qsort(d->child, n, sizeof(d[0]), cmp); + + for(i=0; i<n; i++) + dsort(&d->child[i], cmp); +} + |