Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | // SPDX-License-Identifier: GPL-2.0+ /* * Handles a buffer that can be allocated and freed * * Copyright 2021 Google LLC * Written by Simon Glass <sjg@chromium.org> */ #ifndef USE_HOSTCC #include <malloc.h> #include <mapmem.h> #include <string.h> #include <vsprintf.h> #endif #include <errno.h> #include <stdarg.h> #include <abuf.h> void abuf_set(struct abuf *abuf, void *data, size_t size) { abuf_uninit(abuf); abuf->data = data; abuf->size = size; } #ifndef USE_HOSTCC void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size) { abuf_set(abuf, map_sysmem(addr, size), size); } ulong abuf_addr(const struct abuf *abuf) { return map_to_sysmem(abuf->data); } #else /* copied from lib/string.c for convenience */ static char *memdup(const void *src, size_t len) { char *p; p = malloc(len); if (!p) return NULL; memcpy(p, src, len); return p; } #endif bool abuf_realloc(struct abuf *abuf, size_t new_size) { void *ptr; if (!new_size) { /* easy case, just need to uninit, freeing any allocation */ abuf_uninit(abuf); return true; } else if (abuf->alloced) { /* currently allocated, so need to reallocate */ ptr = realloc(abuf->data, new_size); if (!ptr) return false; abuf->data = ptr; abuf->size = new_size; return true; } else if (new_size <= abuf->size) { /* * not currently alloced and new size is no larger. Just update * it. Data is lost off the end if new_size < abuf->size */ abuf->size = new_size; return true; } else { /* not currently allocated and new size is larger. Alloc and * copy in data. The new space is not inited. */ ptr = malloc(new_size); if (!ptr) return false; if (abuf->size) memcpy(ptr, abuf->data, abuf->size); abuf->data = ptr; abuf->size = new_size; abuf->alloced = true; return true; } } bool abuf_realloc_inc(struct abuf *abuf, size_t inc) { return abuf_realloc(abuf, abuf->size + inc); } void *abuf_uninit_move(struct abuf *abuf, size_t *sizep) { void *ptr; if (sizep) *sizep = abuf->size; if (!abuf->size) return NULL; if (abuf->alloced) { ptr = abuf->data; } else { ptr = memdup(abuf->data, abuf->size); if (!ptr) return NULL; } /* Clear everything out so there is no record of the data */ abuf_init(abuf); return ptr; } void abuf_init_set(struct abuf *abuf, void *data, size_t size) { abuf_init(abuf); abuf_set(abuf, data, size); } bool abuf_init_size(struct abuf *buf, size_t size) { abuf_init(buf); if (!abuf_realloc(buf, size)) return false; return true; } bool abuf_copy(const struct abuf *old, struct abuf *copy) { char *data; data = malloc(old->size); if (!data) return false; memcpy(data, old->data, old->size); abuf_init_set(copy, data, old->size); copy->alloced = true; return true; } int abuf_printf(struct abuf *buf, const char *fmt, ...) { int maxlen = buf->size; va_list args; int len; va_start(args, fmt); len = vsnprintf(buf->data, buf->size, fmt, args); va_end(args); /* add the terminator */ len++; if (len > 4096) return -E2BIG; if (len > maxlen) { /* make more space and try again */ maxlen = len; if (!abuf_realloc(buf, maxlen)) return -ENOMEM; va_start(args, fmt); len = vsnprintf(buf->data, maxlen, fmt, args); va_end(args); /* check there isn't anything strange going on */ if (len > maxlen) return -EFAULT; } return len; } void abuf_init_const(struct abuf *abuf, const void *data, size_t size) { /* for now there is no flag indicating that the abuf data is constant */ abuf_init_set(abuf, (void *)data, size); } #ifndef USE_HOSTCC void abuf_init_const_addr(struct abuf *abuf, ulong addr, size_t size) { return abuf_init_const(abuf, map_sysmem(addr, size), size); } #endif void abuf_init_move(struct abuf *abuf, void *data, size_t size) { abuf_init_set(abuf, data, size); abuf->alloced = true; } void abuf_uninit(struct abuf *abuf) { if (abuf->alloced) free(abuf->data); abuf_init(abuf); } void abuf_init(struct abuf *abuf) { abuf->data = NULL; abuf->size = 0; abuf->alloced = false; } |