Ruby  2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
_sdbm.c
Go to the documentation of this file.
1 /*
2  * sdbm - ndbm work-alike hashed database library
3  * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
4  * author: oz@nexus.yorku.ca
5  * status: public domain.
6  *
7  * core routines
8  */
9 
10 #include "ruby/ruby.h"
11 
12 #ifdef HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15 
16 #include "sdbm.h"
17 
18 /*
19  * sdbm - ndbm work-alike hashed database library
20  * tuning and portability constructs [not nearly enough]
21  * author: oz@nexus.yorku.ca
22  */
23 
24 #define BYTESIZ 8
25 
26 #ifdef BSD42
27 #define SEEK_SET L_SET
28 #define memset(s,c,n) bzero((s), (n)) /* only when c is zero */
29 #define memcpy(s1,s2,n) bcopy((s2), (s1), (n))
30 #define memcmp(s1,s2,n) bcmp((s1),(s2),(n))
31 #endif
32 
33 /*
34  * important tuning parms (hah)
35  */
36 
37 #ifndef SEEDUPS
38 #define SEEDUPS 1 /* always detect duplicates */
39 #endif
40 #ifndef BADMESS
41 #define BADMESS 1 /* generate a message for worst case:
42  cannot make room after SPLTMAX splits */
43 #endif
44 
45 /*
46  * misc
47  */
48 #ifdef DEBUG
49 #define debug(x) printf x
50 #else
51 #define debug(x)
52 #endif
53 
54 #ifdef BIG_E
55 #define GET_SHORT(p, i) (((unsigned)((unsigned char *)(p))[(i)*2] << 8) + (((unsigned char *)(p))[(i)*2 + 1]))
56 #define PUT_SHORT(p, i, s) (((unsigned char *)(p))[(i)*2] = (unsigned char)((s) >> 8), ((unsigned char *)(p))[(i)*2 + 1] = (unsigned char)(s))
57 #else
58 #define GET_SHORT(p, i) ((p)[(i)])
59 #define PUT_SHORT(p, i, s) ((p)[(i)] = (s))
60 #endif
61 
62 /*#include "pair.h"*/
63 static int fitpair proto((char *, int));
64 static void putpair proto((char *, datum, datum));
65 static datum getpair proto((char *, datum));
66 static int delpair proto((char *, datum));
67 static int chkpage proto((char *));
68 static datum getnkey proto((char *, int));
69 static void splpage proto((char *, char *, long));
70 #if SEEDUPS
71 static int duppair proto((char *, datum));
72 #endif
73 
74 #include <stdio.h>
75 #include <stdlib.h>
76 #ifdef DOSISH
77 #include <io.h>
78 #endif
79 #include <sys/types.h>
80 #include <sys/stat.h>
81 #ifdef BSD42
82 #include <sys/file.h>
83 #else
84 #include <fcntl.h>
85 /*#include <memory.h>*/
86 #endif
87 #ifndef O_BINARY
88 #define O_BINARY 0
89 #endif
90 
91 #include <errno.h>
92 #ifndef EPERM
93 #define EPERM EACCES
94 #endif
95 #include <string.h>
96 
97 #ifdef __STDC__
98 #include <stddef.h>
99 #endif
100 
101 #ifndef NULL
102 #define NULL 0
103 #endif
104 
105 /*
106  * externals
107  */
108 #if !defined(__sun) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(errno)
109 extern int errno;
110 #endif
111 
112 /*
113  * forward
114  */
115 static int getdbit proto((DBM *, long));
116 static int setdbit proto((DBM *, long));
117 static int getpage proto((DBM *, long));
118 static datum getnext proto((DBM *));
119 static int makroom proto((DBM *, long, int));
120 
121 /*
122  * useful macros
123  */
124 #define bad(x) ((x).dptr == NULL || (x).dsize < 0)
125 #define exhash(item) sdbm_hash((item).dptr, (item).dsize)
126 #define ioerr(db) ((db)->flags |= DBM_IOERR)
127 
128 #define OFF_PAG(off) (long) (off) * PBLKSIZ
129 #define OFF_DIR(off) (long) (off) * DBLKSIZ
130 
131 static long masks[] = {
132  000000000000L, 000000000001L, 000000000003L,
133  000000000007L, 000000000017L, 000000000037L,
134  000000000077L, 000000000177L, 000000000377L,
135  000000000777L, 000000001777L, 000000003777L,
136  000000007777L, 000000017777L, 000000037777L,
137  000000077777L, 000000177777L, 000000377777L,
138  000000777777L, 000001777777L, 000003777777L,
139  000007777777L, 000017777777L, 000037777777L,
140  000077777777L, 000177777777L, 000377777777L,
141  000777777777L, 001777777777L, 003777777777L,
142  007777777777L, 017777777777L
143 };
144 
145 datum nullitem = {NULL, 0};
146 
148 sdbm_open(register char *file, register int flags, register int mode)
149 {
150  register DBM *db;
151  register char *dirname;
152  register char *pagname;
153  register size_t n;
154 
155  if (file == NULL || !*file)
156  return errno = EINVAL, (DBM *) NULL;
157 /*
158  * need space for two separate filenames
159  */
160  n = strlen(file) * 2 + strlen(DIRFEXT) + strlen(PAGFEXT) + 2;
161 
162  if ((dirname = malloc(n)) == NULL)
163  return errno = ENOMEM, (DBM *) NULL;
164 /*
165  * build the file names
166  */
167  dirname = strcat(strcpy(dirname, file), DIRFEXT);
168  pagname = strcpy(dirname + strlen(dirname) + 1, file);
169  pagname = strcat(pagname, PAGFEXT);
170 
171  db = sdbm_prep(dirname, pagname, flags, mode);
172  free((char *) dirname);
173  return db;
174 }
175 
176 static int
177 fd_set_cloexec(int fd)
178 {
179  /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
180 #ifdef F_GETFD
181  int flags, ret;
182  flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
183  if (flags == -1) {
184  return -1;
185  }
186  if (2 < fd) {
187  if (!(flags & FD_CLOEXEC)) {
188  flags |= FD_CLOEXEC;
189  ret = fcntl(fd, F_SETFD, flags);
190  if (ret == -1) {
191  return -1;
192  }
193  }
194  }
195 #endif
196  return 0;
197 }
198 
200 sdbm_prep(char *dirname, char *pagname, int flags, int mode)
201 {
202  register DBM *db;
203  struct stat dstat;
204 
205  if ((db = (DBM *) malloc(sizeof(DBM))) == NULL)
206  return errno = ENOMEM, (DBM *) NULL;
207 
208  db->pagf = -1;
209  db->dirf = -1;
210  db->flags = 0;
211  db->hmask = 0;
212  db->blkptr = 0;
213  db->keyptr = 0;
214 /*
215  * adjust user flags so that WRONLY becomes RDWR,
216  * as required by this package. Also set our internal
217  * flag for RDONLY.
218  */
219  if (flags & O_WRONLY)
220  flags = (flags & ~O_WRONLY) | O_RDWR;
221  if (flags & O_RDONLY)
222  db->flags = DBM_RDONLY;
223 /*
224  * open the files in sequence, and stat the dirfile.
225  * If we fail anywhere, undo everything, return NULL.
226  */
227  flags |= O_BINARY;
228 #ifdef O_CLOEXEC
229  flags |= O_CLOEXEC;
230 #endif
231 
232  if ((db->pagf = open(pagname, flags, mode)) == -1) goto err;
233  if (fd_set_cloexec(db->pagf) == -1) goto err;
234  if ((db->dirf = open(dirname, flags, mode)) == -1) goto err;
235  if (fd_set_cloexec(db->dirf) == -1) goto err;
236 /*
237  * need the dirfile size to establish max bit number.
238  */
239  if (fstat(db->dirf, &dstat) == -1) goto err;
240 /*
241  * zero size: either a fresh database, or one with a single,
242  * unsplit data page: dirpage is all zeros.
243  */
244  db->dirbno = (!dstat.st_size) ? 0 : -1;
245  db->pagbno = -1;
246  db->maxbno = dstat.st_size * (long) BYTESIZ;
247 
248  (void) memset(db->pagbuf, 0, PBLKSIZ);
249  (void) memset(db->dirbuf, 0, DBLKSIZ);
250 /*
251  * success
252  */
253  return db;
254 
255  err:
256  if (db->pagf != -1)
257  (void) close(db->pagf);
258  if (db->dirf != -1)
259  (void) close(db->dirf);
260  free((char *) db);
261  return (DBM *) NULL;
262 }
263 
264 void
265 sdbm_close(register DBM *db)
266 {
267  if (db == NULL)
268  errno = EINVAL;
269  else {
270  (void) close(db->dirf);
271  (void) close(db->pagf);
272  free((char *) db);
273  }
274 }
275 
277 sdbm_fetch(register DBM *db, datum key)
278 {
279  if (db == NULL || bad(key))
280  return errno = EINVAL, nullitem;
281 
282  if (getpage(db, exhash(key)))
283  return getpair(db->pagbuf, key);
284 
285  return ioerr(db), nullitem;
286 }
287 
288 int
289 sdbm_delete(register DBM *db, datum key)
290 {
291  if (db == NULL || bad(key))
292  return errno = EINVAL, -1;
293  if (sdbm_rdonly(db))
294  return errno = EPERM, -1;
295 
296  if (getpage(db, exhash(key))) {
297  if (!delpair(db->pagbuf, key))
298  return -1;
299 /*
300  * update the page file
301  */
302  if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
303  || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
304  return ioerr(db), -1;
305 
306  return 0;
307  }
308 
309  return ioerr(db), -1;
310 }
311 
312 int
313 sdbm_store(register DBM *db, datum key, datum val, int flags)
314 {
315  int need;
316  register long hash;
317 
318  if (db == NULL || bad(key))
319  return errno = EINVAL, -1;
320  if (sdbm_rdonly(db))
321  return errno = EPERM, -1;
322 
323  need = key.dsize + val.dsize;
324 /*
325  * is the pair too big (or too small) for this database ??
326  */
327  if (need < 0 || need > PAIRMAX)
328  return errno = EINVAL, -1;
329 
330  if (getpage(db, (hash = exhash(key)))) {
331 /*
332  * if we need to replace, delete the key/data pair
333  * first. If it is not there, ignore.
334  */
335  if (flags == DBM_REPLACE)
336  (void) delpair(db->pagbuf, key);
337 #if SEEDUPS
338  else if (duppair(db->pagbuf, key))
339  return 1;
340 #endif
341 /*
342  * if we do not have enough room, we have to split.
343  */
344  if (!fitpair(db->pagbuf, need))
345  if (!makroom(db, hash, need))
346  return ioerr(db), -1;
347 /*
348  * we have enough room or split is successful. insert the key,
349  * and update the page file.
350  */
351  (void) putpair(db->pagbuf, key, val);
352 
353  if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
354  || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
355  return ioerr(db), -1;
356  /*
357  * success
358  */
359  return 0;
360  }
361 
362  return ioerr(db), -1;
363 }
364 
365 /*
366  * makroom - make room by splitting the overfull page
367  * this routine will attempt to make room for SPLTMAX times before
368  * giving up.
369  */
370 static int
371 makroom(register DBM *db, long int hash, int need)
372 {
373  long newp;
374  char twin[PBLKSIZ];
375 #if defined _WIN32
376  char zer[PBLKSIZ];
377  long oldtail;
378 #endif
379  char *pag = db->pagbuf;
380  char *new = twin;
381  register int smax = SPLTMAX;
382 
383  do {
384 /*
385  * split the current page
386  */
387  (void) splpage(pag, new, db->hmask + 1);
388 /*
389  * address of the new page
390  */
391  newp = (hash & db->hmask) | (db->hmask + 1);
392  debug(("newp: %ld\n", newp));
393 /*
394  * write delay, read avoidance/cache shuffle:
395  * select the page for incoming pair: if key is to go to the new page,
396  * write out the previous one, and copy the new one over, thus making
397  * it the current page. If not, simply write the new page, and we are
398  * still looking at the page of interest. current page is not updated
399  * here, as sdbm_store will do so, after it inserts the incoming pair.
400  */
401 
402 #if defined _WIN32
403  /*
404  * Fill hole with 0 if made it.
405  * (hole is NOT read as 0)
406  */
407  oldtail = lseek(db->pagf, 0L, SEEK_END);
408  memset(zer, 0, PBLKSIZ);
409  while (OFF_PAG(newp) > oldtail) {
410  if (lseek(db->pagf, 0L, SEEK_END) < 0 ||
411  write(db->pagf, zer, PBLKSIZ) < 0) {
412 
413  return 0;
414  }
415  oldtail += PBLKSIZ;
416  }
417 #endif
418 
419  if (hash & (db->hmask + 1)) {
420  if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
421  || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
422  return 0;
423  db->pagbno = newp;
424  (void) memcpy(pag, new, PBLKSIZ);
425  }
426  else if (lseek(db->pagf, OFF_PAG(newp), SEEK_SET) < 0
427  || write(db->pagf, new, PBLKSIZ) < 0)
428  return 0;
429 
430  if (!setdbit(db, db->curbit))
431  return 0;
432 /*
433  * see if we have enough room now
434  */
435  if (fitpair(pag, need))
436  return 1;
437 /*
438  * try again... update curbit and hmask as getpage would have
439  * done. because of our update of the current page, we do not
440  * need to read in anything. BUT we have to write the current
441  * [deferred] page out, as the window of failure is too great.
442  */
443  db->curbit = 2 * db->curbit +
444  ((hash & (db->hmask + 1)) ? 2 : 1);
445  db->hmask |= (db->hmask + 1);
446 
447  if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
448  || write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
449  return 0;
450 
451  } while (--smax);
452 /*
453  * if we are here, this is real bad news. After SPLTMAX splits,
454  * we still cannot fit the key. say goodnight.
455  */
456 #if BADMESS
457  (void) (write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44) < 0);
458 #endif
459  return 0;
460 
461 }
462 
463 /*
464  * the following two routines will break if
465  * deletions aren't taken into account. (ndbm bug)
466  */
468 sdbm_firstkey(register DBM *db)
469 {
470  if (db == NULL)
471  return errno = EINVAL, nullitem;
472 /*
473  * start at page 0
474  */
475  (void) memset(db->pagbuf, 0, PBLKSIZ);
476  if (lseek(db->pagf, OFF_PAG(0), SEEK_SET) < 0
477  || read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
478  return ioerr(db), nullitem;
479  db->pagbno = 0;
480  db->blkptr = 0;
481  db->keyptr = 0;
482 
483  return getnext(db);
484 }
485 
487 sdbm_nextkey(register DBM *db)
488 {
489  if (db == NULL)
490  return errno = EINVAL, nullitem;
491  return getnext(db);
492 }
493 
494 /*
495  * all important binary trie traversal
496  */
497 static int
498 getpage(register DBM *db, register long int hash)
499 {
500  register int hbit;
501  register long dbit;
502  register long pagb;
503 
504  dbit = 0;
505  hbit = 0;
506  while (dbit < db->maxbno && getdbit(db, dbit))
507  dbit = 2 * dbit + ((hash & ((long) 1 << hbit++)) ? 2 : 1);
508 
509  debug(("dbit: %ld...", dbit));
510 
511  db->curbit = dbit;
512  db->hmask = masks[hbit];
513 
514  pagb = hash & db->hmask;
515 /*
516  * see if the block we need is already in memory.
517  * note: this lookaside cache has about 10% hit rate.
518  */
519  if (pagb != db->pagbno) {
520 /*
521  * note: here, we assume a "hole" is read as 0s.
522  * if not, must zero pagbuf first.
523  */
524  (void) memset(db->pagbuf, 0, PBLKSIZ);
525 
526  if (lseek(db->pagf, OFF_PAG(pagb), SEEK_SET) < 0
527  || read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
528  return 0;
529  if (!chkpage(db->pagbuf)) {
530  return 0;
531  }
532  db->pagbno = pagb;
533 
534  debug(("pag read: %ld\n", pagb));
535  }
536  return 1;
537 }
538 
539 static int
540 getdbit(register DBM *db, register long int dbit)
541 {
542  register long c;
543  register long dirb;
544 
545  c = dbit / BYTESIZ;
546  dirb = c / DBLKSIZ;
547 
548  if (dirb != db->dirbno) {
549  if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
550  || read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
551  return 0;
552  db->dirbno = dirb;
553 
554  debug(("dir read: %ld\n", dirb));
555  }
556 
557  return db->dirbuf[c % DBLKSIZ] & (1 << (dbit % BYTESIZ));
558 }
559 
560 static int
561 setdbit(register DBM *db, register long int dbit)
562 {
563  register long c;
564  register long dirb;
565 
566  c = dbit / BYTESIZ;
567  dirb = c / DBLKSIZ;
568 
569  if (dirb != db->dirbno) {
570  if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
571  || read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
572  return 0;
573  db->dirbno = dirb;
574 
575  debug(("dir read: %ld\n", dirb));
576  }
577 
578  db->dirbuf[c % DBLKSIZ] |= (1 << (dbit % BYTESIZ));
579 
580  if (dbit >= db->maxbno)
581  db->maxbno += (long) DBLKSIZ * BYTESIZ;
582 
583  if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
584  || write(db->dirf, db->dirbuf, DBLKSIZ) < 0)
585  return 0;
586 
587  return 1;
588 }
589 
590 /*
591  * getnext - get the next key in the page, and if done with
592  * the page, try the next page in sequence
593  */
594 static datum
595 getnext(register DBM *db)
596 {
597  datum key;
598 
599  for (;;) {
600  db->keyptr++;
601  key = getnkey(db->pagbuf, db->keyptr);
602  if (key.dptr != NULL)
603  return key;
604 /*
605  * we either run out, or there is nothing on this page..
606  * try the next one... If we lost our position on the
607  * file, we will have to seek.
608  */
609  db->keyptr = 0;
610  if (db->pagbno != db->blkptr++)
611  if (lseek(db->pagf, OFF_PAG(db->blkptr), SEEK_SET) < 0)
612  break;
613  db->pagbno = db->blkptr;
614  if (read(db->pagf, db->pagbuf, PBLKSIZ) <= 0)
615  break;
616  if (!chkpage(db->pagbuf)) {
617  break;
618  }
619  }
620 
621  return ioerr(db), nullitem;
622 }
623 
624 /* pair.c */
625 /*
626  * sdbm - ndbm work-alike hashed database library
627  * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
628  * author: oz@nexus.yorku.ca
629  * status: public domain.
630  *
631  * page-level routines
632  */
633 
634 #ifndef BSD42
635 /*#include <memory.h>*/
636 #endif
637 
638 #define exhash(item) sdbm_hash((item).dptr, (item).dsize)
639 
640 /*
641  * forward
642  */
643 static int seepair proto((char *, int, char *, int));
644 
645 /*
646  * page format:
647  * +------------------------------+
648  * ino | n | keyoff | datoff | keyoff |
649  * +------------+--------+--------+
650  * | datoff | - - - ----> |
651  * +--------+---------------------+
652  * | F R E E A R E A |
653  * +--------------+---------------+
654  * | <---- - - - | data |
655  * +--------+-----+----+----------+
656  * | key | data | key |
657  * +--------+----------+----------+
658  *
659  * calculating the offsets for free area: if the number
660  * of entries (ino[0]) is zero, the offset to the END of
661  * the free area is the block size. Otherwise, it is the
662  * nth (ino[ino[0]]) entry's offset.
663  */
664 
665 static int
666 fitpair(char *pag, int need)
667 {
668  register int n;
669  register int off;
670  register int free;
671  register short *ino = (short *) pag;
672 
673  off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ;
674  free = off - (n + 1) * (int)sizeof(short);
675  need += 2 * (int)sizeof(short);
676 
677  debug(("free %d need %d\n", free, need));
678 
679  return need <= free;
680 }
681 
682 static void
683 putpair(char *pag, datum key, datum val)
684 {
685  register int n;
686  register int off;
687  register short *ino = (short *) pag;
688 
689  off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ;
690 /*
691  * enter the key first
692  */
693  off -= key.dsize;
694  if (key.dsize)
695  (void) memcpy(pag + off, key.dptr, key.dsize);
696  PUT_SHORT(ino,n + 1,off);
697 /*
698  * now the data
699  */
700  off -= val.dsize;
701  if (val.dsize)
702  (void) memcpy(pag + off, val.dptr, val.dsize);
703  PUT_SHORT(ino,n + 2,off);
704 /*
705  * adjust item count
706  */
707  PUT_SHORT(ino,0,GET_SHORT(ino,0) + 2);
708 }
709 
710 static datum
711 getpair(char *pag, datum key)
712 {
713  register int i;
714  register int n;
715  datum val;
716  register short *ino = (short *) pag;
717 
718  if ((n = GET_SHORT(ino,0)) == 0)
719  return nullitem;
720 
721  if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
722  return nullitem;
723 
724  val.dptr = pag + GET_SHORT(ino,i + 1);
725  val.dsize = GET_SHORT(ino,i) - GET_SHORT(ino,i + 1);
726  return val;
727 }
728 
729 #if SEEDUPS
730 static int
731 duppair(char *pag, datum key)
732 {
733  register short *ino = (short *) pag;
734  return GET_SHORT(ino,0) > 0 &&
735  seepair(pag, GET_SHORT(ino,0), key.dptr, key.dsize) > 0;
736 }
737 #endif
738 
739 static datum
740 getnkey(char *pag, int num)
741 {
742  datum key;
743  register int off;
744  register short *ino = (short *) pag;
745 
746  num = num * 2 - 1;
747  if (GET_SHORT(ino,0) == 0 || num > GET_SHORT(ino,0))
748  return nullitem;
749 
750  off = (num > 1) ? GET_SHORT(ino,num - 1) : PBLKSIZ;
751 
752  key.dptr = pag + GET_SHORT(ino,num);
753  key.dsize = off - GET_SHORT(ino,num);
754 
755  return key;
756 }
757 
758 static int
759 delpair(char *pag, datum key)
760 {
761  register int n;
762  register int i;
763  register short *ino = (short *) pag;
764 
765  if ((n = GET_SHORT(ino,0)) == 0)
766  return 0;
767 
768  if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
769  return 0;
770 /*
771  * found the key. if it is the last entry
772  * [i.e. i == n - 1] we just adjust the entry count.
773  * hard case: move all data down onto the deleted pair,
774  * shift offsets onto deleted offsets, and adjust them.
775  * [note: 0 < i < n]
776  */
777  if (i < n - 1) {
778  register int m;
779  register char *dst = pag + (i == 1 ? PBLKSIZ : GET_SHORT(ino,i - 1));
780  register char *src = pag + GET_SHORT(ino,i + 1);
781  register ptrdiff_t zoo = dst - src;
782 
783  debug(("free-up %"PRIdPTRDIFF" ", zoo));
784 /*
785  * shift data/keys down
786  */
787  m = GET_SHORT(ino,i + 1) - GET_SHORT(ino,n);
788 #ifdef DUFF
789 #define MOVB *--dst = *--src
790 
791  if (m > 0) {
792  register int loop = (m + 8 - 1) >> 3;
793 
794  switch (m & (8 - 1)) {
795  case 0: do {
796  MOVB; case 7: MOVB;
797  case 6: MOVB; case 5: MOVB;
798  case 4: MOVB; case 3: MOVB;
799  case 2: MOVB; case 1: MOVB;
800  } while (--loop);
801  }
802  }
803 #else
804 #ifdef MEMMOVE
805  memmove(dst-m, src-m, m);
806 #else
807  while (m--)
808  *--dst = *--src;
809 #endif
810 #endif
811 /*
812  * adjust offset index up
813  */
814  while (i < n - 1) {
815  PUT_SHORT(ino,i, GET_SHORT(ino,i + 2) + zoo);
816  i++;
817  }
818  }
819  PUT_SHORT(ino, 0, GET_SHORT(ino, 0) - 2);
820  return 1;
821 }
822 
823 /*
824  * search for the key in the page.
825  * return offset index in the range 0 < i < n.
826  * return 0 if not found.
827  */
828 static int
829 seepair(char *pag, register int n, register char *key, register int siz)
830 {
831  register int i;
832  register int off = PBLKSIZ;
833  register short *ino = (short *) pag;
834 
835  for (i = 1; i < n; i += 2) {
836  if (siz == off - GET_SHORT(ino,i) &&
837  memcmp(key, pag + GET_SHORT(ino,i), siz) == 0)
838  return i;
839  off = GET_SHORT(ino,i + 1);
840  }
841  return 0;
842 }
843 
844 static void
845 splpage(char *pag, char *new, long int sbit)
846 {
847  datum key;
848  datum val;
849 
850  register int n;
851  register int off = PBLKSIZ;
852  char cur[PBLKSIZ];
853  register short *ino = (short *) cur;
854 
855  (void) memcpy(cur, pag, PBLKSIZ);
856  (void) memset(pag, 0, PBLKSIZ);
857  (void) memset(new, 0, PBLKSIZ);
858 
859  n = GET_SHORT(ino,0);
860  for (ino++; n > 0; ino += 2) {
861  key.dptr = cur + GET_SHORT(ino,0);
862  key.dsize = off - GET_SHORT(ino,0);
863  val.dptr = cur + GET_SHORT(ino,1);
864  val.dsize = GET_SHORT(ino,0) - GET_SHORT(ino,1);
865 /*
866  * select the page pointer (by looking at sbit) and insert
867  */
868  (void) putpair((exhash(key) & sbit) ? new : pag, key, val);
869 
870  off = GET_SHORT(ino,1);
871  n -= 2;
872  }
873 
874  debug(("%d split %d/%d\n", ((short *) cur)[0] / 2,
875  ((short *) new)[0] / 2,
876  ((short *) pag)[0] / 2));
877 }
878 
879 /*
880  * check page sanity:
881  * number of entries should be something
882  * reasonable, and all offsets in the index should be in order.
883  * this could be made more rigorous.
884  */
885 static int
886 chkpage(char *pag)
887 {
888  register int n;
889  register int off;
890  register short *ino = (short *) pag;
891 
892  if ((n = GET_SHORT(ino,0)) < 0 || n > PBLKSIZ / (int)sizeof(short))
893  return 0;
894 
895  if (n > 0) {
896  off = PBLKSIZ;
897  for (ino++; n > 0; ino += 2) {
898  if (GET_SHORT(ino,0) > off || GET_SHORT(ino,1) > off ||
899  GET_SHORT(ino,1) > GET_SHORT(ino,0))
900  return 0;
901  off = GET_SHORT(ino,1);
902  n -= 2;
903  }
904  }
905  return 1;
906 }
907 
908 /* hash.c */
909 /*
910  * sdbm - ndbm work-alike hashed database library
911  * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
912  * author: oz@nexus.yorku.ca
913  * status: public domain. keep it that way.
914  *
915  * hashing routine
916  */
917 
918 /*
919  * polynomial conversion ignoring overflows
920  * [this seems to work remarkably well, in fact better
921  * then the ndbm hash function. Replace at your own risk]
922  * use: 65599 nice.
923  * 65587 even better.
924  */
925 long
926 sdbm_hash(register char *str, register int len)
927 {
928  register unsigned long n = 0;
929 
930 #ifdef DUFF
931 
932 #define HASHC n = *str++ + 65599 * n
933 
934  if (len > 0) {
935  register int loop = (len + 8 - 1) >> 3;
936 
937  switch(len & (8 - 1)) {
938  case 0: do {
939  HASHC; case 7: HASHC;
940  case 6: HASHC; case 5: HASHC;
941  case 4: HASHC; case 3: HASHC;
942  case 2: HASHC; case 1: HASHC;
943  } while (--loop);
944  }
945 
946  }
947 #else
948  while (len--)
949  n = ((*str++) & 255) + 65587L * n;
950 #endif
951  return n;
952 }
memset
void * memset(void *, int, size_t)
DBM::dirf
int dirf
Definition: sdbm.h:21
strcpy
char * strcpy(char *__restrict, const char *__restrict)
DBLKSIZ
#define DBLKSIZ
Definition: sdbm.h:12
GET_SHORT
#define GET_SHORT(p, i)
Definition: _sdbm.c:57
stat::st_size
off_t st_size
Definition: rb_mjit_min_header-2.7.2.h:2431
DBM::maxbno
off_t maxbno
Definition: sdbm.h:25
OFF_PAG
#define OFF_PAG(off)
Definition: _sdbm.c:127
stat
Definition: rb_mjit_min_header-2.7.2.h:2423
DBM::keyptr
int keyptr
Definition: sdbm.h:24
proto
#define proto(p)
Definition: sdbm.h:60
int
__inline__ int
Definition: rb_mjit_min_header-2.7.2.h:2877
DBM::pagbno
long pagbno
Definition: sdbm.h:30
O_CLOEXEC
#define O_CLOEXEC
Definition: dir.c:28
i
uint32_t i
Definition: rb_mjit_min_header-2.7.2.h:5499
exhash
#define exhash(item)
Definition: _sdbm.c:637
sdbm_delete
int sdbm_delete(register DBM *db, datum key)
Definition: _sdbm.c:288
long
#define long
Definition: rb_mjit_min_header-2.7.2.h:2921
sdbm.h
datum::dptr
char * dptr
Definition: sdbm.h:51
short
#define short
Definition: rb_mjit_min_header-2.7.2.h:2917
sdbm_open
DBM * sdbm_open(register char *file, register int flags, register int mode)
Definition: _sdbm.c:147
OFF_DIR
#define OFF_DIR(off)
Definition: _sdbm.c:128
sdbm_hash
long sdbm_hash(register char *str, register int len)
Definition: _sdbm.c:925
DBM::flags
int flags
Definition: sdbm.h:23
NULL
#define NULL
Definition: _sdbm.c:101
fcntl
int fcntl(int, int,...)
Definition: win32.c:4282
ruby.h
strlen
size_t strlen(const char *)
L
#define L(x)
Definition: asm.h:125
void
void
Definition: rb_mjit_min_header-2.7.2.h:13321
DBM::curbit
long curbit
Definition: sdbm.h:26
DBM::hmask
long hmask
Definition: sdbm.h:27
F_GETFD
#define F_GETFD
Definition: win32.h:603
sdbm_close
void sdbm_close(register DBM *db)
Definition: _sdbm.c:264
lseek
off_t lseek(int __fildes, off_t __offset, int __whence)
sdbm_rdonly
#define sdbm_rdonly(db)
Definition: sdbm.h:42
bad
#define bad(x)
Definition: _sdbm.c:123
DBM_RDONLY
#define DBM_RDONLY
Definition: sdbm.h:36
datum
Definition: sdbm.h:50
DBM_REPLACE
#define DBM_REPLACE
Definition: sdbm.h:67
PUT_SHORT
#define PUT_SHORT(p, i, s)
Definition: _sdbm.c:58
sdbm_nextkey
datum sdbm_nextkey(register DBM *db)
Definition: _sdbm.c:486
SEEK_END
#define SEEK_END
Definition: io.c:867
PBLKSIZ
#define PBLKSIZ
Definition: sdbm.h:13
debug
#define debug(x)
Definition: _sdbm.c:50
memcmp
int memcmp(const void *s1, const void *s2, size_t len)
Definition: memcmp.c:7
FD_CLOEXEC
#define FD_CLOEXEC
Definition: win32.h:610
sdbm_prep
DBM * sdbm_prep(char *dirname, char *pagname, int flags, int mode)
Definition: _sdbm.c:199
DBM::pagf
int pagf
Definition: sdbm.h:22
O_BINARY
#define O_BINARY
Definition: _sdbm.c:87
key
key
Definition: openssl_missing.h:181
EPERM
#define EPERM
Definition: _sdbm.c:92
PAGFEXT
#define PAGFEXT
Definition: sdbm.h:18
F_SETFD
#define F_SETFD
Definition: win32.h:604
ioerr
#define ioerr(db)
Definition: _sdbm.c:125
PRIdPTRDIFF
#define PRIdPTRDIFF
Definition: ruby.h:190
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
sdbm_firstkey
datum sdbm_firstkey(register DBM *db)
Definition: _sdbm.c:467
PAIRMAX
#define PAIRMAX
Definition: sdbm.h:14
datum::dsize
int dsize
Definition: sdbm.h:52
src
__inline__ const void *__restrict src
Definition: rb_mjit_min_header-2.7.2.h:2874
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
fstat
int fstat(int __fd, struct stat *__sbuf)
close
int close(int __fildes)
DBM::pagbuf
char pagbuf[PBLKSIZ]
Definition: sdbm.h:31
strcat
char * strcat(char *__restrict, const char *__restrict)
io.h
memmove
#define memmove(dst, src, len)
Definition: rb_mjit_min_header-2.7.2.h:2886
BYTESIZ
#define BYTESIZ
Definition: _sdbm.c:24
ENOMEM
#define ENOMEM
Definition: rb_mjit_min_header-2.7.2.h:10997
sdbm_fetch
datum sdbm_fetch(register DBM *db, datum key)
Definition: _sdbm.c:276
free
#define free(x)
Definition: dln.c:52
err
int err
Definition: win32.c:135
DBM::dirbuf
char dirbuf[DBLKSIZ]
Definition: sdbm.h:33
SEEK_SET
#define SEEK_SET
Definition: io.c:865
errno
int errno
sdbm_store
int sdbm_store(register DBM *db, datum key, datum val, int flags)
Definition: _sdbm.c:312
len
uint8_t len
Definition: escape.c:17
write
_ssize_t write(int __fd, const void *__buf, size_t __nbyte)
ptrdiff_t
long int ptrdiff_t
Definition: rb_mjit_min_header-2.7.2.h:805
SPLTMAX
#define SPLTMAX
Definition: sdbm.h:15
read
_ssize_t read(int __fd, void *__buf, size_t __nbyte)
DBM
Definition: sdbm.h:20
malloc
void * malloc(size_t) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__alloc_size__(1)))
DBM::dirbno
long dirbno
Definition: sdbm.h:32
EINVAL
#define EINVAL
Definition: rb_mjit_min_header-2.7.2.h:11007
DBM::blkptr
long blkptr
Definition: sdbm.h:28
nullitem
datum nullitem
Definition: _sdbm.c:144
DIRFEXT
#define DIRFEXT
Definition: sdbm.h:17
n
const char size_t n
Definition: rb_mjit_min_header-2.7.2.h:5491