Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

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