release
[hcoop/zz_old/debian/djbdns.git] / cdb.c
CommitLineData
dc0d77d7
CE
1/* Public domain. */
2
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <sys/mman.h>
6#include <unistd.h>
7#include "error.h"
8#include "seek.h"
9#include "byte.h"
10#include "cdb.h"
11
12void cdb_free(struct cdb *c)
13{
14 if (c->map) {
15 munmap(c->map,c->size);
16 c->map = 0;
17 }
18}
19
20void cdb_findstart(struct cdb *c)
21{
22 c->loop = 0;
23}
24
25void cdb_init(struct cdb *c,int fd)
26{
27 struct stat st;
28 char *x;
29
30 cdb_free(c);
31 cdb_findstart(c);
32 c->fd = fd;
33
34 if (fstat(fd,&st) == 0)
35 if (st.st_size <= 0xffffffff) {
36 x = mmap(0,st.st_size,PROT_READ,MAP_SHARED,fd,0);
37 if (x + 1) {
38 c->size = st.st_size;
39 c->map = x;
40 }
41 }
42}
43
44int cdb_read(struct cdb *c,char *buf,unsigned int len,uint32 pos)
45{
46 if (c->map) {
47 if ((pos > c->size) || (c->size - pos < len)) goto FORMAT;
48 byte_copy(buf,len,c->map + pos);
49 }
50 else {
51 if (seek_set(c->fd,pos) == -1) return -1;
52 while (len > 0) {
53 int r;
54 do
55 r = read(c->fd,buf,len);
56 while ((r == -1) && (errno == error_intr));
57 if (r == -1) return -1;
58 if (r == 0) goto FORMAT;
59 buf += r;
60 len -= r;
61 }
62 }
63 return 0;
64
65 FORMAT:
66 errno = error_proto;
67 return -1;
68}
69
70static int match(struct cdb *c,const char *key,unsigned int len,uint32 pos)
71{
72 char buf[32];
73 int n;
74
75 while (len > 0) {
76 n = sizeof buf;
77 if (n > len) n = len;
78 if (cdb_read(c,buf,n,pos) == -1) return -1;
79 if (byte_diff(buf,n,key)) return 0;
80 pos += n;
81 key += n;
82 len -= n;
83 }
84 return 1;
85}
86
87int cdb_findnext(struct cdb *c,const char *key,unsigned int len)
88{
89 char buf[8];
90 uint32 pos;
91 uint32 u;
92
93 if (!c->loop) {
94 u = cdb_hash(key,len);
95 if (cdb_read(c,buf,8,(u << 3) & 2047) == -1) return -1;
96 uint32_unpack(buf + 4,&c->hslots);
97 if (!c->hslots) return 0;
98 uint32_unpack(buf,&c->hpos);
99 c->khash = u;
100 u >>= 8;
101 u %= c->hslots;
102 u <<= 3;
103 c->kpos = c->hpos + u;
104 }
105
106 while (c->loop < c->hslots) {
107 if (cdb_read(c,buf,8,c->kpos) == -1) return -1;
108 uint32_unpack(buf + 4,&pos);
109 if (!pos) return 0;
110 c->loop += 1;
111 c->kpos += 8;
112 if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos;
113 uint32_unpack(buf,&u);
114 if (u == c->khash) {
115 if (cdb_read(c,buf,8,pos) == -1) return -1;
116 uint32_unpack(buf,&u);
117 if (u == len)
118 switch(match(c,key,len,pos + 8)) {
119 case -1:
120 return -1;
121 case 1:
122 uint32_unpack(buf + 4,&c->dlen);
123 c->dpos = pos + 8 + len;
124 return 1;
125 }
126 }
127 }
128
129 return 0;
130}
131
132int cdb_find(struct cdb *c,const char *key,unsigned int len)
133{
134 cdb_findstart(c);
135 return cdb_findnext(c,key,len);
136}