Imported Upstream version 2.5.1
[ossec-hids.git] / src / analysisd / cdb / cdb.c
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
16 void cdb_free(struct cdb *c)
17 {
18   if (c->map) {
19     munmap(c->map,c->size);
20     c->map = 0;
21   }
22 }
23
24 void cdb_findstart(struct cdb *c)
25 {
26   c->loop = 0;
27 }
28
29 void 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
48 int 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
75 static 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
92 int 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
137 int cdb_find(struct cdb *c,char *key,unsigned int len)
138 {
139   cdb_findstart(c);
140   return cdb_findnext(c,key,len);
141 }