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*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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
40typedef 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
48int
49pathexists(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