Home | History | Annotate | Line # | Download | only in citrus
      1 /*	$NetBSD: citrus_db.c,v 1.5 2008/02/09 14:56:20 junyoung 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.5 2008/02/09 14:56:20 junyoung 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 	uint32_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 		uint32_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 	uint32_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 	_region_init(&r, __UNCONST(key), strlen(key));
    193 
    194 	return _citrus_db_lookup(db, &r, data, dl);
    195 }
    196 
    197 int
    198 _citrus_db_lookup8_by_string(struct _citrus_db *db, const char *key,
    199 			     uint8_t *rval, struct _citrus_db_locator *dl)
    200 {
    201 	int ret;
    202 	struct _region r;
    203 
    204 	ret = _citrus_db_lookup_by_string(db, key, &r, dl);
    205 	if (ret)
    206 		return ret;
    207 
    208 	if (_region_size(&r) != 1)
    209 		return EFTYPE;
    210 
    211 	if (rval)
    212 		memcpy(rval, _region_head(&r), 1);
    213 
    214 	return 0;
    215 }
    216 
    217 int
    218 _citrus_db_lookup16_by_string(struct _citrus_db *db, const char *key,
    219 			      uint16_t *rval, struct _citrus_db_locator *dl)
    220 {
    221 	int ret;
    222 	struct _region r;
    223 	uint16_t val;
    224 
    225 	ret = _citrus_db_lookup_by_string(db, key, &r, dl);
    226 	if (ret)
    227 		return ret;
    228 
    229 	if (_region_size(&r) != 2)
    230 		return EFTYPE;
    231 
    232 	if (rval) {
    233 		memcpy(&val, _region_head(&r), 2);
    234 		*rval = be16toh(val);
    235 	}
    236 
    237 	return 0;
    238 }
    239 
    240 int
    241 _citrus_db_lookup32_by_string(struct _citrus_db *db, const char *key,
    242 			      uint32_t *rval, struct _citrus_db_locator *dl)
    243 {
    244 	int ret;
    245 	struct _region r;
    246 	uint32_t val;
    247 
    248 	ret = _citrus_db_lookup_by_string(db, key, &r, dl);
    249 	if (ret)
    250 		return ret;
    251 
    252 	if (_region_size(&r) != 4)
    253 		return EFTYPE;
    254 
    255 	if (rval) {
    256 		memcpy(&val, _region_head(&r), 4);
    257 		*rval = be32toh(val);
    258 	}
    259 
    260 	return 0;
    261 }
    262 
    263 int
    264 _citrus_db_lookup_string_by_string(struct _citrus_db *db, const char *key,
    265 				   const char **rdata,
    266 				   struct _citrus_db_locator *dl)
    267 {
    268 	int ret;
    269 	struct _region r;
    270 
    271 	ret = _citrus_db_lookup_by_string(db, key, &r, dl);
    272 	if (ret)
    273 		return ret;
    274 
    275 	/* check whether the string is null terminated */
    276 	if (_region_size(&r) == 0)
    277 		return EFTYPE;
    278 	if (*((const char*)_region_head(&r)+_region_size(&r)-1) != '\0')
    279 		return EFTYPE;
    280 
    281 	if (rdata)
    282 		*rdata = _region_head(&r);
    283 
    284 	return 0;
    285 }
    286 
    287 int
    288 _citrus_db_get_number_of_entries(struct _citrus_db *db)
    289 {
    290 	struct _memstream ms;
    291 	struct _citrus_db_header_x *dhx;
    292 
    293 	_memstream_bind(&ms, &db->db_region);
    294 
    295 	dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
    296 	_DIAGASSERT(dhx);
    297 	return (int)be32toh(dhx->dhx_num_entries);
    298 }
    299 
    300 int
    301 _citrus_db_get_entry(struct _citrus_db *db, int idx,
    302 		     struct _region *key, struct _region *data)
    303 {
    304 	uint32_t num_entries;
    305 	size_t offset;
    306 	struct _memstream ms;
    307 	struct _citrus_db_header_x *dhx;
    308 	struct _citrus_db_entry_x *dex;
    309 
    310 	_memstream_bind(&ms, &db->db_region);
    311 
    312 	dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
    313 	_DIAGASSERT(dhx);
    314 	num_entries = be32toh(dhx->dhx_num_entries);
    315 	if (idx < 0 || (uint32_t)idx >= num_entries)
    316 		return EINVAL;
    317 
    318 	/* seek to the next entry */
    319 	offset = be32toh(dhx->dhx_entry_offset) + idx * _CITRUS_DB_ENTRY_SIZE;
    320 	if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
    321 		return EFTYPE;
    322 	/* get the entry record */
    323 	dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
    324 	if (dex == NULL)
    325 		return EFTYPE;
    326 	/* seek to the head of the key. */
    327 	if (_memstream_seek(&ms, be32toh(dex->dex_key_offset), SEEK_SET))
    328 		return EFTYPE;
    329 	/* get the region of the key. */
    330 	if (_memstream_getregion(&ms, key, be32toh(dex->dex_key_size))==NULL)
    331 		return EFTYPE;
    332 	/* seek to the head of the data. */
    333 	if (_memstream_seek(&ms, be32toh(dex->dex_data_offset), SEEK_SET))
    334 		return EFTYPE;
    335 	/* get the region of the data. */
    336 	if (_memstream_getregion(&ms, data, be32toh(dex->dex_data_size))==NULL)
    337 		return EFTYPE;
    338 
    339 	return 0;
    340 }
    341