Annotation of src/usr.bin/rcs/buf.c, Revision 1.9
1.9 ! ray 1: /* $OpenBSD: buf.c,v 1.8 2006/08/16 07:39:15 ray Exp $ */
1.1 joris 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 "includes.h"
28:
29: #include "buf.h"
30: #include "xmalloc.h"
31: #include "worklist.h"
32:
33: #define BUF_INCR 128
34:
35: struct rcs_buf {
36: u_int cb_flags;
37:
38: /* buffer handle and size */
39: u_char *cb_buf;
40: size_t cb_size;
41:
42: /* start and length of valid data in buffer */
43: u_char *cb_cur;
44: size_t cb_len;
45: };
46:
47: #define SIZE_LEFT(b) (b->cb_size - (size_t)(b->cb_cur - b->cb_buf) \
48: - b->cb_len)
49:
50: static void rcs_buf_grow(BUF *, size_t);
51:
52: /*
53: * rcs_buf_alloc()
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 rcs_buf_free(),
57: * once the buffer is no longer needed.
58: */
59: BUF *
60: rcs_buf_alloc(size_t len, u_int flags)
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_flags = flags;
72: b->cb_size = len;
73: b->cb_cur = b->cb_buf;
74: b->cb_len = 0;
75:
76: return (b);
77: }
78:
79: /*
80: * rcs_buf_load()
81: *
82: * Open the file specified by <path> and load all of its contents into a
83: * buffer.
1.8 ray 84: * Returns the loaded buffer on success or NULL on failure.
85: * Sets errno on error.
1.1 joris 86: */
87: BUF *
88: rcs_buf_load(const char *path, u_int flags)
89: {
90: int fd;
91: ssize_t ret;
92: size_t len;
93: u_char *bp;
94: struct stat st;
95: BUF *buf;
96:
1.8 ray 97: buf = NULL;
98:
99: if ((fd = open(path, O_RDONLY, 0600)) == -1)
100: goto out;
1.1 joris 101:
102: if (fstat(fd, &st) == -1)
1.8 ray 103: goto out;
1.1 joris 104:
1.8 ray 105: if (st.st_size > SIZE_MAX) {
106: errno = EFBIG;
107: goto out;
108: }
109: buf = rcs_buf_alloc(st.st_size, flags);
1.1 joris 110: for (bp = buf->cb_cur; ; bp += (size_t)ret) {
111: len = SIZE_LEFT(buf);
112: ret = read(fd, bp, len);
113: if (ret == -1) {
1.8 ray 114: int saved_errno;
115:
116: saved_errno = errno;
1.1 joris 117: rcs_buf_free(buf);
1.8 ray 118: buf = NULL;
119: errno = saved_errno;
120: goto out;
1.1 joris 121: } else if (ret == 0)
122: break;
123:
124: buf->cb_len += (size_t)ret;
125: }
126:
1.8 ray 127: out:
128: if (fd != -1) {
129: int saved_errno;
130:
131: /* We may want to preserve errno here. */
132: saved_errno = errno;
133: (void)close(fd);
134: errno = saved_errno;
135: }
1.1 joris 136:
137: return (buf);
138: }
139:
140: /*
141: * rcs_buf_free()
142: *
143: * Free the buffer <b> and all associated data.
144: */
145: void
146: rcs_buf_free(BUF *b)
147: {
148: if (b->cb_buf != NULL)
149: xfree(b->cb_buf);
150: xfree(b);
151: }
152:
153: /*
154: * rcs_buf_release()
155: *
156: * Free the buffer <b>'s structural information but do not free the contents
157: * of the buffer. Instead, they are returned and should be freed later using
158: * free().
159: */
160: void *
161: rcs_buf_release(BUF *b)
162: {
1.4 niallo 163: void *tmp;
1.1 joris 164:
165: tmp = b->cb_buf;
166: xfree(b);
167: return (tmp);
1.5 niallo 168: }
169:
170: /*
171: * rcs_buf_get()
172: */
173: void *
174: rcs_buf_get(BUF *b)
175: {
176: return (b->cb_buf);
1.1 joris 177: }
178:
179: /*
180: * rcs_buf_empty()
181: *
182: * Empty the contents of the buffer <b> and reset pointers.
183: */
184: void
185: rcs_buf_empty(BUF *b)
186: {
187: memset(b->cb_buf, 0, b->cb_size);
188: b->cb_cur = b->cb_buf;
189: b->cb_len = 0;
190: }
191:
192: /*
193: * rcs_buf_putc()
194: *
195: * Append a single character <c> to the end of the buffer <b>.
196: */
197: void
198: rcs_buf_putc(BUF *b, int c)
199: {
200: u_char *bp;
201:
202: bp = b->cb_cur + b->cb_len;
203: if (bp == (b->cb_buf + b->cb_size)) {
204: /* extend */
205: if (b->cb_flags & BUF_AUTOEXT)
206: rcs_buf_grow(b, (size_t)BUF_INCR);
207: else
208: errx(1, "rcs_buf_putc failed");
209:
210: /* the buffer might have been moved */
211: bp = b->cb_cur + b->cb_len;
212: }
213: *bp = (u_char)c;
214: b->cb_len++;
215: }
216:
217: /*
218: * rcs_buf_getc()
219: *
220: * Return u_char at buffer position <pos>.
221: *
222: */
223: u_char
224: rcs_buf_getc(BUF *b, size_t pos)
225: {
226: return (b->cb_cur[pos]);
227: }
228:
229: /*
230: * rcs_buf_append()
231: *
232: * Append <len> bytes of data pointed to by <data> to the buffer <b>. If the
233: * buffer is too small to accept all data, it will attempt to append as much
234: * data as possible, or if the BUF_AUTOEXT flag is set for the buffer, it
235: * will get resized to an appropriate size to accept all data.
236: * Returns the number of bytes successfully appended to the buffer.
237: */
1.7 ray 238: size_t
1.1 joris 239: rcs_buf_append(BUF *b, const void *data, size_t len)
240: {
241: size_t left, rlen;
242: u_char *bp, *bep;
243:
244: bp = b->cb_cur + b->cb_len;
245: bep = b->cb_buf + b->cb_size;
246: left = bep - bp;
247: rlen = len;
248:
249: if (left < len) {
250: if (b->cb_flags & BUF_AUTOEXT) {
251: rcs_buf_grow(b, len - left);
252: bp = b->cb_cur + b->cb_len;
253: } else
254: rlen = bep - bp;
255: }
256:
257: memcpy(bp, data, rlen);
258: b->cb_len += rlen;
259:
260: return (rlen);
261: }
262:
263: /*
264: * rcs_buf_fappend()
265: *
266: */
1.7 ray 267: size_t
1.1 joris 268: rcs_buf_fappend(BUF *b, const char *fmt, ...)
269: {
1.7 ray 270: size_t ret;
271: int n;
1.1 joris 272: char *str;
273: va_list vap;
274:
275: va_start(vap, fmt);
1.7 ray 276: n = vasprintf(&str, fmt, vap);
1.1 joris 277: va_end(vap);
278:
1.7 ray 279: if (n == -1)
1.1 joris 280: errx(1, "rcs_buf_fappend: failed to format data");
281:
1.7 ray 282: ret = rcs_buf_append(b, str, n);
1.1 joris 283: xfree(str);
284: return (ret);
285: }
286:
287: /*
288: * rcs_buf_len()
289: *
290: * Returns the size of the buffer that is being used.
291: */
292: size_t
293: rcs_buf_len(BUF *b)
294: {
295: return (b->cb_len);
296: }
297:
298: /*
299: * rcs_buf_write_fd()
300: *
301: * Write the contents of the buffer <b> to the specified <fd>
302: */
303: int
304: rcs_buf_write_fd(BUF *b, int fd)
305: {
306: u_char *bp;
307: size_t len;
308: ssize_t ret;
309:
310: len = b->cb_len;
311: bp = b->cb_cur;
312:
313: do {
314: ret = write(fd, bp, len);
315: if (ret == -1) {
316: if (errno == EINTR || errno == EAGAIN)
317: continue;
318: return (-1);
319: }
320:
321: len -= (size_t)ret;
322: bp += (size_t)ret;
323: } while (len > 0);
324:
325: return (0);
326: }
327:
328: /*
329: * rcs_buf_write()
330: *
331: * Write the contents of the buffer <b> to the file whose path is given in
332: * <path>. If the file does not exist, it is created with mode <mode>.
333: */
334: int
335: rcs_buf_write(BUF *b, const char *path, mode_t mode)
336: {
337: int fd;
338: open:
339: if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) == -1) {
340: if (errno == EACCES && unlink(path) != -1)
341: goto open;
342: else
1.3 xsa 343: err(1, "%s", path);
1.1 joris 344: }
345:
346: if (rcs_buf_write_fd(b, fd) == -1) {
347: (void)unlink(path);
348: errx(1, "rcs_buf_write: rcs_buf_write_fd: `%s'", path);
349: }
350:
351: if (fchmod(fd, mode) < 0)
352: warn("permissions not set on file %s", path);
353:
354: (void)close(fd);
355:
356: return (0);
357: }
358:
359: /*
360: * rcs_buf_write_stmp()
361: *
362: * Write the contents of the buffer <b> to a temporary file whose path is
363: * specified using <template> (see mkstemp.3). NB. This function will modify
364: * <template>, as per mkstemp
365: */
366: void
1.6 ray 367: rcs_buf_write_stmp(BUF *b, char *template)
1.1 joris 368: {
369: int fd;
370:
371: if ((fd = mkstemp(template)) == -1)
1.3 xsa 372: err(1, "%s", template);
1.1 joris 373:
374: rcs_worklist_add(template, &rcs_temp_files);
375:
376: if (rcs_buf_write_fd(b, fd) == -1) {
377: (void)unlink(template);
378: errx(1, "rcs_buf_write_stmp: rcs_buf_write_fd: `%s'", template);
379: }
380:
381: (void)close(fd);
382: }
383:
384: /*
385: * rcs_buf_grow()
386: *
387: * Grow the buffer <b> by <len> bytes. The contents are unchanged by this
388: * operation regardless of the result.
389: */
390: static void
391: rcs_buf_grow(BUF *b, size_t len)
392: {
393: void *tmp;
394: size_t diff;
395:
396: diff = b->cb_cur - b->cb_buf;
397: tmp = xrealloc(b->cb_buf, 1, b->cb_size + len);
398: b->cb_buf = tmp;
399: b->cb_size += len;
400:
401: /* readjust pointers in case the buffer moved in memory */
402: b->cb_cur = b->cb_buf + diff;
403: }