1*9a747e4fSDavid du Colombier #include "ratfs.h" 2*9a747e4fSDavid du Colombier #include <ip.h> 3*9a747e4fSDavid du Colombier 4*9a747e4fSDavid du Colombier enum { 5*9a747e4fSDavid du Colombier Maxdoms = 10, /* max domains in a path */ 6*9a747e4fSDavid du Colombier Timeout = 15*60, /* seconds until temporarily trusted addr times out */ 7*9a747e4fSDavid du Colombier }; 8*9a747e4fSDavid du Colombier 9*9a747e4fSDavid du Colombier static int accountmatch(char*, char**, int, char*); 10*9a747e4fSDavid du Colombier static Node* acctwalk(char*, Node*); 11*9a747e4fSDavid du Colombier static int dommatch(char*, char*); 12*9a747e4fSDavid du Colombier static Address* ipsearch(ulong, Address*, int); 13*9a747e4fSDavid du Colombier static Node* ipwalk(char*, Node*); 14*9a747e4fSDavid du Colombier static Node* trwalk(char*, Node*); 15*9a747e4fSDavid du Colombier static int usermatch(char*, char*); 16*9a747e4fSDavid du Colombier 17*9a747e4fSDavid du Colombier /* 18*9a747e4fSDavid du Colombier * Do a walk 19*9a747e4fSDavid du Colombier */ 20*9a747e4fSDavid du Colombier char* 21*9a747e4fSDavid du Colombier walk(char *name, Fid *fidp) 22*9a747e4fSDavid du Colombier { 23*9a747e4fSDavid du Colombier Node *np; 24*9a747e4fSDavid du Colombier 25*9a747e4fSDavid du Colombier if((fidp->node->d.mode & DMDIR) == 0) 26*9a747e4fSDavid du Colombier return "not a directory"; 27*9a747e4fSDavid du Colombier 28*9a747e4fSDavid du Colombier if(strcmp(name, ".") == 0) 29*9a747e4fSDavid du Colombier return 0; 30*9a747e4fSDavid du Colombier if(strcmp(name, "..") == 0){ 31*9a747e4fSDavid du Colombier fidp->node = fidp->node->parent; 32*9a747e4fSDavid du Colombier fidp->name = 0; 33*9a747e4fSDavid du Colombier return 0; 34*9a747e4fSDavid du Colombier } 35*9a747e4fSDavid du Colombier 36*9a747e4fSDavid du Colombier switch(fidp->node->d.type){ 37*9a747e4fSDavid du Colombier case Directory: 38*9a747e4fSDavid du Colombier case Addrdir: 39*9a747e4fSDavid du Colombier np = dirwalk(name, fidp->node); 40*9a747e4fSDavid du Colombier break; 41*9a747e4fSDavid du Colombier case Trusted: 42*9a747e4fSDavid du Colombier np = trwalk(name, fidp->node); 43*9a747e4fSDavid du Colombier break; 44*9a747e4fSDavid du Colombier case IPaddr: 45*9a747e4fSDavid du Colombier np = ipwalk(name, fidp->node); 46*9a747e4fSDavid du Colombier break; 47*9a747e4fSDavid du Colombier case Acctaddr: 48*9a747e4fSDavid du Colombier np = acctwalk(name, fidp->node); 49*9a747e4fSDavid du Colombier break; 50*9a747e4fSDavid du Colombier default: 51*9a747e4fSDavid du Colombier return "directory botch in walk"; 52*9a747e4fSDavid du Colombier } 53*9a747e4fSDavid du Colombier if(np) { 54*9a747e4fSDavid du Colombier fidp->node = np; 55*9a747e4fSDavid du Colombier fidp->name = np->d.name; 56*9a747e4fSDavid du Colombier return 0; 57*9a747e4fSDavid du Colombier } 58*9a747e4fSDavid du Colombier return "file does not exist"; 59*9a747e4fSDavid du Colombier } 60*9a747e4fSDavid du Colombier 61*9a747e4fSDavid du Colombier /* 62*9a747e4fSDavid du Colombier * Walk to a subdirectory 63*9a747e4fSDavid du Colombier */ 64*9a747e4fSDavid du Colombier Node* 65*9a747e4fSDavid du Colombier dirwalk(char *name, Node *np) 66*9a747e4fSDavid du Colombier { 67*9a747e4fSDavid du Colombier Node *p; 68*9a747e4fSDavid du Colombier 69*9a747e4fSDavid du Colombier for(p = np->children; p; p = p->sibs) 70*9a747e4fSDavid du Colombier if(strcmp(name, p->d.name) == 0) 71*9a747e4fSDavid du Colombier break; 72*9a747e4fSDavid du Colombier return p; 73*9a747e4fSDavid du Colombier } 74*9a747e4fSDavid du Colombier 75*9a747e4fSDavid du Colombier /* 76*9a747e4fSDavid du Colombier * Walk the directory of trusted files 77*9a747e4fSDavid du Colombier */ 78*9a747e4fSDavid du Colombier static Node* 79*9a747e4fSDavid du Colombier trwalk(char *name, Node *np) 80*9a747e4fSDavid du Colombier { 81*9a747e4fSDavid du Colombier Node *p; 82*9a747e4fSDavid du Colombier ulong peerip; 83*9a747e4fSDavid du Colombier uchar addr[IPv4addrlen]; 84*9a747e4fSDavid du Colombier 85*9a747e4fSDavid du Colombier v4parseip(addr, name); 86*9a747e4fSDavid du Colombier peerip = nhgetl(addr); 87*9a747e4fSDavid du Colombier 88*9a747e4fSDavid du Colombier for(p = np->children; p; p = p->sibs) 89*9a747e4fSDavid du Colombier if((peerip&p->ip.mask) == p->ip.ipaddr) 90*9a747e4fSDavid du Colombier break; 91*9a747e4fSDavid du Colombier return p; 92*9a747e4fSDavid du Colombier } 93*9a747e4fSDavid du Colombier 94*9a747e4fSDavid du Colombier /* 95*9a747e4fSDavid du Colombier * Walk a directory of IP addresses 96*9a747e4fSDavid du Colombier */ 97*9a747e4fSDavid du Colombier static Node* 98*9a747e4fSDavid du Colombier ipwalk(char *name, Node *np) 99*9a747e4fSDavid du Colombier { 100*9a747e4fSDavid du Colombier Address *ap; 101*9a747e4fSDavid du Colombier ulong peerip; 102*9a747e4fSDavid du Colombier uchar addr[IPv4addrlen]; 103*9a747e4fSDavid du Colombier 104*9a747e4fSDavid du Colombier v4parseip(addr, name); 105*9a747e4fSDavid du Colombier peerip = nhgetl(addr); 106*9a747e4fSDavid du Colombier 107*9a747e4fSDavid du Colombier if(debugfd >= 0) 108*9a747e4fSDavid du Colombier fprint(debugfd, "%d.%d.%d.%d - ", addr[0]&0xff, addr[1]&0xff, 109*9a747e4fSDavid du Colombier addr[2]&0xff, addr[3]&0xff); 110*9a747e4fSDavid du Colombier ap = ipsearch(peerip, np->addrs, np->count); 111*9a747e4fSDavid du Colombier if(ap == 0) 112*9a747e4fSDavid du Colombier return 0; 113*9a747e4fSDavid du Colombier 114*9a747e4fSDavid du Colombier dummy.d.name = ap->name; 115*9a747e4fSDavid du Colombier return &dummy; 116*9a747e4fSDavid du Colombier } 117*9a747e4fSDavid du Colombier 118*9a747e4fSDavid du Colombier /* 119*9a747e4fSDavid du Colombier * Walk a directory of account names 120*9a747e4fSDavid du Colombier */ 121*9a747e4fSDavid du Colombier static Node* 122*9a747e4fSDavid du Colombier acctwalk(char *name, Node *np) 123*9a747e4fSDavid du Colombier { 124*9a747e4fSDavid du Colombier int i, n; 125*9a747e4fSDavid du Colombier Address *ap; 126*9a747e4fSDavid du Colombier char *p, *cp, *user; 127*9a747e4fSDavid du Colombier char buf[512]; 128*9a747e4fSDavid du Colombier char *doms[Maxdoms]; 129*9a747e4fSDavid du Colombier 130*9a747e4fSDavid du Colombier strecpy(buf, buf+sizeof buf, name); 131*9a747e4fSDavid du Colombier subslash(buf); 132*9a747e4fSDavid du Colombier 133*9a747e4fSDavid du Colombier p = buf; 134*9a747e4fSDavid du Colombier for(n = 0; n < Maxdoms; n++) { 135*9a747e4fSDavid du Colombier cp = strchr(p, '!'); 136*9a747e4fSDavid du Colombier if(cp == 0) 137*9a747e4fSDavid du Colombier break; 138*9a747e4fSDavid du Colombier *cp = 0; 139*9a747e4fSDavid du Colombier doms[n] = p; 140*9a747e4fSDavid du Colombier p = cp+1; 141*9a747e4fSDavid du Colombier } 142*9a747e4fSDavid du Colombier user = p; 143*9a747e4fSDavid du Colombier 144*9a747e4fSDavid du Colombier for(i = 0; i < np->count; i++){ 145*9a747e4fSDavid du Colombier ap = &np->addrs[i]; 146*9a747e4fSDavid du Colombier if (accountmatch(ap->name, doms, n, user)) { 147*9a747e4fSDavid du Colombier dummy.d.name = ap->name; 148*9a747e4fSDavid du Colombier return &dummy; 149*9a747e4fSDavid du Colombier } 150*9a747e4fSDavid du Colombier } 151*9a747e4fSDavid du Colombier return 0; 152*9a747e4fSDavid du Colombier } 153*9a747e4fSDavid du Colombier 154*9a747e4fSDavid du Colombier /* 155*9a747e4fSDavid du Colombier * binary search sorted IP address list 156*9a747e4fSDavid du Colombier */ 157*9a747e4fSDavid du Colombier 158*9a747e4fSDavid du Colombier static Address* 159*9a747e4fSDavid du Colombier ipsearch(ulong addr, Address *base, int n) 160*9a747e4fSDavid du Colombier { 161*9a747e4fSDavid du Colombier ulong top, bot, mid; 162*9a747e4fSDavid du Colombier Address *ap; 163*9a747e4fSDavid du Colombier 164*9a747e4fSDavid du Colombier bot = 0; 165*9a747e4fSDavid du Colombier top = n; 166*9a747e4fSDavid du Colombier for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) { 167*9a747e4fSDavid du Colombier ap = &base[mid]; 168*9a747e4fSDavid du Colombier if((addr&ap->ip.mask) == ap->ip.ipaddr) 169*9a747e4fSDavid du Colombier return ap; 170*9a747e4fSDavid du Colombier if(addr < ap->ip.ipaddr) 171*9a747e4fSDavid du Colombier top = mid; 172*9a747e4fSDavid du Colombier else if(mid != n-1 && addr >= base[mid+1].ip.ipaddr) 173*9a747e4fSDavid du Colombier bot = mid; 174*9a747e4fSDavid du Colombier else 175*9a747e4fSDavid du Colombier break; 176*9a747e4fSDavid du Colombier } 177*9a747e4fSDavid du Colombier return 0; 178*9a747e4fSDavid du Colombier } 179*9a747e4fSDavid du Colombier 180*9a747e4fSDavid du Colombier /* 181*9a747e4fSDavid du Colombier * Read a directory 182*9a747e4fSDavid du Colombier */ 183*9a747e4fSDavid du Colombier int 184*9a747e4fSDavid du Colombier dread(Fid *fidp, int cnt) 185*9a747e4fSDavid du Colombier { 186*9a747e4fSDavid du Colombier uchar *q, *eq, *oq; 187*9a747e4fSDavid du Colombier int n, skip; 188*9a747e4fSDavid du Colombier Node *np; 189*9a747e4fSDavid du Colombier 190*9a747e4fSDavid du Colombier if(debugfd >= 0) 191*9a747e4fSDavid du Colombier fprint(debugfd, "dread %d\n", cnt); 192*9a747e4fSDavid du Colombier 193*9a747e4fSDavid du Colombier np = fidp->node; 194*9a747e4fSDavid du Colombier oq = q = rbuf+IOHDRSZ; 195*9a747e4fSDavid du Colombier eq = q+cnt; 196*9a747e4fSDavid du Colombier if(fidp->dirindex >= np->count) 197*9a747e4fSDavid du Colombier return 0; 198*9a747e4fSDavid du Colombier 199*9a747e4fSDavid du Colombier skip = fidp->dirindex; 200*9a747e4fSDavid du Colombier for(np = np->children; skip > 0 && np; np = np->sibs) 201*9a747e4fSDavid du Colombier skip--; 202*9a747e4fSDavid du Colombier if(np == 0) 203*9a747e4fSDavid du Colombier return 0; 204*9a747e4fSDavid du Colombier 205*9a747e4fSDavid du Colombier for(; q < eq && np; np = np->sibs){ 206*9a747e4fSDavid du Colombier if(debugfd >= 0) 207*9a747e4fSDavid du Colombier printnode(np); 208*9a747e4fSDavid du Colombier if((n=convD2M(&np->d, q, eq-q)) <= BIT16SZ) 209*9a747e4fSDavid du Colombier break; 210*9a747e4fSDavid du Colombier q += n; 211*9a747e4fSDavid du Colombier fidp->dirindex++; 212*9a747e4fSDavid du Colombier } 213*9a747e4fSDavid du Colombier return q - oq; 214*9a747e4fSDavid du Colombier } 215*9a747e4fSDavid du Colombier 216*9a747e4fSDavid du Colombier /* 217*9a747e4fSDavid du Colombier * Read a directory of IP addresses or account names 218*9a747e4fSDavid du Colombier */ 219*9a747e4fSDavid du Colombier int 220*9a747e4fSDavid du Colombier hread(Fid *fidp, int cnt) 221*9a747e4fSDavid du Colombier { 222*9a747e4fSDavid du Colombier uchar *q, *eq, *oq; 223*9a747e4fSDavid du Colombier int i, n, path; 224*9a747e4fSDavid du Colombier Address *p; 225*9a747e4fSDavid du Colombier Node *np; 226*9a747e4fSDavid du Colombier 227*9a747e4fSDavid du Colombier if(debugfd >= 0) 228*9a747e4fSDavid du Colombier fprint(debugfd, "hread %d\n", cnt); 229*9a747e4fSDavid du Colombier 230*9a747e4fSDavid du Colombier np = fidp->node; 231*9a747e4fSDavid du Colombier oq = q = rbuf+IOHDRSZ; 232*9a747e4fSDavid du Colombier eq = q+cnt; 233*9a747e4fSDavid du Colombier if(fidp->dirindex >= np->count) 234*9a747e4fSDavid du Colombier return 0; 235*9a747e4fSDavid du Colombier 236*9a747e4fSDavid du Colombier path = np->baseqid; 237*9a747e4fSDavid du Colombier for(i = fidp->dirindex; q < eq && i < np->count; i++){ 238*9a747e4fSDavid du Colombier p = &np->addrs[i]; 239*9a747e4fSDavid du Colombier dummy.d.name = p->name; 240*9a747e4fSDavid du Colombier dummy.d.qid.path = path++; 241*9a747e4fSDavid du Colombier if((n=convD2M(&dummy.d, q, eq-q)) <= BIT16SZ) 242*9a747e4fSDavid du Colombier break; 243*9a747e4fSDavid du Colombier q += n; 244*9a747e4fSDavid du Colombier } 245*9a747e4fSDavid du Colombier fidp->dirindex = i; 246*9a747e4fSDavid du Colombier return q - oq; 247*9a747e4fSDavid du Colombier } 248*9a747e4fSDavid du Colombier 249*9a747e4fSDavid du Colombier /* 250*9a747e4fSDavid du Colombier * Find a directory node by type 251*9a747e4fSDavid du Colombier */ 252*9a747e4fSDavid du Colombier Node* 253*9a747e4fSDavid du Colombier finddir(int type) 254*9a747e4fSDavid du Colombier { 255*9a747e4fSDavid du Colombier Node *np; 256*9a747e4fSDavid du Colombier 257*9a747e4fSDavid du Colombier for(np = root->children; np; np = np->sibs) 258*9a747e4fSDavid du Colombier if (np->d.type == type) 259*9a747e4fSDavid du Colombier return np; 260*9a747e4fSDavid du Colombier return 0; 261*9a747e4fSDavid du Colombier } 262*9a747e4fSDavid du Colombier 263*9a747e4fSDavid du Colombier /* 264*9a747e4fSDavid du Colombier * Remove temporary pseudo-files that have timed-out 265*9a747e4fSDavid du Colombier * from the trusted directory 266*9a747e4fSDavid du Colombier */ 267*9a747e4fSDavid du Colombier void 268*9a747e4fSDavid du Colombier cleantrusted(void) 269*9a747e4fSDavid du Colombier { 270*9a747e4fSDavid du Colombier Node *np, **l; 271*9a747e4fSDavid du Colombier ulong t; 272*9a747e4fSDavid du Colombier 273*9a747e4fSDavid du Colombier np = finddir(Trusted); 274*9a747e4fSDavid du Colombier if (np == 0) 275*9a747e4fSDavid du Colombier return; 276*9a747e4fSDavid du Colombier 277*9a747e4fSDavid du Colombier t = time(0)-Timeout; 278*9a747e4fSDavid du Colombier l = &np->children; 279*9a747e4fSDavid du Colombier for (np = np->children; np; np = *l) { 280*9a747e4fSDavid du Colombier if(np->d.type == Trustedtemp && t >= np->d.mtime) { 281*9a747e4fSDavid du Colombier *l = np->sibs; 282*9a747e4fSDavid du Colombier if(debugfd >= 0) 283*9a747e4fSDavid du Colombier fprint(debugfd, "Deleting %s\n", np->d.name); 284*9a747e4fSDavid du Colombier np->parent->count--; 285*9a747e4fSDavid du Colombier free(np); 286*9a747e4fSDavid du Colombier } else 287*9a747e4fSDavid du Colombier l = &np->sibs; 288*9a747e4fSDavid du Colombier } 289*9a747e4fSDavid du Colombier } 290*9a747e4fSDavid du Colombier 291*9a747e4fSDavid du Colombier /* 292*9a747e4fSDavid du Colombier * match path components to prohibited domain & user specifications. patterns include: 293*9a747e4fSDavid du Colombier * domain, domain! or domain!* - all users in domain 294*9a747e4fSDavid du Colombier * *.domain, *.domain! or *.domain!* - all users in domain and its subdomains 295*9a747e4fSDavid du Colombier * !user or *!user - user in all domains 296*9a747e4fSDavid du Colombier * domain!user - user in domain 297*9a747e4fSDavid du Colombier * *.domain!user - user in domain and its subdomains 298*9a747e4fSDavid du Colombier * 299*9a747e4fSDavid du Colombier * if "user" has a trailing '*', it matches all user names beginning with "user" 300*9a747e4fSDavid du Colombier * 301*9a747e4fSDavid du Colombier * there are special semantics for the "domain, domain! or domain!*" specifications: 302*9a747e4fSDavid du Colombier * the first two forms match when the domain is anywhere in at list of source-routed 303*9a747e4fSDavid du Colombier * domains while the latter matches only when the domain is the last hop. the same is 304*9a747e4fSDavid du Colombier * true for the *.domain!* form of the pattern. 305*9a747e4fSDavid du Colombier */ 306*9a747e4fSDavid du Colombier static int 307*9a747e4fSDavid du Colombier accountmatch(char *spec, char **doms, int ndoms, char *user) 308*9a747e4fSDavid du Colombier { 309*9a747e4fSDavid du Colombier char *cp, *userp; 310*9a747e4fSDavid du Colombier int i, ret; 311*9a747e4fSDavid du Colombier 312*9a747e4fSDavid du Colombier userp = 0; 313*9a747e4fSDavid du Colombier ret = 0; 314*9a747e4fSDavid du Colombier cp = strchr(spec, '!'); 315*9a747e4fSDavid du Colombier if(cp){ 316*9a747e4fSDavid du Colombier *cp++ = 0; /* restored below */ 317*9a747e4fSDavid du Colombier if(*cp) 318*9a747e4fSDavid du Colombier if(strcmp(cp, "*")) /* "!*" is the same as no user field */ 319*9a747e4fSDavid du Colombier userp = cp; /* there is a user name */ 320*9a747e4fSDavid du Colombier } 321*9a747e4fSDavid du Colombier 322*9a747e4fSDavid du Colombier if(userp == 0){ /* no user field - domain match only */ 323*9a747e4fSDavid du Colombier for(i = 0; i < ndoms && doms[i]; i++) 324*9a747e4fSDavid du Colombier if(dommatch(doms[i], spec) == 0) 325*9a747e4fSDavid du Colombier ret = 1; 326*9a747e4fSDavid du Colombier } else { 327*9a747e4fSDavid du Colombier /* check for "!user", "*!user" or "domain!user" */ 328*9a747e4fSDavid du Colombier if(usermatch(user, userp) == 0){ 329*9a747e4fSDavid du Colombier if(*spec == 0 || strcmp(spec, "*") == 0) 330*9a747e4fSDavid du Colombier ret = 1; 331*9a747e4fSDavid du Colombier else if(ndoms > 0 && dommatch(doms[ndoms-1], spec) == 0) 332*9a747e4fSDavid du Colombier ret = 1; 333*9a747e4fSDavid du Colombier } 334*9a747e4fSDavid du Colombier } 335*9a747e4fSDavid du Colombier if(cp) 336*9a747e4fSDavid du Colombier cp[-1] = '!'; 337*9a747e4fSDavid du Colombier return ret; 338*9a747e4fSDavid du Colombier } 339*9a747e4fSDavid du Colombier 340*9a747e4fSDavid du Colombier /* 341*9a747e4fSDavid du Colombier * match a user name. the only meta-char is '*' which matches all 342*9a747e4fSDavid du Colombier * characters. we only allow it as "*", which matches anything or 343*9a747e4fSDavid du Colombier * an * at the end of the name (e.g., "username*") which matches 344*9a747e4fSDavid du Colombier * trailing characters. 345*9a747e4fSDavid du Colombier */ 346*9a747e4fSDavid du Colombier static int 347*9a747e4fSDavid du Colombier usermatch(char *pathuser, char *specuser) 348*9a747e4fSDavid du Colombier { 349*9a747e4fSDavid du Colombier int n; 350*9a747e4fSDavid du Colombier 351*9a747e4fSDavid du Colombier n = strlen(specuser)-1; 352*9a747e4fSDavid du Colombier if(specuser[n] == '*'){ 353*9a747e4fSDavid du Colombier if(n == 0) /* match everything */ 354*9a747e4fSDavid du Colombier return 0; 355*9a747e4fSDavid du Colombier return strncmp(pathuser, specuser, n); 356*9a747e4fSDavid du Colombier } 357*9a747e4fSDavid du Colombier return strcmp(pathuser, specuser); 358*9a747e4fSDavid du Colombier } 359*9a747e4fSDavid du Colombier 360*9a747e4fSDavid du Colombier /* 361*9a747e4fSDavid du Colombier * Match a domain specification 362*9a747e4fSDavid du Colombier */ 363*9a747e4fSDavid du Colombier static int 364*9a747e4fSDavid du Colombier dommatch(char *pathdom, char *specdom) 365*9a747e4fSDavid du Colombier { 366*9a747e4fSDavid du Colombier int n; 367*9a747e4fSDavid du Colombier 368*9a747e4fSDavid du Colombier if (*specdom == '*'){ 369*9a747e4fSDavid du Colombier if (specdom[1] == '.' && specdom[2]){ 370*9a747e4fSDavid du Colombier specdom += 2; 371*9a747e4fSDavid du Colombier n = strlen(pathdom)-strlen(specdom); 372*9a747e4fSDavid du Colombier if(n == 0 || (n > 0 && pathdom[n-1] == '.')) 373*9a747e4fSDavid du Colombier return strcmp(pathdom+n, specdom); 374*9a747e4fSDavid du Colombier return n; 375*9a747e4fSDavid du Colombier } 376*9a747e4fSDavid du Colombier } 377*9a747e4fSDavid du Colombier return strcmp(pathdom, specdom); 378*9a747e4fSDavid du Colombier } 379*9a747e4fSDavid du Colombier 380*9a747e4fSDavid du Colombier /* 381*9a747e4fSDavid du Colombier * Custom allocators to avoid malloc overheads on small objects. 382*9a747e4fSDavid du Colombier * We never free these. (See below.) 383*9a747e4fSDavid du Colombier */ 384*9a747e4fSDavid du Colombier typedef struct Stringtab Stringtab; 385*9a747e4fSDavid du Colombier struct Stringtab { 386*9a747e4fSDavid du Colombier Stringtab *link; 387*9a747e4fSDavid du Colombier char *str; 388*9a747e4fSDavid du Colombier }; 389*9a747e4fSDavid du Colombier static Stringtab* 390*9a747e4fSDavid du Colombier taballoc(void) 391*9a747e4fSDavid du Colombier { 392*9a747e4fSDavid du Colombier static Stringtab *t; 393*9a747e4fSDavid du Colombier static uint nt; 394*9a747e4fSDavid du Colombier 395*9a747e4fSDavid du Colombier if(nt == 0){ 396*9a747e4fSDavid du Colombier t = malloc(64*sizeof(Stringtab)); 397*9a747e4fSDavid du Colombier if(t == 0) 398*9a747e4fSDavid du Colombier fatal("out of memory"); 399*9a747e4fSDavid du Colombier nt = 64; 400*9a747e4fSDavid du Colombier } 401*9a747e4fSDavid du Colombier nt--; 402*9a747e4fSDavid du Colombier return t++; 403*9a747e4fSDavid du Colombier } 404*9a747e4fSDavid du Colombier 405*9a747e4fSDavid du Colombier static char* 406*9a747e4fSDavid du Colombier xstrdup(char *s) 407*9a747e4fSDavid du Colombier { 408*9a747e4fSDavid du Colombier char *r; 409*9a747e4fSDavid du Colombier int len; 410*9a747e4fSDavid du Colombier static char *t; 411*9a747e4fSDavid du Colombier static int nt; 412*9a747e4fSDavid du Colombier 413*9a747e4fSDavid du Colombier len = strlen(s)+1; 414*9a747e4fSDavid du Colombier if(len >= 8192) 415*9a747e4fSDavid du Colombier fatal("strdup big string"); 416*9a747e4fSDavid du Colombier 417*9a747e4fSDavid du Colombier if(nt < len){ 418*9a747e4fSDavid du Colombier t = malloc(8192); 419*9a747e4fSDavid du Colombier if(t == 0) 420*9a747e4fSDavid du Colombier fatal("out of memory"); 421*9a747e4fSDavid du Colombier nt = 8192; 422*9a747e4fSDavid du Colombier } 423*9a747e4fSDavid du Colombier r = t; 424*9a747e4fSDavid du Colombier t += len; 425*9a747e4fSDavid du Colombier nt -= len; 426*9a747e4fSDavid du Colombier strcpy(r, s); 427*9a747e4fSDavid du Colombier return r; 428*9a747e4fSDavid du Colombier } 429*9a747e4fSDavid du Colombier 430*9a747e4fSDavid du Colombier /* 431*9a747e4fSDavid du Colombier * Return a uniquely allocated copy of a string. 432*9a747e4fSDavid du Colombier * Don't free these -- they stay in the table for the 433*9a747e4fSDavid du Colombier * next caller who wants that particular string. 434*9a747e4fSDavid du Colombier * String comparison can be done with pointer comparison 435*9a747e4fSDavid du Colombier * if you know both strings are atoms. 436*9a747e4fSDavid du Colombier */ 437*9a747e4fSDavid du Colombier static Stringtab *stab[1024]; 438*9a747e4fSDavid du Colombier 439*9a747e4fSDavid du Colombier static uint 440*9a747e4fSDavid du Colombier hash(char *s) 441*9a747e4fSDavid du Colombier { 442*9a747e4fSDavid du Colombier uint h; 443*9a747e4fSDavid du Colombier uchar *p; 444*9a747e4fSDavid du Colombier 445*9a747e4fSDavid du Colombier h = 0; 446*9a747e4fSDavid du Colombier for(p=(uchar*)s; *p; p++) 447*9a747e4fSDavid du Colombier h = h*37 + *p; 448*9a747e4fSDavid du Colombier return h; 449*9a747e4fSDavid du Colombier } 450*9a747e4fSDavid du Colombier 451*9a747e4fSDavid du Colombier char* 452*9a747e4fSDavid du Colombier atom(char *str) 453*9a747e4fSDavid du Colombier { 454*9a747e4fSDavid du Colombier uint h; 455*9a747e4fSDavid du Colombier Stringtab *tab; 456*9a747e4fSDavid du Colombier 457*9a747e4fSDavid du Colombier h = hash(str) % nelem(stab); 458*9a747e4fSDavid du Colombier for(tab=stab[h]; tab; tab=tab->link) 459*9a747e4fSDavid du Colombier if(strcmp(str, tab->str) == 0) 460*9a747e4fSDavid du Colombier return tab->str; 461*9a747e4fSDavid du Colombier 462*9a747e4fSDavid du Colombier tab = taballoc(); 463*9a747e4fSDavid du Colombier tab->str = xstrdup(str); 464*9a747e4fSDavid du Colombier tab->link = stab[h]; 465*9a747e4fSDavid du Colombier stab[h] = tab; 466*9a747e4fSDavid du Colombier return tab->str; 467*9a747e4fSDavid du Colombier } 468