Raw
1 /*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://developers.google.com/open-source/licenses/bsd
7 */
8
9 #define REFTABLE_ALLOW_BANNED_ALLOCATORS
10 #include "basics.h"
11 #include "reftable-basics.h"
12 #include "reftable-error.h"
13
14 static void *(*reftable_malloc_ptr)(size_t sz);
15 static void *(*reftable_realloc_ptr)(void *, size_t);
16 static void (*reftable_free_ptr)(void *);
17
18 void *reftable_malloc(size_t sz)
19 {
20 if (!sz)
21 return NULL;
22 if (reftable_malloc_ptr)
23 return (*reftable_malloc_ptr)(sz);
24 return malloc(sz);
25 }
26
27 void *reftable_realloc(void *p, size_t sz)
28 {
29 if (!sz) {
30 reftable_free(p);
31 return NULL;
32 }
33
34 if (reftable_realloc_ptr)
35 return (*reftable_realloc_ptr)(p, sz);
36 return realloc(p, sz);
37 }
38
39 void reftable_free(void *p)
40 {
41 if (reftable_free_ptr)
42 reftable_free_ptr(p);
43 else
44 free(p);
45 }
46
47 void *reftable_calloc(size_t nelem, size_t elsize)
48 {
49 void *p;
50
51 if (nelem && elsize > SIZE_MAX / nelem)
52 return NULL;
53
54 p = reftable_malloc(nelem * elsize);
55 if (!p)
56 return NULL;
57
58 memset(p, 0, nelem * elsize);
59 return p;
60 }
61
62 char *reftable_strdup(const char *str)
63 {
64 size_t len = strlen(str);
65 char *result = reftable_malloc(len + 1);
66 if (!result)
67 return NULL;
68 memcpy(result, str, len + 1);
69 return result;
70 }
71
72 void reftable_set_alloc(void *(*malloc)(size_t),
73 void *(*realloc)(void *, size_t), void (*free)(void *))
74 {
75 reftable_malloc_ptr = malloc;
76 reftable_realloc_ptr = realloc;
77 reftable_free_ptr = free;
78 }
79
80 void reftable_buf_init(struct reftable_buf *buf)
81 {
82 struct reftable_buf empty = REFTABLE_BUF_INIT;
83 *buf = empty;
84 }
85
86 void reftable_buf_release(struct reftable_buf *buf)
87 {
88 reftable_free(buf->buf);
89 reftable_buf_init(buf);
90 }
91
92 void reftable_buf_reset(struct reftable_buf *buf)
93 {
94 if (buf->alloc) {
95 buf->len = 0;
96 buf->buf[0] = '\0';
97 }
98 }
99
100 int reftable_buf_setlen(struct reftable_buf *buf, size_t len)
101 {
102 if (len > buf->len)
103 return -1;
104 if (len == buf->len)
105 return 0;
106 buf->buf[len] = '\0';
107 buf->len = len;
108 return 0;
109 }
110
111 int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b)
112 {
113 size_t len = a->len < b->len ? a->len : b->len;
114 if (len) {
115 int cmp = memcmp(a->buf, b->buf, len);
116 if (cmp)
117 return cmp;
118 }
119 return a->len < b->len ? -1 : a->len != b->len;
120 }
121
122 int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len)
123 {
124 size_t newlen = buf->len + len;
125
126 if (newlen + 1 > buf->alloc) {
127 if (REFTABLE_ALLOC_GROW(buf->buf, newlen + 1, buf->alloc))
128 return REFTABLE_OUT_OF_MEMORY_ERROR;
129 }
130
131 memcpy(buf->buf + buf->len, data, len);
132 buf->buf[newlen] = '\0';
133 buf->len = newlen;
134
135 return 0;
136 }
137
138 int reftable_buf_addstr(struct reftable_buf *buf, const char *s)
139 {
140 return reftable_buf_add(buf, s, strlen(s));
141 }
142
143 char *reftable_buf_detach(struct reftable_buf *buf)
144 {
145 char *result = buf->buf;
146 reftable_buf_init(buf);
147 return result;
148 }
149
150 size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args)
151 {
152 size_t lo = 0;
153 size_t hi = sz;
154
155 if (!sz)
156 return 0;
157
158 /* Invariants:
159 *
160 * (hi == sz) || f(hi) == true
161 * (lo == 0 && f(0) == true) || fi(lo) == false
162 */
163 while (hi - lo > 1) {
164 size_t mid = lo + (hi - lo) / 2;
165 int ret = f(mid, args);
166 if (ret < 0)
167 return sz;
168
169 if (ret > 0)
170 hi = mid;
171 else
172 lo = mid;
173 }
174
175 if (lo)
176 return hi;
177
178 return f(0, args) ? 0 : 1;
179 }
180
181 void free_names(char **a)
182 {
183 char **p;
184 if (!a) {
185 return;
186 }
187 for (p = a; *p; p++) {
188 reftable_free(*p);
189 }
190 reftable_free(a);
191 }
192
193 size_t names_length(const char **names)
194 {
195 const char **p = names;
196 while (*p)
197 p++;
198 return p - names;
199 }
200
201 int parse_names(char *buf, int size, char ***out)
202 {
203 char **names = NULL;
204 size_t names_cap = 0;
205 size_t names_len = 0;
206 char *p = buf;
207 char *end = buf + size;
208 int err = 0;
209
210 while (p < end) {
211 char *next = strchr(p, '\n');
212 if (!next) {
213 err = REFTABLE_FORMAT_ERROR;
214 goto done;
215 } else if (next < end) {
216 *next = '\0';
217 } else {
218 next = end;
219 }
220
221 if (p < next) {
222 if (REFTABLE_ALLOC_GROW(names, names_len + 1,
223 names_cap)) {
224 err = REFTABLE_OUT_OF_MEMORY_ERROR;
225 goto done;
226 }
227
228 names[names_len] = reftable_strdup(p);
229 if (!names[names_len++]) {
230 err = REFTABLE_OUT_OF_MEMORY_ERROR;
231 goto done;
232 }
233 }
234 p = next + 1;
235 }
236
237 if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap)) {
238 err = REFTABLE_OUT_OF_MEMORY_ERROR;
239 goto done;
240 }
241 names[names_len] = NULL;
242
243 *out = names;
244 return 0;
245 done:
246 for (size_t i = 0; i < names_len; i++)
247 reftable_free(names[i]);
248 reftable_free(names);
249 return err;
250 }
251
252 int names_equal(const char **a, const char **b)
253 {
254 size_t i = 0;
255 for (; a[i] && b[i]; i++)
256 if (strcmp(a[i], b[i]))
257 return 0;
258 return a[i] == b[i];
259 }
260
261 size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b)
262 {
263 size_t p = 0;
264 for (; p < a->len && p < b->len; p++)
265 if (a->buf[p] != b->buf[p])
266 break;
267 return p;
268 }
269
270 uint32_t hash_size(enum reftable_hash id)
271 {
272 if (!id)
273 return REFTABLE_HASH_SIZE_SHA1;
274 switch (id) {
275 case REFTABLE_HASH_SHA1:
276 return REFTABLE_HASH_SIZE_SHA1;
277 case REFTABLE_HASH_SHA256:
278 return REFTABLE_HASH_SIZE_SHA256;
279 }
280 abort();
281 }