223 lines
4.1 KiB
C
223 lines
4.1 KiB
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\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);
|
||
|
|
}
|
||
|
|
|