1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1989-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Eduardo Krell <ekrell@adexus.cl>                   *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 
24 /*
25  * 3d file system library implementation
26  *
27  * debug trace levels are controlled by /#option/debug
28  * debug level n enables tracing for all levels less than or equal to n
29  *
30  *	level	trace
31  *	  0	no trace
32  *	  1	basic calls
33  *	  2	mounted fs
34  *	  3	fs control
35  *	  4	pathcanon
36  *	  5	pathreal
37  *	  6	pathnext
38  *	  7	*unused*
39  *	  8	*unused*
40  *	  9	*unused*
41  *	 10	getkey
42  */
43 
44 #include "3d.h"
45 
46 #include <cs.h>
47 
48 /*
49  * keep 3d tables from buf,siz in state.table.fd
50  * if force!=0 then state.table.fd set to TABLE_FD
51  * 0 returned if state.table.fd is ok
52  */
53 
54 int
keep(const char * buf,size_t siz,int force)55 keep(const char* buf, size_t siz, int force)
56 {
57 	int	n;
58 
59 	if (force && state.in_2d || siz > sizeof(state.table.buf))
60 	{
61 		if (state.table.fd > 0)
62 			cancel(&state.table.fd);
63 		return(-1);
64 	}
65 	if (state.table.fd > 0)
66 	{
67 		char	tmp[sizeof(state.table.buf)];
68 
69 		if (peek(state.table.fd, tmp, sizeof(tmp) - 1) == siz && !memcmp(tmp, buf, siz))
70 			return(0);
71 		cancel(&state.table.fd);
72 	}
73 #if _stream_peek || _socket_peek
74 	{
75 		int	fds[2];
76 
77 		state.in_2d++;
78 #if _socket_peek
79 		n = cspipe(&cs, fds);
80 #else
81 		n = pipe(fds);
82 #endif
83 		state.in_2d--;
84 		if (!n && fds[1] == TABLE_FD)
85 		{
86 #if _pipe_rw || _lib_socketpair
87 			fds[1] = fds[0];
88 			fds[0] = TABLE_FD;
89 #else
90 			CLOSE(fds[0]);
91 			state.in_2d++;
92 			n = pipe(fds);
93 			state.in_2d--;
94 			CLOSE(TABLE_FD);
95 #endif
96 		}
97 		if (!n)
98 		{
99 			if (fds[0] == TABLE_FD) state.table.fd = fds[0];
100 			else
101 			{
102 				if (force) CLOSE(TABLE_FD);
103 				state.table.fd = FCNTL(fds[0], F_DUPFD, TABLE_FD);
104 				CLOSE(fds[0]);
105 			}
106 			n = WRITE(fds[1], buf, siz) == siz;
107 			CLOSE(fds[1]);
108 			if (n)
109 			{
110 				state.table.size = siz;
111 				reserve(&state.table.fd);
112 				return(0);
113 			}
114 		}
115 	}
116 #else
117 	sfsprintf(state.path.name, sizeof(state.path.name), "/tmp/3D#%d", state.pid);
118 	if ((n = OPEN(state.path.name, O_CREAT, S_IRUSR|S_IRGRP|S_IROTH)) >= 0)
119 	{
120 		UNLINK(state.path.name);
121 		if (force) CLOSE(TABLE_FD);
122 		if (n == TABLE_FD) state.table.fd = TABLE_FD;
123 		else
124 		{
125 			state.table.fd = FCNTL(n, F_DUPFD, TABLE_FD);
126 			CLOSE(n);
127 		}
128 		if (WRITE(state.table.fd, buf, siz) == siz && !LSEEK(state.table.fd, 0L, 0))
129 		{
130 			state.table.size = siz;
131 			reserve(&state.table.fd);
132 			return(0);
133 		}
134 	}
135 #endif
136 	if (state.table.fd > 0)
137 		cancel(&state.table.fd);
138 	return(-1);
139 }
140 
141 /*
142  * enable/disable/test 3d/anno state
143  * allows state transitions without changing the tables
144  */
145 
146 int
fs3d(register int op)147 fs3d(register int op)
148 {
149 	register int	po;
150 	register int	n;
151 
152 	if ((n = FS3D_op(op)) == FS3D_OP_INIT || !state.pid)
153 		init(1, 0, 0);
154 	if (!state.in_2d)
155 		po = FS3D_ON;
156 	else if (state.limit != TABSIZE)
157 		po = FS3D_LIMIT(state.limit);
158 	else
159 		po = FS3D_OFF;
160 	switch (n)
161 	{
162 	case FS3D_OP_INIT:
163 	case FS3D_OP_TEST:
164 		break;
165 	case FS3D_OP_LIMIT:
166 		if ((n = FS3D_arg(op)) <= 0 || n > TABSIZE)
167 			n = TABSIZE;
168 		state.limit = n;
169 		state.in_2d = 0;
170 		break;
171 	case FS3D_OP_OFF:
172 		if (state.level > 0)
173 			po = -1;
174 		else
175 		{
176 			state.limit = TABSIZE;
177 			state.in_2d = 1;
178 		}
179 		break;
180 	case FS3D_OP_ON:
181 		state.limit = TABSIZE;
182 		state.in_2d = 0;
183 		break;
184 	default:
185 		po = -1;
186 		break;
187 	}
188 	message((-1, "fs3d(%d)=%d", op, po));
189 	return po;
190 }
191 
192 /*
193  * for code that includes <fs3d.h>
194  */
195 
196 int
fs3d_mount(const char * source,char * target,int flags,void * data)197 fs3d_mount(const char* source, char* target, int flags, void* data)
198 {
199 	return mount(source, target, flags, data, 0, 0);
200 }
201 
202 /*
203  * return 6 char lower case hash of key
204  * end is end of key string
205  * 0 returned at end of keys
206  * state.key.value is set to key value
207  * if `no<key>' then state.key.invert gets value and state.key.value=""
208  * otherwise state.key.invert=0
209  * state.key.next is set to next key if any
210  */
211 
212 unsigned long
getkey(register const char * key,register const char * end,int alt)213 getkey(register const char* key, register const char* end, int alt)
214 {
215 	register const char*	val;
216 	register unsigned long	x = 0;
217 	register int		invert;
218 	register int		c;
219 #if DEBUG
220 	const char*		beg;
221 #endif
222 
223 	if (key)
224 	{
225 #if DEBUG
226 		beg = key;
227 #endif
228 		if (key < end - 1 && *key == 'n' && *(key + 1) == 'o')
229 		{
230 			key += 2;
231 			invert = 1;
232 		}
233 		else invert = 0;
234 		if (key < end)
235 		{
236 			val = ((end - key) > HASHKEYMAX) ? key + HASHKEYMAX : end;
237 			while (key < end && (c = *key) != '=' && c != '/' && c != alt)
238 			{
239 				if (key < val)
240 					x = (c >= '0' && c <= '9') ? HASHKEYPART(x, HASHKEYN(c)) : HASHKEYPART(x, c);
241 				key++;
242 			}
243 			if (key < end && c == '=')
244 				key++;
245 		}
246 		if (key >= end || *key == '/' || *key == alt)
247 		{
248 			state.key.value = state.one;
249 			state.key.valsize = 1;
250 		}
251 		else
252 		{
253 			state.key.value = (char*)key;
254 			while (key < end && *key != '/' && *key != alt)
255 				key++;
256 			state.key.valsize = (char*)key - state.key.value;
257 		}
258 		while (key < end && (*key == '/' || *key == alt))
259 			key++;
260 		if (key < end && *key == '#' && *(key - 1) == '/')
261 			key++;
262 		if (invert)
263 		{
264 			state.key.invert = state.key.value;
265 			state.key.invertsize = state.key.valsize;
266 			state.key.value = state.null;
267 			state.key.valsize = 0;
268 		}
269 		else state.key.invert = 0;
270 		state.key.next = (key < end) ? (char*)key : (char*)0;
271 		message((-10, "getkey: key=%-*s hash=%x value=%-*s next=%-*s", end - beg, beg, x, state.key.valsize, state.key.value, state.key.next ? end - state.key.next : 6, state.key.next));
272 	}
273 	else state.key.next = 0;
274 	return(x);
275 }
276 
277 #if FS
278 
279 /*
280  * return mount pointer for path
281  * under is set to the part of the path under the mount
282  */
283 
284 Mount_t*
getmount(register const char * path,const char ** under)285 getmount(register const char* path, const char** under)
286 {
287 	register Map_t*	map;
288 	int		n;
289 	int		oerrno;
290 	struct stat	st;
291 
292 	if (!(map = search(&state.vmount, path, strlen(path), NiL, T_PREFIX)) || ((Mount_t*)map->val)->fs == state.fs)
293 		return(0);
294 	if (under)
295 	{
296 		if (*(path += map->keysize)) path++;
297 		else
298 		{
299 			oerrno = errno;
300 			n = !STAT(path - map->keysize, &st) && !S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode);
301 			errno = oerrno;
302 			if (n) return(0);
303 			else path = (const char*)state.dot;
304 		}
305 		*under = path;
306 	}
307 	return((Mount_t*)map->val);
308 }
309 
310 #endif
311 
312 int
nosys(void)313 nosys(void)
314 {
315 	errno = EINVAL;
316 	return(-1);
317 }
318 
319 /*
320  * copy t into s, return a pointer to the end of s ('\0')
321  */
322 
323 char*
strcopy(register char * s,register const char * t)324 strcopy(register char* s, register const char* t)
325 {
326 	if (!t) return(s);
327 	while (*s++ = *t++);
328 	return(--s);
329 }
330 
331 /*
332  * return map for <key,keysize> in tab
333  * if val!=0 then key=val inserted if not already entered
334  * valsize==0 causes string val to be malloc'd on insertion
335  * key is malloc'd on insertion if (valsize|T_ALLOCATE)
336  * valsize==T_DELETE for deletion
337  * valsize==T_PREFIX for longest path prefix search and val==visit_mask
338  */
339 
340 Map_t*
search(Table_t * tab,const char * key,int keysize,const char * val,int valsize)341 search(Table_t* tab, const char* key, int keysize, const char* val, int valsize)
342 {
343 	register Map_t*		lo;
344 	register Map_t*		mid;
345 	register Map_t*		hi;
346 	register const char*	sp;
347 	register const char*	se;
348 	register const char*	tp;
349 	register const char*	te;
350 	int			n;
351 	Map_t*			end;
352 
353 	se = key + keysize;
354 	lo = tab->table;
355 	end = lo + tab->size;
356 	if (valsize == T_PREFIX)
357 	{
358 		mid = 0;
359 		hi = end;
360 		while (lo < hi)
361 		{
362 			sp = key;
363 			tp = lo->key;
364 			te = tp + lo->keysize;
365 message((-12, "T_PREFIX: %-*s: key=%-*s mid=%-*s", keysize, key, lo->keysize, lo->key, mid ? mid->keysize : 1, mid ? mid->key : "-"));
366 			for (;;)
367 			{
368 				if (tp >= te)
369 				{
370 					if ((sp >= se || *sp == '/') && (!val || !(*((long*)val) & (1 << (lo - tab->table)))))
371 					{
372 						mid = lo;
373 						if (sp >= se)
374 							goto prefix;
375 					}
376 					break;
377 				}
378 				if (sp >= se || (n = *((unsigned char*)sp++) - *((unsigned char*)tp++)) < 0)
379 					goto prefix;
380 				if (n > 0)
381 				{
382 					if (mid && mid->keysize >= (sp - key))
383 						goto prefix;
384 					break;
385 				}
386 			}
387 			lo++;
388 		}
389 	prefix:
390 		if (mid && val) *((long*)val) |= (1 << (mid - tab->table));
391 		return(mid);
392 	}
393 	if (end > lo)
394 	{
395 		hi = end - 1;
396 		while (lo <= hi)
397 		{
398 			mid = lo + (hi - lo) / 2;
399 			sp = key;
400 			tp = mid->key;
401 			te = tp + mid->keysize;
402 			for (;;)
403 			{
404 				if (tp >= te)
405 				{
406 					if (sp >= se)
407 					{
408 						if (valsize != T_DELETE)
409 							return(mid);
410 						if (mid->valsize & T_ALLOCATE)
411 							free(mid->key);
412 #if FS
413 						if ((mid->valsize & T_SIZE) == T_MOUNT)
414 							((Mount_t*)mid->val)->fs = 0;
415 						else
416 #endif
417 						if (!(mid->valsize & T_SIZE))
418 							free(mid->val);
419 						for (; mid < end; mid++)
420 							*mid = *(mid + 1);
421 						tab->size--;
422 						return(0);
423 					}
424 					lo = mid + 1;
425 					break;
426 				}
427 				if (sp >= se || (n = *((unsigned char*)sp++) - *((unsigned char*)tp++)) < 0)
428 				{
429 					hi = mid - 1;
430 					break;
431 				}
432 				if (n > 0)
433 				{
434 					lo = mid + 1;
435 					break;
436 				}
437 			}
438 		}
439 	}
440 	if (!val || valsize == T_DELETE || tab->size >= elementsof(tab->table))
441 		return(0);
442 	tab->size++;
443 	for (hi = end; hi > lo; hi--)
444 		*hi = *(hi - 1);
445 	lo->keysize = keysize;
446 	if (valsize & T_ALLOCATE) lo->key = strcpy(newof(0, char, keysize, 1), key);
447 	else lo->key = (char*)key;
448 	if ((lo->valsize = valsize) & T_SIZE) lo->val = (char*)val;
449 	else lo->val = strcpy(newof(0, char, strlen(val), 1), val);
450 	return(lo);
451 }
452 
453 /*
454  * iterate fun over tab
455  * terminates on first negative return from fun
456  */
457 
458 int
iterate(register Table_t * tab,int (* fun)(Map_t *,char *,int),register char * buf,int flags)459 iterate(register Table_t* tab, int (*fun)(Map_t*, char*, int), register char* buf, int flags)
460 {
461 	register Map_t*	cp;
462 	register Map_t*	ep;
463 	register int	n;
464 	register int	sum;
465 
466 	sum = 0;
467 	for (ep = (cp = tab->table) + tab->size; cp < ep; cp++)
468 	{
469 		if ((n = (*fun)(cp, buf, flags)) < 0)
470 			return(0);
471 		if (buf) buf += n;
472 		sum += n;
473 	}
474 	return(sum);
475 }
476 
477 #if FS
478 
479 /*
480  * initialize open file info
481  */
482 
483 int
fileinit(int fd,struct stat * st,Mount_t * mp,int force)484 fileinit(int fd, struct stat* st, Mount_t* mp, int force)
485 {
486 	register File_t*	f;
487 	int			ffd;
488 	int			ffl;
489 	struct stat		sb;
490 
491 	f = state.file + fd;
492 	if (!force && (f->flags & FILE_ERROR) || !st && FSTAT(fd, st = &sb) || (ffd = FCNTL(fd, F_GETFD, NiL)) == -1 || (ffl = FCNTL(fd, F_GETFL, NiL)) == -1)
493 	{
494 		f->flags = FILE_ERROR;
495 		return -1;
496 	}
497 	f->oflag = ffl;
498 	f->open = 0;
499 	f->flags = FILE_OPEN;
500 	if (S_ISREG(st->st_mode))
501 		f->flags |= FILE_REGULAR;
502 	if (ffd & FD_CLOEXEC)
503 		f->flags |= FILE_CLOEXEC;
504 	if ((ffl & O_ACCMODE) != O_RDONLY)
505 		f->flags |= FILE_WRITE;
506 	f->id.fid[0] = st->st_ino;
507 	f->id.fid[1] = st->st_dev;
508 	if ((f->mount = mp) && fd > state.cache)
509 		state.cache = fd;
510 	if (fd > state.open)
511 		state.open = fd;
512 	return 0;
513 }
514 
515 #endif
516