]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/mkhash.c
ndb/dnstcp: restrict DNS zone transfers to clients listed as dnsslave=
[plan9front.git] / sys / src / cmd / ndb / mkhash.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ndb.h>
5
6 /*
7  *  make the hash table completely in memory and then write as a file
8  */
9
10 uchar *ht;
11 ulong hlen;
12 Ndb *db;
13 ulong nextchain;
14
15 char*
16 syserr(void)
17 {
18         static char buf[ERRMAX];
19
20         errstr(buf, sizeof buf);
21         return buf;
22 }
23
24 void
25 enter(char *val, ulong dboff)
26 {
27         ulong h;
28         uchar *last;
29         ulong ptr;
30
31         h = ndbhash(val, hlen);
32         h *= NDBPLEN;
33         last = &ht[h];
34         ptr = NDBGETP(last);
35         if(ptr == NDBNAP){
36                 NDBPUTP(dboff, last);
37                 return;
38         }
39
40         if(ptr & NDBCHAIN){
41                 /* walk the chain to the last entry */
42                 for(;;){
43                         ptr &= ~NDBCHAIN;
44                         last = &ht[ptr+NDBPLEN];
45                         ptr = NDBGETP(last);
46                         if(ptr == NDBNAP){
47                                 NDBPUTP(dboff, last);
48                                 return;
49                         }
50                         if(!(ptr & NDBCHAIN)){
51                                 NDBPUTP(nextchain|NDBCHAIN, last);
52                                 break;
53                         }
54                 }
55         } else
56                 NDBPUTP(nextchain|NDBCHAIN, last);
57
58         /* add a chained entry */
59         NDBPUTP(ptr, &ht[nextchain]);
60         NDBPUTP(dboff, &ht[nextchain + NDBPLEN]);
61         nextchain += 2*NDBPLEN;
62 }
63
64 uchar nbuf[16*1024];
65
66 void
67 main(int argc, char **argv)
68 {
69         Ndbtuple *t, *nt;
70         int n;
71         Dir *d; 
72         uchar buf[8];
73         char file[128];
74         int fd;
75         ulong off;
76         uchar *p;
77
78         if(argc != 3){
79                 fprint(2, "usage: mkhash file attribute\n");
80                 exits("usage");
81         }
82         db = ndbopen(argv[1]);
83         if(db == 0){
84                 fprint(2, "mkhash: can't open %s\n", argv[1]);
85                 exits(syserr());
86         }
87
88         /* try a bigger than normal buffer */
89         Binits(&db->b, Bfildes(&db->b), OREAD, nbuf, sizeof(nbuf));
90
91         /* count entries to calculate hash size */
92         n = 0;
93
94         while(nt = ndbparse(db)){
95                 for(t = nt; t; t = t->entry){
96                         if(strcmp(t->attr, argv[2]) == 0)
97                                 n++;
98                 }
99                 ndbfree(nt);
100         }
101
102         /* allocate an array large enough for worst case */
103         hlen = 2*n+1;
104         n = hlen*NDBPLEN + hlen*2*NDBPLEN;
105         ht = mallocz(n, 1);
106         if(ht == 0){
107                 fprint(2, "mkhash: not enough memory\n");
108                 exits(syserr());
109         }
110         for(p = ht; p < &ht[n]; p += NDBPLEN)
111                 NDBPUTP(NDBNAP, p);
112         nextchain = hlen*NDBPLEN;
113
114         /* create the in core hash table */
115         Bseek(&db->b, 0, 0);
116         off = 0;
117         while(nt = ndbparse(db)){
118                 for(t = nt; t; t = t->entry){
119                         if(strcmp(t->attr, argv[2]) == 0)
120                                 enter(t->val, off);
121                 }
122                 ndbfree(nt);
123                 off = Boffset(&db->b);
124         }
125
126         /* create the hash file */
127         snprint(file, sizeof(file), "%s.%s", argv[1], argv[2]);
128         fd = create(file, ORDWR, 0664);
129         if(fd < 0){
130                 fprint(2, "mkhash: can't create %s\n", file);
131                 exits(syserr());
132         }
133         NDBPUTUL(db->mtime, buf);
134         NDBPUTUL(hlen, buf+NDBULLEN);
135         if(write(fd, buf, NDBHLEN) != NDBHLEN){
136                 fprint(2, "mkhash: writing %s\n", file);
137                 exits(syserr());
138         }
139         if(write(fd, ht, nextchain) != nextchain){
140                 fprint(2, "mkhash: writing %s\n", file);
141                 exits(syserr());
142         }
143         close(fd);
144
145         /* make sure file didn't change while we were making the hash */
146         d = dirstat(argv[1]);
147         if(d == nil || d->qid.path != db->qid.path
148            || d->qid.vers != db->qid.vers){
149                 fprint(2, "mkhash: %s changed underfoot\n", argv[1]);
150                 remove(file);
151                 exits("changed");
152         }
153
154         exits(0);
155 }