Home | History | Annotate | Line # | Download | only in citrus
citrus_db.c revision 1.2
      1 /*	$NetBSD: citrus_db.c,v 1.2 2003/07/16 08:13:51 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.2 2003/07/16 08:13:51 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 	/* check whether the string is null terminated */
    277 	if (_region_size(&r) == 0)
    278 		return EFTYPE;
    279 	if (*((const char*)_region_head(&r)+_region_size(&r)-1) != '\0')
    280 		return EFTYPE;
    281 
    282 	if (rdata)
    283 		*rdata = _region_head(&r);
    284 
    285 	return 0;
    286 }
    287 
    288 int
    289 _citrus_db_get_number_of_entries(struct _citrus_db *db)
    290 {
    291 	struct _memstream ms;
    292 	struct _citrus_db_header_x *dhx;
    293 
    294 	_memstream_bind(&ms, &db->db_region);
    295 
    296 	dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
    297 	_DIAGASSERT(dhx);
    298 	return (int)be32toh(dhx->dhx_num_entries);
    299 }
    300 
    301 int
    302 _citrus_db_get_entry(struct _citrus_db *db, int idx,
    303 		     struct _region *key, struct _region *data)
    304 {
    305 	u_int32_t num_entries;
    306 	size_t offset;
    307 	struct _memstream ms;
    308 	struct _citrus_db_header_x *dhx;
    309 	struct _citrus_db_entry_x *dex;
    310 
    311 	_memstream_bind(&ms, &db->db_region);
    312 
    313 	dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
    314 	_DIAGASSERT(dhx);
    315 	num_entries = be32toh(dhx->dhx_num_entries);
    316 	if (idx<0 || (u_int32_t)idx>=num_entries)
    317 		return EINVAL;
    318 
    319 	/* seek to the next entry */
    320 	offset = be32toh(dhx->dhx_entry_offset) + idx * _CITRUS_DB_ENTRY_SIZE;
    321 	if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
    322 		return EFTYPE;
    323 	/* get the entry record */
    324 	dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
    325 	if (dex == NULL)
    326 		return EFTYPE;
    327 	/* seek to the head of the key. */
    328 	if (_memstream_seek(&ms, be32toh(dex->dex_key_offset), SEEK_SET))
    329 		return EFTYPE;
    330 	/* get the region of the key. */
    331 	if (_memstream_getregion(&ms, key, be32toh(dex->dex_key_size))==NULL)
    332 		return EFTYPE;
    333 	/* seek to the head of the data. */
    334 	if (_memstream_seek(&ms, be32toh(dex->dex_data_offset), SEEK_SET))
    335 		return EFTYPE;
    336 	/* get the region of the data. */
    337 	if (_memstream_getregion(&ms, data, be32toh(dex->dex_data_size))==NULL)
    338 		return EFTYPE;
    339 
    340 	return 0;
    341 }
    342