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#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 */
29void 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 */
35void 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 */
42void 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 */
49int 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 */
56int 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 */
64int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len);
65
66/* Equivalent to `reftable_buf_add(buf, s, strlen(s))`. */
67int 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 */
74char *reftable_buf_detach(struct reftable_buf *buf);
75
76/* Bigendian en/decoding of integers */
77
78static 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
85static 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
93static 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
102static 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
115static 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
122static 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
130static 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
139static 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 */
160size_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 */
166void 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 */
174int parse_names(char *buf, int size, char ***out);
175
176/* compares two NULL-terminated arrays of strings. */
177int names_equal(const char **a, const char **b);
178
179/* returns the array size of a NULL-terminated array of strings. */
180size_t names_length(const char **names);
181
182/* Allocation routines; they invoke the functions set through
183 * reftable_set_alloc() */
184void *reftable_malloc(size_t sz);
185void *reftable_realloc(void *p, size_t sz);
186void reftable_free(void *p);
187void *reftable_calloc(size_t nelem, size_t elsize);
188char *reftable_strdup(const char *str);
189
190static 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
218static 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` */
279size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b);
280
281uint32_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