Converted repo to Git.
[vcfs.git] / store.c
CommitLineData
d5cf5351 1#include <stdlib.h>
2#include <string.h>
3#include <stdio.h>
4#include <errno.h>
5
6#include "store.h"
7
8struct 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
21static ssize_t cacheget(struct store *st, struct addr *a, void *buf, size_t len)
22{
23 int he, i;
24
db5f6d16 25 he = a->hash[0] | ((a->hash[1] & 0x0f) << 8);
d5cf5351 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
37static void cacheput(struct store *st, struct addr *a, const void *data, ssize_t len)
38{
39 int he, i;
40 struct storecache tmp;
41
db5f6d16 42 he = a->hash[0] | ((a->hash[1] & 0x0f) << 8);
d5cf5351 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];
efe8eeeb 51 memmove(&st->cache[he * 4 + 1], &st->cache[he * 4], i * sizeof(struct storecache));
d5cf5351 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);
efe8eeeb 57 memmove(&st->cache[he * 4 + 1], &st->cache[he * 4], 3 * sizeof(struct storecache));
d5cf5351 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
66int 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
79ssize_t storeget(struct store *st, void *buf, size_t len, struct addr *at)
80{
81 ssize_t sz;
487044bb 82 struct addr at2;
d5cf5351 83
487044bb 84 at2 = *at;
53439346 85 sz = cacheget(st, &at2, buf, len);
d5cf5351 86 if(sz != -2) {
87 if(sz == -1)
88 errno = ENOENT;
89 return(sz);
90 }
53439346 91 sz = st->ops->get(st, buf, len, &at2);
d5cf5351 92 if((sz < 0) && (errno == ENOENT))
53439346 93 cacheput(st, &at2, NULL, -1);
d5cf5351 94 else if(sz >= 0)
53439346 95 cacheput(st, &at2, buf, sz);
d5cf5351 96 return(sz);
97}
98
99int releasestore(struct store *st)
100{
101 int err;
102
103 if((err = st->ops->release(st)) != 0)
104 return(err);
105 free(st);
106 return(0);
107}
108
109int addrcmp(struct addr *a1, struct addr *a2)
110{
111 return(memcmp(a1->hash, a2->hash, 32));
112}
113
114char *formataddr(struct addr *a)
115{
116 int i;
117 static char buf[65];
118
119 for(i = 0; i < 32; i++)
120 sprintf(buf + (i * 2), "%02x", a->hash[i]);
121 buf[64] = 0;
122 return(buf);
123}
124
125static int hex2int(char hex)
126{
127 if((hex >= 'a') && (hex <= 'f'))
128 return(hex - 'a' + 10);
129 if((hex >= 'A') && (hex <= 'F'))
130 return(hex - 'A' + 10);
131 if((hex >= '0') && (hex <= '9'))
132 return(hex - '0');
133 return(-1);
134}
135
136int parseaddr(char *p, struct addr *a)
137{
138 int i, d;
139
140 for(i = 0; i < 32; i++) {
141 if((d = hex2int(*p++)) < 0)
142 return(-1);
143 while(*p == ' ')
144 p++;
145 a->hash[i] = d << 4;
146 if((d = hex2int(*p++)) < 0)
147 return(-1);
148 while(*p == ' ')
149 p++;
150 a->hash[i] |= d;
151 }
152 if(*p != 0)
153 return(-1);
154 return(0);
155}
156
157int niladdr(struct addr *a)
158{
159 int i;
160
161 for(i = 0; i < 32; i++) {
162 if(a->hash[i])
163 return(0);
164 }
165 return(1);
166}