public
Description: A lua binding to the tinycdb library by Michael Tokarev
Homepage: http://asbradbury.org/projects/lua-tinycdb/
Clone URL: git://github.com/asb/lua-tinycdb.git
lua-tinycdb / cdb_seek.c
100644 101 lines (91 sloc) 2.713 kb
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
/* $Id: cdb_seek.c,v 1.7 2006/09/03 09:51:25 mjt Exp $
* old interface for reading cdb file
*
* This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
* Public domain.
*/
 
#include <unistd.h>
#include "cdb_int.h"
 
#ifndef SEEK_SET
# define SEEK_SET 0
#endif
 
/* read a chunk from file, ignoring interrupts (EINTR) */
 
int
cdb_bread(int fd, void *buf, int len)
{
  int l;
  while(len > 0) {
    do l = read(fd, buf, len);
    while(l < 0 && errno == EINTR);
    if (l <= 0) {
      if (!l)
        errno = EIO;
      return -1;
    }
    buf = (char*)buf + l;
    len -= l;
  }
  return 0;
}
 
/* find a given key in cdb file, seek a file pointer to it's value and
place data length to *dlenp. */
 
int
cdb_seek(int fd, const void *key, unsigned klen, unsigned *dlenp)
{
  unsigned htstart; /* hash table start position */
  unsigned htsize; /* number of elements in a hash table */
  unsigned httodo; /* hash table elements left to look */
  unsigned hti; /* hash table index */
  unsigned pos; /* position in a file */
  unsigned hval; /* key's hash value */
  unsigned char rbuf[64]; /* read buffer */
  int needseek = 1; /* if we should seek to a hash slot */
 
  hval = cdb_hash(key, klen);
  pos = (hval & 0xff) << 3; /* position in TOC */
  /* read the hash table parameters */
  if (lseek(fd, pos, SEEK_SET) < 0 || cdb_bread(fd, rbuf, 8) < 0)
    return -1;
  if ((htsize = cdb_unpack(rbuf + 4)) == 0)
    return 0;
  hti = (hval >> 8) % htsize; /* start position in hash table */
  httodo = htsize;
  htstart = cdb_unpack(rbuf);
 
  for(;;) {
    if (needseek && lseek(fd, htstart + (hti << 3), SEEK_SET) < 0)
      return -1;
    if (cdb_bread(fd, rbuf, 8) < 0)
      return -1;
    if ((pos = cdb_unpack(rbuf + 4)) == 0) /* not found */
      return 0;
 
    if (cdb_unpack(rbuf) != hval) /* hash value not matched */
      needseek = 0;
    else { /* hash value matched */
      if (lseek(fd, pos, SEEK_SET) < 0 || cdb_bread(fd, rbuf, 8) < 0)
return -1;
      if (cdb_unpack(rbuf) == klen) { /* key length matches */
/* read the key from file and compare with wanted */
unsigned l = klen, c;
const char *k = (const char*)key;
if (dlenp)
*dlenp = cdb_unpack(rbuf + 4); /* save value length */
for(;;) {
if (!l) /* the whole key read and matches, return */
return 1;
c = l > sizeof(rbuf) ? sizeof(rbuf) : l;
if (cdb_bread(fd, rbuf, c) < 0)
return -1;
if (memcmp(rbuf, k, c) != 0) /* no, it differs, stop here */
break;
k += c; l -= c;
}
      }
      needseek = 1; /* we're looked to other place, should seek back */
    }
    if (!--httodo)
      return 0;
    if (++hti == htsize) {
      hti = 0;
      needseek = 1;
    }
  }
}