87275123f98283c32a8b805c0501209ffc6990d1
[vcfs.git] / store.c
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 }