You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cdb_find.c 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /* $Id: cdb_init.c,v 1.12 2008-11-06 18:07:04 mjt Exp $
  2. * cdb_init, cdb_free and cdb_read routines
  3. *
  4. * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
  5. * Public domain.
  6. */
  7. #include "cdb.h"
  8. int
  9. cdb_find(struct cdb *cdbp, const void *key, unsigned klen)
  10. {
  11. const unsigned char *htp; /* hash table pointer */
  12. const unsigned char *htab; /* hash table */
  13. const unsigned char *htend; /* end of hash table */
  14. unsigned httodo; /* ht bytes left to look */
  15. unsigned pos, n;
  16. unsigned hval;
  17. if (klen >= cdbp->cdb_dend) /* if key size is too large */
  18. return 0;
  19. hval = cdb_hash (key, klen);
  20. /* find (pos,n) hash table to use */
  21. /* first 2048 bytes (toc) are always available */
  22. /* (hval % 256) * 8 */
  23. htp = cdbp->cdb_mem + ((hval << 3) & 2047); /* index in toc (256x8) */
  24. n = cdb_unpack (htp + 4); /* table size */
  25. if (!n) /* empty table */
  26. return 0; /* not found */
  27. httodo = n << 3; /* bytes of htab to lookup */
  28. pos = cdb_unpack (htp); /* htab position */
  29. if (n > (cdbp->cdb_fsize >> 3) /* overflow of httodo ? */
  30. || pos < cdbp->cdb_dend /* is htab inside data section ? */
  31. || pos > cdbp->cdb_fsize /* htab start within file ? */
  32. || httodo > cdbp->cdb_fsize - pos) /* entrie htab within file ? */
  33. return errno = EPROTO, -1;
  34. htab = cdbp->cdb_mem + pos; /* htab pointer */
  35. htend = htab + httodo; /* after end of htab */
  36. /* htab starting position: rest of hval modulo htsize, 8bytes per elt */
  37. htp = htab + (((hval >> 8) % n) << 3);
  38. for (;;) {
  39. pos = cdb_unpack (htp + 4); /* record position */
  40. if (!pos)
  41. return 0;
  42. if (cdb_unpack (htp) == hval) {
  43. if (pos > cdbp->cdb_dend - 8) /* key+val lengths */
  44. return errno = EPROTO, -1;
  45. if (cdb_unpack (cdbp->cdb_mem + pos) == klen) {
  46. if (cdbp->cdb_dend - klen < pos + 8)
  47. return errno = EPROTO, -1;
  48. if (memcmp (key, cdbp->cdb_mem + pos + 8, klen) == 0) {
  49. n = cdb_unpack (cdbp->cdb_mem + pos + 4);
  50. pos += 8;
  51. if (cdbp->cdb_dend < n || cdbp->cdb_dend - n < pos + klen)
  52. return errno = EPROTO, -1;
  53. cdbp->cdb_kpos = pos;
  54. cdbp->cdb_klen = klen;
  55. cdbp->cdb_vpos = pos + klen;
  56. cdbp->cdb_vlen = n;
  57. return 1;
  58. }
  59. }
  60. }
  61. httodo -= 8;
  62. if (!httodo)
  63. return 0;
  64. if ((htp += 8) >= htend)
  65. htp = htab;
  66. }
  67. }
  68. int
  69. cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp,
  70. const void *key, unsigned klen)
  71. {
  72. unsigned n, pos;
  73. cdbfp->cdb_cdbp = cdbp;
  74. cdbfp->cdb_key = key;
  75. cdbfp->cdb_klen = klen;
  76. cdbfp->cdb_hval = cdb_hash(key, klen);
  77. cdbfp->cdb_htp = cdbp->cdb_mem + ((cdbfp->cdb_hval << 3) & 2047);
  78. n = cdb_unpack(cdbfp->cdb_htp + 4);
  79. cdbfp->cdb_httodo = n << 3;
  80. if (!n)
  81. return 0;
  82. pos = cdb_unpack(cdbfp->cdb_htp);
  83. if (n > (cdbp->cdb_fsize >> 3)
  84. || pos < cdbp->cdb_dend
  85. || pos > cdbp->cdb_fsize
  86. || cdbfp->cdb_httodo > cdbp->cdb_fsize - pos)
  87. return errno = EPROTO, -1;
  88. cdbfp->cdb_htab = cdbp->cdb_mem + pos;
  89. cdbfp->cdb_htend = cdbfp->cdb_htab + cdbfp->cdb_httodo;
  90. cdbfp->cdb_htp = cdbfp->cdb_htab + (((cdbfp->cdb_hval >> 8) % n) << 3);
  91. return 1;
  92. }
  93. int
  94. cdb_findnext(struct cdb_find *cdbfp) {
  95. struct cdb *cdbp = cdbfp->cdb_cdbp;
  96. unsigned pos, n;
  97. unsigned klen = cdbfp->cdb_klen;
  98. while(cdbfp->cdb_httodo) {
  99. pos = cdb_unpack(cdbfp->cdb_htp + 4);
  100. if (!pos)
  101. return 0;
  102. n = cdb_unpack(cdbfp->cdb_htp) == cdbfp->cdb_hval;
  103. if ((cdbfp->cdb_htp += 8) >= cdbfp->cdb_htend)
  104. cdbfp->cdb_htp = cdbfp->cdb_htab;
  105. cdbfp->cdb_httodo -= 8;
  106. if (n) {
  107. if (pos > cdbp->cdb_fsize - 8)
  108. return errno = EPROTO, -1;
  109. if (cdb_unpack(cdbp->cdb_mem + pos) == klen) {
  110. if (cdbp->cdb_fsize - klen < pos + 8)
  111. return errno = EPROTO, -1;
  112. if (memcmp(cdbfp->cdb_key,
  113. cdbp->cdb_mem + pos + 8, klen) == 0) {
  114. n = cdb_unpack(cdbp->cdb_mem + pos + 4);
  115. pos += 8;
  116. if (cdbp->cdb_fsize < n ||
  117. cdbp->cdb_fsize - n < pos + klen)
  118. return errno = EPROTO, -1;
  119. cdbp->cdb_kpos = pos;
  120. cdbp->cdb_klen = klen;
  121. cdbp->cdb_vpos = pos + klen;
  122. cdbp->cdb_vlen = n;
  123. return 1;
  124. }
  125. }
  126. }
  127. }
  128. return 0;
  129. }