1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-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 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24  * Glenn Fowler
25  * AT&T Research
26  *
27  * return 1 if path exisis
28  * maintains a cache to minimize stat(2) calls
29  * path is modified in-place but restored on return
30  * path components checked in pairs to cut stat()'s
31  * in half by checking ENOTDIR vs. ENOENT
32  * case ignorance infection unavoidable here
33  */
34 
35 #include "lclib.h"
36 
37 #include <ls.h>
38 #include <error.h>
39 
40 typedef struct Tree_s
41 {
42 	struct Tree_s*	next;
43 	struct Tree_s*	tree;
44 	int		mode;
45 	char		name[1];
46 } Tree_t;
47 
48 int
pathexists(char * path,int mode)49 pathexists(char* path, int mode)
50 {
51 	register char*		s;
52 	register char*		e;
53 	register Tree_t*	p;
54 	register Tree_t*	t;
55 	register int		c;
56 	char*			ee;
57 	int			cc;
58 	int			x;
59 	struct stat		st;
60 	int			(*cmp)(const char*, const char*);
61 
62 	static Tree_t		tree;
63 
64 	t = &tree;
65 	e = (c = *path) == '/' ? path + 1 : path;
66 	cmp = strchr(astconf("PATH_ATTRIBUTES", path, NiL), 'c') ? strcasecmp : strcmp;
67 	if ((ast.locale.set & (AST_LC_debug|AST_LC_find)) == (AST_LC_debug|AST_LC_find))
68 		sfprintf(sfstderr, "locale test %s\n", path);
69 	while (c)
70 	{
71 		p = t;
72 		for (s = e; *e && *e != '/'; e++);
73 		c = *e;
74 		*e = 0;
75 		for (t = p->tree; t && (*cmp)(s, t->name); t = t->next);
76 		if (!t)
77 		{
78 			if (!(t = newof(0, Tree_t, 1, strlen(s))))
79 			{
80 				*e = c;
81 				return 0;
82 			}
83 			strcpy(t->name, s);
84 			t->next = p->tree;
85 			p->tree = t;
86 			if (c)
87 			{
88 				*e = c;
89 				for (s = ee = e + 1; *ee && *ee != '/'; ee++);
90 				cc = *ee;
91 				*ee = 0;
92 			}
93 			else
94 				ee = 0;
95 			if ((ast.locale.set & (AST_LC_debug|AST_LC_find)) == (AST_LC_debug|AST_LC_find))
96 				sfprintf(sfstderr, "locale stat %s\n", path);
97 			x = stat(path, &st);
98 			if (ee)
99 			{
100 				e = ee;
101 				c = cc;
102 				if (!x || errno == ENOENT)
103 					t->mode = PATH_READ|PATH_EXECUTE;
104 				if (!(p = newof(0, Tree_t, 1, strlen(s))))
105 				{
106 					*e = c;
107 					return 0;
108 				}
109 				strcpy(p->name, s);
110 				p->next = t->tree;
111 				t->tree = p;
112 				t = p;
113 			}
114 			if (x)
115 			{
116 				*e = c;
117 				return 0;
118 			}
119 			if (st.st_mode & (S_IRUSR|S_IRGRP|S_IROTH))
120 				t->mode |= PATH_READ;
121 			if (st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
122 				t->mode |= PATH_WRITE;
123 			if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
124 				t->mode |= PATH_EXECUTE;
125 			if (!S_ISDIR(st.st_mode))
126 				t->mode |= PATH_REGULAR;
127 		}
128 		*e++ = c;
129 		if (!t->mode || c && (t->mode & PATH_REGULAR))
130 			return 0;
131 	}
132 	mode &= (PATH_READ|PATH_WRITE|PATH_EXECUTE|PATH_REGULAR);
133 	return (t->mode & mode) == mode;
134 }
135