1 /* $OpenBSD: buf.c,v 1.22 2011/07/06 15:36:52 nicm Exp $ */ 2 /* 3 * Copyright (c) 2003 Jean-Francois Brousseau <jfb@openbsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 18 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/queue.h> 28 #include <sys/stat.h> 29 30 #include <err.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 #include "buf.h" 38 #include "xmalloc.h" 39 #include "worklist.h" 40 41 #define BUF_INCR 128 42 43 struct buf { 44 /* buffer handle, buffer size, and data length */ 45 u_char *cb_buf; 46 size_t cb_size; 47 size_t cb_len; 48 }; 49 50 #define SIZE_LEFT(b) (b->cb_size - b->cb_len) 51 52 static void buf_grow(BUF *, size_t); 53 54 /* 55 * Create a new buffer structure and return a pointer to it. This structure 56 * uses dynamically-allocated memory and must be freed with buf_free(), once 57 * the buffer is no longer needed. 58 */ 59 BUF * 60 buf_alloc(size_t len) 61 { 62 BUF *b; 63 64 b = xmalloc(sizeof(*b)); 65 /* Postpone creation of zero-sized buffers */ 66 if (len > 0) 67 b->cb_buf = xcalloc(1, len); 68 else 69 b->cb_buf = NULL; 70 71 b->cb_size = len; 72 b->cb_len = 0; 73 74 return (b); 75 } 76 77 /* 78 * Open the file specified by <path> and load all of its contents into a 79 * buffer. 80 * Returns the loaded buffer on success or NULL on failure. 81 * Sets errno on error. 82 */ 83 BUF * 84 buf_load(const char *path) 85 { 86 int fd; 87 ssize_t ret; 88 size_t len; 89 u_char *bp; 90 struct stat st; 91 BUF *buf; 92 93 buf = NULL; 94 95 if ((fd = open(path, O_RDONLY, 0600)) == -1) 96 goto out; 97 98 if (fstat(fd, &st) == -1) 99 goto out; 100 101 if (st.st_size > SIZE_MAX) { 102 errno = EFBIG; 103 goto out; 104 } 105 buf = buf_alloc(st.st_size); 106 for (bp = buf->cb_buf; ; bp += (size_t)ret) { 107 len = SIZE_LEFT(buf); 108 ret = read(fd, bp, len); 109 if (ret == -1) { 110 int saved_errno; 111 112 saved_errno = errno; 113 buf_free(buf); 114 buf = NULL; 115 errno = saved_errno; 116 goto out; 117 } else if (ret == 0) 118 break; 119 120 buf->cb_len += (size_t)ret; 121 } 122 123 out: 124 if (fd != -1) { 125 int saved_errno; 126 127 /* We may want to preserve errno here. */ 128 saved_errno = errno; 129 (void)close(fd); 130 errno = saved_errno; 131 } 132 133 return (buf); 134 } 135 136 void 137 buf_free(BUF *b) 138 { 139 if (b->cb_buf != NULL) 140 xfree(b->cb_buf); 141 xfree(b); 142 } 143 144 /* 145 * Free the buffer <b>'s structural information but do not free the contents 146 * of the buffer. Instead, they are returned and should be freed later using 147 * xfree(). 148 */ 149 void * 150 buf_release(BUF *b) 151 { 152 void *tmp; 153 154 tmp = b->cb_buf; 155 xfree(b); 156 return (tmp); 157 } 158 159 u_char * 160 buf_get(BUF *b) 161 { 162 return (b->cb_buf); 163 } 164 165 /* 166 * Empty the contents of the buffer <b> and reset pointers. 167 */ 168 void 169 buf_empty(BUF *b) 170 { 171 memset(b->cb_buf, 0, b->cb_size); 172 b->cb_len = 0; 173 } 174 175 /* 176 * Append a single character <c> to the end of the buffer <b>. 177 */ 178 void 179 buf_putc(BUF *b, int c) 180 { 181 u_char *bp; 182 183 if (SIZE_LEFT(b) == 0) 184 buf_grow(b, BUF_INCR); 185 bp = b->cb_buf + b->cb_len; 186 *bp = (u_char)c; 187 b->cb_len++; 188 } 189 190 /* 191 * Append a string <s> to the end of buffer <b>. 192 */ 193 void 194 buf_puts(BUF *b, const char *str) 195 { 196 buf_append(b, str, strlen(str)); 197 } 198 199 /* 200 * Return u_char at buffer position <pos>. 201 */ 202 u_char 203 buf_getc(BUF *b, size_t pos) 204 { 205 return (b->cb_buf[pos]); 206 } 207 208 /* 209 * Append <len> bytes of data pointed to by <data> to the buffer <b>. If the 210 * buffer is too small to accept all data, it will get resized to an 211 * appropriate size to accept all data. 212 * Returns the number of bytes successfully appended to the buffer. 213 */ 214 size_t 215 buf_append(BUF *b, const void *data, size_t len) 216 { 217 size_t left, rlen; 218 u_char *bp; 219 220 left = SIZE_LEFT(b); 221 rlen = len; 222 223 if (left < len) 224 buf_grow(b, len - left); 225 bp = b->cb_buf + b->cb_len; 226 memcpy(bp, data, rlen); 227 b->cb_len += rlen; 228 229 return (rlen); 230 } 231 232 /* 233 * Returns the size of the buffer that is being used. 234 */ 235 size_t 236 buf_len(BUF *b) 237 { 238 return (b->cb_len); 239 } 240 241 /* 242 * Write the contents of the buffer <b> to the specified <fd> 243 */ 244 int 245 buf_write_fd(BUF *b, int fd) 246 { 247 u_char *bp; 248 size_t len; 249 ssize_t ret; 250 251 len = b->cb_len; 252 bp = b->cb_buf; 253 254 do { 255 ret = write(fd, bp, len); 256 if (ret == -1) { 257 if (errno == EINTR || errno == EAGAIN) 258 continue; 259 return (-1); 260 } 261 262 len -= (size_t)ret; 263 bp += (size_t)ret; 264 } while (len > 0); 265 266 return (0); 267 } 268 269 /* 270 * Write the contents of the buffer <b> to the file whose path is given in 271 * <path>. If the file does not exist, it is created with mode <mode>. 272 */ 273 int 274 buf_write(BUF *b, const char *path, mode_t mode) 275 { 276 int fd; 277 open: 278 if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { 279 if (errno == EACCES && unlink(path) != -1) 280 goto open; 281 else 282 err(1, "%s", path); 283 } 284 285 if (buf_write_fd(b, fd) == -1) { 286 (void)unlink(path); 287 errx(1, "buf_write: buf_write_fd: `%s'", path); 288 } 289 290 if (fchmod(fd, mode) < 0) 291 warn("permissions not set on file %s", path); 292 293 (void)close(fd); 294 295 return (0); 296 } 297 298 /* 299 * Write the contents of the buffer <b> to a temporary file whose path is 300 * specified using <template> (see mkstemp.3). 301 * NB. This function will modify <template>, as per mkstemp 302 */ 303 void 304 buf_write_stmp(BUF *b, char *template) 305 { 306 int fd; 307 308 if ((fd = mkstemp(template)) == -1) 309 err(1, "%s", template); 310 311 worklist_add(template, &temp_files); 312 313 if (buf_write_fd(b, fd) == -1) { 314 (void)unlink(template); 315 errx(1, "buf_write_stmp: buf_write_fd: `%s'", template); 316 } 317 318 (void)close(fd); 319 } 320 321 /* 322 * Grow the buffer <b> by <len> bytes. The contents are unchanged by this 323 * operation regardless of the result. 324 */ 325 static void 326 buf_grow(BUF *b, size_t len) 327 { 328 b->cb_buf = xrealloc(b->cb_buf, 1, b->cb_size + len); 329 b->cb_size += len; 330 } 331