1 /* $OpenBSD: buf.c,v 1.74 2009/03/25 21:19:20 joris 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/stat.h> 28 #include <sys/time.h> 29 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <unistd.h> 35 36 #include "atomicio.h" 37 #include "cvs.h" 38 #include "buf.h" 39 40 #define BUF_INCR 128 41 #define BUF_GROW(bp, len) \ 42 do { \ 43 b->cb_buf = xrealloc(b->cb_buf, 1, b->cb_size + len); \ 44 b->cb_size += len; \ 45 } while (0); 46 47 struct cvs_buf { 48 u_char *cb_buf; 49 size_t cb_size; 50 size_t cb_len; 51 }; 52 53 BUF * 54 cvs_buf_alloc(size_t len) 55 { 56 BUF *b; 57 58 b = xmalloc(sizeof(*b)); 59 if (len > 0) 60 b->cb_buf = xcalloc(1, len); 61 else 62 b->cb_buf = NULL; 63 64 b->cb_size = len; 65 b->cb_len = 0; 66 67 return (b); 68 } 69 70 BUF * 71 cvs_buf_load(const char *path) 72 { 73 int fd; 74 BUF *bp; 75 76 if ((fd = open(path, O_RDONLY, 0600)) == -1) 77 fatal("cvs_buf_load: failed to load '%s' : %s", path, 78 strerror(errno)); 79 80 bp = cvs_buf_load_fd(fd); 81 (void)close(fd); 82 return (bp); 83 } 84 85 BUF * 86 cvs_buf_load_fd(int fd) 87 { 88 struct stat st; 89 BUF *buf; 90 91 if (fstat(fd, &st) == -1) 92 fatal("cvs_buf_load_fd: fstat: %s", strerror(errno)); 93 94 if (lseek(fd, 0, SEEK_SET) == -1) 95 fatal("cvs_buf_load_fd: lseek: %s", strerror(errno)); 96 97 if (st.st_size > SIZE_MAX) 98 fatal("cvs_buf_load_fd: file size too big"); 99 buf = cvs_buf_alloc(st.st_size); 100 if (atomicio(read, fd, buf->cb_buf, buf->cb_size) != buf->cb_size) 101 fatal("cvs_buf_load_fd: read: %s", strerror(errno)); 102 buf->cb_len = buf->cb_size; 103 104 return (buf); 105 } 106 107 void 108 cvs_buf_free(BUF *b) 109 { 110 if (b->cb_buf != NULL) 111 xfree(b->cb_buf); 112 xfree(b); 113 } 114 115 u_char * 116 cvs_buf_release(BUF *b) 117 { 118 u_char *tmp; 119 120 tmp = b->cb_buf; 121 xfree(b); 122 return (tmp); 123 } 124 125 void 126 cvs_buf_putc(BUF *b, int c) 127 { 128 u_char *bp; 129 130 bp = b->cb_buf + b->cb_len; 131 if (bp == (b->cb_buf + b->cb_size)) { 132 BUF_GROW(b, BUF_INCR); 133 bp = b->cb_buf + b->cb_len; 134 } 135 *bp = (u_char)c; 136 b->cb_len++; 137 } 138 139 void 140 cvs_buf_puts(BUF *b, const char *str) 141 { 142 cvs_buf_append(b, str, strlen(str)); 143 } 144 145 void 146 cvs_buf_append(BUF *b, const void *data, size_t len) 147 { 148 size_t left; 149 u_char *bp, *bep; 150 151 bp = b->cb_buf + b->cb_len; 152 bep = b->cb_buf + b->cb_size; 153 left = bep - bp; 154 155 if (left < len) { 156 BUF_GROW(b, len - left); 157 bp = b->cb_buf + b->cb_len; 158 } 159 160 memcpy(bp, data, len); 161 b->cb_len += len; 162 } 163 164 size_t 165 cvs_buf_len(BUF *b) 166 { 167 return (b->cb_len); 168 } 169 170 int 171 cvs_buf_write_fd(BUF *b, int fd) 172 { 173 if (atomicio(vwrite, fd, b->cb_buf, b->cb_len) != b->cb_len) 174 return (-1); 175 return (0); 176 } 177 178 int 179 cvs_buf_write(BUF *b, const char *path, mode_t mode) 180 { 181 int fd; 182 open: 183 if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) { 184 if (errno == EACCES && unlink(path) != -1) 185 goto open; 186 else 187 fatal("open: `%s': %s", path, strerror(errno)); 188 } 189 190 if (cvs_buf_write_fd(b, fd) == -1) { 191 (void)unlink(path); 192 fatal("cvs_buf_write: cvs_buf_write_fd: `%s'", path); 193 } 194 195 if (fchmod(fd, mode) < 0) 196 cvs_log(LP_ERR, "permissions not set on file %s", path); 197 198 (void)close(fd); 199 200 return (0); 201 } 202 203 int 204 cvs_buf_write_stmp(BUF *b, char *template, struct timeval *tv) 205 { 206 int fd; 207 208 if ((fd = mkstemp(template)) == -1) 209 fatal("mkstemp: `%s': %s", template, strerror(errno)); 210 211 if (cvs_buf_write_fd(b, fd) == -1) { 212 (void)unlink(template); 213 fatal("cvs_buf_write_stmp: cvs_buf_write_fd: `%s'", template); 214 } 215 216 if (tv != NULL) { 217 if (futimes(fd, tv) == -1) 218 fatal("cvs_buf_write_stmp: futimes failed"); 219 } 220 221 cvs_worklist_add(template, &temp_files); 222 223 if (lseek(fd, 0, SEEK_SET) < 0) 224 fatal("cvs_buf_write_stmp: lseek: %s", strerror(errno)); 225 226 return (fd); 227 } 228 229 u_char * 230 cvs_buf_get(BUF *bp) 231 { 232 return (bp->cb_buf); 233 } 234 235 int 236 cvs_buf_differ(const BUF *b1, const BUF *b2) 237 { 238 if (b1->cb_len != b2->cb_len) 239 return (1); 240 241 return (memcmp(b1->cb_buf, b2->cb_buf, b1->cb_len)); 242 } 243