Use or instead of add.
[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];
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
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;
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
97int 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
107int addrcmp(struct addr *a1, struct addr *a2)
108{
109 return(memcmp(a1->hash, a2->hash, 32));
110}
111
112char *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
123static 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
134int 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
155int 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}