Git fork
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
14static void *(*reftable_malloc_ptr)(size_t sz);
15static void *(*reftable_realloc_ptr)(void *, size_t);
16static void (*reftable_free_ptr)(void *);
17
18void *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
27void *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
39void reftable_free(void *p)
40{
41 if (reftable_free_ptr)
42 reftable_free_ptr(p);
43 else
44 free(p);
45}
46
47void *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
62char *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
72void 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
80void reftable_buf_init(struct reftable_buf *buf)
81{
82 struct reftable_buf empty = REFTABLE_BUF_INIT;
83 *buf = empty;
84}
85
86void reftable_buf_release(struct reftable_buf *buf)
87{
88 reftable_free(buf->buf);
89 reftable_buf_init(buf);
90}
91
92void reftable_buf_reset(struct reftable_buf *buf)
93{
94 if (buf->alloc) {
95 buf->len = 0;
96 buf->buf[0] = '\0';
97 }
98}
99
100int 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
111int 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
122int 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
138int reftable_buf_addstr(struct reftable_buf *buf, const char *s)
139{
140 return reftable_buf_add(buf, s, strlen(s));
141}
142
143char *reftable_buf_detach(struct reftable_buf *buf)
144{
145 char *result = buf->buf;
146 reftable_buf_init(buf);
147 return result;
148}
149
150size_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 /* Invariants:
156 *
157 * (hi == sz) || f(hi) == true
158 * (lo == 0 && f(0) == true) || fi(lo) == false
159 */
160 while (hi - lo > 1) {
161 size_t mid = lo + (hi - lo) / 2;
162 int ret = f(mid, args);
163 if (ret < 0)
164 return sz;
165
166 if (ret > 0)
167 hi = mid;
168 else
169 lo = mid;
170 }
171
172 if (lo)
173 return hi;
174
175 return f(0, args) ? 0 : 1;
176}
177
178void free_names(char **a)
179{
180 char **p;
181 if (!a) {
182 return;
183 }
184 for (p = a; *p; p++) {
185 reftable_free(*p);
186 }
187 reftable_free(a);
188}
189
190size_t names_length(const char **names)
191{
192 const char **p = names;
193 while (*p)
194 p++;
195 return p - names;
196}
197
198int parse_names(char *buf, int size, char ***out)
199{
200 char **names = NULL;
201 size_t names_cap = 0;
202 size_t names_len = 0;
203 char *p = buf;
204 char *end = buf + size;
205 int err = 0;
206
207 while (p < end) {
208 char *next = strchr(p, '\n');
209 if (!next) {
210 err = REFTABLE_FORMAT_ERROR;
211 goto done;
212 } else if (next < end) {
213 *next = '\0';
214 } else {
215 next = end;
216 }
217
218 if (p < next) {
219 if (REFTABLE_ALLOC_GROW(names, names_len + 1,
220 names_cap)) {
221 err = REFTABLE_OUT_OF_MEMORY_ERROR;
222 goto done;
223 }
224
225 names[names_len] = reftable_strdup(p);
226 if (!names[names_len++]) {
227 err = REFTABLE_OUT_OF_MEMORY_ERROR;
228 goto done;
229 }
230 }
231 p = next + 1;
232 }
233
234 if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap)) {
235 err = REFTABLE_OUT_OF_MEMORY_ERROR;
236 goto done;
237 }
238 names[names_len] = NULL;
239
240 *out = names;
241 return 0;
242done:
243 for (size_t i = 0; i < names_len; i++)
244 reftable_free(names[i]);
245 reftable_free(names);
246 return err;
247}
248
249int names_equal(const char **a, const char **b)
250{
251 size_t i = 0;
252 for (; a[i] && b[i]; i++)
253 if (strcmp(a[i], b[i]))
254 return 0;
255 return a[i] == b[i];
256}
257
258size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b)
259{
260 size_t p = 0;
261 for (; p < a->len && p < b->len; p++)
262 if (a->buf[p] != b->buf[p])
263 break;
264 return p;
265}
266
267uint32_t hash_size(enum reftable_hash id)
268{
269 if (!id)
270 return REFTABLE_HASH_SIZE_SHA1;
271 switch (id) {
272 case REFTABLE_HASH_SHA1:
273 return REFTABLE_HASH_SIZE_SHA1;
274 case REFTABLE_HASH_SHA256:
275 return REFTABLE_HASH_SIZE_SHA256;
276 }
277 abort();
278}