| 1 |
/* old interface for reading cdb file
|
| 2 |
*
|
| 3 |
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
|
| 4 |
* Public domain.
|
| 5 |
*/
|
| 6 |
|
| 7 |
#include "common/setup_before.h"
|
| 8 |
#include <stdio.h>
|
| 9 |
#include "cdb_int.h"
|
| 10 |
#include "common/setup_after.h"
|
| 11 |
|
| 12 |
#ifndef SEEK_SET
|
| 13 |
# define SEEK_SET 0
|
| 14 |
#endif
|
| 15 |
|
| 16 |
/* read a chunk from file, ignoring interrupts (EINTR) */
|
| 17 |
|
| 18 |
int
|
| 19 |
cdb_bread(FILE *fd, void *buf, int len)
|
| 20 |
{
|
| 21 |
int l;
|
| 22 |
while(len > 0) {
|
| 23 |
do l = fread(buf, 1, len, fd);
|
| 24 |
while(l < 0 && errno == EINTR);
|
| 25 |
if (l <= 0) {
|
| 26 |
if (!l)
|
| 27 |
errno = EIO;
|
| 28 |
return -1;
|
| 29 |
}
|
| 30 |
buf = (char*)buf + l;
|
| 31 |
len -= l;
|
| 32 |
}
|
| 33 |
return 0;
|
| 34 |
}
|
| 35 |
|
| 36 |
/* find a given key in cdb file, seek a file pointer to it's value and
|
| 37 |
place data length to *dlenp. */
|
| 38 |
|
| 39 |
int
|
| 40 |
cdb_seek(FILE *fd, const void *key, unsigned klen, unsigned *dlenp)
|
| 41 |
{
|
| 42 |
unsigned htstart; /* hash table start position */
|
| 43 |
unsigned htsize; /* number of elements in a hash table */
|
| 44 |
unsigned httodo; /* hash table elements left to look */
|
| 45 |
unsigned hti; /* hash table index */
|
| 46 |
unsigned pos; /* position in a file */
|
| 47 |
unsigned hval; /* key's hash value */
|
| 48 |
unsigned char rbuf[64]; /* read buffer */
|
| 49 |
int needseek = 1; /* if we should seek to a hash slot */
|
| 50 |
|
| 51 |
hval = cdb_hash(key, klen);
|
| 52 |
pos = (hval & 0xff) << 3; /* position in TOC */
|
| 53 |
/* read the hash table parameters */
|
| 54 |
if (fseek(fd, pos, SEEK_SET) || cdb_bread(fd, rbuf, 8) < 0)
|
| 55 |
return -1;
|
| 56 |
if ((htsize = cdb_unpack(rbuf + 4)) == 0)
|
| 57 |
return 0;
|
| 58 |
hti = (hval >> 8) % htsize; /* start position in hash table */
|
| 59 |
httodo = htsize;
|
| 60 |
htstart = cdb_unpack(rbuf);
|
| 61 |
|
| 62 |
for(;;) {
|
| 63 |
if (needseek && fseek(fd, htstart + (hti << 3), SEEK_SET))
|
| 64 |
return -1;
|
| 65 |
if (cdb_bread(fd, rbuf, 8) < 0)
|
| 66 |
return -1;
|
| 67 |
if ((pos = cdb_unpack(rbuf + 4)) == 0) /* not found */
|
| 68 |
return 0;
|
| 69 |
|
| 70 |
if (cdb_unpack(rbuf) != hval) /* hash value not matched */
|
| 71 |
needseek = 0;
|
| 72 |
else { /* hash value matched */
|
| 73 |
if (fseek(fd, pos, SEEK_SET) || cdb_bread(fd, rbuf, 8) < 0)
|
| 74 |
return -1;
|
| 75 |
if (cdb_unpack(rbuf) == klen) { /* key length matches */
|
| 76 |
/* read the key from file and compare with wanted */
|
| 77 |
unsigned l = klen, c;
|
| 78 |
const char *k = (const char*)key;
|
| 79 |
if (*dlenp)
|
| 80 |
*dlenp = cdb_unpack(rbuf + 4); /* save value length */
|
| 81 |
for(;;) {
|
| 82 |
if (!l) /* the whole key read and matches, return */
|
| 83 |
return 1;
|
| 84 |
c = l > sizeof(rbuf) ? sizeof(rbuf) : l;
|
| 85 |
if (cdb_bread(fd, rbuf, c) < 0)
|
| 86 |
return -1;
|
| 87 |
if (memcmp(rbuf, k, c) != 0) /* no, it differs, stop here */
|
| 88 |
break;
|
| 89 |
k += c; l -= c;
|
| 90 |
}
|
| 91 |
}
|
| 92 |
needseek = 1; /* we're looked to other place, should seek back */
|
| 93 |
}
|
| 94 |
if (!--httodo)
|
| 95 |
return 0;
|
| 96 |
if (++hti == htsize) {
|
| 97 |
hti = 0;
|
| 98 |
needseek = 1;
|
| 99 |
}
|
| 100 |
}
|
| 101 |
}
|