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