chiark / gitweb /
Merge branches 'idx/verh' and 'idx/qmqpc'
[qmail] / cdb_seek.c
1 #include <sys/types.h>
2 #include <errno.h>
3 extern int errno;
4 #include "cdb.h"
5
6 #ifndef SEEK_SET
7 #define SEEK_SET 0
8 #endif
9
10 int cdb_bread(fd,buf,len)
11 int fd;
12 char *buf;
13 int len;
14 {
15   int r;
16   while (len > 0) {
17     do
18       r = read(fd,buf,len);
19     while ((r == -1) && (errno == EINTR));
20     if (r == -1) return -1;
21     if (r == 0) { errno = EIO; return -1; }
22     buf += r;
23     len -= r;
24   }
25   return 0;
26 }
27
28 static int match(fd,key,len)
29 int fd;
30 char *key;
31 unsigned int len;
32 {
33   char buf[32];
34   int n;
35   int i;
36
37   while (len > 0) {
38     n = sizeof(buf);
39     if (n > len) n = len;
40     if (cdb_bread(fd,buf,n) == -1) return -1;
41     for (i = 0;i < n;++i) if (buf[i] != key[i]) return 0;
42     key += n;
43     len -= n;
44   }
45   return 1;
46 }
47
48 int cdb_seek(fd,key,len,dlen)
49 int fd;
50 char *key;
51 unsigned int len;
52 uint32 *dlen;
53 {
54   char packbuf[8];
55   uint32 pos;
56   uint32 h;
57   uint32 lenhash;
58   uint32 h2;
59   uint32 loop;
60   uint32 poskd;
61
62   h = cdb_hash(key,len);
63
64   pos = 8 * (h & 255);
65   if (lseek(fd,(off_t) pos,SEEK_SET) == -1) return -1;
66
67   if (cdb_bread(fd,packbuf,8) == -1) return -1;
68
69   pos = cdb_unpack(packbuf);
70   lenhash = cdb_unpack(packbuf + 4);
71
72   if (!lenhash) return 0;
73   h2 = (h >> 8) % lenhash;
74
75   for (loop = 0;loop < lenhash;++loop) {
76     if (lseek(fd,(off_t) (pos + 8 * h2),SEEK_SET) == -1) return -1;
77     if (cdb_bread(fd,packbuf,8) == -1) return -1;
78     poskd = cdb_unpack(packbuf + 4);
79     if (!poskd) return 0;
80     if (cdb_unpack(packbuf) == h) {
81       if (lseek(fd,(off_t) poskd,SEEK_SET) == -1) return -1;
82       if (cdb_bread(fd,packbuf,8) == -1) return -1;
83       if (cdb_unpack(packbuf) == len)
84         switch(match(fd,key,len)) {
85           case -1:
86             return -1;
87           case 1:
88             *dlen = cdb_unpack(packbuf + 4);
89             return 1;
90         }
91     }
92     if (++h2 == lenhash) h2 = 0;
93   }
94   return 0;
95 }