| 1 |
sysadm |
1.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 |
|
|
}
|