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