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