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 #ifndef BASICS_H
10 #define BASICS_H
11
12 /*
13 * miscellaneous utilities that are not provided by Git.
14 */
15
16 #include "system.h"
17 #include "reftable-basics.h"
18
19 #ifdef __GNUC__
20 #define REFTABLE_UNUSED __attribute__((__unused__))
21 #else
22 #define REFTABLE_UNUSED
23 #endif
24
25 /*
26 * Initialize the buffer such that it is ready for use. This is equivalent to
27 * using REFTABLE_BUF_INIT for stack-allocated variables.
28 */
29 void reftable_buf_init(struct reftable_buf *buf);
30
31 /*
32 * Release memory associated with the buffer. The buffer is reinitialized such
33 * that it can be reused for subsequent operations.
34 */
35 void reftable_buf_release(struct reftable_buf *buf);
36
37 /*
38 * Reset the buffer such that it is effectively empty, without releasing the
39 * memory that this structure holds on to. This is equivalent to calling
40 * `reftable_buf_setlen(buf, 0)`.
41 */
42 void reftable_buf_reset(struct reftable_buf *buf);
43
44 /*
45 * Trim the buffer to a shorter length by updating the `len` member and writing
46 * a NUL byte to `buf[len]`. Returns 0 on success, -1 when `len` points outside
47 * of the array.
48 */
49 int reftable_buf_setlen(struct reftable_buf *buf, size_t len);
50
51 /*
52 * Lexicographically compare the two buffers. Returns 0 when both buffers have
53 * the same contents, -1 when `a` is lexicographically smaller than `b`, and 1
54 * otherwise.
55 */
56 int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b);
57
58 /*
59 * Append `len` bytes from `data` to the buffer. This function works with
60 * arbitrary byte sequences, including ones that contain embedded NUL
61 * characters. As such, we use `void *` as input type. Returns 0 on success,
62 * REFTABLE_OUT_OF_MEMORY_ERROR on allocation failure.
63 */
64 int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len);
65
66 /* Equivalent to `reftable_buf_add(buf, s, strlen(s))`. */
67 int reftable_buf_addstr(struct reftable_buf *buf, const char *s);
68
69 /*
70 * Detach the buffer from the structure such that the underlying memory is now
71 * owned by the caller. The buffer is reinitialized such that it can be reused
72 * for subsequent operations.
73 */
74 char *reftable_buf_detach(struct reftable_buf *buf);
75
76 /* Bigendian en/decoding of integers */
77
78 static inline void reftable_put_be16(void *out, uint16_t i)
79 {
80 unsigned char *p = out;
81 p[0] = (uint8_t)((i >> 8) & 0xff);
82 p[1] = (uint8_t)((i >> 0) & 0xff);
83 }
84
85 static inline void reftable_put_be24(void *out, uint32_t i)
86 {
87 unsigned char *p = out;
88 p[0] = (uint8_t)((i >> 16) & 0xff);
89 p[1] = (uint8_t)((i >> 8) & 0xff);
90 p[2] = (uint8_t)((i >> 0) & 0xff);
91 }
92
93 static inline void reftable_put_be32(void *out, uint32_t i)
94 {
95 unsigned char *p = out;
96 p[0] = (uint8_t)((i >> 24) & 0xff);
97 p[1] = (uint8_t)((i >> 16) & 0xff);
98 p[2] = (uint8_t)((i >> 8) & 0xff);
99 p[3] = (uint8_t)((i >> 0) & 0xff);
100 }
101
102 static inline void reftable_put_be64(void *out, uint64_t i)
103 {
104 unsigned char *p = out;
105 p[0] = (uint8_t)((i >> 56) & 0xff);
106 p[1] = (uint8_t)((i >> 48) & 0xff);
107 p[2] = (uint8_t)((i >> 40) & 0xff);
108 p[3] = (uint8_t)((i >> 32) & 0xff);
109 p[4] = (uint8_t)((i >> 24) & 0xff);
110 p[5] = (uint8_t)((i >> 16) & 0xff);
111 p[6] = (uint8_t)((i >> 8) & 0xff);
112 p[7] = (uint8_t)((i >> 0) & 0xff);
113 }
114
115 static inline uint16_t reftable_get_be16(const void *in)
116 {
117 const unsigned char *p = in;
118 return (uint16_t)(p[0]) << 8 |
119 (uint16_t)(p[1]) << 0;
120 }
121
122 static inline uint32_t reftable_get_be24(const void *in)
123 {
124 const unsigned char *p = in;
125 return (uint32_t)(p[0]) << 16 |
126 (uint32_t)(p[1]) << 8 |
127 (uint32_t)(p[2]) << 0;
128 }
129
130 static inline uint32_t reftable_get_be32(const void *in)
131 {
132 const unsigned char *p = in;
133 return (uint32_t)(p[0]) << 24 |
134 (uint32_t)(p[1]) << 16 |
135 (uint32_t)(p[2]) << 8|
136 (uint32_t)(p[3]) << 0;
137 }
138
139 static inline uint64_t reftable_get_be64(const void *in)
140 {
141 const unsigned char *p = in;
142 return (uint64_t)(p[0]) << 56 |
143 (uint64_t)(p[1]) << 48 |
144 (uint64_t)(p[2]) << 40 |
145 (uint64_t)(p[3]) << 32 |
146 (uint64_t)(p[4]) << 24 |
147 (uint64_t)(p[5]) << 16 |
148 (uint64_t)(p[6]) << 8 |
149 (uint64_t)(p[7]) << 0;
150 }
151
152 /*
153 * find smallest index i in [0, sz) at which `f(i) > 0`, assuming that f is
154 * ascending. Return sz if `f(i) == 0` for all indices. The search is aborted
155 * and `sz` is returned in case `f(i) < 0`.
156 *
157 * Contrary to bsearch(3), this returns something useful if the argument is not
158 * found.
159 */
160 size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
161
162 /*
163 * Frees a NULL terminated array of malloced strings. The array itself is also
164 * freed.
165 */
166 void free_names(char **a);
167
168 /*
169 * Parse a newline separated list of names. `size` is the length of the buffer,
170 * without terminating '\0'. Empty names are discarded.
171 *
172 * Returns 0 on success, a reftable error code on error.
173 */
174 int parse_names(char *buf, int size, char ***out);
175
176 /* compares two NULL-terminated arrays of strings. */
177 int names_equal(const char **a, const char **b);
178
179 /* returns the array size of a NULL-terminated array of strings. */
180 size_t names_length(const char **names);
181
182 /* Allocation routines; they invoke the functions set through
183 * reftable_set_alloc() */
184 void *reftable_malloc(size_t sz);
185 void *reftable_realloc(void *p, size_t sz);
186 void reftable_free(void *p);
187 void *reftable_calloc(size_t nelem, size_t elsize);
188 char *reftable_strdup(const char *str);
189
190 static inline int reftable_alloc_size(size_t nelem, size_t elsize, size_t *out)
191 {
192 if (nelem && elsize > SIZE_MAX / nelem)
193 return -1;
194 *out = nelem * elsize;
195 return 0;
196 }
197
198 #define REFTABLE_ALLOC_ARRAY(x, alloc) do { \
199 size_t alloc_size; \
200 if (reftable_alloc_size(sizeof(*(x)), (alloc), &alloc_size) < 0) { \
201 errno = ENOMEM; \
202 (x) = NULL; \
203 } else { \
204 (x) = reftable_malloc(alloc_size); \
205 } \
206 } while (0)
207 #define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x)))
208 #define REFTABLE_REALLOC_ARRAY(x, alloc) do { \
209 size_t alloc_size; \
210 if (reftable_alloc_size(sizeof(*(x)), (alloc), &alloc_size) < 0) { \
211 errno = ENOMEM; \
212 (x) = NULL; \
213 } else { \
214 (x) = reftable_realloc((x), alloc_size); \
215 } \
216 } while (0)
217
218 static inline void *reftable_alloc_grow(void *p, size_t nelem, size_t elsize,
219 size_t *allocp)
220 {
221 void *new_p;
222 size_t alloc = *allocp * 2 + 1, alloc_bytes;
223 if (alloc < nelem)
224 alloc = nelem;
225 if (reftable_alloc_size(elsize, alloc, &alloc_bytes) < 0) {
226 errno = ENOMEM;
227 return p;
228 }
229 new_p = reftable_realloc(p, alloc_bytes);
230 if (!new_p)
231 return p;
232 *allocp = alloc;
233 return new_p;
234 }
235
236 #define REFTABLE_ALLOC_GROW(x, nr, alloc) ( \
237 (nr) > (alloc) && ( \
238 (x) = reftable_alloc_grow((x), (nr), sizeof(*(x)), &(alloc)), \
239 (nr) > (alloc) \
240 ) \
241 )
242
243 #define REFTABLE_ALLOC_GROW_OR_NULL(x, nr, alloc) do { \
244 size_t reftable_alloc_grow_or_null_alloc = alloc; \
245 if (REFTABLE_ALLOC_GROW((x), (nr), reftable_alloc_grow_or_null_alloc)) { \
246 REFTABLE_FREE_AND_NULL(x); \
247 alloc = 0; \
248 } else { \
249 alloc = reftable_alloc_grow_or_null_alloc; \
250 } \
251 } while (0)
252
253 #define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0)
254
255 #ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS
256 # define REFTABLE_BANNED(func) use_reftable_##func##_instead
257 # undef malloc
258 # define malloc(sz) REFTABLE_BANNED(malloc)
259 # undef realloc
260 # define realloc(ptr, sz) REFTABLE_BANNED(realloc)
261 # undef free
262 # define free(ptr) REFTABLE_BANNED(free)
263 # undef calloc
264 # define calloc(nelem, elsize) REFTABLE_BANNED(calloc)
265 # undef strdup
266 # define strdup(str) REFTABLE_BANNED(strdup)
267 #endif
268
269 #define REFTABLE_SWAP(a, b) do { \
270 void *_swap_a_ptr = &(a); \
271 void *_swap_b_ptr = &(b); \
272 unsigned char _swap_buffer[sizeof(a) - 2 * sizeof(a) * (sizeof(a) != sizeof(b))]; \
273 memcpy(_swap_buffer, _swap_a_ptr, sizeof(a)); \
274 memcpy(_swap_a_ptr, _swap_b_ptr, sizeof(a)); \
275 memcpy(_swap_b_ptr, _swap_buffer, sizeof(a)); \
276 } while (0)
277
278 /* Find the longest shared prefix size of `a` and `b` */
279 size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b);
280
281 uint32_t hash_size(enum reftable_hash id);
282
283 /*
284 * Format IDs that identify the hash function used by a reftable. Note that
285 * these constants end up on disk and thus mustn't change. The format IDs are
286 * "sha1" and "s256" in big endian, respectively.
287 */
288 #define REFTABLE_FORMAT_ID_SHA1 ((uint32_t) 0x73686131)
289 #define REFTABLE_FORMAT_ID_SHA256 ((uint32_t) 0x73323536)
290
291 #endif