|  | /* | 
|  | * Copyright 2020 Google LLC | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style | 
|  | * license that can be found in the LICENSE file or at | 
|  | * https://developers.google.com/open-source/licenses/bsd | 
|  | */ | 
|  |  | 
|  | #ifndef BASICS_H | 
|  | #define BASICS_H | 
|  |  | 
|  | /* | 
|  | * miscellaneous utilities that are not provided by Git. | 
|  | */ | 
|  |  | 
|  | #include "system.h" | 
|  | #include "reftable-basics.h" | 
|  |  | 
|  | #ifdef __GNUC__ | 
|  | #define REFTABLE_UNUSED __attribute__((__unused__)) | 
|  | #else | 
|  | #define REFTABLE_UNUSED | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * Initialize the buffer such that it is ready for use. This is equivalent to | 
|  | * using REFTABLE_BUF_INIT for stack-allocated variables. | 
|  | */ | 
|  | void reftable_buf_init(struct reftable_buf *buf); | 
|  |  | 
|  | /* | 
|  | * Release memory associated with the buffer. The buffer is reinitialized such | 
|  | * that it can be reused for subsequent operations. | 
|  | */ | 
|  | void reftable_buf_release(struct reftable_buf *buf); | 
|  |  | 
|  | /* | 
|  | * Reset the buffer such that it is effectively empty, without releasing the | 
|  | * memory that this structure holds on to. This is equivalent to calling | 
|  | * `reftable_buf_setlen(buf, 0)`. | 
|  | */ | 
|  | void reftable_buf_reset(struct reftable_buf *buf); | 
|  |  | 
|  | /* | 
|  | * Trim the buffer to a shorter length by updating the `len` member and writing | 
|  | * a NUL byte to `buf[len]`. Returns 0 on success, -1 when `len` points outside | 
|  | * of the array. | 
|  | */ | 
|  | int reftable_buf_setlen(struct reftable_buf *buf, size_t len); | 
|  |  | 
|  | /* | 
|  | * Lexicographically compare the two buffers. Returns 0 when both buffers have | 
|  | * the same contents, -1 when `a` is lexicographically smaller than `b`, and 1 | 
|  | * otherwise. | 
|  | */ | 
|  | int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b); | 
|  |  | 
|  | /* | 
|  | * Append `len` bytes from `data` to the buffer. This function works with | 
|  | * arbitrary byte sequences, including ones that contain embedded NUL | 
|  | * characters. As such, we use `void *` as input type. Returns 0 on success, | 
|  | * REFTABLE_OUT_OF_MEMORY_ERROR on allocation failure. | 
|  | */ | 
|  | int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len); | 
|  |  | 
|  | /* Equivalent to `reftable_buf_add(buf, s, strlen(s))`. */ | 
|  | int reftable_buf_addstr(struct reftable_buf *buf, const char *s); | 
|  |  | 
|  | /* | 
|  | * Detach the buffer from the structure such that the underlying memory is now | 
|  | * owned by the caller. The buffer is reinitialized such that it can be reused | 
|  | * for subsequent operations. | 
|  | */ | 
|  | char *reftable_buf_detach(struct reftable_buf *buf); | 
|  |  | 
|  | /* Bigendian en/decoding of integers */ | 
|  |  | 
|  | static inline void reftable_put_be16(void *out, uint16_t i) | 
|  | { | 
|  | unsigned char *p = out; | 
|  | p[0] = (uint8_t)((i >> 8) & 0xff); | 
|  | p[1] = (uint8_t)((i >> 0) & 0xff); | 
|  | } | 
|  |  | 
|  | static inline void reftable_put_be24(void *out, uint32_t i) | 
|  | { | 
|  | unsigned char *p = out; | 
|  | p[0] = (uint8_t)((i >> 16) & 0xff); | 
|  | p[1] = (uint8_t)((i >>  8) & 0xff); | 
|  | p[2] = (uint8_t)((i >>  0) & 0xff); | 
|  | } | 
|  |  | 
|  | static inline void reftable_put_be32(void *out, uint32_t i) | 
|  | { | 
|  | unsigned char *p = out; | 
|  | p[0] = (uint8_t)((i >> 24) & 0xff); | 
|  | p[1] = (uint8_t)((i >> 16) & 0xff); | 
|  | p[2] = (uint8_t)((i >>  8) & 0xff); | 
|  | p[3] = (uint8_t)((i >>  0) & 0xff); | 
|  | } | 
|  |  | 
|  | static inline void reftable_put_be64(void *out, uint64_t i) | 
|  | { | 
|  | unsigned char *p = out; | 
|  | p[0] = (uint8_t)((i >> 56) & 0xff); | 
|  | p[1] = (uint8_t)((i >> 48) & 0xff); | 
|  | p[2] = (uint8_t)((i >> 40) & 0xff); | 
|  | p[3] = (uint8_t)((i >> 32) & 0xff); | 
|  | p[4] = (uint8_t)((i >> 24) & 0xff); | 
|  | p[5] = (uint8_t)((i >> 16) & 0xff); | 
|  | p[6] = (uint8_t)((i >>  8) & 0xff); | 
|  | p[7] = (uint8_t)((i >>  0) & 0xff); | 
|  | } | 
|  |  | 
|  | static inline uint16_t reftable_get_be16(const void *in) | 
|  | { | 
|  | const unsigned char *p = in; | 
|  | return (uint16_t)(p[0]) << 8 | | 
|  | (uint16_t)(p[1]) << 0; | 
|  | } | 
|  |  | 
|  | static inline uint32_t reftable_get_be24(const void *in) | 
|  | { | 
|  | const unsigned char *p = in; | 
|  | return (uint32_t)(p[0]) << 16 | | 
|  | (uint32_t)(p[1]) << 8 | | 
|  | (uint32_t)(p[2]) << 0; | 
|  | } | 
|  |  | 
|  | static inline uint32_t reftable_get_be32(const void *in) | 
|  | { | 
|  | const unsigned char *p = in; | 
|  | return (uint32_t)(p[0]) << 24 | | 
|  | (uint32_t)(p[1]) << 16 | | 
|  | (uint32_t)(p[2]) <<  8| | 
|  | (uint32_t)(p[3]) <<  0; | 
|  | } | 
|  |  | 
|  | static inline uint64_t reftable_get_be64(const void *in) | 
|  | { | 
|  | const unsigned char *p = in; | 
|  | return (uint64_t)(p[0]) << 56 | | 
|  | (uint64_t)(p[1]) << 48 | | 
|  | (uint64_t)(p[2]) << 40 | | 
|  | (uint64_t)(p[3]) << 32 | | 
|  | (uint64_t)(p[4]) << 24 | | 
|  | (uint64_t)(p[5]) << 16 | | 
|  | (uint64_t)(p[6]) <<  8 | | 
|  | (uint64_t)(p[7]) <<  0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * find smallest index i in [0, sz) at which `f(i) > 0`, assuming that f is | 
|  | * ascending. Return sz if `f(i) == 0` for all indices. The search is aborted | 
|  | * and `sz` is returned in case `f(i) < 0`. | 
|  | * | 
|  | * Contrary to bsearch(3), this returns something useful if the argument is not | 
|  | * found. | 
|  | */ | 
|  | size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args); | 
|  |  | 
|  | /* | 
|  | * Frees a NULL terminated array of malloced strings. The array itself is also | 
|  | * freed. | 
|  | */ | 
|  | void free_names(char **a); | 
|  |  | 
|  | /* | 
|  | * Parse a newline separated list of names. `size` is the length of the buffer, | 
|  | * without terminating '\0'. Empty names are discarded. Returns a `NULL` | 
|  | * pointer when allocations fail. | 
|  | */ | 
|  | char **parse_names(char *buf, int size); | 
|  |  | 
|  | /* compares two NULL-terminated arrays of strings. */ | 
|  | int names_equal(const char **a, const char **b); | 
|  |  | 
|  | /* returns the array size of a NULL-terminated array of strings. */ | 
|  | size_t names_length(const char **names); | 
|  |  | 
|  | /* Allocation routines; they invoke the functions set through | 
|  | * reftable_set_alloc() */ | 
|  | void *reftable_malloc(size_t sz); | 
|  | void *reftable_realloc(void *p, size_t sz); | 
|  | void reftable_free(void *p); | 
|  | void *reftable_calloc(size_t nelem, size_t elsize); | 
|  | char *reftable_strdup(const char *str); | 
|  |  | 
|  | static inline int reftable_alloc_size(size_t nelem, size_t elsize, size_t *out) | 
|  | { | 
|  | if (nelem && elsize > SIZE_MAX / nelem) | 
|  | return -1; | 
|  | *out = nelem * elsize; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define REFTABLE_ALLOC_ARRAY(x, alloc) do { \ | 
|  | size_t alloc_size; \ | 
|  | if (reftable_alloc_size(sizeof(*(x)), (alloc), &alloc_size) < 0) { \ | 
|  | errno = ENOMEM; \ | 
|  | (x) = NULL; \ | 
|  | } else { \ | 
|  | (x) = reftable_malloc(alloc_size); \ | 
|  | } \ | 
|  | } while (0) | 
|  | #define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x))) | 
|  | #define REFTABLE_REALLOC_ARRAY(x, alloc) do { \ | 
|  | size_t alloc_size; \ | 
|  | if (reftable_alloc_size(sizeof(*(x)), (alloc), &alloc_size) < 0) { \ | 
|  | errno = ENOMEM; \ | 
|  | (x) = NULL; \ | 
|  | } else { \ | 
|  | (x) = reftable_realloc((x), alloc_size); \ | 
|  | } \ | 
|  | } while (0) | 
|  |  | 
|  | static inline void *reftable_alloc_grow(void *p, size_t nelem, size_t elsize, | 
|  | size_t *allocp) | 
|  | { | 
|  | void *new_p; | 
|  | size_t alloc = *allocp * 2 + 1, alloc_bytes; | 
|  | if (alloc < nelem) | 
|  | alloc = nelem; | 
|  | if (reftable_alloc_size(elsize, alloc, &alloc_bytes) < 0) { | 
|  | errno = ENOMEM; | 
|  | return p; | 
|  | } | 
|  | new_p = reftable_realloc(p, alloc_bytes); | 
|  | if (!new_p) | 
|  | return p; | 
|  | *allocp = alloc; | 
|  | return new_p; | 
|  | } | 
|  |  | 
|  | #define REFTABLE_ALLOC_GROW(x, nr, alloc) ( \ | 
|  | (nr) > (alloc) && ( \ | 
|  | (x) = reftable_alloc_grow((x), (nr), sizeof(*(x)), &(alloc)), \ | 
|  | (nr) > (alloc) \ | 
|  | ) \ | 
|  | ) | 
|  |  | 
|  | #define REFTABLE_ALLOC_GROW_OR_NULL(x, nr, alloc) do { \ | 
|  | size_t reftable_alloc_grow_or_null_alloc = alloc; \ | 
|  | if (REFTABLE_ALLOC_GROW((x), (nr), reftable_alloc_grow_or_null_alloc)) { \ | 
|  | REFTABLE_FREE_AND_NULL(x); \ | 
|  | alloc = 0; \ | 
|  | } else { \ | 
|  | alloc = reftable_alloc_grow_or_null_alloc; \ | 
|  | } \ | 
|  | } while (0) | 
|  |  | 
|  | #define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0) | 
|  |  | 
|  | #ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS | 
|  | # define REFTABLE_BANNED(func) use_reftable_##func##_instead | 
|  | # undef malloc | 
|  | # define malloc(sz) REFTABLE_BANNED(malloc) | 
|  | # undef realloc | 
|  | # define realloc(ptr, sz) REFTABLE_BANNED(realloc) | 
|  | # undef free | 
|  | # define free(ptr) REFTABLE_BANNED(free) | 
|  | # undef calloc | 
|  | # define calloc(nelem, elsize) REFTABLE_BANNED(calloc) | 
|  | # undef strdup | 
|  | # define strdup(str) REFTABLE_BANNED(strdup) | 
|  | #endif | 
|  |  | 
|  | #define REFTABLE_SWAP(a, b) do {								\ | 
|  | void *_swap_a_ptr = &(a);								\ | 
|  | void *_swap_b_ptr = &(b);								\ | 
|  | unsigned char _swap_buffer[sizeof(a) - 2 * sizeof(a) * (sizeof(a) != sizeof(b))];	\ | 
|  | memcpy(_swap_buffer, _swap_a_ptr, sizeof(a));						\ | 
|  | memcpy(_swap_a_ptr, _swap_b_ptr, sizeof(a));						\ | 
|  | memcpy(_swap_b_ptr, _swap_buffer, sizeof(a));						\ | 
|  | } while (0) | 
|  |  | 
|  | /* Find the longest shared prefix size of `a` and `b` */ | 
|  | size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b); | 
|  |  | 
|  | uint32_t hash_size(enum reftable_hash id); | 
|  |  | 
|  | /* | 
|  | * Format IDs that identify the hash function used by a reftable. Note that | 
|  | * these constants end up on disk and thus mustn't change. The format IDs are | 
|  | * "sha1" and "s256" in big endian, respectively. | 
|  | */ | 
|  | #define REFTABLE_FORMAT_ID_SHA1   ((uint32_t) 0x73686131) | 
|  | #define REFTABLE_FORMAT_ID_SHA256 ((uint32_t) 0x73323536) | 
|  |  | 
|  | #endif |