xref: /netbsd-src/lib/libc/citrus/citrus_db.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: citrus_db.c,v 1.1 2003/06/25 09:51:28 tshiozak Exp $	*/
2 
3 /*-
4  * Copyright (c)2003 Citrus Project,
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #if defined(LIBC_SCCS) && !defined(lint)
31 __RCSID("$NetBSD: citrus_db.c,v 1.1 2003/06/25 09:51:28 tshiozak Exp $");
32 #endif /* LIBC_SCCS and not lint */
33 
34 #include "namespace.h"
35 #include <assert.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <sys/types.h>
42 
43 #include "citrus_namespace.h"
44 #include "citrus_bcs.h"
45 #include "citrus_region.h"
46 #include "citrus_memstream.h"
47 #include "citrus_mmap.h"
48 #include "citrus_db.h"
49 #include "citrus_db_file.h"
50 
51 struct _citrus_db {
52 	/* private */
53 	struct _region db_region;
54 	u_int32_t (*db_hashfunc)(void *, struct _citrus_region *);
55 	void *db_hashfunc_closure;
56 };
57 
58 int
59 _citrus_db_open(struct _citrus_db **rdb, struct _region *r, const char *magic,
60 		u_int32_t (*hashfunc)(void *, struct _citrus_region *),
61 		void *hashfunc_closure)
62 {
63 	struct _memstream ms;
64 	struct _citrus_db *db;
65 	struct _citrus_db_header_x *dhx;
66 
67 	_memstream_bind(&ms, r);
68 
69 	/* sanity check */
70 	dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
71 	if (dhx == NULL)
72 		return EFTYPE;
73 	if (strncmp(dhx->dhx_magic, magic, _CITRUS_DB_MAGIC_SIZE) != 0)
74 		return EFTYPE;
75 	if (_memstream_seek(&ms, be32toh(dhx->dhx_entry_offset), SEEK_SET))
76 		return EFTYPE;
77 
78 	if (be32toh(dhx->dhx_num_entries)*_CITRUS_DB_ENTRY_SIZE >
79 	    _memstream_remainder(&ms))
80 		return EFTYPE;
81 
82 	db = malloc(sizeof(*db));
83 	if (db==NULL)
84 		return errno;
85 	db->db_region = *r;
86 	db->db_hashfunc = hashfunc;
87 	db->db_hashfunc_closure = hashfunc_closure;
88 	*rdb = db;
89 
90 	return 0;
91 }
92 
93 void
94 _citrus_db_close(struct _citrus_db *db)
95 {
96 	free(db);
97 }
98 
99 int
100 _citrus_db_lookup(struct _citrus_db *db, struct _citrus_region *key,
101 		  struct _citrus_region *data, struct _citrus_db_locator *dl)
102 {
103 	u_int32_t hashval, num_entries;
104 	size_t offset;
105 	struct _memstream ms;
106 	struct _citrus_db_header_x *dhx;
107 	struct _citrus_db_entry_x *dex;
108 	struct _citrus_region r;
109 
110 	_memstream_bind(&ms, &db->db_region);
111 
112 	dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
113 	_DIAGASSERT(dhx);
114 	num_entries = be32toh(dhx->dhx_num_entries);
115 	if (num_entries == 0)
116 		return ENOENT;
117 
118 	if (dl != NULL && dl->dl_offset>0) {
119 		hashval = dl->dl_hashval;
120 		offset = dl->dl_offset;
121 		if (offset >= _region_size(&db->db_region))
122 			return ENOENT;
123 	} else {
124 		hashval =
125 		    db->db_hashfunc(db->db_hashfunc_closure, key)%num_entries;
126 		offset =
127 		    be32toh(dhx->dhx_entry_offset) +
128 		    hashval * _CITRUS_DB_ENTRY_SIZE;
129 		if (dl)
130 			dl->dl_hashval = hashval;
131 	}
132 	do {
133 		/* seek to the next entry */
134 		if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
135 			return EFTYPE;
136 		/* get the entry record */
137 		dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
138 		if (dex == NULL)
139 			return EFTYPE;
140 
141 		/* jump to next entry having the same hash value. */
142 		offset = be32toh(dex->dex_next_offset);
143 
144 		/* save the current position */
145 		if (dl) {
146 			dl->dl_offset = offset;
147 			if (offset==0)
148 				dl->dl_offset = _region_size(&db->db_region);
149 		}
150 
151 		/* compare hash value. */
152 		if (be32toh(dex->dex_hash_value) != hashval)
153 			/* not found */
154 			break;
155 		/* compare key length */
156 		if (be32toh(dex->dex_key_size) == _region_size(key)) {
157 			/* seek to the head of the key. */
158 			if (_memstream_seek(&ms, be32toh(dex->dex_key_offset),
159 					    SEEK_SET))
160 				return EFTYPE;
161 			/* get the region of the key */
162 			if (_memstream_getregion(&ms, &r,
163 						 _region_size(key)) == NULL)
164 				return EFTYPE;
165 			/* compare key byte stream */
166 			if (memcmp(_region_head(&r), _region_head(key),
167 				   _region_size(key)) == 0) {
168 				/* match */
169 				if (_memstream_seek(
170 					&ms, be32toh(dex->dex_data_offset),
171 					SEEK_SET))
172 					return EFTYPE;
173 				if (_memstream_getregion(
174 					&ms, data,
175 					be32toh(dex->dex_data_size)) == NULL)
176 					return EFTYPE;
177 				return 0;
178 			}
179 		}
180 	} while (offset != 0);
181 
182 	return ENOENT;
183 }
184 
185 int
186 _citrus_db_lookup_by_string(struct _citrus_db *db, const char *key,
187 			    struct _citrus_region *data,
188 			    struct _citrus_db_locator *dl)
189 {
190 	struct _region r;
191 
192 	/* LINTED: discard const */
193 	_region_init(&r, (char *)key, strlen(key));
194 
195 	return _citrus_db_lookup(db, &r, data, dl);
196 }
197 
198 int
199 _citrus_db_lookup8_by_string(struct _citrus_db *db, const char *key,
200 			     u_int8_t *rval, struct _citrus_db_locator *dl)
201 {
202 	int ret;
203 	struct _region r;
204 
205 	ret = _citrus_db_lookup_by_string(db, key, &r, dl);
206 	if (ret)
207 		return ret;
208 
209 	if (_region_size(&r) != 1)
210 		return EFTYPE;
211 
212 	if (rval)
213 		memcpy(rval, _region_head(&r), 1);
214 
215 	return 0;
216 }
217 
218 int
219 _citrus_db_lookup16_by_string(struct _citrus_db *db, const char *key,
220 			      u_int16_t *rval, struct _citrus_db_locator *dl)
221 {
222 	int ret;
223 	struct _region r;
224 	u_int16_t val;
225 
226 	ret = _citrus_db_lookup_by_string(db, key, &r, dl);
227 	if (ret)
228 		return ret;
229 
230 	if (_region_size(&r) != 2)
231 		return EFTYPE;
232 
233 	if (rval) {
234 		memcpy(&val, _region_head(&r), 2);
235 		*rval = be16toh(val);
236 	}
237 
238 	return 0;
239 }
240 
241 int
242 _citrus_db_lookup32_by_string(struct _citrus_db *db, const char *key,
243 			      u_int32_t *rval, struct _citrus_db_locator *dl)
244 {
245 	int ret;
246 	struct _region r;
247 	u_int32_t val;
248 
249 	ret = _citrus_db_lookup_by_string(db, key, &r, dl);
250 	if (ret)
251 		return ret;
252 
253 	if (_region_size(&r) != 4)
254 		return EFTYPE;
255 
256 	if (rval) {
257 		memcpy(&val, _region_head(&r), 4);
258 		*rval = be32toh(val);
259 	}
260 
261 	return 0;
262 }
263 
264 int
265 _citrus_db_lookup_string_by_string(struct _citrus_db *db, const char *key,
266 				   const char **rdata,
267 				   struct _citrus_db_locator *dl)
268 {
269 	int ret;
270 	struct _region r;
271 
272 	ret = _citrus_db_lookup_by_string(db, key, &r, dl);
273 	if (ret)
274 		return ret;
275 
276 	if (_region_size(&r) == 0)
277 		return EFTYPE;
278 
279 	/* check whether the string is null terminated */
280 	if (*((const char*)_region_head(&r)+_region_size(&r)) != '\0')
281 		return EFTYPE;
282 
283 	if (rdata)
284 		*rdata = _region_head(&r);
285 
286 	return 0;
287 }
288 
289 int
290 _citrus_db_get_number_of_entries(struct _citrus_db *db)
291 {
292 	struct _memstream ms;
293 	struct _citrus_db_header_x *dhx;
294 
295 	_memstream_bind(&ms, &db->db_region);
296 
297 	dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
298 	_DIAGASSERT(dhx);
299 	return (int)be32toh(dhx->dhx_num_entries);
300 }
301 
302 int
303 _citrus_db_get_entry(struct _citrus_db *db, int idx,
304 		     struct _region *key, struct _region *data)
305 {
306 	u_int32_t num_entries;
307 	size_t offset;
308 	struct _memstream ms;
309 	struct _citrus_db_header_x *dhx;
310 	struct _citrus_db_entry_x *dex;
311 
312 	_memstream_bind(&ms, &db->db_region);
313 
314 	dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
315 	_DIAGASSERT(dhx);
316 	num_entries = be32toh(dhx->dhx_num_entries);
317 	if (idx<0 || (u_int32_t)idx>=num_entries)
318 		return EINVAL;
319 
320 	/* seek to the next entry */
321 	offset = be32toh(dhx->dhx_entry_offset) + idx * _CITRUS_DB_ENTRY_SIZE;
322 	if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
323 		return EFTYPE;
324 	/* get the entry record */
325 	dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
326 	if (dex == NULL)
327 		return EFTYPE;
328 	/* seek to the head of the key. */
329 	if (_memstream_seek(&ms, be32toh(dex->dex_key_offset), SEEK_SET))
330 		return EFTYPE;
331 	/* get the region of the key. */
332 	if (_memstream_getregion(&ms, key, be32toh(dex->dex_key_size))==NULL)
333 		return EFTYPE;
334 	/* seek to the head of the data. */
335 	if (_memstream_seek(&ms, be32toh(dex->dex_data_offset), SEEK_SET))
336 		return EFTYPE;
337 	/* get the region of the data. */
338 	if (_memstream_getregion(&ms, data, be32toh(dex->dex_data_size))==NULL)
339 		return EFTYPE;
340 
341 	return 0;
342 }
343