File: | s/lib/dbm/src/hash.c |
Warning: | line 1105, column 13 Potential leak of memory pointed to by 'store' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /*- | |||
2 | * Copyright (c) 1990, 1993, 1994 | |||
3 | * The Regents of the University of California. All rights reserved. | |||
4 | * | |||
5 | * This code is derived from software contributed to Berkeley by | |||
6 | * Margo Seltzer. | |||
7 | * | |||
8 | * Redistribution and use in source and binary forms, with or without | |||
9 | * modification, are permitted provided that the following conditions | |||
10 | * are met: | |||
11 | * 1. Redistributions of source code must retain the above copyright | |||
12 | * notice, this list of conditions and the following disclaimer. | |||
13 | * 2. Redistributions in binary form must reproduce the above copyright | |||
14 | * notice, this list of conditions and the following disclaimer in the | |||
15 | * documentation and/or other materials provided with the distribution. | |||
16 | * 3. ***REMOVED*** - see | |||
17 | * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change | |||
18 | * 4. Neither the name of the University nor the names of its contributors | |||
19 | * may be used to endorse or promote products derived from this software | |||
20 | * without specific prior written permission. | |||
21 | * | |||
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
32 | * SUCH DAMAGE. | |||
33 | */ | |||
34 | ||||
35 | #if defined(LIBC_SCCS) && !defined(lint) | |||
36 | static char sccsid[] = "@(#)hash.c 8.9 (Berkeley) 6/16/94"; | |||
37 | #endif /* LIBC_SCCS and not lint */ | |||
38 | ||||
39 | #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) | |||
40 | #include <sys/param.h> | |||
41 | #endif | |||
42 | ||||
43 | #if !defined(macintosh) | |||
44 | #ifdef XP_OS2 | |||
45 | #include <sys/types.h> | |||
46 | #endif | |||
47 | #include <sys/stat.h> | |||
48 | #endif | |||
49 | ||||
50 | #if defined(macintosh) | |||
51 | #include <unix.h> | |||
52 | #include <unistd.h> | |||
53 | #endif | |||
54 | ||||
55 | #include <errno(*__errno_location ()).h> | |||
56 | #include <fcntl.h> | |||
57 | #include <stdio.h> | |||
58 | #include <stdlib.h> | |||
59 | #include <string.h> | |||
60 | ||||
61 | #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) | |||
62 | #include <unistd.h> | |||
63 | #endif | |||
64 | #if defined(_WIN32) || defined(_WINDOWS) | |||
65 | #include <windows.h> | |||
66 | #endif | |||
67 | ||||
68 | #include <assert.h> | |||
69 | ||||
70 | #include "mcom_db.h" | |||
71 | #include "hash.h" | |||
72 | #include "page.h" | |||
73 | ||||
74 | /* | |||
75 | #include "extern.h" | |||
76 | */ | |||
77 | static int alloc_segs(HTAB *, int); | |||
78 | static int flush_meta(HTAB *); | |||
79 | static int hash_access(HTAB *, ACTION, DBT *, DBT *); | |||
80 | static int hash_close(DB *); | |||
81 | static int hash_delete(const DB *, const DBT *, uint); | |||
82 | static int hash_fd(const DB *); | |||
83 | static int hash_get(const DB *, const DBT *, DBT *, uint); | |||
84 | static int hash_put(const DB *, DBT *, const DBT *, uint); | |||
85 | static void *hash_realloc(SEGMENT **, size_t, size_t); | |||
86 | static int hash_seq(const DB *, DBT *, DBT *, uint); | |||
87 | static int hash_sync(const DB *, uint); | |||
88 | static int hdestroy(HTAB *); | |||
89 | static HTAB *init_hash(HTAB *, const char *, HASHINFO *); | |||
90 | static int init_htab(HTAB *, int); | |||
91 | #if BYTE_ORDER1234 == LITTLE_ENDIAN1234 | |||
92 | static void swap_header(HTAB *); | |||
93 | static void swap_header_copy(HASHHDR *, HASHHDR *); | |||
94 | #endif | |||
95 | ||||
96 | /* Fast arithmetic, relying on powers of 2, */ | |||
97 | #define MOD(x, y)((x) & ((y)-1)) ((x) & ((y)-1)) | |||
98 | ||||
99 | #define RETURN_ERROR(ERR, LOC){ save_errno = ERR; goto LOC; } \ | |||
100 | { \ | |||
101 | save_errno = ERR; \ | |||
102 | goto LOC; \ | |||
103 | } | |||
104 | ||||
105 | /* Return values */ | |||
106 | #define SUCCESS(0) (0) | |||
107 | #define DBM_ERROR(-1) (-1) | |||
108 | #define ABNORMAL(1) (1) | |||
109 | ||||
110 | #ifdef HASH_STATISTICS | |||
111 | int hash_accesses, hash_collisions, hash_expansions, hash_overflows; | |||
112 | #endif | |||
113 | ||||
114 | /* A new Lou (montulli@mozilla.com) routine. | |||
115 | * | |||
116 | * The database is screwed. | |||
117 | * | |||
118 | * This closes the file, flushing buffers as appropriate. | |||
119 | */ | |||
120 | static void | |||
121 | dbm_remove_database(DB *dbp) | |||
122 | { | |||
123 | HTAB *hashp = (HTAB *)dbp->internal; | |||
124 | ||||
125 | assert(0)((0) ? (void) (0) : __assert_fail ("0", "hash.c", 125, __extension__ __PRETTY_FUNCTION__)); | |||
126 | ||||
127 | if (!hashp) | |||
128 | return; | |||
129 | hdestroy(hashp); | |||
130 | dbp->internal = NULL((void*)0); | |||
131 | } | |||
132 | ||||
133 | /************************** INTERFACE ROUTINES ***************************/ | |||
134 | /* OPEN/CLOSE */ | |||
135 | ||||
136 | extern DB * | |||
137 | dbm_hash_open(const char *file, int flags, int mode, const HASHINFO *info, int dflags) | |||
138 | { | |||
139 | HTAB *hashp = NULL((void*)0); | |||
140 | struct stat statbuf; | |||
141 | DB *dbp; | |||
142 | int bpages, hdrsize, new_table, nsegs, save_errno; | |||
143 | ||||
144 | if ((flags & O_ACCMODE0003) == O_WRONLY01) { | |||
| ||||
145 | errno(*__errno_location ()) = EINVAL22; | |||
146 | return NULL((void*)0); | |||
147 | } | |||
148 | ||||
149 | /* zero the statbuffer so that | |||
150 | * we can check it for a non-zero | |||
151 | * date to see if stat succeeded | |||
152 | */ | |||
153 | memset(&statbuf, 0, sizeof(struct stat)); | |||
154 | ||||
155 | if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB)))) { | |||
156 | errno(*__errno_location ()) = ENOMEM12; | |||
157 | return NULL((void*)0); | |||
158 | } | |||
159 | hashp->fp = NO_FILE-1; | |||
160 | if (file) | |||
161 | hashp->filename = strdup(file); | |||
162 | ||||
163 | /* | |||
164 | * Even if user wants write only, we need to be able to read | |||
165 | * the actual file, so we need to open it read/write. But, the | |||
166 | * field in the hashp structure needs to be accurate so that | |||
167 | * we can check accesses. | |||
168 | */ | |||
169 | hashp->flags = flags; | |||
170 | ||||
171 | new_table = 0; | |||
172 | if (!file
| |||
173 | if (errno(*__errno_location ()) == ENOENT2) | |||
174 | errno(*__errno_location ()) = 0; /* Just in case someone looks at errno */ | |||
175 | new_table = 1; | |||
176 | } else if (statbuf.st_mtimest_mtim.tv_sec && statbuf.st_size == 0) { | |||
177 | /* check for a zero length file and delete it | |||
178 | * if it exists | |||
179 | */ | |||
180 | new_table = 1; | |||
181 | } | |||
182 | hashp->file_size = statbuf.st_size; | |||
183 | ||||
184 | if (file
| |||
185 | #if defined(_WIN32) || defined(_WINDOWS) || defined(macintosh) || defined(XP_OS2) | |||
186 | if ((hashp->fp = DBFILE_OPEN(file, flags | O_BINARY, mode)open((file), (flags | O_BINARY), (mode))) == -1) | |||
187 | RETURN_ERROR(errno, error1){ save_errno = (*__errno_location ()); goto error1; }; | |||
188 | #else | |||
189 | if ((hashp->fp = open(file, flags, mode)) == -1) | |||
190 | RETURN_ERROR(errno, error1){ save_errno = (*__errno_location ()); goto error1; }; | |||
191 | (void)fcntl(hashp->fp, F_SETFD2, 1); | |||
192 | #endif | |||
193 | } | |||
194 | if (new_table
| |||
195 | if (!init_hash(hashp, file, (HASHINFO *)info)) | |||
196 | RETURN_ERROR(errno, error1){ save_errno = (*__errno_location ()); goto error1; }; | |||
197 | } else { | |||
198 | /* Table already exists */ | |||
199 | if (info && info->hash) | |||
200 | hashp->hash = info->hash; | |||
201 | else | |||
202 | hashp->hash = dbm_default_hash; | |||
203 | ||||
204 | hdrsize = read(hashp->fp, (char *)&hashp->hdr, sizeof(HASHHDR)); | |||
205 | if (hdrsize == -1) | |||
206 | RETURN_ERROR(errno, error1){ save_errno = (*__errno_location ()); goto error1; }; | |||
207 | if (hdrsize != sizeof(HASHHDR)) | |||
208 | RETURN_ERROR(EFTYPE, error1){ save_errno = 22; goto error1; }; | |||
209 | #if BYTE_ORDER1234 == LITTLE_ENDIAN1234 | |||
210 | swap_header(hashp); | |||
211 | #endif | |||
212 | /* Verify file type, versions and hash function */ | |||
213 | if (hashp->MAGIChdr.magic != HASHMAGIC0x061561) | |||
214 | RETURN_ERROR(EFTYPE, error1){ save_errno = 22; goto error1; }; | |||
215 | #define OLDHASHVERSION1 1 | |||
216 | if (hashp->VERSIONhdr.version != HASHVERSION2 && | |||
217 | hashp->VERSIONhdr.version != OLDHASHVERSION1) | |||
218 | RETURN_ERROR(EFTYPE, error1){ save_errno = 22; goto error1; }; | |||
219 | if (hashp->hash(CHARKEY"%$sniglet^&", sizeof(CHARKEY"%$sniglet^&")) != hashp->H_CHARKEYhdr.h_charkey) | |||
220 | RETURN_ERROR(EFTYPE, error1){ save_errno = 22; goto error1; }; | |||
221 | if (hashp->NKEYShdr.nkeys < 0) /* Old bad database. */ | |||
222 | RETURN_ERROR(EFTYPE, error1){ save_errno = 22; goto error1; }; | |||
223 | ||||
224 | /* | |||
225 | * Figure out how many segments we need. Max_Bucket is the | |||
226 | * maximum bucket number, so the number of buckets is | |||
227 | * max_bucket + 1. | |||
228 | */ | |||
229 | nsegs = (hashp->MAX_BUCKEThdr.max_bucket + 1 + hashp->SGSIZEhdr.ssize - 1) / | |||
230 | hashp->SGSIZEhdr.ssize; | |||
231 | hashp->nsegs = 0; | |||
232 | if (alloc_segs(hashp, nsegs)) | |||
233 | /* If alloc_segs fails, errno will have been set. */ | |||
234 | RETURN_ERROR(errno, error1){ save_errno = (*__errno_location ()); goto error1; }; | |||
235 | /* Read in bitmaps */ | |||
236 | bpages = (hashp->SPAREShdr.spares[hashp->OVFL_POINThdr.ovfl_point] + | |||
237 | (hashp->BSIZEhdr.bsize << BYTE_SHIFT3) - 1) >> | |||
238 | (hashp->BSHIFThdr.bshift + BYTE_SHIFT3); | |||
239 | ||||
240 | hashp->nmaps = bpages; | |||
241 | (void)memset(&hashp->mapp[0], 0, bpages * sizeof(uint32 *)); | |||
242 | } | |||
243 | ||||
244 | /* Initialize Buffer Manager */ | |||
245 | if (info && info->cachesize) | |||
246 | dbm_buf_init(hashp, (int32)info->cachesize); | |||
247 | else | |||
248 | dbm_buf_init(hashp, DEF_BUFSIZE65536l); | |||
249 | ||||
250 | hashp->new_file = new_table; | |||
251 | #ifdef macintosh | |||
252 | hashp->save_file = file && !(hashp->flags & O_RDONLY00); | |||
253 | #else | |||
254 | hashp->save_file = file && (hashp->flags & O_RDWR02); | |||
255 | #endif | |||
256 | hashp->cbucket = -1; | |||
257 | if (!(dbp = (DB *)malloc(sizeof(DB)))) { | |||
258 | RETURN_ERROR(ENOMEM, error1){ save_errno = 12; goto error1; }; | |||
259 | } | |||
260 | dbp->internal = hashp; | |||
261 | dbp->close = hash_close; | |||
262 | dbp->del = hash_delete; | |||
263 | dbp->fd = hash_fd; | |||
264 | dbp->get = hash_get; | |||
265 | dbp->put = hash_put; | |||
266 | dbp->seq = hash_seq; | |||
267 | dbp->sync = hash_sync; | |||
268 | dbp->type = DB_HASH; | |||
269 | ||||
270 | #ifdef HASH_STATISTICS | |||
271 | hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0; | |||
272 | #endif | |||
273 | return (dbp); | |||
274 | ||||
275 | error1: | |||
276 | hdestroy(hashp); | |||
277 | errno(*__errno_location ()) = save_errno; | |||
278 | return (NULL((void*)0)); | |||
279 | } | |||
280 | ||||
281 | static int | |||
282 | hash_close(DB *dbp) | |||
283 | { | |||
284 | HTAB *hashp; | |||
285 | int retval; | |||
286 | ||||
287 | if (!dbp) | |||
288 | return (DBM_ERROR(-1)); | |||
289 | ||||
290 | hashp = (HTAB *)dbp->internal; | |||
291 | if (!hashp) | |||
292 | return (DBM_ERROR(-1)); | |||
293 | ||||
294 | retval = hdestroy(hashp); | |||
295 | free(dbp); | |||
296 | return (retval); | |||
297 | } | |||
298 | ||||
299 | static int | |||
300 | hash_fd(const DB *dbp) | |||
301 | { | |||
302 | HTAB *hashp; | |||
303 | ||||
304 | if (!dbp) | |||
305 | return (DBM_ERROR(-1)); | |||
306 | ||||
307 | hashp = (HTAB *)dbp->internal; | |||
308 | if (!hashp) | |||
309 | return (DBM_ERROR(-1)); | |||
310 | ||||
311 | if (hashp->fp == -1) { | |||
312 | errno(*__errno_location ()) = ENOENT2; | |||
313 | return (-1); | |||
314 | } | |||
315 | return (hashp->fp); | |||
316 | } | |||
317 | ||||
318 | /************************** LOCAL CREATION ROUTINES **********************/ | |||
319 | static HTAB * | |||
320 | init_hash(HTAB *hashp, const char *file, HASHINFO *info) | |||
321 | { | |||
322 | struct stat statbuf; | |||
323 | int nelem; | |||
324 | ||||
325 | nelem = 1; | |||
326 | hashp->NKEYShdr.nkeys = 0; | |||
327 | hashp->LORDERhdr.lorder = BYTE_ORDER1234; | |||
328 | hashp->BSIZEhdr.bsize = DEF_BUCKET_SIZE4096; | |||
329 | hashp->BSHIFThdr.bshift = DEF_BUCKET_SHIFT12; | |||
330 | hashp->SGSIZEhdr.ssize = DEF_SEGSIZE256; | |||
331 | hashp->SSHIFThdr.sshift = DEF_SEGSIZE_SHIFT8; | |||
332 | hashp->DSIZEhdr.dsize = DEF_DIRSIZE256; | |||
333 | hashp->FFACTORhdr.ffactor = DEF_FFACTOR65536l; | |||
334 | hashp->hash = dbm_default_hash; | |||
335 | memset(hashp->SPAREShdr.spares, 0, sizeof(hashp->SPAREShdr.spares)); | |||
336 | memset(hashp->BITMAPShdr.bitmaps, 0, sizeof(hashp->BITMAPShdr.bitmaps)); | |||
337 | ||||
338 | /* Fix bucket size to be optimal for file system */ | |||
339 | if (file != NULL((void*)0)) { | |||
340 | if (stat(file, &statbuf)) | |||
341 | return (NULL((void*)0)); | |||
342 | ||||
343 | #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) && !defined(XP_OS2) | |||
344 | #if defined(__QNX__) && !defined(__QNXNTO__) | |||
345 | hashp->BSIZEhdr.bsize = 512; /* preferred blk size on qnx4 */ | |||
346 | #else | |||
347 | hashp->BSIZEhdr.bsize = statbuf.st_blksize; | |||
348 | #endif | |||
349 | ||||
350 | /* new code added by Lou to reduce block | |||
351 | * size down below MAX_BSIZE | |||
352 | */ | |||
353 | if (hashp->BSIZEhdr.bsize > MAX_BSIZE32l * 1024l) | |||
354 | hashp->BSIZEhdr.bsize = MAX_BSIZE32l * 1024l; | |||
355 | #endif | |||
356 | hashp->BSHIFThdr.bshift = dbm_log2((uint32)hashp->BSIZEhdr.bsize); | |||
357 | } | |||
358 | ||||
359 | if (info) { | |||
360 | if (info->bsize) { | |||
361 | /* Round pagesize up to power of 2 */ | |||
362 | hashp->BSHIFThdr.bshift = dbm_log2(info->bsize); | |||
363 | hashp->BSIZEhdr.bsize = 1 << hashp->BSHIFThdr.bshift; | |||
364 | if (hashp->BSIZEhdr.bsize > MAX_BSIZE32l * 1024l) { | |||
365 | errno(*__errno_location ()) = EINVAL22; | |||
366 | return (NULL((void*)0)); | |||
367 | } | |||
368 | } | |||
369 | if (info->ffactor) | |||
370 | hashp->FFACTORhdr.ffactor = info->ffactor; | |||
371 | if (info->hash) | |||
372 | hashp->hash = info->hash; | |||
373 | if (info->nelem) | |||
374 | nelem = info->nelem; | |||
375 | if (info->lorder) { | |||
376 | if (info->lorder != BIG_ENDIAN4321 && | |||
377 | info->lorder != LITTLE_ENDIAN1234) { | |||
378 | errno(*__errno_location ()) = EINVAL22; | |||
379 | return (NULL((void*)0)); | |||
380 | } | |||
381 | hashp->LORDERhdr.lorder = info->lorder; | |||
382 | } | |||
383 | } | |||
384 | /* init_htab sets errno if it fails */ | |||
385 | if (init_htab(hashp, nelem)) | |||
386 | return (NULL((void*)0)); | |||
387 | else | |||
388 | return (hashp); | |||
389 | } | |||
390 | /* | |||
391 | * This calls alloc_segs which may run out of memory. Alloc_segs will | |||
392 | * set errno, so we just pass the error information along. | |||
393 | * | |||
394 | * Returns 0 on No Error | |||
395 | */ | |||
396 | static int | |||
397 | init_htab(HTAB *hashp, int nelem) | |||
398 | { | |||
399 | register int nbuckets, nsegs; | |||
400 | int l2; | |||
401 | ||||
402 | /* | |||
403 | * Divide number of elements by the fill factor and determine a | |||
404 | * desired number of buckets. Allocate space for the next greater | |||
405 | * power of two number of buckets. | |||
406 | */ | |||
407 | nelem = (nelem - 1) / hashp->FFACTORhdr.ffactor + 1; | |||
408 | ||||
409 | l2 = dbm_log2((uint32)PR_MAX(nelem, 2)((nelem)>(2)?(nelem):(2))); | |||
410 | nbuckets = 1 << l2; | |||
411 | ||||
412 | hashp->SPAREShdr.spares[l2] = l2 + 1; | |||
413 | hashp->SPAREShdr.spares[l2 + 1] = l2 + 1; | |||
414 | hashp->OVFL_POINThdr.ovfl_point = l2; | |||
415 | hashp->LAST_FREEDhdr.last_freed = 2; | |||
416 | ||||
417 | /* First bitmap page is at: splitpoint l2 page offset 1 */ | |||
418 | if (dbm_ibitmap(hashp, (int)OADDR_OF(l2, 1)((uint32)((uint32)(l2) << 11) + (1)), l2 + 1, 0)) | |||
419 | return (-1); | |||
420 | ||||
421 | hashp->MAX_BUCKEThdr.max_bucket = hashp->LOW_MASKhdr.low_mask = nbuckets - 1; | |||
422 | hashp->HIGH_MASKhdr.high_mask = (nbuckets << 1) - 1; | |||
423 | hashp->HDRPAGEShdr.hdrpages = ((PR_MAX(sizeof(HASHHDR), MINHDRSIZE)((sizeof(HASHHDR))>(512)?(sizeof(HASHHDR)):(512)) - 1) >> | |||
424 | hashp->BSHIFThdr.bshift) + | |||
425 | 1; | |||
426 | ||||
427 | nsegs = (nbuckets - 1) / hashp->SGSIZEhdr.ssize + 1; | |||
428 | nsegs = 1 << dbm_log2((uint32)nsegs); | |||
429 | ||||
430 | if (nsegs > hashp->DSIZEhdr.dsize) | |||
431 | hashp->DSIZEhdr.dsize = nsegs; | |||
432 | return (alloc_segs(hashp, nsegs)); | |||
433 | } | |||
434 | ||||
435 | /********************** DESTROY/CLOSE ROUTINES ************************/ | |||
436 | ||||
437 | /* | |||
438 | * Flushes any changes to the file if necessary and destroys the hashp | |||
439 | * structure, freeing all allocated space. | |||
440 | */ | |||
441 | static int | |||
442 | hdestroy(HTAB *hashp) | |||
443 | { | |||
444 | int i, save_errno; | |||
445 | ||||
446 | save_errno = 0; | |||
447 | ||||
448 | #ifdef HASH_STATISTICS | |||
449 | (void)fprintf(stderrstderr, "hdestroy: accesses %ld collisions %ld\n", | |||
450 | hash_accesses, hash_collisions); | |||
451 | (void)fprintf(stderrstderr, "hdestroy: expansions %ld\n", | |||
452 | hash_expansions); | |||
453 | (void)fprintf(stderrstderr, "hdestroy: overflows %ld\n", | |||
454 | hash_overflows); | |||
455 | (void)fprintf(stderrstderr, "keys %ld maxp %d segmentcount %d\n", | |||
456 | hashp->NKEYShdr.nkeys, hashp->MAX_BUCKEThdr.max_bucket, hashp->nsegs); | |||
457 | ||||
458 | for (i = 0; i < NCACHED32; i++) | |||
459 | (void)fprintf(stderrstderr, | |||
460 | "spares[%d] = %d\n", i, hashp->SPAREShdr.spares[i]); | |||
461 | #endif | |||
462 | /* | |||
463 | * Call on buffer manager to free buffers, and if required, | |||
464 | * write them to disk. | |||
465 | */ | |||
466 | if (dbm_buf_free(hashp, 1, hashp->save_file)) | |||
467 | save_errno = errno(*__errno_location ()); | |||
468 | if (hashp->dir) { | |||
469 | free(*hashp->dir); /* Free initial segments */ | |||
470 | /* Free extra segments */ | |||
471 | while (hashp->exsegs--) | |||
472 | free(hashp->dir[--hashp->nsegs]); | |||
473 | free(hashp->dir); | |||
474 | } | |||
475 | if (flush_meta(hashp) && !save_errno) | |||
476 | save_errno = errno(*__errno_location ()); | |||
477 | /* Free Bigmaps */ | |||
478 | for (i = 0; i < hashp->nmaps; i++) | |||
479 | if (hashp->mapp[i]) | |||
480 | free(hashp->mapp[i]); | |||
481 | ||||
482 | if (hashp->fp != -1) | |||
483 | (void)close(hashp->fp); | |||
484 | ||||
485 | if (hashp->filename) { | |||
486 | #if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2) | |||
487 | if (hashp->is_temp) | |||
488 | (void)unlink(hashp->filename); | |||
489 | #endif | |||
490 | free(hashp->filename); | |||
491 | } | |||
492 | if (hashp->tmp_buf) | |||
493 | free(hashp->tmp_buf); | |||
494 | if (hashp->tmp_key) | |||
495 | free(hashp->tmp_key); | |||
496 | free(hashp); | |||
497 | if (save_errno) { | |||
498 | errno(*__errno_location ()) = save_errno; | |||
499 | return (DBM_ERROR(-1)); | |||
500 | } | |||
501 | return (SUCCESS(0)); | |||
502 | } | |||
503 | ||||
504 | #if defined(_WIN32) || defined(_WINDOWS) | |||
505 | /* | |||
506 | * Close and reopen file to force file length update on windows. | |||
507 | * | |||
508 | * Returns: | |||
509 | * 0 == OK | |||
510 | * -1 DBM_ERROR | |||
511 | */ | |||
512 | static int | |||
513 | update_EOF(HTAB *hashp) | |||
514 | { | |||
515 | #if defined(DBM_REOPEN_ON_FLUSH) | |||
516 | char *file = hashp->filename; | |||
517 | off_t file_size; | |||
518 | int flags; | |||
519 | int mode = -1; | |||
520 | struct stat statbuf; | |||
521 | ||||
522 | memset(&statbuf, 0, sizeof statbuf); | |||
523 | ||||
524 | /* make sure we won't lose the file by closing it. */ | |||
525 | if (!file || (stat(file, &statbuf) && (errno(*__errno_location ()) == ENOENT2))) { | |||
526 | /* pretend we did it. */ | |||
527 | return 0; | |||
528 | } | |||
529 | ||||
530 | (void)close(hashp->fp); | |||
531 | ||||
532 | flags = hashp->flags & ~(O_TRUNC01000 | O_CREAT0100 | O_EXCL0200); | |||
533 | ||||
534 | if ((hashp->fp = DBFILE_OPEN(file, flags | O_BINARY, mode)open((file), (flags | O_BINARY), (mode))) == -1) | |||
535 | return -1; | |||
536 | file_size = lseek(hashp->fp, (off_t)0, SEEK_END2); | |||
537 | if (file_size == -1) | |||
538 | return -1; | |||
539 | hashp->file_size = file_size; | |||
540 | return 0; | |||
541 | #else | |||
542 | int fd = hashp->fp; | |||
543 | off_t file_size = lseek(fd, (off_t)0, SEEK_END2); | |||
544 | HANDLE handle = (HANDLE)_get_osfhandle(fd); | |||
545 | BOOL cool = FlushFileBuffers(handle); | |||
546 | #ifdef DEBUG3 | |||
547 | if (!cool) { | |||
548 | DWORD err = GetLastError(); | |||
549 | (void)fprintf(stderrstderr, | |||
550 | "FlushFileBuffers failed, last error = %d, 0x%08x\n", | |||
551 | err, err); | |||
552 | } | |||
553 | #endif | |||
554 | if (file_size == -1) | |||
555 | return -1; | |||
556 | hashp->file_size = file_size; | |||
557 | return cool ? 0 : -1; | |||
558 | #endif | |||
559 | } | |||
560 | #endif | |||
561 | ||||
562 | /* | |||
563 | * Write modified pages to disk | |||
564 | * | |||
565 | * Returns: | |||
566 | * 0 == OK | |||
567 | * -1 DBM_ERROR | |||
568 | */ | |||
569 | static int | |||
570 | hash_sync(const DB *dbp, uint flags) | |||
571 | { | |||
572 | HTAB *hashp; | |||
573 | ||||
574 | if (flags != 0) { | |||
575 | errno(*__errno_location ()) = EINVAL22; | |||
576 | return (DBM_ERROR(-1)); | |||
577 | } | |||
578 | ||||
579 | if (!dbp) | |||
580 | return (DBM_ERROR(-1)); | |||
581 | ||||
582 | hashp = (HTAB *)dbp->internal; | |||
583 | if (!hashp) | |||
584 | return (DBM_ERROR(-1)); | |||
585 | ||||
586 | if (!hashp->save_file) | |||
587 | return (0); | |||
588 | if (dbm_buf_free(hashp, 0, 1) || flush_meta(hashp)) | |||
589 | return (DBM_ERROR(-1)); | |||
590 | #if defined(_WIN32) || defined(_WINDOWS) | |||
591 | if (hashp->updateEOF && hashp->filename && !hashp->is_temp) { | |||
592 | int status = update_EOF(hashp); | |||
593 | hashp->updateEOF = 0; | |||
594 | if (status) | |||
595 | return status; | |||
596 | } | |||
597 | #endif | |||
598 | hashp->new_file = 0; | |||
599 | return (0); | |||
600 | } | |||
601 | ||||
602 | /* | |||
603 | * Returns: | |||
604 | * 0 == OK | |||
605 | * -1 indicates that errno should be set | |||
606 | */ | |||
607 | static int | |||
608 | flush_meta(HTAB *hashp) | |||
609 | { | |||
610 | HASHHDR *whdrp; | |||
611 | #if BYTE_ORDER1234 == LITTLE_ENDIAN1234 | |||
612 | HASHHDR whdr; | |||
613 | #endif | |||
614 | int fp, i, wsize; | |||
615 | ||||
616 | if (!hashp->save_file) | |||
617 | return (0); | |||
618 | hashp->MAGIChdr.magic = HASHMAGIC0x061561; | |||
619 | hashp->VERSIONhdr.version = HASHVERSION2; | |||
620 | hashp->H_CHARKEYhdr.h_charkey = hashp->hash(CHARKEY"%$sniglet^&", sizeof(CHARKEY"%$sniglet^&")); | |||
621 | ||||
622 | fp = hashp->fp; | |||
623 | whdrp = &hashp->hdr; | |||
624 | #if BYTE_ORDER1234 == LITTLE_ENDIAN1234 | |||
625 | whdrp = &whdr; | |||
626 | swap_header_copy(&hashp->hdr, whdrp); | |||
627 | #endif | |||
628 | if ((lseek(fp, (off_t)0, SEEK_SET0) == -1) || | |||
629 | ((wsize = write(fp, (char *)whdrp, sizeof(HASHHDR))) == -1)) | |||
630 | return (-1); | |||
631 | else if (wsize != sizeof(HASHHDR)) { | |||
632 | errno(*__errno_location ()) = EFTYPE22; | |||
633 | hashp->dbmerrno = errno(*__errno_location ()); | |||
634 | return (-1); | |||
635 | } | |||
636 | for (i = 0; i < NCACHED32; i++) | |||
637 | if (hashp->mapp[i]) | |||
638 | if (dbm_put_page(hashp, (char *)hashp->mapp[i], | |||
639 | hashp->BITMAPShdr.bitmaps[i], 0, 1)) | |||
640 | return (-1); | |||
641 | return (0); | |||
642 | } | |||
643 | ||||
644 | /*******************************SEARCH ROUTINES *****************************/ | |||
645 | /* | |||
646 | * All the access routines return | |||
647 | * | |||
648 | * Returns: | |||
649 | * 0 on SUCCESS | |||
650 | * 1 to indicate an external DBM_ERROR (i.e. key not found, etc) | |||
651 | * -1 to indicate an internal DBM_ERROR (i.e. out of memory, etc) | |||
652 | */ | |||
653 | static int | |||
654 | hash_get( | |||
655 | const DB *dbp, | |||
656 | const DBT *key, | |||
657 | DBT *data, | |||
658 | uint flag) | |||
659 | { | |||
660 | HTAB *hashp; | |||
661 | int rv; | |||
662 | ||||
663 | hashp = (HTAB *)dbp->internal; | |||
664 | if (!hashp) | |||
665 | return (DBM_ERROR(-1)); | |||
666 | ||||
667 | if (flag) { | |||
668 | hashp->dbmerrno = errno(*__errno_location ()) = EINVAL22; | |||
669 | return (DBM_ERROR(-1)); | |||
670 | } | |||
671 | ||||
672 | rv = hash_access(hashp, HASH_GET, (DBT *)key, data); | |||
673 | ||||
674 | if (rv == DATABASE_CORRUPTED_ERROR-999) { | |||
675 | #if defined(unix) && defined(DEBUG1) | |||
676 | printf("\n\nDBM Database has been corrupted, tell Lou...\n\n"); | |||
677 | #endif | |||
678 | dbm_remove_database((DB *)dbp); | |||
679 | } | |||
680 | ||||
681 | return (rv); | |||
682 | } | |||
683 | ||||
684 | static int | |||
685 | hash_put( | |||
686 | const DB *dbp, | |||
687 | DBT *key, | |||
688 | const DBT *data, | |||
689 | uint flag) | |||
690 | { | |||
691 | HTAB *hashp; | |||
692 | int rv; | |||
693 | ||||
694 | hashp = (HTAB *)dbp->internal; | |||
695 | if (!hashp) | |||
696 | return (DBM_ERROR(-1)); | |||
697 | ||||
698 | if (flag && flag != R_NOOVERWRITE8) { | |||
699 | hashp->dbmerrno = errno(*__errno_location ()) = EINVAL22; | |||
700 | return (DBM_ERROR(-1)); | |||
701 | } | |||
702 | if ((hashp->flags & O_ACCMODE0003) == O_RDONLY00) { | |||
703 | hashp->dbmerrno = errno(*__errno_location ()) = EPERM1; | |||
704 | return (DBM_ERROR(-1)); | |||
705 | } | |||
706 | ||||
707 | rv = hash_access(hashp, flag == R_NOOVERWRITE8 ? HASH_PUTNEW : HASH_PUT, | |||
708 | (DBT *)key, (DBT *)data); | |||
709 | ||||
710 | if (rv == DATABASE_CORRUPTED_ERROR-999) { | |||
711 | #if defined(unix) && defined(DEBUG1) | |||
712 | printf("\n\nDBM Database has been corrupted, tell Lou...\n\n"); | |||
713 | #endif | |||
714 | dbm_remove_database((DB *)dbp); | |||
715 | } | |||
716 | ||||
717 | return (rv); | |||
718 | } | |||
719 | ||||
720 | static int | |||
721 | hash_delete( | |||
722 | const DB *dbp, | |||
723 | const DBT *key, | |||
724 | uint flag) /* Ignored */ | |||
725 | { | |||
726 | HTAB *hashp; | |||
727 | int rv; | |||
728 | ||||
729 | hashp = (HTAB *)dbp->internal; | |||
730 | if (!hashp) | |||
731 | return (DBM_ERROR(-1)); | |||
732 | ||||
733 | if (flag && flag != R_CURSOR1) { | |||
734 | hashp->dbmerrno = errno(*__errno_location ()) = EINVAL22; | |||
735 | return (DBM_ERROR(-1)); | |||
736 | } | |||
737 | if ((hashp->flags & O_ACCMODE0003) == O_RDONLY00) { | |||
738 | hashp->dbmerrno = errno(*__errno_location ()) = EPERM1; | |||
739 | return (DBM_ERROR(-1)); | |||
740 | } | |||
741 | rv = hash_access(hashp, HASH_DELETE, (DBT *)key, NULL((void*)0)); | |||
742 | ||||
743 | if (rv == DATABASE_CORRUPTED_ERROR-999) { | |||
744 | #if defined(unix) && defined(DEBUG1) | |||
745 | printf("\n\nDBM Database has been corrupted, tell Lou...\n\n"); | |||
746 | #endif | |||
747 | dbm_remove_database((DB *)dbp); | |||
748 | } | |||
749 | ||||
750 | return (rv); | |||
751 | } | |||
752 | ||||
753 | #define MAX_OVERFLOW_HASH_ACCESS_LOOPS2000 2000 | |||
754 | /* | |||
755 | * Assume that hashp has been set in wrapper routine. | |||
756 | */ | |||
757 | static int | |||
758 | hash_access( | |||
759 | HTAB *hashp, | |||
760 | ACTION action, | |||
761 | DBT *key, DBT *val) | |||
762 | { | |||
763 | register BUFHEAD *rbufp; | |||
764 | BUFHEAD *bufp, *save_bufp; | |||
765 | register uint16 *bp; | |||
766 | register long n, ndx, off; | |||
767 | register size_t size; | |||
768 | register char *kp; | |||
769 | uint16 pageno; | |||
770 | uint32 ovfl_loop_count = 0; | |||
771 | int32 last_overflow_page_no = -1; | |||
772 | ||||
773 | #ifdef HASH_STATISTICS | |||
774 | hash_accesses++; | |||
775 | #endif | |||
776 | ||||
777 | off = hashp->BSIZEhdr.bsize; | |||
778 | size = key->size; | |||
779 | kp = (char *)key->data; | |||
780 | rbufp = dbm_get_buf(hashp, dbm_call_hash(hashp, kp, size), NULL((void*)0), 0); | |||
781 | if (!rbufp) | |||
782 | return (DATABASE_CORRUPTED_ERROR-999); | |||
783 | save_bufp = rbufp; | |||
784 | ||||
785 | /* Pin the bucket chain */ | |||
786 | rbufp->flags |= BUF_PIN0x0008; | |||
787 | for (bp = (uint16 *)rbufp->page, n = *bp++, ndx = 1; ndx < n;) { | |||
788 | ||||
789 | if (bp[1] >= REAL_KEY4) { | |||
790 | /* Real key/data pair */ | |||
791 | if (size == (unsigned long)(off - *bp) && | |||
792 | memcmp(kp, rbufp->page + *bp, size) == 0) | |||
793 | goto found; | |||
794 | off = bp[1]; | |||
795 | #ifdef HASH_STATISTICS | |||
796 | hash_collisions++; | |||
797 | #endif | |||
798 | bp += 2; | |||
799 | ndx += 2; | |||
800 | } else if (bp[1] == OVFLPAGE0) { | |||
801 | ||||
802 | /* database corruption: overflow loop detection */ | |||
803 | if (last_overflow_page_no == (int32)*bp) | |||
804 | return (DATABASE_CORRUPTED_ERROR-999); | |||
805 | ||||
806 | last_overflow_page_no = *bp; | |||
807 | ||||
808 | rbufp = dbm_get_buf(hashp, *bp, rbufp, 0); | |||
809 | if (!rbufp) { | |||
810 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
811 | return (DBM_ERROR(-1)); | |||
812 | } | |||
813 | ||||
814 | ovfl_loop_count++; | |||
815 | if (ovfl_loop_count > MAX_OVERFLOW_HASH_ACCESS_LOOPS2000) | |||
816 | return (DATABASE_CORRUPTED_ERROR-999); | |||
817 | ||||
818 | /* FOR LOOP INIT */ | |||
819 | bp = (uint16 *)rbufp->page; | |||
820 | n = *bp++; | |||
821 | ndx = 1; | |||
822 | off = hashp->BSIZEhdr.bsize; | |||
823 | } else if (bp[1] < REAL_KEY4) { | |||
824 | if ((ndx = | |||
825 | dbm_find_bigpair(hashp, rbufp, ndx, kp, (int)size)) > 0) | |||
826 | goto found; | |||
827 | if (ndx == -2) { | |||
828 | bufp = rbufp; | |||
829 | if (!(pageno = | |||
830 | dbm_find_last_page(hashp, &bufp))) { | |||
831 | ndx = 0; | |||
832 | rbufp = bufp; | |||
833 | break; /* FOR */ | |||
834 | } | |||
835 | rbufp = dbm_get_buf(hashp, pageno, bufp, 0); | |||
836 | if (!rbufp) { | |||
837 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
838 | return (DBM_ERROR(-1)); | |||
839 | } | |||
840 | /* FOR LOOP INIT */ | |||
841 | bp = (uint16 *)rbufp->page; | |||
842 | n = *bp++; | |||
843 | ndx = 1; | |||
844 | off = hashp->BSIZEhdr.bsize; | |||
845 | } else { | |||
846 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
847 | return (DBM_ERROR(-1)); | |||
848 | } | |||
849 | } | |||
850 | } | |||
851 | ||||
852 | /* Not found */ | |||
853 | switch (action) { | |||
854 | case HASH_PUT: | |||
855 | case HASH_PUTNEW: | |||
856 | if (dbm_addel(hashp, rbufp, key, val)) { | |||
857 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
858 | return (DBM_ERROR(-1)); | |||
859 | } else { | |||
860 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
861 | return (SUCCESS(0)); | |||
862 | } | |||
863 | case HASH_GET: | |||
864 | case HASH_DELETE: | |||
865 | default: | |||
866 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
867 | return (ABNORMAL(1)); | |||
868 | } | |||
869 | ||||
870 | found: | |||
871 | switch (action) { | |||
872 | case HASH_PUTNEW: | |||
873 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
874 | return (ABNORMAL(1)); | |||
875 | case HASH_GET: | |||
876 | bp = (uint16 *)rbufp->page; | |||
877 | if (bp[ndx + 1] < REAL_KEY4) { | |||
878 | if (dbm_big_return(hashp, rbufp, ndx, val, 0)) | |||
879 | return (DBM_ERROR(-1)); | |||
880 | } else { | |||
881 | val->data = (uint8 *)rbufp->page + (int)bp[ndx + 1]; | |||
882 | val->size = bp[ndx] - bp[ndx + 1]; | |||
883 | } | |||
884 | break; | |||
885 | case HASH_PUT: | |||
886 | if ((dbm_delpair(hashp, rbufp, ndx)) || | |||
887 | (dbm_addel(hashp, rbufp, key, val))) { | |||
888 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
889 | return (DBM_ERROR(-1)); | |||
890 | } | |||
891 | break; | |||
892 | case HASH_DELETE: | |||
893 | if (dbm_delpair(hashp, rbufp, ndx)) | |||
894 | return (DBM_ERROR(-1)); | |||
895 | break; | |||
896 | default: | |||
897 | abort(); | |||
898 | } | |||
899 | save_bufp->flags &= ~BUF_PIN0x0008; | |||
900 | return (SUCCESS(0)); | |||
901 | } | |||
902 | ||||
903 | static int | |||
904 | hash_seq( | |||
905 | const DB *dbp, | |||
906 | DBT *key, DBT *data, | |||
907 | uint flag) | |||
908 | { | |||
909 | register uint32 bucket; | |||
910 | register BUFHEAD *bufp = NULL((void*)0); | |||
911 | HTAB *hashp; | |||
912 | uint16 *bp, ndx; | |||
913 | ||||
914 | hashp = (HTAB *)dbp->internal; | |||
915 | if (!hashp) | |||
916 | return (DBM_ERROR(-1)); | |||
917 | ||||
918 | if (flag && flag != R_FIRST3 && flag != R_NEXT7) { | |||
919 | hashp->dbmerrno = errno(*__errno_location ()) = EINVAL22; | |||
920 | return (DBM_ERROR(-1)); | |||
921 | } | |||
922 | #ifdef HASH_STATISTICS | |||
923 | hash_accesses++; | |||
924 | #endif | |||
925 | if ((hashp->cbucket < 0) || (flag == R_FIRST3)) { | |||
926 | hashp->cbucket = 0; | |||
927 | hashp->cndx = 1; | |||
928 | hashp->cpage = NULL((void*)0); | |||
929 | } | |||
930 | ||||
931 | for (bp = NULL((void*)0); !bp || !bp[0];) { | |||
932 | if (!(bufp = hashp->cpage)) { | |||
933 | for (bucket = hashp->cbucket; | |||
934 | bucket <= (uint32)hashp->MAX_BUCKEThdr.max_bucket; | |||
935 | bucket++, hashp->cndx = 1) { | |||
936 | bufp = dbm_get_buf(hashp, bucket, NULL((void*)0), 0); | |||
937 | if (!bufp) | |||
938 | return (DBM_ERROR(-1)); | |||
939 | hashp->cpage = bufp; | |||
940 | bp = (uint16 *)bufp->page; | |||
941 | if (bp[0]) | |||
942 | break; | |||
943 | } | |||
944 | hashp->cbucket = bucket; | |||
945 | if (hashp->cbucket > hashp->MAX_BUCKEThdr.max_bucket) { | |||
946 | hashp->cbucket = -1; | |||
947 | return (ABNORMAL(1)); | |||
948 | } | |||
949 | } else | |||
950 | bp = (uint16 *)hashp->cpage->page; | |||
951 | ||||
952 | #ifdef DEBUG1 | |||
953 | assert(bp)((bp) ? (void) (0) : __assert_fail ("bp", "hash.c", 953, __extension__ __PRETTY_FUNCTION__)); | |||
954 | assert(bufp)((bufp) ? (void) (0) : __assert_fail ("bufp", "hash.c", 954, __extension__ __PRETTY_FUNCTION__)); | |||
955 | #endif | |||
956 | while (bp[hashp->cndx + 1] == OVFLPAGE0) { | |||
957 | bufp = hashp->cpage = | |||
958 | dbm_get_buf(hashp, bp[hashp->cndx], bufp, 0); | |||
959 | if (!bufp) | |||
960 | return (DBM_ERROR(-1)); | |||
961 | bp = (uint16 *)(bufp->page); | |||
962 | hashp->cndx = 1; | |||
963 | } | |||
964 | if (!bp[0]) { | |||
965 | hashp->cpage = NULL((void*)0); | |||
966 | ++hashp->cbucket; | |||
967 | } | |||
968 | } | |||
969 | ndx = hashp->cndx; | |||
970 | if (bp[ndx + 1] < REAL_KEY4) { | |||
971 | if (dbm_big_keydata(hashp, bufp, key, data, 1)) | |||
972 | return (DBM_ERROR(-1)); | |||
973 | } else { | |||
974 | key->data = (uint8 *)hashp->cpage->page + bp[ndx]; | |||
975 | key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZEhdr.bsize) - bp[ndx]; | |||
976 | data->data = (uint8 *)hashp->cpage->page + bp[ndx + 1]; | |||
977 | data->size = bp[ndx] - bp[ndx + 1]; | |||
978 | ndx += 2; | |||
979 | if (ndx > bp[0]) { | |||
980 | hashp->cpage = NULL((void*)0); | |||
981 | hashp->cbucket++; | |||
982 | hashp->cndx = 1; | |||
983 | } else | |||
984 | hashp->cndx = ndx; | |||
985 | } | |||
986 | return (SUCCESS(0)); | |||
987 | } | |||
988 | ||||
989 | /********************************* UTILITIES ************************/ | |||
990 | ||||
991 | /* | |||
992 | * Returns: | |||
993 | * 0 ==> OK | |||
994 | * -1 ==> Error | |||
995 | */ | |||
996 | extern int | |||
997 | dbm_expand_table(HTAB *hashp) | |||
998 | { | |||
999 | uint32 old_bucket, new_bucket; | |||
1000 | int new_segnum, spare_ndx; | |||
1001 | size_t dirsize; | |||
1002 | ||||
1003 | #ifdef HASH_STATISTICS | |||
1004 | hash_expansions++; | |||
1005 | #endif | |||
1006 | new_bucket = ++hashp->MAX_BUCKEThdr.max_bucket; | |||
1007 | old_bucket = (hashp->MAX_BUCKEThdr.max_bucket & hashp->LOW_MASKhdr.low_mask); | |||
1008 | ||||
1009 | new_segnum = new_bucket >> hashp->SSHIFThdr.sshift; | |||
1010 | ||||
1011 | /* Check if we need a new segment */ | |||
1012 | if (new_segnum >= hashp->nsegs) { | |||
1013 | /* Check if we need to expand directory */ | |||
1014 | if (new_segnum >= hashp->DSIZEhdr.dsize) { | |||
1015 | /* Reallocate directory */ | |||
1016 | dirsize = hashp->DSIZEhdr.dsize * sizeof(SEGMENT *); | |||
1017 | if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1)) | |||
1018 | return (-1); | |||
1019 | hashp->DSIZEhdr.dsize = dirsize << 1; | |||
1020 | } | |||
1021 | if ((hashp->dir[new_segnum] = | |||
1022 | (SEGMENT)calloc((size_t)hashp->SGSIZEhdr.ssize, sizeof(BUFHEAD *))) == NULL((void*)0)) | |||
1023 | return (-1); | |||
1024 | hashp->exsegs++; | |||
1025 | hashp->nsegs++; | |||
1026 | } | |||
1027 | /* | |||
1028 | * If the split point is increasing (MAX_BUCKET's log base 2 | |||
1029 | * * increases), we need to copy the current contents of the spare | |||
1030 | * split bucket to the next bucket. | |||
1031 | */ | |||
1032 | spare_ndx = dbm_log2((uint32)(hashp->MAX_BUCKEThdr.max_bucket + 1)); | |||
1033 | if (spare_ndx > hashp->OVFL_POINThdr.ovfl_point) { | |||
1034 | hashp->SPAREShdr.spares[spare_ndx] = hashp->SPAREShdr.spares[hashp->OVFL_POINThdr.ovfl_point]; | |||
1035 | hashp->OVFL_POINThdr.ovfl_point = spare_ndx; | |||
1036 | } | |||
1037 | ||||
1038 | if (new_bucket > (uint32)hashp->HIGH_MASKhdr.high_mask) { | |||
1039 | /* Starting a new doubling */ | |||
1040 | hashp->LOW_MASKhdr.low_mask = hashp->HIGH_MASKhdr.high_mask; | |||
1041 | hashp->HIGH_MASKhdr.high_mask = new_bucket | hashp->LOW_MASKhdr.low_mask; | |||
1042 | } | |||
1043 | /* Relocate records to the new bucket */ | |||
1044 | return (dbm_split_page(hashp, old_bucket, new_bucket)); | |||
1045 | } | |||
1046 | ||||
1047 | /* | |||
1048 | * If realloc guarantees that the pointer is not destroyed if the realloc | |||
1049 | * fails, then this routine can go away. | |||
1050 | */ | |||
1051 | static void * | |||
1052 | hash_realloc( | |||
1053 | SEGMENT **p_ptr, | |||
1054 | size_t oldsize, size_t newsize) | |||
1055 | { | |||
1056 | register void *p; | |||
1057 | ||||
1058 | if ((p = malloc(newsize))) { | |||
1059 | memmove(p, *p_ptr, oldsize); | |||
1060 | memset((char *)p + oldsize, 0, newsize - oldsize); | |||
1061 | free(*p_ptr); | |||
1062 | *p_ptr = (SEGMENT *)p; | |||
1063 | } | |||
1064 | return (p); | |||
1065 | } | |||
1066 | ||||
1067 | extern uint32 | |||
1068 | dbm_call_hash(HTAB *hashp, char *k, size_t len) | |||
1069 | { | |||
1070 | uint32 n, bucket; | |||
1071 | ||||
1072 | n = hashp->hash(k, len); | |||
1073 | bucket = n & hashp->HIGH_MASKhdr.high_mask; | |||
1074 | if (bucket > (uint32)hashp->MAX_BUCKEThdr.max_bucket) | |||
1075 | bucket = bucket & hashp->LOW_MASKhdr.low_mask; | |||
1076 | return (bucket); | |||
1077 | } | |||
1078 | ||||
1079 | /* | |||
1080 | * Allocate segment table. On error, set errno. | |||
1081 | * | |||
1082 | * Returns 0 on success | |||
1083 | */ | |||
1084 | static int | |||
1085 | alloc_segs( | |||
1086 | HTAB *hashp, | |||
1087 | int nsegs) | |||
1088 | { | |||
1089 | register int i; | |||
1090 | register SEGMENT store; | |||
1091 | ||||
1092 | if ((hashp->dir = | |||
1093 | (SEGMENT *)calloc((size_t)hashp->DSIZEhdr.dsize, sizeof(SEGMENT))) == NULL((void*)0)) { | |||
1094 | errno(*__errno_location ()) = ENOMEM12; | |||
1095 | return (-1); | |||
1096 | } | |||
1097 | /* Allocate segments */ | |||
1098 | if ((store = | |||
1099 | (SEGMENT)calloc((size_t)nsegs << hashp->SSHIFThdr.sshift, sizeof(BUFHEAD *))) == NULL((void*)0)) { | |||
1100 | errno(*__errno_location ()) = ENOMEM12; | |||
1101 | return (-1); | |||
1102 | } | |||
1103 | for (i = 0; i < nsegs; i++, hashp->nsegs++) | |||
1104 | hashp->dir[i] = &store[i << hashp->SSHIFThdr.sshift]; | |||
1105 | return (0); | |||
| ||||
1106 | } | |||
1107 | ||||
1108 | #if BYTE_ORDER1234 == LITTLE_ENDIAN1234 | |||
1109 | /* | |||
1110 | * Hashp->hdr needs to be byteswapped. | |||
1111 | */ | |||
1112 | static void | |||
1113 | swap_header_copy( | |||
1114 | HASHHDR *srcp, HASHHDR *destp) | |||
1115 | { | |||
1116 | int i; | |||
1117 | ||||
1118 | P_32_COPY(srcp->magic, destp->magic){ ((char *)&(destp->magic))[0] = ((char *)&(srcp-> magic))[3]; ((char *)&(destp->magic))[1] = ((char *)& (srcp->magic))[2]; ((char *)&(destp->magic))[2] = ( (char *)&(srcp->magic))[1]; ((char *)&(destp->magic ))[3] = ((char *)&(srcp->magic))[0]; }; | |||
1119 | P_32_COPY(srcp->version, destp->version){ ((char *)&(destp->version))[0] = ((char *)&(srcp ->version))[3]; ((char *)&(destp->version))[1] = (( char *)&(srcp->version))[2]; ((char *)&(destp-> version))[2] = ((char *)&(srcp->version))[1]; ((char * )&(destp->version))[3] = ((char *)&(srcp->version ))[0]; }; | |||
1120 | P_32_COPY(srcp->lorder, destp->lorder){ ((char *)&(destp->lorder))[0] = ((char *)&(srcp-> lorder))[3]; ((char *)&(destp->lorder))[1] = ((char *) &(srcp->lorder))[2]; ((char *)&(destp->lorder)) [2] = ((char *)&(srcp->lorder))[1]; ((char *)&(destp ->lorder))[3] = ((char *)&(srcp->lorder))[0]; }; | |||
1121 | P_32_COPY(srcp->bsize, destp->bsize){ ((char *)&(destp->bsize))[0] = ((char *)&(srcp-> bsize))[3]; ((char *)&(destp->bsize))[1] = ((char *)& (srcp->bsize))[2]; ((char *)&(destp->bsize))[2] = ( (char *)&(srcp->bsize))[1]; ((char *)&(destp->bsize ))[3] = ((char *)&(srcp->bsize))[0]; }; | |||
1122 | P_32_COPY(srcp->bshift, destp->bshift){ ((char *)&(destp->bshift))[0] = ((char *)&(srcp-> bshift))[3]; ((char *)&(destp->bshift))[1] = ((char *) &(srcp->bshift))[2]; ((char *)&(destp->bshift)) [2] = ((char *)&(srcp->bshift))[1]; ((char *)&(destp ->bshift))[3] = ((char *)&(srcp->bshift))[0]; }; | |||
1123 | P_32_COPY(srcp->dsize, destp->dsize){ ((char *)&(destp->dsize))[0] = ((char *)&(srcp-> dsize))[3]; ((char *)&(destp->dsize))[1] = ((char *)& (srcp->dsize))[2]; ((char *)&(destp->dsize))[2] = ( (char *)&(srcp->dsize))[1]; ((char *)&(destp->dsize ))[3] = ((char *)&(srcp->dsize))[0]; }; | |||
1124 | P_32_COPY(srcp->ssize, destp->ssize){ ((char *)&(destp->ssize))[0] = ((char *)&(srcp-> ssize))[3]; ((char *)&(destp->ssize))[1] = ((char *)& (srcp->ssize))[2]; ((char *)&(destp->ssize))[2] = ( (char *)&(srcp->ssize))[1]; ((char *)&(destp->ssize ))[3] = ((char *)&(srcp->ssize))[0]; }; | |||
1125 | P_32_COPY(srcp->sshift, destp->sshift){ ((char *)&(destp->sshift))[0] = ((char *)&(srcp-> sshift))[3]; ((char *)&(destp->sshift))[1] = ((char *) &(srcp->sshift))[2]; ((char *)&(destp->sshift)) [2] = ((char *)&(srcp->sshift))[1]; ((char *)&(destp ->sshift))[3] = ((char *)&(srcp->sshift))[0]; }; | |||
1126 | P_32_COPY(srcp->ovfl_point, destp->ovfl_point){ ((char *)&(destp->ovfl_point))[0] = ((char *)&(srcp ->ovfl_point))[3]; ((char *)&(destp->ovfl_point))[1 ] = ((char *)&(srcp->ovfl_point))[2]; ((char *)&(destp ->ovfl_point))[2] = ((char *)&(srcp->ovfl_point))[1 ]; ((char *)&(destp->ovfl_point))[3] = ((char *)&( srcp->ovfl_point))[0]; }; | |||
1127 | P_32_COPY(srcp->last_freed, destp->last_freed){ ((char *)&(destp->last_freed))[0] = ((char *)&(srcp ->last_freed))[3]; ((char *)&(destp->last_freed))[1 ] = ((char *)&(srcp->last_freed))[2]; ((char *)&(destp ->last_freed))[2] = ((char *)&(srcp->last_freed))[1 ]; ((char *)&(destp->last_freed))[3] = ((char *)&( srcp->last_freed))[0]; }; | |||
1128 | P_32_COPY(srcp->max_bucket, destp->max_bucket){ ((char *)&(destp->max_bucket))[0] = ((char *)&(srcp ->max_bucket))[3]; ((char *)&(destp->max_bucket))[1 ] = ((char *)&(srcp->max_bucket))[2]; ((char *)&(destp ->max_bucket))[2] = ((char *)&(srcp->max_bucket))[1 ]; ((char *)&(destp->max_bucket))[3] = ((char *)&( srcp->max_bucket))[0]; }; | |||
1129 | P_32_COPY(srcp->high_mask, destp->high_mask){ ((char *)&(destp->high_mask))[0] = ((char *)&(srcp ->high_mask))[3]; ((char *)&(destp->high_mask))[1] = ((char *)&(srcp->high_mask))[2]; ((char *)&(destp ->high_mask))[2] = ((char *)&(srcp->high_mask))[1]; ((char *)&(destp->high_mask))[3] = ((char *)&(srcp ->high_mask))[0]; }; | |||
1130 | P_32_COPY(srcp->low_mask, destp->low_mask){ ((char *)&(destp->low_mask))[0] = ((char *)&(srcp ->low_mask))[3]; ((char *)&(destp->low_mask))[1] = ( (char *)&(srcp->low_mask))[2]; ((char *)&(destp-> low_mask))[2] = ((char *)&(srcp->low_mask))[1]; ((char *)&(destp->low_mask))[3] = ((char *)&(srcp->low_mask ))[0]; }; | |||
1131 | P_32_COPY(srcp->ffactor, destp->ffactor){ ((char *)&(destp->ffactor))[0] = ((char *)&(srcp ->ffactor))[3]; ((char *)&(destp->ffactor))[1] = (( char *)&(srcp->ffactor))[2]; ((char *)&(destp-> ffactor))[2] = ((char *)&(srcp->ffactor))[1]; ((char * )&(destp->ffactor))[3] = ((char *)&(srcp->ffactor ))[0]; }; | |||
1132 | P_32_COPY(srcp->nkeys, destp->nkeys){ ((char *)&(destp->nkeys))[0] = ((char *)&(srcp-> nkeys))[3]; ((char *)&(destp->nkeys))[1] = ((char *)& (srcp->nkeys))[2]; ((char *)&(destp->nkeys))[2] = ( (char *)&(srcp->nkeys))[1]; ((char *)&(destp->nkeys ))[3] = ((char *)&(srcp->nkeys))[0]; }; | |||
1133 | P_32_COPY(srcp->hdrpages, destp->hdrpages){ ((char *)&(destp->hdrpages))[0] = ((char *)&(srcp ->hdrpages))[3]; ((char *)&(destp->hdrpages))[1] = ( (char *)&(srcp->hdrpages))[2]; ((char *)&(destp-> hdrpages))[2] = ((char *)&(srcp->hdrpages))[1]; ((char *)&(destp->hdrpages))[3] = ((char *)&(srcp->hdrpages ))[0]; }; | |||
1134 | P_32_COPY(srcp->h_charkey, destp->h_charkey){ ((char *)&(destp->h_charkey))[0] = ((char *)&(srcp ->h_charkey))[3]; ((char *)&(destp->h_charkey))[1] = ((char *)&(srcp->h_charkey))[2]; ((char *)&(destp ->h_charkey))[2] = ((char *)&(srcp->h_charkey))[1]; ((char *)&(destp->h_charkey))[3] = ((char *)&(srcp ->h_charkey))[0]; }; | |||
1135 | for (i = 0; i < NCACHED32; i++) { | |||
1136 | P_32_COPY(srcp->spares[i], destp->spares[i]){ ((char *)&(destp->spares[i]))[0] = ((char *)&(srcp ->spares[i]))[3]; ((char *)&(destp->spares[i]))[1] = ((char *)&(srcp->spares[i]))[2]; ((char *)&(destp ->spares[i]))[2] = ((char *)&(srcp->spares[i]))[1]; ((char *)&(destp->spares[i]))[3] = ((char *)&(srcp ->spares[i]))[0]; }; | |||
1137 | P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]){ ((char *)&(destp->bitmaps[i]))[0] = ((char *)&(srcp ->bitmaps[i]))[1]; ((char *)&(destp->bitmaps[i]))[1 ] = ((char *)&(srcp->bitmaps[i]))[0]; }; | |||
1138 | } | |||
1139 | } | |||
1140 | ||||
1141 | static void | |||
1142 | swap_header(HTAB *hashp) | |||
1143 | { | |||
1144 | HASHHDR *hdrp; | |||
1145 | int i; | |||
1146 | ||||
1147 | hdrp = &hashp->hdr; | |||
1148 | ||||
1149 | M_32_SWAP(hdrp->magic){ uint32 _tmp = hdrp->magic; ((char *)&hdrp->magic) [0] = ((char *)&_tmp)[3]; ((char *)&hdrp->magic)[1 ] = ((char *)&_tmp)[2]; ((char *)&hdrp->magic)[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->magic)[3] = ( (char *)&_tmp)[0]; }; | |||
1150 | M_32_SWAP(hdrp->version){ uint32 _tmp = hdrp->version; ((char *)&hdrp->version )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->version )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->version )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->version )[3] = ((char *)&_tmp)[0]; }; | |||
1151 | M_32_SWAP(hdrp->lorder){ uint32 _tmp = hdrp->lorder; ((char *)&hdrp->lorder )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->lorder) [1] = ((char *)&_tmp)[2]; ((char *)&hdrp->lorder)[ 2] = ((char *)&_tmp)[1]; ((char *)&hdrp->lorder)[3 ] = ((char *)&_tmp)[0]; }; | |||
1152 | M_32_SWAP(hdrp->bsize){ uint32 _tmp = hdrp->bsize; ((char *)&hdrp->bsize) [0] = ((char *)&_tmp)[3]; ((char *)&hdrp->bsize)[1 ] = ((char *)&_tmp)[2]; ((char *)&hdrp->bsize)[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->bsize)[3] = ( (char *)&_tmp)[0]; }; | |||
1153 | M_32_SWAP(hdrp->bshift){ uint32 _tmp = hdrp->bshift; ((char *)&hdrp->bshift )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->bshift) [1] = ((char *)&_tmp)[2]; ((char *)&hdrp->bshift)[ 2] = ((char *)&_tmp)[1]; ((char *)&hdrp->bshift)[3 ] = ((char *)&_tmp)[0]; }; | |||
1154 | M_32_SWAP(hdrp->dsize){ uint32 _tmp = hdrp->dsize; ((char *)&hdrp->dsize) [0] = ((char *)&_tmp)[3]; ((char *)&hdrp->dsize)[1 ] = ((char *)&_tmp)[2]; ((char *)&hdrp->dsize)[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->dsize)[3] = ( (char *)&_tmp)[0]; }; | |||
1155 | M_32_SWAP(hdrp->ssize){ uint32 _tmp = hdrp->ssize; ((char *)&hdrp->ssize) [0] = ((char *)&_tmp)[3]; ((char *)&hdrp->ssize)[1 ] = ((char *)&_tmp)[2]; ((char *)&hdrp->ssize)[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->ssize)[3] = ( (char *)&_tmp)[0]; }; | |||
1156 | M_32_SWAP(hdrp->sshift){ uint32 _tmp = hdrp->sshift; ((char *)&hdrp->sshift )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->sshift) [1] = ((char *)&_tmp)[2]; ((char *)&hdrp->sshift)[ 2] = ((char *)&_tmp)[1]; ((char *)&hdrp->sshift)[3 ] = ((char *)&_tmp)[0]; }; | |||
1157 | M_32_SWAP(hdrp->ovfl_point){ uint32 _tmp = hdrp->ovfl_point; ((char *)&hdrp->ovfl_point )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->ovfl_point )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->ovfl_point )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->ovfl_point )[3] = ((char *)&_tmp)[0]; }; | |||
1158 | M_32_SWAP(hdrp->last_freed){ uint32 _tmp = hdrp->last_freed; ((char *)&hdrp->last_freed )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->last_freed )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->last_freed )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->last_freed )[3] = ((char *)&_tmp)[0]; }; | |||
1159 | M_32_SWAP(hdrp->max_bucket){ uint32 _tmp = hdrp->max_bucket; ((char *)&hdrp->max_bucket )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->max_bucket )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->max_bucket )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->max_bucket )[3] = ((char *)&_tmp)[0]; }; | |||
1160 | M_32_SWAP(hdrp->high_mask){ uint32 _tmp = hdrp->high_mask; ((char *)&hdrp->high_mask )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->high_mask )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->high_mask )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->high_mask )[3] = ((char *)&_tmp)[0]; }; | |||
1161 | M_32_SWAP(hdrp->low_mask){ uint32 _tmp = hdrp->low_mask; ((char *)&hdrp->low_mask )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->low_mask )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->low_mask )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->low_mask )[3] = ((char *)&_tmp)[0]; }; | |||
1162 | M_32_SWAP(hdrp->ffactor){ uint32 _tmp = hdrp->ffactor; ((char *)&hdrp->ffactor )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->ffactor )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->ffactor )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->ffactor )[3] = ((char *)&_tmp)[0]; }; | |||
1163 | M_32_SWAP(hdrp->nkeys){ uint32 _tmp = hdrp->nkeys; ((char *)&hdrp->nkeys) [0] = ((char *)&_tmp)[3]; ((char *)&hdrp->nkeys)[1 ] = ((char *)&_tmp)[2]; ((char *)&hdrp->nkeys)[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->nkeys)[3] = ( (char *)&_tmp)[0]; }; | |||
1164 | M_32_SWAP(hdrp->hdrpages){ uint32 _tmp = hdrp->hdrpages; ((char *)&hdrp->hdrpages )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->hdrpages )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->hdrpages )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->hdrpages )[3] = ((char *)&_tmp)[0]; }; | |||
1165 | M_32_SWAP(hdrp->h_charkey){ uint32 _tmp = hdrp->h_charkey; ((char *)&hdrp->h_charkey )[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->h_charkey )[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->h_charkey )[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->h_charkey )[3] = ((char *)&_tmp)[0]; }; | |||
1166 | for (i = 0; i < NCACHED32; i++) { | |||
1167 | M_32_SWAP(hdrp->spares[i]){ uint32 _tmp = hdrp->spares[i]; ((char *)&hdrp->spares [i])[0] = ((char *)&_tmp)[3]; ((char *)&hdrp->spares [i])[1] = ((char *)&_tmp)[2]; ((char *)&hdrp->spares [i])[2] = ((char *)&_tmp)[1]; ((char *)&hdrp->spares [i])[3] = ((char *)&_tmp)[0]; }; | |||
1168 | M_16_SWAP(hdrp->bitmaps[i]){ uint16 _tmp = hdrp->bitmaps[i]; ((char *)&hdrp->bitmaps [i])[0] = ((char *)&_tmp)[1]; ((char *)&hdrp->bitmaps [i])[1] = ((char *)&_tmp)[0]; }; | |||
1169 | } | |||
1170 | } | |||
1171 | #endif |