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