ref: dde3628d54073e0569bf565e6ec861e42cfa35f6
dir: /sys/src/cmd/disk/9660/direc.c/
#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", name, name, p+1); *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); }