Branch data Line data Source code
1 : : /* cdb_seek.c: old interface for reading cdb file
2 : : *
3 : : * This file is a part of tinycdb package.
4 : : * Copyright (C) 2001-2023 Michael Tokarev <mjt+cdb@corpit.ru>
5 : : *
6 : : * Permission is hereby granted, free of charge, to any person obtaining a
7 : : * copy of this software and associated documentation files (the "Software"),
8 : : * to deal in the Software without restriction, including without limitation
9 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 : : * and/or sell copies of the Software, and to permit persons to whom the
11 : : * Software is furnished to do so, subject to the following conditions:
12 : : *
13 : : * The above copyright notice and this permission notice shall be included
14 : : * in all copies or substantial portions of the Software.
15 : : *
16 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 : : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 : : * DEALINGS IN THE SOFTWARE.
23 : : */
24 : :
25 : : #include <unistd.h>
26 : : #include "cdb_int.h"
27 : :
28 : : #ifndef SEEK_SET
29 : : # define SEEK_SET 0
30 : : #endif
31 : :
32 : : /* read a chunk from file, ignoring interrupts (EINTR) */
33 : :
34 : : int
35 : 126 : cdb_bread(int fd, void *buf, int len)
36 : : {
37 : : int l;
38 [ + + ]: 252 : while(len > 0) {
39 : 126 : do l = read(fd, buf, len);
40 [ - + - - ]: 126 : while(l < 0 && errno == EINTR);
41 [ - + ]: 126 : if (l <= 0) {
42 [ # # ]: 0 : if (!l)
43 : 0 : errno = EIO;
44 : 0 : return -1;
45 : : }
46 : 126 : buf = (char*)buf + l;
47 : 126 : len -= l;
48 : : }
49 : 126 : return 0;
50 : : }
51 : :
52 : : /* find a given key in cdb file, seek a file pointer to it's value and
53 : : place data length to *dlenp. */
54 : :
55 : : int
56 : 63 : cdb_seek(int fd, const void *key, unsigned klen, unsigned *dlenp)
57 : : {
58 : : unsigned htstart; /* hash table start position */
59 : : unsigned htsize; /* number of elements in a hash table */
60 : : unsigned httodo; /* hash table elements left to look */
61 : : unsigned hti; /* hash table index */
62 : : unsigned pos; /* position in a file */
63 : : unsigned hval; /* key's hash value */
64 : : unsigned char rbuf[64]; /* read buffer */
65 : 63 : int needseek = 1; /* if we should seek to a hash slot */
66 : :
67 : 63 : hval = cdb_hash(key, klen);
68 : 63 : pos = (hval & 0xff) << 3; /* position in TOC */
69 : : /* read the hash table parameters */
70 [ + - - + ]: 63 : if (lseek(fd, pos, SEEK_SET) < 0 || cdb_bread(fd, rbuf, 8) < 0)
71 : 0 : return -1;
72 [ + + ]: 63 : if ((htsize = cdb_unpack(rbuf + 4)) == 0)
73 : 44 : return 0;
74 : 19 : hti = (hval >> 8) % htsize; /* start position in hash table */
75 : 19 : httodo = htsize;
76 : 19 : htstart = cdb_unpack(rbuf);
77 : :
78 : : for(;;) {
79 [ + - - + ]: 19 : if (needseek && lseek(fd, htstart + (hti << 3), SEEK_SET) < 0)
80 : 0 : return -1;
81 [ - + ]: 19 : if (cdb_bread(fd, rbuf, 8) < 0)
82 : 0 : return -1;
83 [ - + ]: 19 : if ((pos = cdb_unpack(rbuf + 4)) == 0) /* not found */
84 : 0 : return 0;
85 : :
86 [ - + ]: 19 : if (cdb_unpack(rbuf) != hval) /* hash value not matched */
87 : 0 : needseek = 0;
88 : : else { /* hash value matched */
89 [ + - - + ]: 19 : if (lseek(fd, pos, SEEK_SET) < 0 || cdb_bread(fd, rbuf, 8) < 0)
90 : 0 : return -1;
91 [ + - ]: 19 : if (cdb_unpack(rbuf) == klen) { /* key length matches */
92 : : /* read the key from file and compare with wanted */
93 : 19 : unsigned l = klen, c;
94 : 19 : const char *k = (const char*)key;
95 [ + - ]: 19 : if (dlenp)
96 : 19 : *dlenp = cdb_unpack(rbuf + 4); /* save value length */
97 : : for(;;) {
98 [ + + ]: 38 : if (!l) /* the whole key read and matches, return */
99 : 19 : return 1;
100 : 19 : c = l > sizeof(rbuf) ? sizeof(rbuf) : l;
101 [ - + ]: 19 : if (cdb_bread(fd, rbuf, c) < 0)
102 : 0 : return -1;
103 [ - + ]: 19 : if (memcmp(rbuf, k, c) != 0) /* no, it differs, stop here */
104 : 0 : break;
105 : 19 : k += c; l -= c;
106 : : }
107 : : }
108 : 0 : needseek = 1; /* we're looked to other place, should seek back */
109 : : }
110 [ # # ]: 0 : if (!--httodo)
111 : 0 : return 0;
112 [ # # ]: 0 : if (++hti == htsize) {
113 : 0 : hti = 0;
114 : 0 : needseek = 1;
115 : : }
116 : : }
117 : : }
|