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