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