1 #define _FILE_OFFSET_BITS 64
2 
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include "byte.h"
8 #include "cdb.h"
9 #include "havepread.h"
10 #ifdef __MINGW32__
11 #include "windows.h"
12 #else
13 #include <sys/mman.h>
14 #endif
15 
cdb_free(struct cdb * c)16 void cdb_free(struct cdb *c) {
17   if (c->map) {
18 #ifdef __MINGW32__
19     UnmapViewOfFile(c->map);
20 #else
21     munmap(c->map,c->size);
22 #endif
23     c->map = 0;
24   }
25 }
26 
cdb_findstart(struct cdb * c)27 void cdb_findstart(struct cdb *c) {
28   c->loop = 0;
29 }
30 
cdb_init(struct cdb * c,int64 fd)31 void cdb_init(struct cdb *c,int64 fd) {
32 #ifndef __MINGW32__
33   struct stat st;
34   char *x;
35 #endif
36 
37   cdb_free(c);
38   cdb_findstart(c);
39   c->fd = fd;
40 
41 #ifdef __MINGW32__
42   {
43     HANDLE m=CreateFileMapping((HANDLE)(uintptr_t)fd,0,PAGE_READONLY,0,0,NULL);
44     if (m)
45       if ((c->map=MapViewOfFile(m,FILE_MAP_READ,0,0,0)))
46 	c->size=GetFileSize((HANDLE)(uintptr_t)fd,NULL);
47     CloseHandle(m);
48   }
49 #else
50   if (fstat(fd,&st) == 0)
51     if (st.st_size <= 0xffffffff) {
52       x = mmap(0,st.st_size,PROT_READ,MAP_SHARED,fd,0);
53       if (x != MAP_FAILED) {
54 	c->size = st.st_size;
55 	c->map = x;
56       }
57     }
58 #endif
59 }
60 
cdb_read(struct cdb * c,unsigned char * buf,unsigned long len,uint32 pos)61 int cdb_read(struct cdb *c,unsigned char *buf,unsigned long len,uint32 pos) {
62   if (c->map) {
63     if ((pos > c->size) || (c->size - pos < len)) goto FORMAT;
64     byte_copy(buf,len,c->map + pos);
65   }
66   else {
67 #ifndef HAVE_PREAD
68     if (lseek(c->fd,pos,SEEK_SET) == -1) return -1;
69 #endif
70     while (len > 0) {
71       ssize_t r;
72       do
73 #ifdef HAVE_PREAD
74 	r = pread(c->fd,buf,len,pos);
75 #else
76         r = read(c->fd,buf,len);
77 #endif
78       while ((r == -1) && (errno == EINTR));
79       if (r == -1) return -1;
80       if (r == 0) goto FORMAT;
81       buf += r;
82       len -= r;
83 #ifdef HAVE_PREAD
84       pos += r;
85 #endif
86     }
87   }
88   return 0;
89 
90   FORMAT:
91 #ifdef EPROTO
92   errno = EPROTO;
93 #else
94   errno = EINVAL;
95 #endif
96   return -1;
97 }
98 
match(struct cdb * c,const unsigned char * key,unsigned long int len,uint32 pos)99 static int match(struct cdb *c,const unsigned char *key,unsigned long int len,uint32 pos) {
100   unsigned char buf[32];
101   unsigned long n;
102 
103   while (len > 0) {
104     n = sizeof buf;
105     if (n > len) n = len;
106     if (cdb_read(c,buf,n,pos) == -1) return -1;
107     if (byte_diff(buf,n,key)) return 0;
108     pos += n;
109     key += n;
110     len -= n;
111   }
112   return 1;
113 }
114 
cdb_findnext(struct cdb * c,const unsigned char * key,unsigned long int len)115 int cdb_findnext(struct cdb *c,const unsigned char *key,unsigned long int len) {
116   unsigned char buf[8];
117   uint32 pos;
118   uint32 u;
119 
120   if (!c->loop) {
121     u = cdb_hash(key,len);
122     if (cdb_read(c,buf,8,(u << 3) & 2047) == -1) return -1;
123     uint32_unpack((char*)buf + 4,&c->hslots);
124     if (!c->hslots) return 0;
125     uint32_unpack((char*)buf,&c->hpos);
126     c->khash = u;
127     u >>= 8;
128     u %= c->hslots;
129     u <<= 3;
130     c->kpos = c->hpos + u;
131   }
132 
133   while (c->loop < c->hslots) {
134     if (cdb_read(c,buf,8,c->kpos) == -1) return -1;
135     uint32_unpack((char*)buf + 4,&pos);
136     if (!pos) return 0;
137     c->loop += 1;
138     c->kpos += 8;
139     if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos;
140     uint32_unpack((char*)buf,&u);
141     if (u == c->khash) {
142       if (cdb_read(c,buf,8,pos) == -1) return -1;
143       uint32_unpack((char*)buf,&u);
144       if (u == len)
145 	switch(match(c,key,len,pos + 8)) {
146 	  case -1:
147 	    return -1;
148 	  case 1:
149 	    uint32_unpack((char*)buf + 4,&c->dlen);
150 	    c->dpos = pos + 8 + len;
151 	    return 1;
152 	}
153     }
154   }
155 
156   return 0;
157 }
158 
cdb_find(struct cdb * c,const unsigned char * key,unsigned long int len)159 int cdb_find(struct cdb *c,const unsigned char *key,unsigned long int len) {
160   cdb_findstart(c);
161   return cdb_findnext(c,key,len);
162 }
163