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