xref: /plan9/sys/src/cmd/disk/9660/direc.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <libsec.h>
5 
6 #include "iso9660.h"
7 
8 void
mkdirec(Direc * direc,XDir * d)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
strecmp(char * a,char * ea,char * b)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*
dbsearch(char * name,int nname,Direc * d,int n)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*
walkdirec(Direc * d,char * name)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*
adddirec(Direc * root,char * name,XDir * d)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", 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
copydirec(Direc * dst,Direc * src)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
_checknames(Direc * d,int (* isbadname)(char *),int isroot)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
checknames(Direc * d,int (* isbadname)(char *))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
convertnames(Direc * d,char * (* cvt)(char *,char *))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
dsort(Direc * d,int (* cmp)(const void *,const 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 }
222 
223