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