|
1 /* Public domain. */ |
|
2 |
|
3 #include <sys/types.h> |
|
4 #include <sys/stat.h> |
|
5 #include <sys/mman.h> |
|
6 #include "readwrite.h" |
|
7 #include "error.h" |
|
8 #include "seek.h" |
|
9 #include "byte.h" |
|
10 #include "cdb.h" |
|
11 |
|
12 void cdb_free(struct cdb *c) |
|
13 { |
|
14 if (c->map) { |
|
15 munmap(c->map,c->size); |
|
16 c->map = 0; |
|
17 } |
|
18 } |
|
19 |
|
20 void cdb_findstart(struct cdb *c) |
|
21 { |
|
22 c->loop = 0; |
|
23 } |
|
24 |
|
25 void 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 |
|
44 int 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 |
|
70 static int match(struct cdb *c,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 |
|
87 int cdb_findnext(struct cdb *c,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 |
|
132 int cdb_find(struct cdb *c,char *key,unsigned int len) |
|
133 { |
|
134 cdb_findstart(c); |
|
135 return cdb_findnext(c,key,len); |
|
136 } |