00001
00002
00003 #include <sys/types.h>
00004 #include <sys/stat.h>
00005 #include <sys/mman.h>
00006 #include "readwrite.h"
00007 #include "error.h"
00008 #include "seek.h"
00009 #include "byte.h"
00010 #include "cdb.h"
00011
00012 void cdb_free(struct cdb *c)
00013 {
00014 if (c->map) {
00015 munmap(c->map,c->size);
00016 c->map = 0;
00017 }
00018 }
00019
00020 void cdb_findstart(struct cdb *c)
00021 {
00022 c->loop = 0;
00023 }
00024
00025 void cdb_init(struct cdb *c,int fd)
00026 {
00027 struct stat st;
00028 char *x;
00029
00030 cdb_free(c);
00031 cdb_findstart(c);
00032 c->fd = fd;
00033
00034 if (fstat(fd,&st) == 0)
00035 if (st.st_size <= 0xffffffff) {
00036 x = mmap(0,st.st_size,PROT_READ,MAP_SHARED,fd,0);
00037 if (x + 1) {
00038 c->size = st.st_size;
00039 c->map = x;
00040 }
00041 }
00042 }
00043
00044 int cdb_read(struct cdb *c,char *buf,unsigned int len,uint32 pos)
00045 {
00046 if (c->map) {
00047 if ((pos > c->size) || (c->size - pos < len)) goto FORMAT;
00048 byte_copy(buf,len,c->map + pos);
00049 }
00050 else {
00051 if (seek_set(c->fd,pos) == -1) return -1;
00052 while (len > 0) {
00053 int r;
00054 do
00055 r = read(c->fd,buf,len);
00056 while ((r == -1) && (errno == error_intr));
00057 if (r == -1) return -1;
00058 if (r == 0) goto FORMAT;
00059 buf += r;
00060 len -= r;
00061 }
00062 }
00063 return 0;
00064
00065 FORMAT:
00066 errno = error_proto;
00067 return -1;
00068 }
00069
00070 static int match(struct cdb *c,char *key,unsigned int len,uint32 pos)
00071 {
00072 char buf[32];
00073 int n;
00074
00075 while (len > 0) {
00076 n = sizeof buf;
00077 if (n > len) n = len;
00078 if (cdb_read(c,buf,n,pos) == -1) return -1;
00079 if (byte_diff(buf,n,key)) return 0;
00080 pos += n;
00081 key += n;
00082 len -= n;
00083 }
00084 return 1;
00085 }
00086
00087 int cdb_findnext(struct cdb *c,char *key,unsigned int len)
00088 {
00089 char buf[8];
00090 uint32 pos;
00091 uint32 u;
00092
00093 if (!c->loop) {
00094 u = cdb_hash(key,len);
00095 if (cdb_read(c,buf,8,(u << 3) & 2047) == -1) return -1;
00096 uint32_unpack(buf + 4,&c->hslots);
00097 if (!c->hslots) return 0;
00098 uint32_unpack(buf,&c->hpos);
00099 c->khash = u;
00100 u >>= 8;
00101 u %= c->hslots;
00102 u <<= 3;
00103 c->kpos = c->hpos + u;
00104 }
00105
00106 while (c->loop < c->hslots) {
00107 if (cdb_read(c,buf,8,c->kpos) == -1) return -1;
00108 uint32_unpack(buf + 4,&pos);
00109 if (!pos) return 0;
00110 c->loop += 1;
00111 c->kpos += 8;
00112 if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos;
00113 uint32_unpack(buf,&u);
00114 if (u == c->khash) {
00115 if (cdb_read(c,buf,8,pos) == -1) return -1;
00116 uint32_unpack(buf,&u);
00117 if (u == len)
00118 switch(match(c,key,len,pos + 8)) {
00119 case -1:
00120 return -1;
00121 case 1:
00122 uint32_unpack(buf + 4,&c->dlen);
00123 c->dpos = pos + 8 + len;
00124 return 1;
00125 }
00126 }
00127 }
00128
00129 return 0;
00130 }
00131
00132 int cdb_find(struct cdb *c,char *key,unsigned int len)
00133 {
00134 cdb_findstart(c);
00135 return cdb_findnext(c,key,len);
00136 }
00137