|  | #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); | 
|  | } | 
|  |  |