1 /* $NetBSD: cdbr.c,v 1.1 2013/12/11 01:24:08 joerg Exp $ */
3 * Copyright (c) 2010 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Joerg Sonnenberger.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #if HAVE_NBTOOL_CONFIG_H
35 #include "nbtool_config.h"
38 #include <sys/cdefs.h>
39 __RCSID("$NetBSD: cdbr.c,v 1.1 2013/12/11 01:24:08 joerg Exp $");
41 #if !defined(_KERNEL) && !defined(_STANDALONE)
42 #include "namespace.h"
45 #if !HAVE_NBTOOL_CONFIG_H
46 #include <sys/bitops.h>
48 #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
49 #include <sys/endian.h>
52 #if defined(_KERNEL) || defined(_STANDALONE)
55 #include <sys/systm.h>
56 #include <lib/libkern/libkern.h>
57 #define SET_ERRNO(val)
58 #define malloc(size) kmem_alloc(size, KM_SLEEP)
59 #define free(ptr) kmem_free(ptr, sizeof(struct cdbr))
71 #define SET_ERRNO(val) errno = (val)
74 #if !defined(_KERNEL) && !defined(_STANDALONE)
76 __weak_alias(cdbr_close
,_cdbr_close
)
77 __weak_alias(cdbr_find
,_cdbr_find
)
78 __weak_alias(cdbr_get
,_cdbr_get
)
79 __weak_alias(cdbr_open
,_cdbr_open
)
80 __weak_alias(cdbr_open_mem
,_cdbr_open_mem
)
84 #if HAVE_NBTOOL_CONFIG_H
85 #define fast_divide32_prepare(d,m,s1,s2) (void)0
86 #define fast_remainder32(v,d,m,s1,s2) (v%d)
90 void (*unmap
)(void *, void *, size_t);
101 uint32_t entries_index
;
108 uint32_t entries_index_m
;
109 uint8_t entries_s1
, entries_s2
;
110 uint8_t entries_index_s1
, entries_index_s2
;
113 #if !defined(_KERNEL) && !defined(_STANDALONE)
115 cdbr_unmap(void *cookie __unused
, void *base
, size_t size
)
122 cdbr_open(const char *path
, int flags
)
130 if ((fd
= open(path
, O_RDONLY
)) == -1)
132 if (fstat(fd
, &sb
) == -1) {
137 if (sb
.st_size
>= SSIZE_MAX
) {
144 size
= (size_t)sb
.st_size
;
145 base
= mmap(NULL
, size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, fd
, 0);
148 if (base
== MAP_FAILED
)
151 cdbr
= cdbr_open_mem(base
, size
, flags
, cdbr_unmap
, NULL
);
159 cdbr_open_mem(void *base
, size_t size
, int flags
,
160 void (*unmap
)(void *, void *, size_t), void *cookie
)
164 if (size
< 40 || memcmp(buf
, "NBCDB\n\0\001", 8)) {
169 cdbr
= malloc(sizeof(*cdbr
));
171 cdbr
->cookie
= cookie
;
173 cdbr
->data_size
= le32dec(buf
+ 24);
174 cdbr
->entries
= le32dec(buf
+ 28);
175 cdbr
->entries_index
= le32dec(buf
+ 32);
176 cdbr
->seed
= le32dec(buf
+ 36);
178 if (cdbr
->data_size
< 0x100)
179 cdbr
->offset_size
= 1;
180 else if (cdbr
->data_size
< 0x10000)
181 cdbr
->offset_size
= 2;
183 cdbr
->offset_size
= 4;
185 if (cdbr
->entries_index
< 0x100)
186 cdbr
->index_size
= 1;
187 else if (cdbr
->entries_index
< 0x10000)
188 cdbr
->index_size
= 2;
190 cdbr
->index_size
= 4;
192 cdbr
->mmap_base
= base
;
193 cdbr
->mmap_size
= size
;
195 cdbr
->hash_base
= cdbr
->mmap_base
+ 40;
196 cdbr
->offset_base
= cdbr
->hash_base
+ cdbr
->entries_index
* cdbr
->index_size
;
197 if (cdbr
->entries_index
* cdbr
->index_size
% cdbr
->offset_size
)
198 cdbr
->offset_base
+= cdbr
->offset_size
-
199 cdbr
->entries_index
* cdbr
->index_size
% cdbr
->offset_size
;
200 cdbr
->data_base
= cdbr
->offset_base
+ (cdbr
->entries
+ 1) * cdbr
->offset_size
;
202 if (cdbr
->hash_base
< cdbr
->mmap_base
||
203 cdbr
->offset_base
< cdbr
->mmap_base
||
204 cdbr
->data_base
< cdbr
->mmap_base
||
205 cdbr
->data_base
+ cdbr
->data_size
< cdbr
->mmap_base
||
206 cdbr
->data_base
+ cdbr
->data_size
>
207 cdbr
->mmap_base
+ cdbr
->mmap_size
) {
214 fast_divide32_prepare(cdbr
->entries
, &cdbr
->entries_m
,
215 &cdbr
->entries_s1
, &cdbr
->entries_s2
);
217 if (cdbr
->entries_index
) {
218 fast_divide32_prepare(cdbr
->entries_index
,
219 &cdbr
->entries_index_m
,
220 &cdbr
->entries_index_s1
, &cdbr
->entries_index_s2
);
226 static inline uint32_t
227 get_uintX(const uint8_t *addr
, uint32_t idx
, int size
)
232 return /* LINTED */le32toh(*(const uint32_t *)addr
);
234 return /* LINTED */le16toh(*(const uint16_t *)addr
);
240 cdbr_entries(struct cdbr
*cdbr
)
243 return cdbr
->entries
;
247 cdbr_get(struct cdbr
*cdbr
, uint32_t idx
, const void **data
, size_t *data_len
)
251 if (idx
>= cdbr
->entries
) {
256 start
= get_uintX(cdbr
->offset_base
, idx
, cdbr
->offset_size
);
257 end
= get_uintX(cdbr
->offset_base
, idx
+ 1, cdbr
->offset_size
);
264 if (end
> cdbr
->data_size
) {
269 *data
= cdbr
->data_base
+ start
;
270 *data_len
= end
- start
;
276 cdbr_find(struct cdbr
*cdbr
, const void *key
, size_t key_len
,
277 const void **data
, size_t *data_len
)
279 uint32_t hashes
[3], idx
;
281 if (cdbr
->entries_index
== 0) {
286 mi_vector_hash(key
, key_len
, cdbr
->seed
, hashes
);
288 hashes
[0] = fast_remainder32(hashes
[0], cdbr
->entries_index
,
289 cdbr
->entries_index_m
, cdbr
->entries_index_s1
,
290 cdbr
->entries_index_s2
);
291 hashes
[1] = fast_remainder32(hashes
[1], cdbr
->entries_index
,
292 cdbr
->entries_index_m
, cdbr
->entries_index_s1
,
293 cdbr
->entries_index_s2
);
294 hashes
[2] = fast_remainder32(hashes
[2], cdbr
->entries_index
,
295 cdbr
->entries_index_m
, cdbr
->entries_index_s1
,
296 cdbr
->entries_index_s2
);
298 idx
= get_uintX(cdbr
->hash_base
, hashes
[0], cdbr
->index_size
);
299 idx
+= get_uintX(cdbr
->hash_base
, hashes
[1], cdbr
->index_size
);
300 idx
+= get_uintX(cdbr
->hash_base
, hashes
[2], cdbr
->index_size
);
302 return cdbr_get(cdbr
, fast_remainder32(idx
, cdbr
->entries
,
303 cdbr
->entries_m
, cdbr
->entries_s1
, cdbr
->entries_s2
), data
,
308 cdbr_close(struct cdbr
*cdbr
)
311 (*cdbr
->unmap
)(cdbr
->cookie
, cdbr
->mmap_base
, cdbr
->mmap_size
);