/* 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 */ #define REFTABLE_ALLOW_BANNED_ALLOCATORS #include "basics.h" #include "reftable-basics.h" #include "reftable-error.h" static void *(*reftable_malloc_ptr)(size_t sz); static void *(*reftable_realloc_ptr)(void *, size_t); static void (*reftable_free_ptr)(void *); void *reftable_malloc(size_t sz) { if (!sz) return NULL; if (reftable_malloc_ptr) return (*reftable_malloc_ptr)(sz); return malloc(sz); } void *reftable_realloc(void *p, size_t sz) { if (!sz) { reftable_free(p); return NULL; } if (reftable_realloc_ptr) return (*reftable_realloc_ptr)(p, sz); return realloc(p, sz); } void reftable_free(void *p) { if (reftable_free_ptr) reftable_free_ptr(p); else free(p); } void *reftable_calloc(size_t nelem, size_t elsize) { void *p; if (nelem && elsize > SIZE_MAX / nelem) return NULL; p = reftable_malloc(nelem * elsize); if (!p) return NULL; memset(p, 0, nelem * elsize); return p; } char *reftable_strdup(const char *str) { size_t len = strlen(str); char *result = reftable_malloc(len + 1); if (!result) return NULL; memcpy(result, str, len + 1); return result; } void reftable_set_alloc(void *(*malloc)(size_t), void *(*realloc)(void *, size_t), void (*free)(void *)) { reftable_malloc_ptr = malloc; reftable_realloc_ptr = realloc; reftable_free_ptr = free; } void reftable_buf_init(struct reftable_buf *buf) { struct reftable_buf empty = REFTABLE_BUF_INIT; *buf = empty; } void reftable_buf_release(struct reftable_buf *buf) { reftable_free(buf->buf); reftable_buf_init(buf); } void reftable_buf_reset(struct reftable_buf *buf) { if (buf->alloc) { buf->len = 0; buf->buf[0] = '\0'; } } int reftable_buf_setlen(struct reftable_buf *buf, size_t len) { if (len > buf->len) return -1; if (len == buf->len) return 0; buf->buf[len] = '\0'; buf->len = len; return 0; } int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b) { size_t len = a->len < b->len ? a->len : b->len; if (len) { int cmp = memcmp(a->buf, b->buf, len); if (cmp) return cmp; } return a->len < b->len ? -1 : a->len != b->len; } int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len) { size_t newlen = buf->len + len; if (newlen + 1 > buf->alloc) { if (REFTABLE_ALLOC_GROW(buf->buf, newlen + 1, buf->alloc)) return REFTABLE_OUT_OF_MEMORY_ERROR; } memcpy(buf->buf + buf->len, data, len); buf->buf[newlen] = '\0'; buf->len = newlen; return 0; } int reftable_buf_addstr(struct reftable_buf *buf, const char *s) { return reftable_buf_add(buf, s, strlen(s)); } char *reftable_buf_detach(struct reftable_buf *buf) { char *result = buf->buf; reftable_buf_init(buf); return result; } size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args) { size_t lo = 0; size_t hi = sz; /* Invariants: * * (hi == sz) || f(hi) == true * (lo == 0 && f(0) == true) || fi(lo) == false */ while (hi - lo > 1) { size_t mid = lo + (hi - lo) / 2; int ret = f(mid, args); if (ret < 0) return sz; if (ret > 0) hi = mid; else lo = mid; } if (lo) return hi; return f(0, args) ? 0 : 1; } void free_names(char **a) { char **p; if (!a) { return; } for (p = a; *p; p++) { reftable_free(*p); } reftable_free(a); } size_t names_length(const char **names) { const char **p = names; while (*p) p++; return p - names; } char **parse_names(char *buf, int size) { char **names = NULL; size_t names_cap = 0; size_t names_len = 0; char *p = buf; char *end = buf + size; while (p < end) { char *next = strchr(p, '\n'); if (next && next < end) { *next = 0; } else { next = end; } if (p < next) { if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap)) goto err; names[names_len] = reftable_strdup(p); if (!names[names_len++]) goto err; } p = next + 1; } if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap)) goto err; names[names_len] = NULL; return names; err: for (size_t i = 0; i < names_len; i++) reftable_free(names[i]); reftable_free(names); return NULL; } int names_equal(const char **a, const char **b) { size_t i = 0; for (; a[i] && b[i]; i++) if (strcmp(a[i], b[i])) return 0; return a[i] == b[i]; } size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b) { size_t p = 0; for (; p < a->len && p < b->len; p++) if (a->buf[p] != b->buf[p]) break; return p; } uint32_t hash_size(enum reftable_hash id) { if (!id) return REFTABLE_HASH_SIZE_SHA1; switch (id) { case REFTABLE_HASH_SHA1: return REFTABLE_HASH_SIZE_SHA1; case REFTABLE_HASH_SHA256: return REFTABLE_HASH_SIZE_SHA256; } abort(); }