cdb.c
changeset 0 eeadadee24f6
equal deleted inserted replaced
-1:000000000000 0:eeadadee24f6
       
     1 /* Public domain. */
       
     2 
       
     3 #include <sys/types.h>
       
     4 #include <sys/stat.h>
       
     5 #include <sys/mman.h>
       
     6 #include "readwrite.h"
       
     7 #include "error.h"
       
     8 #include "seek.h"
       
     9 #include "byte.h"
       
    10 #include "cdb.h"
       
    11 
       
    12 void cdb_free(struct cdb *c)
       
    13 {
       
    14   if (c->map) {
       
    15     munmap(c->map,c->size);
       
    16     c->map = 0;
       
    17   }
       
    18 }
       
    19 
       
    20 void cdb_findstart(struct cdb *c)
       
    21 {
       
    22   c->loop = 0;
       
    23 }
       
    24 
       
    25 void cdb_init(struct cdb *c,int fd)
       
    26 {
       
    27   struct stat st;
       
    28   char *x;
       
    29 
       
    30   cdb_free(c);
       
    31   cdb_findstart(c);
       
    32   c->fd = fd;
       
    33 
       
    34   if (fstat(fd,&st) == 0)
       
    35     if (st.st_size <= 0xffffffff) {
       
    36       x = mmap(0,st.st_size,PROT_READ,MAP_SHARED,fd,0);
       
    37       if (x + 1) {
       
    38 	c->size = st.st_size;
       
    39 	c->map = x;
       
    40       }
       
    41     }
       
    42 }
       
    43 
       
    44 int cdb_read(struct cdb *c,char *buf,unsigned int len,uint32 pos)
       
    45 {
       
    46   if (c->map) {
       
    47     if ((pos > c->size) || (c->size - pos < len)) goto FORMAT;
       
    48     byte_copy(buf,len,c->map + pos);
       
    49   }
       
    50   else {
       
    51     if (seek_set(c->fd,pos) == -1) return -1;
       
    52     while (len > 0) {
       
    53       int r;
       
    54       do
       
    55         r = read(c->fd,buf,len);
       
    56       while ((r == -1) && (errno == error_intr));
       
    57       if (r == -1) return -1;
       
    58       if (r == 0) goto FORMAT;
       
    59       buf += r;
       
    60       len -= r;
       
    61     }
       
    62   }
       
    63   return 0;
       
    64 
       
    65   FORMAT:
       
    66   errno = error_proto;
       
    67   return -1;
       
    68 }
       
    69 
       
    70 static int match(struct cdb *c,char *key,unsigned int len,uint32 pos)
       
    71 {
       
    72   char buf[32];
       
    73   int n;
       
    74 
       
    75   while (len > 0) {
       
    76     n = sizeof buf;
       
    77     if (n > len) n = len;
       
    78     if (cdb_read(c,buf,n,pos) == -1) return -1;
       
    79     if (byte_diff(buf,n,key)) return 0;
       
    80     pos += n;
       
    81     key += n;
       
    82     len -= n;
       
    83   }
       
    84   return 1;
       
    85 }
       
    86 
       
    87 int cdb_findnext(struct cdb *c,char *key,unsigned int len)
       
    88 {
       
    89   char buf[8];
       
    90   uint32 pos;
       
    91   uint32 u;
       
    92 
       
    93   if (!c->loop) {
       
    94     u = cdb_hash(key,len);
       
    95     if (cdb_read(c,buf,8,(u << 3) & 2047) == -1) return -1;
       
    96     uint32_unpack(buf + 4,&c->hslots);
       
    97     if (!c->hslots) return 0;
       
    98     uint32_unpack(buf,&c->hpos);
       
    99     c->khash = u;
       
   100     u >>= 8;
       
   101     u %= c->hslots;
       
   102     u <<= 3;
       
   103     c->kpos = c->hpos + u;
       
   104   }
       
   105 
       
   106   while (c->loop < c->hslots) {
       
   107     if (cdb_read(c,buf,8,c->kpos) == -1) return -1;
       
   108     uint32_unpack(buf + 4,&pos);
       
   109     if (!pos) return 0;
       
   110     c->loop += 1;
       
   111     c->kpos += 8;
       
   112     if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos;
       
   113     uint32_unpack(buf,&u);
       
   114     if (u == c->khash) {
       
   115       if (cdb_read(c,buf,8,pos) == -1) return -1;
       
   116       uint32_unpack(buf,&u);
       
   117       if (u == len)
       
   118 	switch(match(c,key,len,pos + 8)) {
       
   119 	  case -1:
       
   120 	    return -1;
       
   121 	  case 1:
       
   122 	    uint32_unpack(buf + 4,&c->dlen);
       
   123 	    c->dpos = pos + 8 + len;
       
   124 	    return 1;
       
   125 	}
       
   126     }
       
   127   }
       
   128 
       
   129   return 0;
       
   130 }
       
   131 
       
   132 int cdb_find(struct cdb *c,char *key,unsigned int len)
       
   133 {
       
   134   cdb_findstart(c);
       
   135   return cdb_findnext(c,key,len);
       
   136 }