xref: /openbsd-src/usr.bin/cvs/buf.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
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