pathexists.c   [plain text]


#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * return 1 if path exisis
 * maintains a cache to minimize stat(2) calls
 * path is modified in-place but restored on return
 * path components checked in pairs to cut stat()'s
 * in half by checking ENOTDIR vs. ENOENT
 */

#include <ast.h>
#include <error.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
/* #include "lclib.h" */
/* #include <ls.h> */

typedef struct Tree_s
{
	struct Tree_s*	next;
	struct Tree_s*	tree;
	int		mode;
	char		name[1];
} Tree_t;

int
pathexists(char* path, int mode)
{
	register char*		s;
	register char*		e;
	register Tree_t*	p;
	register Tree_t*	t;
	register int		c;
	char*			ee;
	int			cc = 0;
	int			x;
	struct stat		st;

	static Tree_t		tree;

	t = &tree;
	e = path + 1;
	c = *path;
	while (c)
	{
		p = t;
		for (s = e; *e && *e != '/'; e++);
		c = *e;
		*e = 0;
		for (t = p->tree; t && !streq(s, t->name); t = t->next);
		if (!t)
		{
			if (!(t = newof(0, Tree_t, 1, strlen(s))))
			{
				*e = c;
				return 0;
			}
			strcpy(t->name, s);
			t->next = p->tree;
			p->tree = t;
			if (c)
			{
				*e = c;
				for (s = ee = e + 1; *ee && *ee != '/'; ee++);
				cc = *ee;
				*ee = 0;
			}
			else
				ee = 0;
			x = stat(path, &st);
			if (ee)
			{
				e = ee;
				c = cc;
				if (!x || errno == ENOENT)
					t->mode = PATH_READ|PATH_EXECUTE;
				if (!(p = newof(0, Tree_t, 1, strlen(s))))
				{
					*e = c;
					return 0;
				}
				strcpy(p->name, s);
				p->next = t->tree;
				t->tree = p;
				t = p;
			}
			if (x)
			{
				*e = c;
				return 0;
			}
			if (st.st_mode & (S_IRUSR|S_IRGRP|S_IROTH))
				t->mode |= PATH_READ;
			if (st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
				t->mode |= PATH_WRITE;
			if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
				t->mode |= PATH_EXECUTE;
			if (!S_ISDIR(st.st_mode))
				t->mode |= PATH_REGULAR;
		}
		*e++ = c;
		if (!t->mode || (c && (t->mode & PATH_REGULAR)))
			return 0;
	}
	mode &= (PATH_READ|PATH_WRITE|PATH_EXECUTE|PATH_REGULAR);
	return (t->mode & mode) == mode;
}