plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

direc.c (4245B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 #include <libsec.h>
      5 
      6 #include "iso9660.h"
      7 
      8 void
      9 mkdirec(Direc *direc, XDir *d)
     10 {
     11 	memset(direc, 0, sizeof(Direc));
     12 	direc->name = atom(d->name);
     13 	direc->uid = atom(d->uid);
     14 	direc->gid = atom(d->gid);
     15 	direc->uidno = d->uidno;
     16 	direc->gidno = d->gidno;
     17 	direc->mode = d->mode;
     18 	direc->length = d->length;
     19 	direc->mtime = d->mtime;
     20 	direc->atime = d->atime;
     21 	direc->ctime = d->ctime;
     22 	direc->symlink = d->symlink;
     23 }
     24 
     25 static int
     26 strecmp(char *a, char *ea, char *b)
     27 {
     28 	int r;
     29 
     30 	if((r = strncmp(a, b, ea-a)) != 0)
     31 		return r;
     32 
     33 	if(b[ea-a] == '\0')
     34 		return 0;
     35 	return 1;
     36 }
     37 
     38 /*
     39  * Binary search a list of directories for the
     40  * entry with name name.
     41  * If no entry is found, return a pointer to
     42  * where a new such entry would go.
     43  */
     44 static Direc*
     45 dbsearch(char *name, int nname, Direc *d, int n)
     46 {
     47 	int i;
     48 
     49 	while(n > 0) {
     50 		i = strecmp(name, name+nname, d[n/2].name);
     51 		if(i < 0)
     52 			n = n/2;
     53 		else if(i > 0) {
     54 			d += n/2+1;
     55 			n -= (n/2+1);
     56 		} else
     57 			return &d[n/2];
     58 	}
     59 	return d;
     60 }
     61 
     62 /*
     63  * Walk to name, starting at d.
     64  */
     65 Direc*
     66 walkdirec(Direc *d, char *name)
     67 {
     68 	char *p, *nextp, *slashp;
     69 	Direc *nd;
     70 
     71 	for(p=name; p && *p; p=nextp) {
     72 		if((slashp = strchr(p, '/')) != nil)
     73 			nextp = slashp+1;
     74 		else
     75 			nextp = slashp = p+strlen(p);
     76 
     77 		nd = dbsearch(p, slashp-p, d->child, d->nchild);
     78 		if(nd >= d->child+d->nchild || strecmp(p, slashp, nd->name) != 0)
     79 			return nil;
     80 		d = nd;
     81 	}
     82 	return d;
     83 }
     84 
     85 /*
     86  * Add the file ``name'' with attributes d to the
     87  * directory ``root''.  Name may contain multiple
     88  * elements; all but the last must exist already.
     89  *
     90  * The child lists are kept sorted by utfname.
     91  */
     92 Direc*
     93 adddirec(Direc *root, char *name, XDir *d)
     94 {
     95 	char *p;
     96 	Direc *nd;
     97 	int off;
     98 
     99 	if(name[0] == '/')
    100 		name++;
    101 	if((p = strrchr(name, '/')) != nil) {
    102 		*p = '\0';
    103 		root = walkdirec(root, name);
    104 		if(root == nil) {
    105 			sysfatal("error in proto file: no entry for /%s but /%s/%s\n", name, name, p+1);
    106 			return nil;
    107 		}
    108 		*p = '/';
    109 		p++;
    110 	} else
    111 		p = name;
    112 
    113 	nd = dbsearch(p, strlen(p), root->child, root->nchild);
    114 	off = nd - root->child;
    115 	if(off < root->nchild && strcmp(nd->name, p) == 0) {
    116 		if ((d->mode & DMDIR) == 0)
    117 			fprint(2, "warning: proto lists %s twice\n", name);
    118 		return nil;
    119 	}
    120 
    121 	if(root->nchild%Ndirblock == 0) {
    122 		root->child = erealloc(root->child, (root->nchild+Ndirblock)*sizeof(Direc));
    123 		nd = root->child + off;
    124 	}
    125 
    126 	memmove(nd+1, nd, (root->nchild - off)*sizeof(Direc));
    127 	mkdirec(nd, d);
    128 	nd->name = atom(p);
    129 	root->nchild++;
    130 	return nd;
    131 }
    132 
    133 /*
    134  * Copy the tree src into dst.
    135  */
    136 void
    137 copydirec(Direc *dst, Direc *src)
    138 {
    139 	int i, n;
    140 
    141 	*dst = *src;
    142 
    143 	if((src->mode & DMDIR) == 0)
    144 		return;
    145 
    146 	n = (src->nchild + Ndirblock - 1);
    147 	n -= n%Ndirblock;
    148 	dst->child = emalloc(n*sizeof(Direc));
    149 
    150 	n = dst->nchild;
    151 	for(i=0; i<n; i++)
    152 		copydirec(&dst->child[i], &src->child[i]);
    153 }
    154 
    155 /*
    156  * Turn the Dbadname flag on for any entries
    157  * that have non-conforming names.
    158  */
    159 static void
    160 _checknames(Direc *d, int (*isbadname)(char*), int isroot)
    161 {
    162 	int i;
    163 
    164 	if(!isroot && isbadname(d->name))
    165 		d->flags |= Dbadname;
    166 
    167 	if(strcmp(d->name, "_conform.map") == 0)
    168 		d->flags |= Dbadname;
    169 
    170 	for(i=0; i<d->nchild; i++)
    171 		_checknames(&d->child[i], isbadname, 0);
    172 }
    173 
    174 void
    175 checknames(Direc *d, int (*isbadname)(char*))
    176 {
    177 	_checknames(d, isbadname, 1);
    178 }
    179 
    180 /*
    181  * Set the names to conform to 8.3
    182  * by changing them to numbers.
    183  * Plan 9 gets the right names from its
    184  * own directory entry.
    185  *
    186  * We used to write a _conform.map file to translate
    187  * names.  Joliet should take care of most of the
    188  * interoperability with other systems now.
    189  */
    190 void
    191 convertnames(Direc *d, char* (*cvt)(char*, char*))
    192 {
    193 	int i;
    194 	char new[1024];
    195 
    196 	if(d->flags & Dbadname)
    197 		cvt(new, conform(d->name, d->mode & DMDIR));
    198 	else
    199 		cvt(new, d->name);
    200 	d->confname = atom(new);
    201 
    202 	for(i=0; i<d->nchild; i++)
    203 		convertnames(&d->child[i], cvt);
    204 }
    205 
    206 /*
    207  * Sort a directory with a given comparison function.
    208  * After this is called on a tree, adddirec should not be,
    209  * since the entries may no longer be sorted as adddirec expects.
    210  */
    211 void
    212 dsort(Direc *d, int (*cmp)(const void*, const void*))
    213 {
    214 	int i, n;
    215 
    216 	n = d->nchild;
    217 	qsort(d->child, n, sizeof(d[0]), cmp);
    218 
    219 	for(i=0; i<n; i++)
    220 		dsort(&d->child[i], cmp);
    221 }