xref: /trueos/usr.bin/csup/stream.c (revision 834fb25a9ed2240101506d137b5be7d71c75f306)
1 /*-
2  * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 
32 #include <assert.h>
33 #include <zlib.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include "misc.h"
44 #include "stream.h"
45 
46 /*
47  * Simple stream API to make my life easier.  If the fgetln() and
48  * funopen() functions were standard and if funopen() wasn't using
49  * wrong types for the function pointers, I could have just used
50  * stdio, but life sucks.
51  *
52  * For now, streams are always block-buffered.
53  */
54 
55 /*
56  * Try to quiet warnings as much as possible with GCC while staying
57  * compatible with other compilers.
58  */
59 #ifndef __unused
60 #if defined(__GNUC__) && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7)
61 #define	__unused	__attribute__((__unused__))
62 #else
63 #define	__unused
64 #endif
65 #endif
66 
67 /*
68  * Flags passed to the flush methods.
69  *
70  * STREAM_FLUSH_CLOSING is passed during the last flush call before
71  * closing a stream.  This allows the zlib filter to emit the EOF
72  * marker as appropriate.  In all other cases, STREAM_FLUSH_NORMAL
73  * should be passed.
74  *
75  * These flags are completely unused in the default flush method,
76  * but they are very important for the flush method of the zlib
77  * filter.
78  */
79 typedef enum {
80 	STREAM_FLUSH_NORMAL,
81 	STREAM_FLUSH_CLOSING
82 } stream_flush_t;
83 
84 /*
85  * This is because buf_new() will always allocate size + 1 bytes,
86  * so our buffer sizes will still be power of 2 values.
87  */
88 #define	STREAM_BUFSIZ	1023
89 
90 struct buf {
91 	char *buf;
92 	size_t size;
93 	size_t in;
94 	size_t off;
95 };
96 
97 struct stream {
98 	void *cookie;
99 	int fd;
100 	int buf;
101 	struct buf *rdbuf;
102 	struct buf *wrbuf;
103 	stream_readfn_t *readfn;
104 	stream_writefn_t *writefn;
105 	stream_closefn_t *closefn;
106 	int eof;
107 	struct stream_filter *filter;
108 	void *fdata;
109 };
110 
111 typedef int	stream_filter_initfn_t(struct stream *, void *);
112 typedef void	stream_filter_finifn_t(struct stream *);
113 typedef int	stream_filter_flushfn_t(struct stream *, struct buf *,
114 		    stream_flush_t);
115 typedef ssize_t	stream_filter_fillfn_t(struct stream *, struct buf *);
116 
117 struct stream_filter {
118 	stream_filter_t id;
119 	stream_filter_initfn_t *initfn;
120 	stream_filter_finifn_t *finifn;
121 	stream_filter_fillfn_t *fillfn;
122 	stream_filter_flushfn_t *flushfn;
123 };
124 
125 /* Low-level buffer API. */
126 #define	buf_avail(buf)		((buf)->size - (buf)->off - (buf)->in)
127 #define	buf_count(buf)		((buf)->in)
128 #define	buf_size(buf)		((buf)->size)
129 
130 static void		 buf_more(struct buf *, size_t);
131 static void		 buf_less(struct buf *, size_t);
132 static void		 buf_grow(struct buf *, size_t);
133 
134 /* Internal stream functions. */
135 static ssize_t		 stream_fill(struct stream *);
136 static ssize_t		 stream_fill_default(struct stream *, struct buf *);
137 static int		 stream_flush_int(struct stream *, stream_flush_t);
138 static int		 stream_flush_default(struct stream *, struct buf *,
139 			     stream_flush_t);
140 
141 /* Filters specific functions. */
142 static struct stream_filter *stream_filter_lookup(stream_filter_t);
143 static int		 stream_filter_init(struct stream *, void *);
144 static void		 stream_filter_fini(struct stream *);
145 
146 /* The zlib stream filter declarations. */
147 #define	ZFILTER_EOF	1				/* Got Z_STREAM_END. */
148 
149 struct zfilter {
150 	int flags;
151 	struct buf *rdbuf;
152 	struct buf *wrbuf;
153 	z_stream *rdstate;
154 	z_stream *wrstate;
155 };
156 
157 static int		 zfilter_init(struct stream *, void *);
158 static void		 zfilter_fini(struct stream *);
159 static ssize_t		 zfilter_fill(struct stream *, struct buf *);
160 static int		 zfilter_flush(struct stream *, struct buf *,
161 			     stream_flush_t);
162 
163 /* The MD5 stream filter. */
164 struct md5filter {
165 	MD5_CTX ctx;
166 	char *md5;
167 	char lastc;
168 #define PRINT	1
169 #define WS	2
170 #define STRING	3
171 #define SEEN	4
172 	int state;
173 };
174 
175 static int		 md5filter_init(struct stream *, void *);
176 static void		 md5filter_fini(struct stream *);
177 static ssize_t		 md5filter_fill(struct stream *, struct buf *);
178 static int		 md5filter_flush(struct stream *, struct buf *,
179 			     stream_flush_t);
180 static int		 md5rcsfilter_flush(struct stream *, struct buf *,
181 			     stream_flush_t);
182 
183 /* The available stream filters. */
184 struct stream_filter stream_filters[] = {
185 	{
186 		STREAM_FILTER_NULL,
187 		NULL,
188 		NULL,
189 		stream_fill_default,
190 		stream_flush_default
191 	},
192 	{
193 	       	STREAM_FILTER_ZLIB,
194 		zfilter_init,
195 		zfilter_fini,
196 		zfilter_fill,
197 		zfilter_flush
198 	},
199 	{
200 		STREAM_FILTER_MD5,
201 		md5filter_init,
202 		md5filter_fini,
203 		md5filter_fill,
204 		md5filter_flush
205 	},
206 	{
207 		STREAM_FILTER_MD5RCS,
208 		md5filter_init,
209 		md5filter_fini,
210 		md5filter_fill,
211 		md5rcsfilter_flush
212 	}
213 
214 };
215 
216 
217 /* Create a new buffer. */
218 struct buf *
buf_new(size_t size)219 buf_new(size_t size)
220 {
221 	struct buf *buf;
222 
223 	buf = xmalloc(sizeof(struct buf));
224 	/*
225 	 * We keep one spare byte so that stream_getln() can put a '\0'
226 	 * there in case the stream doesn't have an ending newline.
227 	 */
228 	buf->buf = xmalloc(size + 1);
229 	memset(buf->buf, 0, size + 1);
230 	buf->size = size;
231 	buf->in = 0;
232 	buf->off = 0;
233 	return (buf);
234 }
235 
236 /*
237  * Grow the size of the buffer.  If "need" is 0, bump its size to the
238  * next power of 2 value.  Otherwise, bump it to the next power of 2
239  * value bigger than "need".
240  */
241 static void
buf_grow(struct buf * buf,size_t need)242 buf_grow(struct buf *buf, size_t need)
243 {
244 
245 	if (need == 0)
246 		buf->size = buf->size * 2 + 1; /* Account for the spare byte. */
247 	else {
248 		assert(need > buf->size);
249 		while (buf->size < need)
250 			buf->size = buf->size * 2 + 1;
251 	}
252 	buf->buf = xrealloc(buf->buf, buf->size + 1);
253 }
254 
255 /* Make more room in the buffer if needed. */
256 static void
buf_prewrite(struct buf * buf)257 buf_prewrite(struct buf *buf)
258 {
259 
260 	if (buf_count(buf) == buf_size(buf))
261 		buf_grow(buf, 0);
262 	if (buf_count(buf) > 0 && buf_avail(buf) == 0) {
263 		memmove(buf->buf, buf->buf + buf->off, buf_count(buf));
264 		buf->off = 0;
265 	}
266 }
267 
268 /* Account for "n" bytes being added in the buffer. */
269 static void
buf_more(struct buf * buf,size_t n)270 buf_more(struct buf *buf, size_t n)
271 {
272 
273 	assert(n <= buf_avail(buf));
274 	buf->in += n;
275 }
276 
277 /* Account for "n" bytes having been read in the buffer. */
278 static void
buf_less(struct buf * buf,size_t n)279 buf_less(struct buf *buf, size_t n)
280 {
281 
282 	assert(n <= buf_count(buf));
283 	buf->in -= n;
284 	if (buf->in == 0)
285 		buf->off = 0;
286 	else
287 		buf->off += n;
288 }
289 
290 /* Free a buffer. */
291 void
buf_free(struct buf * buf)292 buf_free(struct buf *buf)
293 {
294 
295 	free(buf->buf);
296 	free(buf);
297 }
298 
299 static struct stream *
stream_new(stream_readfn_t * readfn,stream_writefn_t * writefn,stream_closefn_t * closefn)300 stream_new(stream_readfn_t *readfn, stream_writefn_t *writefn,
301     stream_closefn_t *closefn)
302 {
303 	struct stream *stream;
304 
305 	stream = xmalloc(sizeof(struct stream));
306 	if (readfn == NULL && writefn == NULL) {
307 		errno = EINVAL;
308 		return (NULL);
309 	}
310 	if (readfn != NULL)
311 		stream->rdbuf = buf_new(STREAM_BUFSIZ);
312 	else
313 		stream->rdbuf = NULL;
314 	if (writefn != NULL)
315 		stream->wrbuf = buf_new(STREAM_BUFSIZ);
316 	else
317 		stream->wrbuf = NULL;
318 	stream->cookie = NULL;
319 	stream->fd = -1;
320 	stream->buf = 0;
321 	stream->readfn = readfn;
322 	stream->writefn = writefn;
323 	stream->closefn = closefn;
324 	stream->filter = stream_filter_lookup(STREAM_FILTER_NULL);
325 	stream->fdata = NULL;
326 	stream->eof = 0;
327 	return (stream);
328 }
329 
330 /* Create a new stream associated with a void *. */
331 struct stream *
stream_open(void * cookie,stream_readfn_t * readfn,stream_writefn_t * writefn,stream_closefn_t * closefn)332 stream_open(void *cookie, stream_readfn_t *readfn, stream_writefn_t *writefn,
333     stream_closefn_t *closefn)
334 {
335 	struct stream *stream;
336 
337 	stream = stream_new(readfn, writefn, closefn);
338 	stream->cookie = cookie;
339 	return (stream);
340 }
341 
342 /* Associate a file descriptor with a stream. */
343 struct stream *
stream_open_fd(int fd,stream_readfn_t * readfn,stream_writefn_t * writefn,stream_closefn_t * closefn)344 stream_open_fd(int fd, stream_readfn_t *readfn, stream_writefn_t *writefn,
345     stream_closefn_t *closefn)
346 {
347 	struct stream *stream;
348 
349 	stream = stream_new(readfn, writefn, closefn);
350 	stream->cookie = &stream->fd;
351 	stream->fd = fd;
352 	return (stream);
353 }
354 
355 /* Associate a buf with a stream. */
356 struct stream *
stream_open_buf(struct buf * b)357 stream_open_buf(struct buf *b)
358 {
359 	struct stream *stream;
360 
361 	stream = stream_new(stream_read_buf, stream_append_buf, stream_close_buf);
362 	stream->cookie = b;
363 	stream->buf = 1;
364 	b->in = 0;
365 	return (stream);
366 }
367 
368 /*
369  * Truncate a buffer, just decrease offset pointer.
370  * XXX: this can be dangerous if not used correctly.
371  */
372 void
stream_truncate_buf(struct buf * b,off_t off)373 stream_truncate_buf(struct buf *b, off_t off)
374 {
375 	b->off += off;
376 }
377 
378 /* Like open() but returns a stream. */
379 struct stream *
stream_open_file(const char * path,int flags,...)380 stream_open_file(const char *path, int flags, ...)
381 {
382 	struct stream *stream;
383 	stream_readfn_t *readfn;
384 	stream_writefn_t *writefn;
385 	va_list ap;
386 	mode_t mode;
387 	int fd;
388 
389 	va_start(ap, flags);
390 	if (flags & O_CREAT) {
391 		/*
392 		 * GCC says I should not be using mode_t here since it's
393 		 * promoted to an int when passed through `...'.
394 		 */
395 		mode = va_arg(ap, int);
396 		fd = open(path, flags, mode);
397 	} else
398 		fd = open(path, flags);
399 	va_end(ap);
400 	if (fd == -1)
401 		return (NULL);
402 
403 	flags &= O_ACCMODE;
404 	if (flags == O_RDONLY) {
405 		readfn = stream_read_fd;
406 		writefn = NULL;
407 	} else if (flags == O_WRONLY) {
408 		readfn = NULL;
409 		writefn = stream_write_fd;
410 	} else if (flags == O_RDWR) {
411 		assert(flags == O_RDWR);
412 		readfn = stream_read_fd;
413 		writefn = stream_write_fd;
414 	} else {
415 		errno = EINVAL;
416 		close(fd);
417 		return (NULL);
418 	}
419 
420 	stream = stream_open_fd(fd, readfn, writefn, stream_close_fd);
421 	if (stream == NULL)
422 		close(fd);
423 	return (stream);
424 }
425 
426 /* Return the file descriptor associated with this stream, or -1. */
427 int
stream_fileno(struct stream * stream)428 stream_fileno(struct stream *stream)
429 {
430 
431 	return (stream->fd);
432 }
433 
434 /* Convenience read function for character buffers. */
435 ssize_t
stream_read_buf(void * cookie,void * buf,size_t size)436 stream_read_buf(void *cookie, void *buf, size_t size)
437 {
438 	struct buf *b;
439 	size_t avail;
440 
441 	/* Use in to be read offset. */
442 	b = (struct buf *)cookie;
443 	/* Just return what we have if the request is to large. */
444 	avail = b->off - b->in;
445 	if (avail < size) {
446 		memcpy(buf, (b->buf + b->in), avail);
447 		b->in += avail;
448 		return (avail);
449 	}
450 	memcpy(buf, (b->buf + b->in), size);
451 	b->in += size;
452 	return (size);
453 }
454 
455 /* Convenience write function for appending character buffers. */
456 ssize_t
stream_append_buf(void * cookie,const void * buf,size_t size)457 stream_append_buf(void *cookie, const void *buf, size_t size)
458 {
459 	struct buf *b;
460 	size_t avail;
461 
462 	/* Use off to be write offset. */
463 	b = (struct buf *)cookie;
464 
465 	avail = b->size - b->off;
466 	if (size > avail)
467 		buf_grow(b, b->size + size);
468 	memcpy((b->buf + b->off), buf, size);
469 	b->off += size;
470 	b->buf[b->off] = '\0';
471 	return (size);
472 }
473 
474 /* Convenience close function for freeing character buffers. */
475 int
stream_close_buf(void * cookie)476 stream_close_buf(void *cookie)
477 {
478 	void *data;
479 
480 	data = cookie;
481 	/* Basically a NOP. */
482 	return (0);
483 }
484 
485 /* Convenience read function for file descriptors. */
486 ssize_t
stream_read_fd(void * cookie,void * buf,size_t size)487 stream_read_fd(void *cookie, void *buf, size_t size)
488 {
489 	ssize_t nbytes;
490 	int fd;
491 
492 	fd = *(int *)cookie;
493 	nbytes = read(fd, buf, size);
494 	return (nbytes);
495 }
496 
497 /* Convenience write function for file descriptors. */
498 ssize_t
stream_write_fd(void * cookie,const void * buf,size_t size)499 stream_write_fd(void *cookie, const void *buf, size_t size)
500 {
501 	ssize_t nbytes;
502 	int fd;
503 
504 	fd = *(int *)cookie;
505 	nbytes = write(fd, buf, size);
506 	return (nbytes);
507 }
508 
509 /* Convenience close function for file descriptors. */
510 int
stream_close_fd(void * cookie)511 stream_close_fd(void *cookie)
512 {
513 	int fd, ret;
514 
515 	fd = *(int *)cookie;
516 	ret = close(fd);
517 	return (ret);
518 }
519 
520 /* Read some bytes from the stream. */
521 ssize_t
stream_read(struct stream * stream,void * buf,size_t size)522 stream_read(struct stream *stream, void *buf, size_t size)
523 {
524 	struct buf *rdbuf;
525 	ssize_t ret;
526 	size_t n;
527 
528 	rdbuf = stream->rdbuf;
529 	if (buf_count(rdbuf) == 0) {
530 		ret = stream_fill(stream);
531 		if (ret <= 0)
532 			return (-1);
533 	}
534 	n = min(size, buf_count(rdbuf));
535 	memcpy(buf, rdbuf->buf + rdbuf->off, n);
536 	buf_less(rdbuf, n);
537 	return (n);
538 }
539 
540 /* A blocking stream_read call. */
541 ssize_t
stream_read_blocking(struct stream * stream,void * buf,size_t size)542 stream_read_blocking(struct stream *stream, void *buf, size_t size)
543 {
544 	struct buf *rdbuf;
545 	ssize_t ret;
546 	size_t n;
547 
548 	rdbuf = stream->rdbuf;
549 	while (buf_count(rdbuf) <= size) {
550 		ret = stream_fill(stream);
551 		if (ret <= 0)
552 			return (-1);
553 	}
554 	/* XXX: Should be at least size bytes in the buffer, right? */
555 	/* Just do this to make sure. */
556 	n = min(size, buf_count(rdbuf));
557 	memcpy(buf, rdbuf->buf + rdbuf->off, n);
558 	buf_less(rdbuf, n);
559 	return (n);
560 }
561 
562 /*
563  * Read a line from the stream and return a pointer to it.
564  *
565  * If "len" is non-NULL, the length of the string will be put into it.
566  * The pointer is only valid until the next stream API call.  The line
567  * can be modified by the caller, provided he doesn't write before or
568  * after it.
569  *
570  * This is somewhat similar to the BSD fgetln() function, except that
571  * "len" can be NULL here.  In that case the string is terminated by
572  * overwriting the '\n' character with a NUL character.  If it's the
573  * last line in the stream and it has no ending newline, we can still
574  * add '\0' after it, because we keep one spare byte in the buffers.
575  *
576  * However, be warned that one can't handle binary lines properly
577  * without knowing the size of the string since those can contain
578  * NUL characters.
579  */
580 char *
stream_getln(struct stream * stream,size_t * len)581 stream_getln(struct stream *stream, size_t *len)
582 {
583 	struct buf *buf;
584 	char *cp, *line;
585 	ssize_t n;
586 	size_t done, size;
587 
588 	buf = stream->rdbuf;
589 	if (buf_count(buf) == 0) {
590 		n = stream_fill(stream);
591 		if (n <= 0)
592 			return (NULL);
593 	}
594 	cp = memchr(buf->buf + buf->off, '\n', buf_count(buf));
595 	for (done = buf_count(buf); cp == NULL; done += n) {
596 		n = stream_fill(stream);
597 		if (n < 0)
598 			return (NULL);
599 		if (n == 0)
600 			/* Last line of the stream. */
601 			cp = buf->buf + buf->off + buf->in - 1;
602 		else
603 			cp = memchr(buf->buf + buf->off + done, '\n',
604 			    buf_count(buf) - done);
605 	}
606 	line = buf->buf + buf->off;
607 	assert(cp >= line);
608 	size = cp - line + 1;
609 	buf_less(buf, size);
610 	if (len != NULL) {
611 		*len = size;
612 	} else {
613 		/* Terminate the string when len == NULL. */
614 		if (line[size - 1] == '\n')
615 			line[size - 1] = '\0';
616 		else
617 			line[size] = '\0';
618 	}
619 	return (line);
620 }
621 
622 /* Write some bytes to a stream. */
623 ssize_t
stream_write(struct stream * stream,const void * src,size_t nbytes)624 stream_write(struct stream *stream, const void *src, size_t nbytes)
625 {
626 	struct buf *buf;
627 	int error;
628 
629 	buf = stream->wrbuf;
630 	if (nbytes > buf_size(buf))
631 		buf_grow(buf, nbytes);
632 	if (nbytes > buf_avail(buf)) {
633 		error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
634 		if (error)
635 			return (-1);
636 	}
637 	memcpy(buf->buf + buf->off + buf->in, src, nbytes);
638 	buf_more(buf, nbytes);
639 	return (nbytes);
640 }
641 
642 /* Formatted output to a stream. */
643 int
stream_printf(struct stream * stream,const char * fmt,...)644 stream_printf(struct stream *stream, const char *fmt, ...)
645 {
646 	struct buf *buf;
647 	va_list ap;
648 	int error, ret;
649 
650 	buf = stream->wrbuf;
651 again:
652 	va_start(ap, fmt);
653 	ret = vsnprintf(buf->buf + buf->off + buf->in, buf_avail(buf), fmt, ap);
654 	va_end(ap);
655 	if (ret < 0)
656 		return (ret);
657 	if ((unsigned)ret >= buf_avail(buf)) {
658 		if ((unsigned)ret >= buf_size(buf))
659 			buf_grow(buf, ret + 1);
660 		if ((unsigned)ret >= buf_avail(buf)) {
661 			error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
662 			if (error)
663 				return (-1);
664 		}
665 		goto again;
666 	}
667 	buf_more(buf, ret);
668 	return (ret);
669 }
670 
671 /* Flush the entire write buffer of the stream. */
672 int
stream_flush(struct stream * stream)673 stream_flush(struct stream *stream)
674 {
675 	int error;
676 
677 	error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
678 	return (error);
679 }
680 
681 /* Internal flush API. */
682 static int
stream_flush_int(struct stream * stream,stream_flush_t how)683 stream_flush_int(struct stream *stream, stream_flush_t how)
684 {
685 	struct buf *buf;
686 	int error;
687 
688 	buf = stream->wrbuf;
689 	error = (*stream->filter->flushfn)(stream, buf, how);
690 	assert(buf_count(buf) == 0);
691 	return (error);
692 }
693 
694 /* The default flush method. */
695 static int
stream_flush_default(struct stream * stream,struct buf * buf,stream_flush_t __unused how)696 stream_flush_default(struct stream *stream, struct buf *buf,
697     stream_flush_t __unused how)
698 {
699 	ssize_t n;
700 
701 	while (buf_count(buf) > 0) {
702 		do {
703 			n = (*stream->writefn)(stream->cookie,
704 			    buf->buf + buf->off, buf_count(buf));
705 		} while (n == -1 && errno == EINTR);
706 		if (n <= 0)
707 			return (-1);
708 		buf_less(buf, n);
709 	}
710 	return (0);
711 }
712 
713 /* Flush the write buffer and call fsync() on the file descriptor. */
714 int
stream_sync(struct stream * stream)715 stream_sync(struct stream *stream)
716 {
717 	int error;
718 
719 	if (stream->fd == -1) {
720 		errno = EINVAL;
721 		return (-1);
722 	}
723 	error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
724 	if (error)
725 		return (-1);
726 	error = fsync(stream->fd);
727 	return (error);
728 }
729 
730 /* Like truncate() but on a stream. */
731 int
stream_truncate(struct stream * stream,off_t size)732 stream_truncate(struct stream *stream, off_t size)
733 {
734 	int error;
735 
736 	if (stream->fd == -1) {
737 		errno = EINVAL;
738 		return (-1);
739 	}
740 	error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
741 	if (error)
742 		return (-1);
743 	error = ftruncate(stream->fd, size);
744 	return (error);
745 }
746 
747 /* Like stream_truncate() except the off_t parameter is an offset. */
748 int
stream_truncate_rel(struct stream * stream,off_t off)749 stream_truncate_rel(struct stream *stream, off_t off)
750 {
751 	struct stat sb;
752 	int error;
753 
754 	if (stream->buf) {
755 		stream_truncate_buf(stream->cookie, off);
756 		return (0);
757 	}
758 	if (stream->fd == -1) {
759 		errno = EINVAL;
760 		return (-1);
761 	}
762 	error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
763 	if (error)
764 		return (-1);
765 	error = fstat(stream->fd, &sb);
766 	if (error)
767 		return (-1);
768 	error = stream_truncate(stream, sb.st_size + off);
769 	return (error);
770 }
771 
772 /* Rewind the stream. */
773 int
stream_rewind(struct stream * stream)774 stream_rewind(struct stream *stream)
775 {
776 	int error;
777 
778 	if (stream->fd == -1) {
779 		errno = EINVAL;
780 		return (-1);
781 	}
782 	if (stream->rdbuf != NULL)
783 		buf_less(stream->rdbuf, buf_count(stream->rdbuf));
784 	if (stream->wrbuf != NULL) {
785 		error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
786 		if (error)
787 			return (error);
788 	}
789 	error = lseek(stream->fd, 0, SEEK_SET);
790 	return (error);
791 }
792 
793 /* Return EOF status. */
794 int
stream_eof(struct stream * stream)795 stream_eof(struct stream *stream)
796 {
797 
798 	return (stream->eof);
799 }
800 
801 /* Close a stream and free any resources held by it. */
802 int
stream_close(struct stream * stream)803 stream_close(struct stream *stream)
804 {
805 	int error;
806 
807 	if (stream == NULL)
808 		return (0);
809 
810 	error = 0;
811 	if (stream->wrbuf != NULL)
812 		error = stream_flush_int(stream, STREAM_FLUSH_CLOSING);
813 	stream_filter_fini(stream);
814 	if (stream->closefn != NULL)
815 		/*
816 		 * We might overwrite a previous error from stream_flush(),
817 		 * but we have no choice, because wether it had worked or
818 		 * not, we need to close the file descriptor.
819 		 */
820 		error = (*stream->closefn)(stream->cookie);
821 	if (stream->rdbuf != NULL)
822 		buf_free(stream->rdbuf);
823 	if (stream->wrbuf != NULL)
824 		buf_free(stream->wrbuf);
825 	free(stream);
826 	return (error);
827 }
828 
829 /* The default fill method. */
830 static ssize_t
stream_fill_default(struct stream * stream,struct buf * buf)831 stream_fill_default(struct stream *stream, struct buf *buf)
832 {
833 	ssize_t n;
834 
835 	if (stream->eof)
836 		return (0);
837 	assert(buf_avail(buf) > 0);
838 	n = (*stream->readfn)(stream->cookie, buf->buf + buf->off + buf->in,
839 	    buf_avail(buf));
840 	if (n < 0)
841 		return (-1);
842 	if (n == 0) {
843 		stream->eof = 1;
844 		return (0);
845 	}
846 	buf_more(buf, n);
847 	return (n);
848 }
849 
850 /*
851  * Refill the read buffer.  This function is not permitted to return
852  * without having made more bytes available, unless there was an error.
853  * Moreover, stream_fill() returns the number of bytes added.
854  */
855 static ssize_t
stream_fill(struct stream * stream)856 stream_fill(struct stream *stream)
857 {
858 	struct stream_filter *filter;
859 	struct buf *buf;
860 #ifndef NDEBUG
861 	size_t oldcount;
862 #endif
863 	ssize_t n;
864 
865 	filter = stream->filter;
866 	buf = stream->rdbuf;
867 	buf_prewrite(buf);
868 #ifndef NDEBUG
869 	oldcount = buf_count(buf);
870 #endif
871 	n = (*filter->fillfn)(stream, buf);
872 	assert((n > 0 && n == (signed)(buf_count(buf) - oldcount)) ||
873 	    (n <= 0 && buf_count(buf) == oldcount));
874 	return (n);
875 }
876 
877 /*
878  * Lookup a stream filter.
879  *
880  * We are not supposed to get passed an invalid filter id, since
881  * filter ids are an enum type and we don't have invalid filter
882  * ids in the enum :-).  Thus, we are not checking for out of
883  * bounds access here.  If it happens, it's the caller's fault
884  * anyway.
885  */
886 static struct stream_filter *
stream_filter_lookup(stream_filter_t id)887 stream_filter_lookup(stream_filter_t id)
888 {
889 	struct stream_filter *filter;
890 
891 	filter = stream_filters;
892 	while (filter->id != id)
893 		filter++;
894 	return (filter);
895 }
896 
897 static int
stream_filter_init(struct stream * stream,void * data)898 stream_filter_init(struct stream *stream, void *data)
899 {
900 	struct stream_filter *filter;
901 	int error;
902 
903 	filter = stream->filter;
904 	if (filter->initfn == NULL)
905 		return (0);
906 	error = (*filter->initfn)(stream, data);
907 	return (error);
908 }
909 
910 static void
stream_filter_fini(struct stream * stream)911 stream_filter_fini(struct stream *stream)
912 {
913 	struct stream_filter *filter;
914 
915 	filter = stream->filter;
916 	if (filter->finifn != NULL)
917 		(*filter->finifn)(stream);
918 }
919 
920 /*
921  * Start a filter on a stream.
922  */
923 int
stream_filter_start(struct stream * stream,stream_filter_t id,void * data)924 stream_filter_start(struct stream *stream, stream_filter_t id, void *data)
925 {
926 	struct stream_filter *filter;
927 	int error;
928 
929 	filter = stream->filter;
930 	if (id == filter->id)
931 		return (0);
932 	stream_filter_fini(stream);
933 	stream->filter = stream_filter_lookup(id);
934 	stream->fdata = NULL;
935 	error = stream_filter_init(stream, data);
936 	return (error);
937 }
938 
939 
940 /* Stop a filter, this is equivalent to setting the null filter. */
941 void
stream_filter_stop(struct stream * stream)942 stream_filter_stop(struct stream *stream)
943 {
944 
945 	stream_filter_start(stream, STREAM_FILTER_NULL, NULL);
946 }
947 
948 /* The zlib stream filter implementation. */
949 
950 /* Take no chances with zlib... */
951 static void *
zfilter_alloc(void __unused * opaque,unsigned int items,unsigned int size)952 zfilter_alloc(void __unused *opaque, unsigned int items, unsigned int size)
953 {
954 
955 	return (xmalloc(items * size));
956 }
957 
958 static void
zfilter_free(void __unused * opaque,void * ptr)959 zfilter_free(void __unused *opaque, void *ptr)
960 {
961 
962 	free(ptr);
963 }
964 
965 static int
zfilter_init(struct stream * stream,void __unused * data)966 zfilter_init(struct stream *stream, void __unused *data)
967 {
968 	struct zfilter *zf;
969 	struct buf *buf;
970 	z_stream *state;
971 	int rv;
972 
973 	zf = xmalloc(sizeof(struct zfilter));
974 	memset(zf, 0, sizeof(struct zfilter));
975 	if (stream->rdbuf != NULL) {
976 		state = xmalloc(sizeof(z_stream));
977 		state->zalloc = zfilter_alloc;
978 		state->zfree = zfilter_free;
979 		state->opaque = Z_NULL;
980 		rv = inflateInit(state);
981 		if (rv != Z_OK)
982 			errx(1, "inflateInit: %s", state->msg);
983 		buf = buf_new(buf_size(stream->rdbuf));
984 		zf->rdbuf = stream->rdbuf;
985 		stream->rdbuf = buf;
986 		zf->rdstate = state;
987 	}
988 	if (stream->wrbuf != NULL) {
989 		state = xmalloc(sizeof(z_stream));
990 		state->zalloc = zfilter_alloc;
991 		state->zfree = zfilter_free;
992 		state->opaque = Z_NULL;
993 		rv = deflateInit(state, Z_DEFAULT_COMPRESSION);
994 		if (rv != Z_OK)
995 			errx(1, "deflateInit: %s", state->msg);
996 		buf = buf_new(buf_size(stream->wrbuf));
997 		zf->wrbuf = stream->wrbuf;
998 		stream->wrbuf = buf;
999 		zf->wrstate = state;
1000 	}
1001 	stream->fdata = zf;
1002 	return (0);
1003 }
1004 
1005 static void
zfilter_fini(struct stream * stream)1006 zfilter_fini(struct stream *stream)
1007 {
1008 	struct zfilter *zf;
1009 	struct buf *zbuf;
1010 	z_stream *state;
1011 	ssize_t n;
1012 
1013 	zf = stream->fdata;
1014 	if (zf->rdbuf != NULL) {
1015 		state = zf->rdstate;
1016 		zbuf = zf->rdbuf;
1017 		/*
1018 		 * Even if it has produced all the bytes, zlib sometimes
1019 		 * hasn't seen the EOF marker, so we need to call inflate()
1020 		 * again to make sure we have eaten all the zlib'ed bytes.
1021 		 */
1022 		if ((zf->flags & ZFILTER_EOF) == 0) {
1023 			n = zfilter_fill(stream, stream->rdbuf);
1024 			assert(n == 0 && zf->flags & ZFILTER_EOF);
1025 		}
1026 		inflateEnd(state);
1027 		free(state);
1028 		buf_free(stream->rdbuf);
1029 		stream->rdbuf = zbuf;
1030 	}
1031 	if (zf->wrbuf != NULL) {
1032 		state = zf->wrstate;
1033 		zbuf = zf->wrbuf;
1034 		/*
1035 		 * Compress the remaining bytes in the buffer, if any,
1036 		 * and emit an EOF marker as appropriate.  We ignore
1037 		 * the error because we can't do anything about it at
1038 		 * this point, and it can happen if we're getting
1039 		 * disconnected.
1040 		 */
1041 		(void)zfilter_flush(stream, stream->wrbuf,
1042 		    STREAM_FLUSH_CLOSING);
1043 		deflateEnd(state);
1044 		free(state);
1045 		buf_free(stream->wrbuf);
1046 		stream->wrbuf = zbuf;
1047 	}
1048 	free(zf);
1049 }
1050 
1051 static int
zfilter_flush(struct stream * stream,struct buf * buf,stream_flush_t how)1052 zfilter_flush(struct stream *stream, struct buf *buf, stream_flush_t how)
1053 {
1054 	struct zfilter *zf;
1055 	struct buf *zbuf;
1056 	z_stream *state;
1057 	size_t lastin, lastout, ate, prod;
1058 	int done, error, flags, rv;
1059 
1060 	zf = stream->fdata;
1061 	state = zf->wrstate;
1062 	zbuf = zf->wrbuf;
1063 
1064 	if (how == STREAM_FLUSH_NORMAL)
1065 		flags = Z_SYNC_FLUSH;
1066 	else
1067 		flags = Z_FINISH;
1068 
1069 	done = 0;
1070 	rv = Z_OK;
1071 
1072 again:
1073 	/*
1074 	 * According to zlib.h, we should have at least 6 bytes
1075 	 * available when using deflate() with Z_SYNC_FLUSH.
1076 	 */
1077 	if ((buf_avail(zbuf) < 6 && flags == Z_SYNC_FLUSH) ||
1078 	    rv == Z_BUF_ERROR || buf_avail(buf) == 0) {
1079 		error = stream_flush_default(stream, zbuf, how);
1080 		if (error)
1081 			return (error);
1082 	}
1083 
1084 	state->next_in = (Bytef *)(buf->buf + buf->off);
1085 	state->avail_in = buf_count(buf);
1086 	state->next_out = (Bytef *)(zbuf->buf + zbuf->off + zbuf->in);
1087 	state->avail_out = buf_avail(zbuf);
1088 	lastin = state->avail_in;
1089 	lastout = state->avail_out;
1090 	rv = deflate(state, flags);
1091 	if (rv != Z_BUF_ERROR && rv != Z_OK && rv != Z_STREAM_END)
1092 		errx(1, "deflate: %s", state->msg);
1093 	ate = lastin - state->avail_in;
1094 	prod = lastout - state->avail_out;
1095 	buf_less(buf, ate);
1096 	buf_more(zbuf, prod);
1097 	if ((flags == Z_SYNC_FLUSH && buf_count(buf) > 0) ||
1098 	    (flags == Z_FINISH && rv != Z_STREAM_END) ||
1099 	    (rv == Z_BUF_ERROR))
1100 		goto again;
1101 
1102 	assert(rv == Z_OK || (rv == Z_STREAM_END && flags == Z_FINISH));
1103 	error = stream_flush_default(stream, zbuf, how);
1104 	return (error);
1105 }
1106 
1107 static ssize_t
zfilter_fill(struct stream * stream,struct buf * buf)1108 zfilter_fill(struct stream *stream, struct buf *buf)
1109 {
1110 	struct zfilter *zf;
1111 	struct buf *zbuf;
1112 	z_stream *state;
1113 	size_t lastin, lastout, new;
1114 	ssize_t n;
1115 	int rv;
1116 
1117 	zf = stream->fdata;
1118 	state = zf->rdstate;
1119 	zbuf = zf->rdbuf;
1120 
1121 	assert(buf_avail(buf) > 0);
1122 	if (buf_count(zbuf) == 0) {
1123 		n = stream_fill_default(stream, zbuf);
1124 		if (n <= 0)
1125 			return (n);
1126 	}
1127 again:
1128 	assert(buf_count(zbuf) > 0);
1129 	state->next_in = (Bytef *)(zbuf->buf + zbuf->off);
1130 	state->avail_in = buf_count(zbuf);
1131 	state->next_out = (Bytef *)(buf->buf + buf->off + buf->in);
1132 	state->avail_out = buf_avail(buf);
1133 	lastin = state->avail_in;
1134 	lastout = state->avail_out;
1135 	rv = inflate(state, Z_SYNC_FLUSH);
1136 	buf_less(zbuf, lastin - state->avail_in);
1137 	new = lastout - state->avail_out;
1138 	if (new == 0 && rv != Z_STREAM_END) {
1139 		n = stream_fill_default(stream, zbuf);
1140 		if (n == -1)
1141 			return (-1);
1142 		if (n == 0)
1143 			return (0);
1144 		goto again;
1145 	}
1146 	if (rv != Z_STREAM_END && rv != Z_OK)
1147 		errx(1, "inflate: %s", state->msg);
1148 	if (rv == Z_STREAM_END)
1149 		zf->flags |= ZFILTER_EOF;
1150 	buf_more(buf, new);
1151 	return (new);
1152 }
1153 
1154 /* The MD5 stream filter implementation. */
1155 static int
md5filter_init(struct stream * stream,void * data)1156 md5filter_init(struct stream *stream, void *data)
1157 {
1158 	struct md5filter *mf;
1159 
1160 	mf = xmalloc(sizeof(struct md5filter));
1161 	MD5_Init(&mf->ctx);
1162 	mf->md5 = data;
1163 	mf->lastc = ';';
1164 	mf->state = PRINT;
1165 	stream->fdata = mf;
1166 	return (0);
1167 }
1168 
1169 static void
md5filter_fini(struct stream * stream)1170 md5filter_fini(struct stream *stream)
1171 {
1172 	struct md5filter *mf;
1173 
1174 	mf = stream->fdata;
1175 	MD5_End(mf->md5, &mf->ctx);
1176 	free(stream->fdata);
1177 }
1178 
1179 static ssize_t
md5filter_fill(struct stream * stream,struct buf * buf)1180 md5filter_fill(struct stream *stream, struct buf *buf)
1181 {
1182 	ssize_t n;
1183 
1184 	assert(buf_avail(buf) > 0);
1185 	n = stream_fill_default(stream, buf);
1186 	return (n);
1187 }
1188 
1189 static int
md5filter_flush(struct stream * stream,struct buf * buf,stream_flush_t how)1190 md5filter_flush(struct stream *stream, struct buf *buf, stream_flush_t how)
1191 {
1192 	struct md5filter *mf;
1193 	int error;
1194 
1195 	mf = stream->fdata;
1196 	MD5_Update(&mf->ctx, buf->buf + buf->off, buf->in);
1197 	error = stream_flush_default(stream, buf, how);
1198 	return (error);
1199 }
1200 
1201 /* MD5 flush for RCS, where whitespaces are omitted. */
1202 static int
md5rcsfilter_flush(struct stream * stream,struct buf * buf,stream_flush_t how)1203 md5rcsfilter_flush(struct stream *stream, struct buf *buf, stream_flush_t how)
1204 {
1205 	struct md5filter *mf;
1206 	char *ptr, *end;
1207 	char *start;
1208 	char space[2];
1209 	int error;
1210 
1211 	mf = stream->fdata;
1212 	space[0] = ' ';
1213 	space[1] = '\0';
1214 	ptr = buf->buf + buf->off;
1215 	end = buf->buf + buf->off + buf->in;
1216 
1217 #define IS_WS(var) ((var) == ' ' || (var) == '\n' || (var) == '\t' || \
1218                     (var) == '\010' || (var) == '\013' || (var) == '\f' || \
1219                     (var) == '\r')
1220 
1221 #define IS_SPECIAL(var) ((var) == '$' || (var) == ',' || (var) == ':' || \
1222 			 (var) == ';' || (var) == '@')
1223 
1224 #define IS_PRINT(var) (!IS_WS(var) && (var) != '@')
1225 
1226 	/* XXX: We can do better than this state machine. */
1227 	while (ptr < end) {
1228 		switch (mf->state) {
1229 			/* Outside RCS statements. */
1230 			case PRINT:
1231 				start = ptr;
1232 				while (ptr < end && IS_PRINT(*ptr)) {
1233 					mf->lastc = *ptr;
1234 					ptr++;
1235 				}
1236 				MD5_Update(&mf->ctx, start, (ptr - start));
1237 				if (ptr < end) {
1238 					if (*ptr == '@') {
1239 						MD5_Update(&mf->ctx, ptr, 1);
1240 						ptr++;
1241 						mf->state = STRING;
1242 					} else {
1243 						mf->state = WS;
1244 					}
1245 				}
1246 				break;
1247 			case WS:
1248 				while (ptr < end && IS_WS(*ptr)) {
1249 					ptr++;
1250 				}
1251 				if (ptr < end) {
1252 					if (*ptr == '@') {
1253 						if (mf->lastc == '@') {
1254 							MD5_Update(&mf->ctx,
1255 							    space, 1);
1256 						}
1257 						MD5_Update(&mf->ctx, ptr, 1);
1258 						ptr++;
1259 						mf->state = STRING;
1260 					} else {
1261 						if (!IS_SPECIAL(*ptr) &&
1262 						    !IS_SPECIAL(mf->lastc)) {
1263 							MD5_Update(&mf->ctx,
1264 							    space, 1);
1265 						}
1266 						mf->state = PRINT;
1267 					}
1268 				}
1269 				break;
1270 			case STRING:
1271 				start = ptr;
1272 				while (ptr < end && *ptr != '@') {
1273 					ptr++;
1274 				}
1275 				MD5_Update(&mf->ctx, start, (ptr - start));
1276 				if (ptr < end) {
1277 					MD5_Update(&mf->ctx, ptr, 1);
1278 					ptr++;
1279 					mf->state = SEEN;
1280 				}
1281 				break;
1282 			case SEEN:
1283 				if (*ptr == '@') {
1284 					MD5_Update(&mf->ctx, ptr, 1);
1285 					ptr++;
1286 					mf->state = STRING;
1287 				} else if(IS_WS(*ptr)) {
1288 					mf->lastc = '@';
1289 					mf->state = WS;
1290 				} else {
1291 					mf->state = PRINT;
1292 				}
1293 				break;
1294 			default:
1295 				err(1, "Invalid state");
1296 				break;
1297 		}
1298 	}
1299 
1300 	error = stream_flush_default(stream, buf, how);
1301 	return (error);
1302 }
1303 
1304