| 1 | #include <stdlib.h> |
| 2 | #include <string.h> |
| 3 | #include <stdio.h> |
| 4 | #include <errno.h> |
| 5 | |
| 6 | #include "store.h" |
| 7 | |
| 8 | struct store *newstore(struct storeops *ops) |
| 9 | { |
| 10 | struct store *new; |
| 11 | |
| 12 | new = malloc(sizeof(*new)); |
| 13 | new->ops = ops; |
| 14 | new->pdata = NULL; |
| 15 | new->cache = calloc(4096 * 4, sizeof(struct storecache)); |
| 16 | return(new); |
| 17 | } |
| 18 | |
| 19 | #define min(a, b) (((b) < (a))?(b):(a)) |
| 20 | |
| 21 | static ssize_t cacheget(struct store *st, struct addr *a, void *buf, size_t len) |
| 22 | { |
| 23 | int he, i; |
| 24 | |
| 25 | he = a->hash[0] | ((a->hash[1] & 0x0f) << 8); |
| 26 | for(i = 0; i < 4; i++) { |
| 27 | if(!addrcmp(&st->cache[he * 4 + i].a, a)) |
| 28 | break; |
| 29 | } |
| 30 | if(i == 4) |
| 31 | return(-2); |
| 32 | if(st->cache[he * 4 + i].data != NULL) |
| 33 | memcpy(buf, st->cache[he * 4 + i].data, min(len, st->cache[he * 4 + i].dlen)); |
| 34 | return(st->cache[he * 4 + i].dlen); |
| 35 | } |
| 36 | |
| 37 | static void cacheput(struct store *st, struct addr *a, const void *data, ssize_t len) |
| 38 | { |
| 39 | int he, i; |
| 40 | struct storecache tmp; |
| 41 | |
| 42 | he = a->hash[0] | ((a->hash[1] & 0x0f) << 8); |
| 43 | for(i = 0; i < 4; i++) { |
| 44 | if(!addrcmp(&st->cache[he * 4 + i].a, a)) |
| 45 | break; |
| 46 | } |
| 47 | if(i == 0) |
| 48 | return; |
| 49 | if(i < 4) { |
| 50 | tmp = st->cache[he * 4 + i]; |
| 51 | memmove(&st->cache[he * 4 + 1], &st->cache[he * 4], i); |
| 52 | st->cache[he * 4] = tmp; |
| 53 | return; |
| 54 | } |
| 55 | if(st->cache[he * 4 + 3].data != NULL) |
| 56 | free(st->cache[he * 4 + 3].data); |
| 57 | memmove(&st->cache[he * 4 + 1], &st->cache[he * 4], 3); |
| 58 | st->cache[he * 4].a = *a; |
| 59 | if(len > 0) |
| 60 | st->cache[he * 4].data = memcpy(malloc(len), data, len); |
| 61 | else |
| 62 | st->cache[he * 4].data = NULL; |
| 63 | st->cache[he * 4].dlen = len; |
| 64 | } |
| 65 | |
| 66 | int storeput(struct store *st, const void *buf, size_t len, struct addr *at) |
| 67 | { |
| 68 | int ret; |
| 69 | struct addr na; |
| 70 | |
| 71 | ret = st->ops->put(st, buf, len, &na); |
| 72 | if(!ret) |
| 73 | cacheput(st, &na, buf, len); |
| 74 | if(at != NULL) |
| 75 | *at = na; |
| 76 | return(ret); |
| 77 | } |
| 78 | |
| 79 | ssize_t storeget(struct store *st, void *buf, size_t len, struct addr *at) |
| 80 | { |
| 81 | ssize_t sz; |
| 82 | |
| 83 | sz = cacheget(st, at, buf, len); |
| 84 | if(sz != -2) { |
| 85 | if(sz == -1) |
| 86 | errno = ENOENT; |
| 87 | return(sz); |
| 88 | } |
| 89 | sz = st->ops->get(st, buf, len, at); |
| 90 | if((sz < 0) && (errno == ENOENT)) |
| 91 | cacheput(st, at, NULL, -1); |
| 92 | else if(sz >= 0) |
| 93 | cacheput(st, at, buf, sz); |
| 94 | return(sz); |
| 95 | } |
| 96 | |
| 97 | int releasestore(struct store *st) |
| 98 | { |
| 99 | int err; |
| 100 | |
| 101 | if((err = st->ops->release(st)) != 0) |
| 102 | return(err); |
| 103 | free(st); |
| 104 | return(0); |
| 105 | } |
| 106 | |
| 107 | int addrcmp(struct addr *a1, struct addr *a2) |
| 108 | { |
| 109 | return(memcmp(a1->hash, a2->hash, 32)); |
| 110 | } |
| 111 | |
| 112 | char *formataddr(struct addr *a) |
| 113 | { |
| 114 | int i; |
| 115 | static char buf[65]; |
| 116 | |
| 117 | for(i = 0; i < 32; i++) |
| 118 | sprintf(buf + (i * 2), "%02x", a->hash[i]); |
| 119 | buf[64] = 0; |
| 120 | return(buf); |
| 121 | } |
| 122 | |
| 123 | static int hex2int(char hex) |
| 124 | { |
| 125 | if((hex >= 'a') && (hex <= 'f')) |
| 126 | return(hex - 'a' + 10); |
| 127 | if((hex >= 'A') && (hex <= 'F')) |
| 128 | return(hex - 'A' + 10); |
| 129 | if((hex >= '0') && (hex <= '9')) |
| 130 | return(hex - '0'); |
| 131 | return(-1); |
| 132 | } |
| 133 | |
| 134 | int parseaddr(char *p, struct addr *a) |
| 135 | { |
| 136 | int i, d; |
| 137 | |
| 138 | for(i = 0; i < 32; i++) { |
| 139 | if((d = hex2int(*p++)) < 0) |
| 140 | return(-1); |
| 141 | while(*p == ' ') |
| 142 | p++; |
| 143 | a->hash[i] = d << 4; |
| 144 | if((d = hex2int(*p++)) < 0) |
| 145 | return(-1); |
| 146 | while(*p == ' ') |
| 147 | p++; |
| 148 | a->hash[i] |= d; |
| 149 | } |
| 150 | if(*p != 0) |
| 151 | return(-1); |
| 152 | return(0); |
| 153 | } |
| 154 | |
| 155 | int niladdr(struct addr *a) |
| 156 | { |
| 157 | int i; |
| 158 | |
| 159 | for(i = 0; i < 32; i++) { |
| 160 | if(a->hash[i]) |
| 161 | return(0); |
| 162 | } |
| 163 | return(1); |
| 164 | } |