xref: /plan9/sys/src/cmd/ratfs/misc.c (revision 40ef9009116dd37656783aaadc8782c1d8bfb056)
19a747e4fSDavid du Colombier #include "ratfs.h"
29a747e4fSDavid du Colombier #include <ip.h>
39a747e4fSDavid du Colombier 
49a747e4fSDavid du Colombier enum {
59a747e4fSDavid du Colombier 	Maxdoms	=	10,		/* max domains in a path */
6*40ef9009SDavid du Colombier 	Timeout =	2*60*60,	/* seconds until temporarily trusted addr times out */
79a747e4fSDavid du Colombier };
89a747e4fSDavid du Colombier 
99a747e4fSDavid du Colombier static	int	accountmatch(char*, char**, int, char*);
109a747e4fSDavid du Colombier static	Node*	acctwalk(char*,  Node*);
119a747e4fSDavid du Colombier static	int	dommatch(char*, char*);
129a747e4fSDavid du Colombier static	Address* ipsearch(ulong, Address*, int);
139a747e4fSDavid du Colombier static	Node*	ipwalk(char*,  Node*);
149a747e4fSDavid du Colombier static	Node*	trwalk(char*, Node*);
159a747e4fSDavid du Colombier static	int	usermatch(char*, char*);
169a747e4fSDavid du Colombier 
179a747e4fSDavid du Colombier /*
189a747e4fSDavid du Colombier  *	Do a walk
199a747e4fSDavid du Colombier  */
209a747e4fSDavid du Colombier char*
walk(char * name,Fid * fidp)219a747e4fSDavid du Colombier walk(char *name, Fid *fidp)
229a747e4fSDavid du Colombier {
239a747e4fSDavid du Colombier 	Node *np;
249a747e4fSDavid du Colombier 
259a747e4fSDavid du Colombier 	if((fidp->node->d.mode & DMDIR) == 0)
269a747e4fSDavid du Colombier 		return "not a directory";
279a747e4fSDavid du Colombier 
289a747e4fSDavid du Colombier 	if(strcmp(name, ".") == 0)
299a747e4fSDavid du Colombier 		return 0;
309a747e4fSDavid du Colombier 	if(strcmp(name, "..") == 0){
319a747e4fSDavid du Colombier 		fidp->node = fidp->node->parent;
329a747e4fSDavid du Colombier 		fidp->name = 0;
339a747e4fSDavid du Colombier 		return 0;
349a747e4fSDavid du Colombier 	}
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier 	switch(fidp->node->d.type){
379a747e4fSDavid du Colombier 	case Directory:
389a747e4fSDavid du Colombier 	case Addrdir:
399a747e4fSDavid du Colombier 		np = dirwalk(name, fidp->node);
409a747e4fSDavid du Colombier 		break;
419a747e4fSDavid du Colombier 	case Trusted:
429a747e4fSDavid du Colombier 		np = trwalk(name, fidp->node);
439a747e4fSDavid du Colombier 		break;
449a747e4fSDavid du Colombier 	case IPaddr:
459a747e4fSDavid du Colombier 		np = ipwalk(name, fidp->node);
469a747e4fSDavid du Colombier 		break;
479a747e4fSDavid du Colombier 	case Acctaddr:
489a747e4fSDavid du Colombier 		np = acctwalk(name, fidp->node);
499a747e4fSDavid du Colombier 		break;
509a747e4fSDavid du Colombier 	default:
519a747e4fSDavid du Colombier 		return "directory botch in walk";
529a747e4fSDavid du Colombier 	}
539a747e4fSDavid du Colombier 	if(np) {
549a747e4fSDavid du Colombier 		fidp->node = np;
559a747e4fSDavid du Colombier 		fidp->name = np->d.name;
569a747e4fSDavid du Colombier 		return 0;
579a747e4fSDavid du Colombier 	}
589a747e4fSDavid du Colombier 	return "file does not exist";
599a747e4fSDavid du Colombier }
609a747e4fSDavid du Colombier 
619a747e4fSDavid du Colombier /*
629a747e4fSDavid du Colombier  *	Walk to a subdirectory
639a747e4fSDavid du Colombier  */
649a747e4fSDavid du Colombier Node*
dirwalk(char * name,Node * np)659a747e4fSDavid du Colombier dirwalk(char *name, Node *np)
669a747e4fSDavid du Colombier {
679a747e4fSDavid du Colombier 	Node *p;
689a747e4fSDavid du Colombier 
699a747e4fSDavid du Colombier 	for(p = np->children; p; p = p->sibs)
709a747e4fSDavid du Colombier 		if(strcmp(name, p->d.name) == 0)
719a747e4fSDavid du Colombier 			break;
729a747e4fSDavid du Colombier 	return p;
739a747e4fSDavid du Colombier }
749a747e4fSDavid du Colombier 
759a747e4fSDavid du Colombier /*
769a747e4fSDavid du Colombier  *	Walk the directory of trusted files
779a747e4fSDavid du Colombier  */
789a747e4fSDavid du Colombier static Node*
trwalk(char * name,Node * np)799a747e4fSDavid du Colombier trwalk(char *name, Node *np)
809a747e4fSDavid du Colombier {
819a747e4fSDavid du Colombier 	Node *p;
829a747e4fSDavid du Colombier 	ulong peerip;
839a747e4fSDavid du Colombier 	uchar addr[IPv4addrlen];
849a747e4fSDavid du Colombier 
859a747e4fSDavid du Colombier 	v4parseip(addr, name);
869a747e4fSDavid du Colombier 	peerip = nhgetl(addr);
879a747e4fSDavid du Colombier 
889a747e4fSDavid du Colombier 	for(p = np->children; p; p = p->sibs)
899a747e4fSDavid du Colombier 		if((peerip&p->ip.mask) == p->ip.ipaddr)
909a747e4fSDavid du Colombier 			break;
919a747e4fSDavid du Colombier 	return p;
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier 
949a747e4fSDavid du Colombier /*
959a747e4fSDavid du Colombier  *	Walk a directory of IP addresses
969a747e4fSDavid du Colombier  */
979a747e4fSDavid du Colombier static Node*
ipwalk(char * name,Node * np)989a747e4fSDavid du Colombier ipwalk(char *name,  Node *np)
999a747e4fSDavid du Colombier {
1009a747e4fSDavid du Colombier 	Address *ap;
1019a747e4fSDavid du Colombier 	ulong peerip;
1029a747e4fSDavid du Colombier 	uchar addr[IPv4addrlen];
1039a747e4fSDavid du Colombier 
1049a747e4fSDavid du Colombier 	v4parseip(addr, name);
1059a747e4fSDavid du Colombier 	peerip = nhgetl(addr);
1069a747e4fSDavid du Colombier 
1079a747e4fSDavid du Colombier 	if(debugfd >= 0)
1089a747e4fSDavid du Colombier 		fprint(debugfd, "%d.%d.%d.%d - ", addr[0]&0xff, addr[1]&0xff,
1099a747e4fSDavid du Colombier 				addr[2]&0xff, addr[3]&0xff);
1109a747e4fSDavid du Colombier 	ap = ipsearch(peerip, np->addrs, np->count);
1119a747e4fSDavid du Colombier 	if(ap == 0)
1129a747e4fSDavid du Colombier 		return 0;
1139a747e4fSDavid du Colombier 
1149a747e4fSDavid du Colombier 	dummy.d.name = ap->name;
1159a747e4fSDavid du Colombier 	return &dummy;
1169a747e4fSDavid du Colombier }
1179a747e4fSDavid du Colombier 
1189a747e4fSDavid du Colombier /*
1199a747e4fSDavid du Colombier  *	Walk a directory of account names
1209a747e4fSDavid du Colombier  */
1219a747e4fSDavid du Colombier static Node*
acctwalk(char * name,Node * np)1229a747e4fSDavid du Colombier acctwalk(char *name, Node *np)
1239a747e4fSDavid du Colombier {
1249a747e4fSDavid du Colombier 	int i, n;
1259a747e4fSDavid du Colombier 	Address *ap;
1269a747e4fSDavid du Colombier 	char *p, *cp, *user;
1279a747e4fSDavid du Colombier 	char buf[512];
1289a747e4fSDavid du Colombier 	char *doms[Maxdoms];
1299a747e4fSDavid du Colombier 
1309a747e4fSDavid du Colombier 	strecpy(buf, buf+sizeof buf, name);
1319a747e4fSDavid du Colombier 	subslash(buf);
1329a747e4fSDavid du Colombier 
1339a747e4fSDavid du Colombier 	p = buf;
1349a747e4fSDavid du Colombier 	for(n = 0; n < Maxdoms; n++) {
1359a747e4fSDavid du Colombier 		cp = strchr(p, '!');
1369a747e4fSDavid du Colombier 		if(cp == 0)
1379a747e4fSDavid du Colombier 			break;
1389a747e4fSDavid du Colombier 		*cp = 0;
1399a747e4fSDavid du Colombier 		doms[n] = p;
1409a747e4fSDavid du Colombier 		p = cp+1;
1419a747e4fSDavid du Colombier 	}
1429a747e4fSDavid du Colombier 	user = p;
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier 	for(i = 0; i < np->count; i++){
1459a747e4fSDavid du Colombier 		ap = &np->addrs[i];
1469a747e4fSDavid du Colombier 		if (accountmatch(ap->name, doms, n, user)) {
1479a747e4fSDavid du Colombier 			dummy.d.name = ap->name;
1489a747e4fSDavid du Colombier 			return &dummy;
1499a747e4fSDavid du Colombier 		}
1509a747e4fSDavid du Colombier 	}
1519a747e4fSDavid du Colombier 	return 0;
1529a747e4fSDavid du Colombier }
1539a747e4fSDavid du Colombier 
1549a747e4fSDavid du Colombier /*
1559a747e4fSDavid du Colombier  * binary search sorted IP address list
1569a747e4fSDavid du Colombier  */
1579a747e4fSDavid du Colombier 
1589a747e4fSDavid du Colombier static Address*
ipsearch(ulong addr,Address * base,int n)1599a747e4fSDavid du Colombier ipsearch(ulong addr, Address *base, int n)
1609a747e4fSDavid du Colombier {
1619a747e4fSDavid du Colombier 	ulong top, bot, mid;
1629a747e4fSDavid du Colombier 	Address *ap;
1639a747e4fSDavid du Colombier 
1649a747e4fSDavid du Colombier 	bot = 0;
1659a747e4fSDavid du Colombier 	top = n;
1669a747e4fSDavid du Colombier 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
1679a747e4fSDavid du Colombier 		ap = &base[mid];
1689a747e4fSDavid du Colombier 		if((addr&ap->ip.mask) == ap->ip.ipaddr)
1699a747e4fSDavid du Colombier 			return ap;
1709a747e4fSDavid du Colombier 		if(addr < ap->ip.ipaddr)
1719a747e4fSDavid du Colombier 			top = mid;
1729a747e4fSDavid du Colombier 		else if(mid != n-1 && addr >= base[mid+1].ip.ipaddr)
1739a747e4fSDavid du Colombier 			bot = mid;
1749a747e4fSDavid du Colombier 		else
1759a747e4fSDavid du Colombier 			break;
1769a747e4fSDavid du Colombier 	}
1779a747e4fSDavid du Colombier 	return 0;
1789a747e4fSDavid du Colombier }
1799a747e4fSDavid du Colombier 
1809a747e4fSDavid du Colombier /*
1819a747e4fSDavid du Colombier  *	Read a directory
1829a747e4fSDavid du Colombier  */
1839a747e4fSDavid du Colombier int
dread(Fid * fidp,int cnt)1849a747e4fSDavid du Colombier dread(Fid *fidp, int cnt)
1859a747e4fSDavid du Colombier {
1869a747e4fSDavid du Colombier 	uchar *q, *eq, *oq;
1879a747e4fSDavid du Colombier 	int n, skip;
1889a747e4fSDavid du Colombier 	Node *np;
1899a747e4fSDavid du Colombier 
1909a747e4fSDavid du Colombier 	if(debugfd >= 0)
1919a747e4fSDavid du Colombier 		fprint(debugfd, "dread %d\n", cnt);
1929a747e4fSDavid du Colombier 
1939a747e4fSDavid du Colombier 	np = fidp->node;
1949a747e4fSDavid du Colombier 	oq = q = rbuf+IOHDRSZ;
1959a747e4fSDavid du Colombier 	eq = q+cnt;
1969a747e4fSDavid du Colombier 	if(fidp->dirindex >= np->count)
1979a747e4fSDavid du Colombier 		return 0;
1989a747e4fSDavid du Colombier 
1999a747e4fSDavid du Colombier 	skip = fidp->dirindex;
2009a747e4fSDavid du Colombier 	for(np = np->children; skip > 0 && np; np = np->sibs)
2019a747e4fSDavid du Colombier 		skip--;
2029a747e4fSDavid du Colombier 	if(np == 0)
2039a747e4fSDavid du Colombier 		return 0;
2049a747e4fSDavid du Colombier 
2059a747e4fSDavid du Colombier 	for(; q < eq && np; np = np->sibs){
2069a747e4fSDavid du Colombier 		if(debugfd >= 0)
2079a747e4fSDavid du Colombier 			printnode(np);
2089a747e4fSDavid du Colombier 		if((n=convD2M(&np->d, q, eq-q)) <= BIT16SZ)
2099a747e4fSDavid du Colombier 			break;
2109a747e4fSDavid du Colombier 		q += n;
2119a747e4fSDavid du Colombier 		fidp->dirindex++;
2129a747e4fSDavid du Colombier 	}
2139a747e4fSDavid du Colombier 	return q - oq;
2149a747e4fSDavid du Colombier }
2159a747e4fSDavid du Colombier 
2169a747e4fSDavid du Colombier /*
2179a747e4fSDavid du Colombier  *	Read a directory of IP addresses or account names
2189a747e4fSDavid du Colombier  */
2199a747e4fSDavid du Colombier int
hread(Fid * fidp,int cnt)2209a747e4fSDavid du Colombier hread(Fid *fidp, int cnt)
2219a747e4fSDavid du Colombier {
2229a747e4fSDavid du Colombier 	uchar *q, *eq, *oq;
2239a747e4fSDavid du Colombier 	int i, n, path;
2249a747e4fSDavid du Colombier 	Address *p;
2259a747e4fSDavid du Colombier 	Node *np;
2269a747e4fSDavid du Colombier 
2279a747e4fSDavid du Colombier 	if(debugfd >= 0)
2289a747e4fSDavid du Colombier 		fprint(debugfd, "hread %d\n", cnt);
2299a747e4fSDavid du Colombier 
2309a747e4fSDavid du Colombier 	np = fidp->node;
2319a747e4fSDavid du Colombier 	oq = q = rbuf+IOHDRSZ;
2329a747e4fSDavid du Colombier 	eq = q+cnt;
2339a747e4fSDavid du Colombier 	if(fidp->dirindex >= np->count)
2349a747e4fSDavid du Colombier 		return 0;
2359a747e4fSDavid du Colombier 
2369a747e4fSDavid du Colombier 	path = np->baseqid;
2379a747e4fSDavid du Colombier 	for(i = fidp->dirindex; q < eq && i < np->count; i++){
2389a747e4fSDavid du Colombier 		p = &np->addrs[i];
2399a747e4fSDavid du Colombier 		dummy.d.name = p->name;
2409a747e4fSDavid du Colombier 		dummy.d.qid.path = path++;
2419a747e4fSDavid du Colombier 		if((n=convD2M(&dummy.d, q, eq-q)) <= BIT16SZ)
2429a747e4fSDavid du Colombier 			break;
2439a747e4fSDavid du Colombier 		q += n;
2449a747e4fSDavid du Colombier 	}
2459a747e4fSDavid du Colombier 	fidp->dirindex = i;
2469a747e4fSDavid du Colombier 	return q - oq;
2479a747e4fSDavid du Colombier }
2489a747e4fSDavid du Colombier 
2499a747e4fSDavid du Colombier /*
2509a747e4fSDavid du Colombier  *	Find a directory node by type
2519a747e4fSDavid du Colombier  */
2529a747e4fSDavid du Colombier Node*
finddir(int type)2539a747e4fSDavid du Colombier finddir(int type)
2549a747e4fSDavid du Colombier {
2559a747e4fSDavid du Colombier 	Node *np;
2569a747e4fSDavid du Colombier 
2579a747e4fSDavid du Colombier 	for(np = root->children; np; np = np->sibs)
2589a747e4fSDavid du Colombier 		if (np->d.type == type)
2599a747e4fSDavid du Colombier 			return np;
2609a747e4fSDavid du Colombier 	return 0;
2619a747e4fSDavid du Colombier }
2629a747e4fSDavid du Colombier 
2639a747e4fSDavid du Colombier /*
2649a747e4fSDavid du Colombier  *	Remove temporary pseudo-files that have timed-out
2659a747e4fSDavid du Colombier  *	from the trusted directory
2669a747e4fSDavid du Colombier  */
2679a747e4fSDavid du Colombier void
cleantrusted(void)2689a747e4fSDavid du Colombier cleantrusted(void)
2699a747e4fSDavid du Colombier {
2709a747e4fSDavid du Colombier 	Node *np, **l;
2719a747e4fSDavid du Colombier 	ulong t;
2729a747e4fSDavid du Colombier 
2739a747e4fSDavid du Colombier 	np = finddir(Trusted);
2749a747e4fSDavid du Colombier 	if (np == 0)
2759a747e4fSDavid du Colombier 		return;
2769a747e4fSDavid du Colombier 
2779a747e4fSDavid du Colombier 	t = time(0)-Timeout;
2789a747e4fSDavid du Colombier 	l = &np->children;
2799a747e4fSDavid du Colombier 	for (np = np->children; np; np = *l) {
2809a747e4fSDavid du Colombier 		if(np->d.type == Trustedtemp && t >= np->d.mtime) {
2819a747e4fSDavid du Colombier 			*l = np->sibs;
2829a747e4fSDavid du Colombier 			if(debugfd >= 0)
2839a747e4fSDavid du Colombier 				fprint(debugfd, "Deleting %s\n", np->d.name);
2849a747e4fSDavid du Colombier 			np->parent->count--;
2859a747e4fSDavid du Colombier 			free(np);
2869a747e4fSDavid du Colombier 		} else
2879a747e4fSDavid du Colombier 			l = &np->sibs;
2889a747e4fSDavid du Colombier 	}
2899a747e4fSDavid du Colombier }
2909a747e4fSDavid du Colombier 
2919a747e4fSDavid du Colombier /*
2929a747e4fSDavid du Colombier  * match path components to prohibited domain & user specifications.  patterns include:
2939a747e4fSDavid du Colombier  *	domain, domain! or domain!*	  - all users in domain
2949a747e4fSDavid du Colombier  *	*.domain, *.domain! or *.domain!* - all users in domain and its subdomains
2959a747e4fSDavid du Colombier  *	!user or *!user			  - user in all domains
2969a747e4fSDavid du Colombier  *	domain!user			  - user in domain
2979a747e4fSDavid du Colombier  *	*.domain!user			  - user in domain and its subdomains
2989a747e4fSDavid du Colombier  *
2999a747e4fSDavid du Colombier  *	if "user" has a trailing '*', it matches all user names beginning with "user"
3009a747e4fSDavid du Colombier  *
3019a747e4fSDavid du Colombier  * there are special semantics for the "domain, domain! or domain!*" specifications:
3029a747e4fSDavid du Colombier  * the first two forms match when the domain is anywhere in at list of source-routed
3039a747e4fSDavid du Colombier  * domains while the latter matches only when the domain is the last hop.  the same is
3049a747e4fSDavid du Colombier  * true for the *.domain!* form of the pattern.
3059a747e4fSDavid du Colombier  */
3069a747e4fSDavid du Colombier static int
accountmatch(char * spec,char ** doms,int ndoms,char * user)3079a747e4fSDavid du Colombier accountmatch(char *spec, char **doms, int ndoms, char *user)
3089a747e4fSDavid du Colombier {
3099a747e4fSDavid du Colombier 	char *cp, *userp;
3109a747e4fSDavid du Colombier 	int i, ret;
3119a747e4fSDavid du Colombier 
3129a747e4fSDavid du Colombier 	userp = 0;
3139a747e4fSDavid du Colombier 	ret = 0;
3149a747e4fSDavid du Colombier 	cp = strchr(spec, '!');
3159a747e4fSDavid du Colombier 	if(cp){
3169a747e4fSDavid du Colombier 		*cp++ = 0;		/* restored below */
3179a747e4fSDavid du Colombier 		if(*cp)
3189a747e4fSDavid du Colombier 		if(strcmp(cp, "*"))	/* "!*" is the same as no user field */
3199a747e4fSDavid du Colombier 			userp = cp;	/* there is a user name */
3209a747e4fSDavid du Colombier 	}
3219a747e4fSDavid du Colombier 
3229a747e4fSDavid du Colombier 	if(userp == 0){			/* no user field - domain match only */
3239a747e4fSDavid du Colombier 		for(i = 0; i < ndoms && doms[i]; i++)
3249a747e4fSDavid du Colombier 			if(dommatch(doms[i], spec) == 0)
3259a747e4fSDavid du Colombier 				ret = 1;
3269a747e4fSDavid du Colombier 	} else {
3279a747e4fSDavid du Colombier 		/* check for "!user", "*!user" or "domain!user" */
3289a747e4fSDavid du Colombier 		if(usermatch(user, userp) == 0){
3299a747e4fSDavid du Colombier 			if(*spec == 0 || strcmp(spec, "*") == 0)
3309a747e4fSDavid du Colombier 				ret = 1;
3319a747e4fSDavid du Colombier 			else if(ndoms > 0  && dommatch(doms[ndoms-1], spec) == 0)
3329a747e4fSDavid du Colombier 				ret = 1;
3339a747e4fSDavid du Colombier 		}
3349a747e4fSDavid du Colombier 	}
3359a747e4fSDavid du Colombier 	if(cp)
3369a747e4fSDavid du Colombier 		cp[-1] = '!';
3379a747e4fSDavid du Colombier 	return ret;
3389a747e4fSDavid du Colombier }
3399a747e4fSDavid du Colombier 
3409a747e4fSDavid du Colombier /*
3419a747e4fSDavid du Colombier  *	match a user name.  the only meta-char is '*' which matches all
3429a747e4fSDavid du Colombier  *	characters.  we only allow it as "*", which matches anything or
3439a747e4fSDavid du Colombier  *	an * at the end of the name (e.g., "username*") which matches
3449a747e4fSDavid du Colombier  *	trailing characters.
3459a747e4fSDavid du Colombier  */
3469a747e4fSDavid du Colombier static int
usermatch(char * pathuser,char * specuser)3479a747e4fSDavid du Colombier usermatch(char *pathuser, char *specuser)
3489a747e4fSDavid du Colombier {
3499a747e4fSDavid du Colombier 	int n;
3509a747e4fSDavid du Colombier 
3519a747e4fSDavid du Colombier 	n = strlen(specuser)-1;
3529a747e4fSDavid du Colombier 	if(specuser[n] == '*'){
3539a747e4fSDavid du Colombier 		if(n == 0)		/* match everything */
3549a747e4fSDavid du Colombier 			return 0;
3559a747e4fSDavid du Colombier 		return strncmp(pathuser, specuser, n);
3569a747e4fSDavid du Colombier 	}
3579a747e4fSDavid du Colombier 	return strcmp(pathuser, specuser);
3589a747e4fSDavid du Colombier }
3599a747e4fSDavid du Colombier 
3609a747e4fSDavid du Colombier /*
3619a747e4fSDavid du Colombier  *	Match a domain specification
3629a747e4fSDavid du Colombier  */
3639a747e4fSDavid du Colombier static int
dommatch(char * pathdom,char * specdom)3649a747e4fSDavid du Colombier dommatch(char *pathdom, char *specdom)
3659a747e4fSDavid du Colombier {
3669a747e4fSDavid du Colombier 	int n;
3679a747e4fSDavid du Colombier 
3689a747e4fSDavid du Colombier 	if (*specdom == '*'){
3699a747e4fSDavid du Colombier 		if (specdom[1] == '.' && specdom[2]){
3709a747e4fSDavid du Colombier 			specdom += 2;
3719a747e4fSDavid du Colombier 			n = strlen(pathdom)-strlen(specdom);
3729a747e4fSDavid du Colombier 			if(n == 0 || (n > 0 && pathdom[n-1] == '.'))
3739a747e4fSDavid du Colombier 				return strcmp(pathdom+n, specdom);
3749a747e4fSDavid du Colombier 			return n;
3759a747e4fSDavid du Colombier 		}
3769a747e4fSDavid du Colombier 	}
3779a747e4fSDavid du Colombier 	return strcmp(pathdom, specdom);
3789a747e4fSDavid du Colombier }
3799a747e4fSDavid du Colombier 
3809a747e4fSDavid du Colombier /*
3819a747e4fSDavid du Colombier  *	Custom allocators to avoid malloc overheads on small objects.
3829a747e4fSDavid du Colombier  * 	We never free these.  (See below.)
3839a747e4fSDavid du Colombier  */
3849a747e4fSDavid du Colombier typedef struct Stringtab	Stringtab;
3859a747e4fSDavid du Colombier struct Stringtab {
3869a747e4fSDavid du Colombier 	Stringtab *link;
3879a747e4fSDavid du Colombier 	char *str;
3889a747e4fSDavid du Colombier };
3899a747e4fSDavid du Colombier static Stringtab*
taballoc(void)3909a747e4fSDavid du Colombier taballoc(void)
3919a747e4fSDavid du Colombier {
3929a747e4fSDavid du Colombier 	static Stringtab *t;
3939a747e4fSDavid du Colombier 	static uint nt;
3949a747e4fSDavid du Colombier 
3959a747e4fSDavid du Colombier 	if(nt == 0){
3969a747e4fSDavid du Colombier 		t = malloc(64*sizeof(Stringtab));
3979a747e4fSDavid du Colombier 		if(t == 0)
3989a747e4fSDavid du Colombier 			fatal("out of memory");
3999a747e4fSDavid du Colombier 		nt = 64;
4009a747e4fSDavid du Colombier 	}
4019a747e4fSDavid du Colombier 	nt--;
4029a747e4fSDavid du Colombier 	return t++;
4039a747e4fSDavid du Colombier }
4049a747e4fSDavid du Colombier 
4059a747e4fSDavid du Colombier static char*
xstrdup(char * s)4069a747e4fSDavid du Colombier xstrdup(char *s)
4079a747e4fSDavid du Colombier {
4089a747e4fSDavid du Colombier 	char *r;
4099a747e4fSDavid du Colombier 	int len;
4109a747e4fSDavid du Colombier 	static char *t;
4119a747e4fSDavid du Colombier 	static int nt;
4129a747e4fSDavid du Colombier 
4139a747e4fSDavid du Colombier 	len = strlen(s)+1;
4149a747e4fSDavid du Colombier 	if(len >= 8192)
4159a747e4fSDavid du Colombier 		fatal("strdup big string");
4169a747e4fSDavid du Colombier 
4179a747e4fSDavid du Colombier 	if(nt < len){
4189a747e4fSDavid du Colombier 		t = malloc(8192);
4199a747e4fSDavid du Colombier 		if(t == 0)
4209a747e4fSDavid du Colombier 			fatal("out of memory");
4219a747e4fSDavid du Colombier 		nt = 8192;
4229a747e4fSDavid du Colombier 	}
4239a747e4fSDavid du Colombier 	r = t;
4249a747e4fSDavid du Colombier 	t += len;
4259a747e4fSDavid du Colombier 	nt -= len;
4269a747e4fSDavid du Colombier 	strcpy(r, s);
4279a747e4fSDavid du Colombier 	return r;
4289a747e4fSDavid du Colombier }
4299a747e4fSDavid du Colombier 
4309a747e4fSDavid du Colombier /*
4319a747e4fSDavid du Colombier  *	Return a uniquely allocated copy of a string.
4329a747e4fSDavid du Colombier  *	Don't free these -- they stay in the table for the
4339a747e4fSDavid du Colombier  *	next caller who wants that particular string.
4349a747e4fSDavid du Colombier  *	String comparison can be done with pointer comparison
4359a747e4fSDavid du Colombier  *	if you know both strings are atoms.
4369a747e4fSDavid du Colombier  */
4379a747e4fSDavid du Colombier static Stringtab *stab[1024];
4389a747e4fSDavid du Colombier 
4399a747e4fSDavid du Colombier static uint
hash(char * s)4409a747e4fSDavid du Colombier hash(char *s)
4419a747e4fSDavid du Colombier {
4429a747e4fSDavid du Colombier 	uint h;
4439a747e4fSDavid du Colombier 	uchar *p;
4449a747e4fSDavid du Colombier 
4459a747e4fSDavid du Colombier 	h = 0;
4469a747e4fSDavid du Colombier 	for(p=(uchar*)s; *p; p++)
4479a747e4fSDavid du Colombier 		h = h*37 + *p;
4489a747e4fSDavid du Colombier 	return h;
4499a747e4fSDavid du Colombier }
4509a747e4fSDavid du Colombier 
4519a747e4fSDavid du Colombier char*
atom(char * str)4529a747e4fSDavid du Colombier atom(char *str)
4539a747e4fSDavid du Colombier {
4549a747e4fSDavid du Colombier 	uint h;
4559a747e4fSDavid du Colombier 	Stringtab *tab;
4569a747e4fSDavid du Colombier 
4579a747e4fSDavid du Colombier 	h = hash(str) % nelem(stab);
4589a747e4fSDavid du Colombier 	for(tab=stab[h]; tab; tab=tab->link)
4599a747e4fSDavid du Colombier 		if(strcmp(str, tab->str) == 0)
4609a747e4fSDavid du Colombier 			return tab->str;
4619a747e4fSDavid du Colombier 
4629a747e4fSDavid du Colombier 	tab = taballoc();
4639a747e4fSDavid du Colombier 	tab->str = xstrdup(str);
4649a747e4fSDavid du Colombier 	tab->link = stab[h];
4659a747e4fSDavid du Colombier 	stab[h] = tab;
4669a747e4fSDavid du Colombier 	return tab->str;
4679a747e4fSDavid du Colombier }
468