Bleh
[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 * sizeof(struct storecache));
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 * sizeof(struct storecache));
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     struct addr at2;
83     
84     at2 = *at;
85     sz = cacheget(st, &at2, buf, len);
86     if(sz != -2) {
87         if(sz == -1)
88             errno = ENOENT;
89         return(sz);
90     }
91     sz = st->ops->get(st, buf, len, &at2);
92     if((sz < 0) && (errno == ENOENT))
93         cacheput(st, &at2, NULL, -1);
94     else if(sz >= 0)
95         cacheput(st, &at2, buf, sz);
96     return(sz);
97 }
98
99 int 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
109 int addrcmp(struct addr *a1, struct addr *a2)
110 {
111     return(memcmp(a1->hash, a2->hash, 32));
112 }
113
114 char *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
125 static 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
136 int 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
157 int 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 }