]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/csup/stream.c
This commit was generated by cvs2svn to compensate for changes in r161389,
[FreeBSD/FreeBSD.git] / contrib / csup / stream.c
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         struct buf *rdbuf;
101         struct buf *wrbuf;
102         stream_readfn_t *readfn;
103         stream_writefn_t *writefn;
104         stream_closefn_t *closefn;
105         int eof;
106         struct stream_filter *filter;
107         void *fdata;
108 };
109
110 typedef int     stream_filter_initfn_t(struct stream *, void *);
111 typedef void    stream_filter_finifn_t(struct stream *);
112 typedef int     stream_filter_flushfn_t(struct stream *, struct buf *,
113                     stream_flush_t);
114 typedef ssize_t stream_filter_fillfn_t(struct stream *, struct buf *);
115
116 struct stream_filter {
117         stream_filter_t id;
118         stream_filter_initfn_t *initfn;
119         stream_filter_finifn_t *finifn;
120         stream_filter_fillfn_t *fillfn;
121         stream_filter_flushfn_t *flushfn;
122 };
123
124 /* Low-level buffer API. */
125 #define buf_avail(buf)          ((buf)->size - (buf)->off - (buf)->in)
126 #define buf_count(buf)          ((buf)->in)
127 #define buf_size(buf)           ((buf)->size)
128
129 static struct buf       *buf_new(size_t);
130 static void              buf_more(struct buf *, size_t);
131 static void              buf_less(struct buf *, size_t);
132 static void              buf_free(struct buf *);
133 static void              buf_grow(struct buf *, size_t);
134
135 /* Internal stream functions. */
136 static ssize_t           stream_fill(struct stream *);
137 static ssize_t           stream_fill_default(struct stream *, struct buf *);
138 static int               stream_flush_int(struct stream *, stream_flush_t);
139 static int               stream_flush_default(struct stream *, struct buf *,
140                              stream_flush_t);
141
142 /* Filters specific functions. */
143 static struct stream_filter *stream_filter_lookup(stream_filter_t);
144 static int               stream_filter_init(struct stream *, void *);
145 static void              stream_filter_fini(struct stream *);
146
147 /* The zlib stream filter declarations. */
148 #define ZFILTER_EOF     1                               /* Got Z_STREAM_END. */
149
150 struct zfilter {
151         int flags;
152         struct buf *rdbuf;
153         struct buf *wrbuf;
154         z_stream *rdstate;
155         z_stream *wrstate;
156 };
157
158 static int               zfilter_init(struct stream *, void *);
159 static void              zfilter_fini(struct stream *);
160 static ssize_t           zfilter_fill(struct stream *, struct buf *);
161 static int               zfilter_flush(struct stream *, struct buf *,
162                              stream_flush_t);
163
164 /* The MD5 stream filter. */
165 struct md5filter {
166         MD5_CTX ctx;
167         char *md5;
168 };
169
170 static int               md5filter_init(struct stream *, void *);
171 static void              md5filter_fini(struct stream *);
172 static ssize_t           md5filter_fill(struct stream *, struct buf *);
173 static int               md5filter_flush(struct stream *, struct buf *,
174                              stream_flush_t);
175
176 /* The available stream filters. */
177 struct stream_filter stream_filters[] = {
178         {
179                 STREAM_FILTER_NULL,
180                 NULL,
181                 NULL,
182                 stream_fill_default,
183                 stream_flush_default
184         },
185         {
186                 STREAM_FILTER_ZLIB,
187                 zfilter_init,
188                 zfilter_fini,
189                 zfilter_fill,
190                 zfilter_flush
191         },
192         {
193                 STREAM_FILTER_MD5,
194                 md5filter_init,
195                 md5filter_fini,
196                 md5filter_fill,
197                 md5filter_flush
198         }
199 };
200
201
202 /* Create a new buffer. */
203 static struct buf *
204 buf_new(size_t size)
205 {
206         struct buf *buf;
207
208         buf = xmalloc(sizeof(struct buf));
209         /*
210          * We keep one spare byte so that stream_getln() can put a '\0'
211          * there in case the stream doesn't have an ending newline.
212          */
213         buf->buf = xmalloc(size + 1);
214         buf->size = size;
215         buf->in = 0;
216         buf->off = 0;
217         return (buf);
218 }
219
220 /*
221  * Grow the size of the buffer.  If "need" is 0, bump its size to the
222  * next power of 2 value.  Otherwise, bump it to the next power of 2
223  * value bigger than "need".
224  */
225 static void
226 buf_grow(struct buf *buf, size_t need)
227 {
228
229         if (need == 0)
230                 buf->size = buf->size * 2 + 1; /* Account for the spare byte. */
231         else {
232                 assert(need > buf->size);
233                 while (buf->size < need)
234                         buf->size = buf->size * 2 + 1;
235         }
236         buf->buf = xrealloc(buf->buf, buf->size + 1);
237 }
238
239 /* Make more room in the buffer if needed. */
240 static void
241 buf_prewrite(struct buf *buf)
242 {
243
244         if (buf_count(buf) == buf_size(buf))
245                 buf_grow(buf, 0);
246         if (buf_count(buf) > 0 && buf_avail(buf) == 0) {
247                 memmove(buf->buf, buf->buf + buf->off, buf_count(buf));
248                 buf->off = 0;
249         }
250 }
251
252 /* Account for "n" bytes being added in the buffer. */
253 static void
254 buf_more(struct buf *buf, size_t n)
255 {
256
257         assert(n <= buf_avail(buf));
258         buf->in += n;
259 }
260
261 /* Account for "n" bytes having been read in the buffer. */
262 static void
263 buf_less(struct buf *buf, size_t n)
264 {
265
266         assert(n <= buf_count(buf));
267         buf->in -= n;
268         if (buf->in == 0)
269                 buf->off = 0;
270         else
271                 buf->off += n;
272 }
273
274 /* Free a buffer. */
275 static void
276 buf_free(struct buf *buf)
277 {
278
279         free(buf->buf);
280         free(buf);
281 }
282
283 static struct stream *
284 stream_new(stream_readfn_t *readfn, stream_writefn_t *writefn,
285     stream_closefn_t *closefn)
286 {
287         struct stream *stream;
288
289         stream = xmalloc(sizeof(struct stream));
290         if (readfn == NULL && writefn == NULL) {
291                 errno = EINVAL;
292                 return (NULL);
293         }
294         if (readfn != NULL)
295                 stream->rdbuf = buf_new(STREAM_BUFSIZ);
296         else
297                 stream->rdbuf = NULL;
298         if (writefn != NULL)
299                 stream->wrbuf = buf_new(STREAM_BUFSIZ);
300         else
301                 stream->wrbuf = NULL;
302         stream->cookie = NULL;
303         stream->fd = -1;
304         stream->readfn = readfn;
305         stream->writefn = writefn;
306         stream->closefn = closefn;
307         stream->filter = stream_filter_lookup(STREAM_FILTER_NULL);
308         stream->fdata = NULL;
309         stream->eof = 0;
310         return (stream);
311 }
312
313 /* Create a new stream associated with a void *. */
314 struct stream *
315 stream_open(void *cookie, stream_readfn_t *readfn, stream_writefn_t *writefn,
316     stream_closefn_t *closefn)
317 {
318         struct stream *stream;
319
320         stream = stream_new(readfn, writefn, closefn);
321         stream->cookie = cookie;
322         return (stream);
323 }
324
325 /* Associate a file descriptor with a stream. */
326 struct stream *
327 stream_open_fd(int fd, stream_readfn_t *readfn, stream_writefn_t *writefn,
328     stream_closefn_t *closefn)
329 {
330         struct stream *stream;
331
332         stream = stream_new(readfn, writefn, closefn);
333         stream->cookie = &stream->fd;
334         stream->fd = fd;
335         return (stream);
336 }
337
338 /* Like open() but returns a stream. */
339 struct stream *
340 stream_open_file(const char *path, int flags, ...)
341 {
342         struct stream *stream;
343         stream_readfn_t *readfn;
344         stream_writefn_t *writefn;
345         va_list ap;
346         mode_t mode;
347         int fd;
348
349         va_start(ap, flags);
350         if (flags & O_CREAT) {
351                 /*
352                  * GCC says I should not be using mode_t here since it's
353                  * promoted to an int when passed through `...'.
354                  */
355                 mode = va_arg(ap, int);
356                 fd = open(path, flags, mode);
357         } else
358                 fd = open(path, flags);
359         va_end(ap);
360         if (fd == -1)
361                 return (NULL);
362
363         flags &= O_ACCMODE;
364         if (flags == O_RDONLY) {
365                 readfn = stream_read_fd;
366                 writefn = NULL;
367         } else if (flags == O_WRONLY) {
368                 readfn = NULL;
369                 writefn = stream_write_fd;
370         } else if (flags == O_RDWR) {
371                 assert(flags == O_RDWR);
372                 readfn = stream_read_fd;
373                 writefn = stream_write_fd;
374         } else {
375                 errno = EINVAL;
376                 close(fd);
377                 return (NULL);
378         }
379
380         stream = stream_open_fd(fd, readfn, writefn, stream_close_fd);
381         if (stream == NULL)
382                 close(fd);
383         return (stream);
384 }
385
386 /* Return the file descriptor associated with this stream, or -1. */
387 int
388 stream_fileno(struct stream *stream)
389 {
390
391         return (stream->fd);
392 }
393
394 /* Convenience read function for file descriptors. */
395 ssize_t
396 stream_read_fd(void *cookie, void *buf, size_t size)
397 {
398         ssize_t nbytes;
399         int fd;
400
401         fd = *(int *)cookie;
402         nbytes = read(fd, buf, size);
403         return (nbytes);
404 }
405
406 /* Convenience write function for file descriptors. */
407 ssize_t
408 stream_write_fd(void *cookie, const void *buf, size_t size)
409 {
410         ssize_t nbytes;
411         int fd;
412
413         fd = *(int *)cookie;
414         nbytes = write(fd, buf, size);
415         return (nbytes);
416 }
417
418 /* Convenience close function for file descriptors. */
419 int
420 stream_close_fd(void *cookie)
421 {
422         int fd, ret;
423
424         fd = *(int *)cookie;
425         ret = close(fd);
426         return (ret);
427 }
428
429 /* Read some bytes from the stream. */
430 ssize_t
431 stream_read(struct stream *stream, void *buf, size_t size)
432 {
433         struct buf *rdbuf;
434         ssize_t ret;
435         size_t n;
436
437         rdbuf = stream->rdbuf;
438         if (buf_count(rdbuf) == 0) {
439                 ret = stream_fill(stream);
440                 if (ret <= 0)
441                         return (-1);
442         }
443         n = min(size, buf_count(rdbuf));
444         memcpy(buf, rdbuf->buf + rdbuf->off, n);
445         buf_less(rdbuf, n);
446         return (n);
447 }
448
449 /*
450  * Read a line from the stream and return a pointer to it.
451  *
452  * If "len" is non-NULL, the length of the string will be put into it.
453  * The pointer is only valid until the next stream API call.  The line
454  * can be modified by the caller, provided he doesn't write before or
455  * after it.
456  *
457  * This is somewhat similar to the BSD fgetln() function, except that
458  * "len" can be NULL here.  In that case the string is terminated by
459  * overwriting the '\n' character with a NUL character.  If it's the
460  * last line in the stream and it has no ending newline, we can still
461  * add '\0' after it, because we keep one spare byte in the buffers.
462  *
463  * However, be warned that one can't handle binary lines properly
464  * without knowing the size of the string since those can contain
465  * NUL characters.
466  */
467 char *
468 stream_getln(struct stream *stream, size_t *len)
469 {
470         struct buf *buf;
471         char *cp, *line;
472         ssize_t n;
473         size_t done, size;
474
475         buf = stream->rdbuf;
476         if (buf_count(buf) == 0) {
477                 n = stream_fill(stream);
478                 if (n <= 0)
479                         return (NULL);
480         }
481         cp = memchr(buf->buf + buf->off, '\n', buf_count(buf));
482         for (done = buf_count(buf); cp == NULL; done += n) {
483                 n = stream_fill(stream);
484                 if (n < 0)
485                         return (NULL);
486                 if (n == 0)
487                         /* Last line of the stream. */
488                         cp = buf->buf + buf->off + buf->in - 1;
489                 else
490                         cp = memchr(buf->buf + buf->off + done, '\n',
491                             buf_count(buf) - done);
492         }
493         line = buf->buf + buf->off;
494         assert(cp >= line);
495         size = cp - line + 1;
496         buf_less(buf, size);
497         if (len != NULL) {
498                 *len = size;
499         } else {
500                 /* Terminate the string when len == NULL. */
501                 if (line[size - 1] == '\n')
502                         line[size - 1] = '\0';
503                 else
504                         line[size] = '\0';
505         }
506         return (line);
507 }
508
509 /* Write some bytes to a stream. */
510 ssize_t
511 stream_write(struct stream *stream, const void *src, size_t nbytes)
512 {
513         struct buf *buf;
514         int error;
515
516         buf = stream->wrbuf;
517         if (nbytes > buf_size(buf))
518                 buf_grow(buf, nbytes);
519         if (nbytes > buf_avail(buf)) {
520                 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
521                 if (error)
522                         return (-1);
523         }
524         memcpy(buf->buf + buf->off + buf->in, src, nbytes);
525         buf_more(buf, nbytes);
526         return (nbytes);
527 }
528
529 /* Formatted output to a stream. */
530 int
531 stream_printf(struct stream *stream, const char *fmt, ...)
532 {
533         struct buf *buf;
534         va_list ap;
535         int error, ret;
536
537         buf = stream->wrbuf;
538 again:
539         va_start(ap, fmt);
540         ret = vsnprintf(buf->buf + buf->off + buf->in, buf_avail(buf), fmt, ap);
541         va_end(ap);
542         if (ret < 0)
543                 return (ret);
544         if ((unsigned)ret >= buf_avail(buf)) {
545                 if ((unsigned)ret >= buf_size(buf))
546                         buf_grow(buf, ret + 1);
547                 if ((unsigned)ret >= buf_avail(buf)) {
548                         error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
549                         if (error)
550                                 return (-1);
551                 }
552                 goto again;
553         }
554         buf_more(buf, ret);
555         return (ret);
556 }
557
558 /* Flush the entire write buffer of the stream. */
559 int
560 stream_flush(struct stream *stream)
561 {
562         int error;
563
564         error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
565         return (error);
566 }
567
568 /* Internal flush API. */
569 static int
570 stream_flush_int(struct stream *stream, stream_flush_t how)
571 {
572         struct buf *buf;
573         int error;
574
575         buf = stream->wrbuf;
576         error = (*stream->filter->flushfn)(stream, buf, how);
577         assert(buf_count(buf) == 0);
578         return (error);
579 }
580
581 /* The default flush method. */
582 static int
583 stream_flush_default(struct stream *stream, struct buf *buf,
584     stream_flush_t __unused how)
585 {
586         ssize_t n;
587
588         while (buf_count(buf) > 0) {
589                 do {
590                         n = (*stream->writefn)(stream->cookie,
591                             buf->buf + buf->off, buf_count(buf));
592                 } while (n == -1 && errno == EINTR);
593                 if (n <= 0)
594                         return (-1);
595                 buf_less(buf, n);
596         }
597         return (0);
598 }
599
600 /* Flush the write buffer and call fsync() on the file descriptor. */
601 int
602 stream_sync(struct stream *stream)
603 {
604         int error;
605
606         if (stream->fd == -1) {
607                 errno = EINVAL;
608                 return (-1);
609         }
610         error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
611         if (error)
612                 return (-1);
613         error = fsync(stream->fd);
614         return (error);
615 }
616
617 /* Like truncate() but on a stream. */
618 int
619 stream_truncate(struct stream *stream, off_t size)
620 {
621         int error;
622
623         if (stream->fd == -1) {
624                 errno = EINVAL;
625                 return (-1);
626         }
627         error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
628         if (error)
629                 return (-1);
630         error = ftruncate(stream->fd, size);
631         return (error);
632 }
633
634 /* Like stream_truncate() except the off_t parameter is an offset. */
635 int
636 stream_truncate_rel(struct stream *stream, off_t off)
637 {
638         struct stat sb;
639         int error;
640
641         if (stream->fd == -1) {
642                 errno = EINVAL;
643                 return (-1);
644         }
645         error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
646         if (error)
647                 return (-1);
648         error = fstat(stream->fd, &sb);
649         if (error)
650                 return (-1);
651         error = stream_truncate(stream, sb.st_size + off);
652         return (error);
653 }
654
655 /* Rewind the stream. */
656 int
657 stream_rewind(struct stream *stream)
658 {
659         int error;
660
661         if (stream->fd == -1) {
662                 errno = EINVAL;
663                 return (-1);
664         }
665         if (stream->rdbuf != NULL)
666                 buf_less(stream->rdbuf, buf_count(stream->rdbuf));
667         if (stream->wrbuf != NULL) {
668                 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
669                 if (error)
670                         return (error);
671         }
672         error = lseek(stream->fd, 0, SEEK_SET);
673         return (error);
674 }
675
676 /* Return EOF status. */
677 int
678 stream_eof(struct stream *stream)
679 {
680
681         return (stream->eof);
682 }
683
684 /* Close a stream and free any resources held by it. */
685 int
686 stream_close(struct stream *stream)
687 {
688         int error;
689
690         if (stream == NULL)
691                 return (0);
692
693         error = 0;
694         if (stream->wrbuf != NULL)
695                 error = stream_flush_int(stream, STREAM_FLUSH_CLOSING);
696         stream_filter_fini(stream);
697         if (stream->closefn != NULL)
698                 /*
699                  * We might overwrite a previous error from stream_flush(),
700                  * but we have no choice, because wether it had worked or
701                  * not, we need to close the file descriptor.
702                  */
703                 error = (*stream->closefn)(stream->cookie);
704         if (stream->rdbuf != NULL)
705                 buf_free(stream->rdbuf);
706         if (stream->wrbuf != NULL)
707                 buf_free(stream->wrbuf);
708         free(stream);
709         return (error);
710 }
711
712 /* The default fill method. */
713 static ssize_t
714 stream_fill_default(struct stream *stream, struct buf *buf)
715 {
716         ssize_t n;
717
718         if (stream->eof)
719                 return (0);
720         assert(buf_avail(buf) > 0);
721         n = (*stream->readfn)(stream->cookie, buf->buf + buf->off + buf->in,
722             buf_avail(buf));
723         if (n < 0)
724                 return (-1);
725         if (n == 0) {
726                 stream->eof = 1;
727                 return (0);
728         }
729         buf_more(buf, n);
730         return (n);
731 }
732
733 /*
734  * Refill the read buffer.  This function is not permitted to return
735  * without having made more bytes available, unless there was an error.
736  * Moreover, stream_fill() returns the number of bytes added.
737  */
738 static ssize_t
739 stream_fill(struct stream *stream)
740 {
741         struct stream_filter *filter;
742         struct buf *buf;
743 #ifndef NDEBUG
744         size_t oldcount;
745 #endif
746         ssize_t n;
747
748         filter = stream->filter;
749         buf = stream->rdbuf;
750         buf_prewrite(buf);
751 #ifndef NDEBUG
752         oldcount = buf_count(buf);
753 #endif
754         n = (*filter->fillfn)(stream, buf);
755         assert((n > 0 && n == (signed)(buf_count(buf) - oldcount)) ||
756             (n <= 0 && buf_count(buf) == oldcount));
757         return (n);
758 }
759
760 /*
761  * Lookup a stream filter.
762  *
763  * We are not supposed to get passed an invalid filter id, since
764  * filter ids are an enum type and we don't have invalid filter
765  * ids in the enum :-).  Thus, we are not checking for out of
766  * bounds access here.  If it happens, it's the caller's fault
767  * anyway.
768  */
769 static struct stream_filter *
770 stream_filter_lookup(stream_filter_t id)
771 {
772         struct stream_filter *filter;
773
774         filter = stream_filters;
775         while (filter->id != id)
776                 filter++;
777         return (filter);
778 }
779
780 static int
781 stream_filter_init(struct stream *stream, void *data)
782 {
783         struct stream_filter *filter;
784         int error;
785
786         filter = stream->filter;
787         if (filter->initfn == NULL)
788                 return (0);
789         error = (*filter->initfn)(stream, data);
790         return (error);
791 }
792
793 static void
794 stream_filter_fini(struct stream *stream)
795 {
796         struct stream_filter *filter;
797
798         filter = stream->filter;
799         if (filter->finifn != NULL)
800                 (*filter->finifn)(stream);
801 }
802
803 /*
804  * Start a filter on a stream.
805  */
806 int
807 stream_filter_start(struct stream *stream, stream_filter_t id, void *data)
808 {
809         struct stream_filter *filter;
810         int error;
811
812         filter = stream->filter;
813         if (id == filter->id)
814                 return (0);
815         stream_filter_fini(stream);
816         stream->filter = stream_filter_lookup(id);
817         stream->fdata = NULL;
818         error = stream_filter_init(stream, data);
819         return (error);
820 }
821
822
823 /* Stop a filter, this is equivalent to setting the null filter. */
824 void
825 stream_filter_stop(struct stream *stream)
826 {
827
828         stream_filter_start(stream, STREAM_FILTER_NULL, NULL);
829 }
830
831 /* The zlib stream filter implementation. */
832
833 /* Take no chances with zlib... */
834 static void *
835 zfilter_alloc(void __unused *opaque, unsigned int items, unsigned int size)
836 {
837
838         return (xmalloc(items * size));
839 }
840
841 static void
842 zfilter_free(void __unused *opaque, void *ptr)
843 {
844
845         free(ptr);
846 }
847
848 static int
849 zfilter_init(struct stream *stream, void __unused *data)
850 {
851         struct zfilter *zf;
852         struct buf *buf;
853         z_stream *state;
854         int rv;
855
856         zf = xmalloc(sizeof(struct zfilter));
857         memset(zf, 0, sizeof(struct zfilter));
858         if (stream->rdbuf != NULL) {
859                 state = xmalloc(sizeof(z_stream));
860                 state->zalloc = zfilter_alloc;
861                 state->zfree = zfilter_free;
862                 state->opaque = Z_NULL;
863                 rv = inflateInit(state);
864                 if (rv != Z_OK)
865                         errx(1, "inflateInit: %s", state->msg);
866                 buf = buf_new(buf_size(stream->rdbuf));
867                 zf->rdbuf = stream->rdbuf;
868                 stream->rdbuf = buf;
869                 zf->rdstate = state;
870         }
871         if (stream->wrbuf != NULL) {
872                 state = xmalloc(sizeof(z_stream));
873                 state->zalloc = zfilter_alloc;
874                 state->zfree = zfilter_free;
875                 state->opaque = Z_NULL;
876                 rv = deflateInit(state, Z_DEFAULT_COMPRESSION);
877                 if (rv != Z_OK)
878                         errx(1, "deflateInit: %s", state->msg);
879                 buf = buf_new(buf_size(stream->wrbuf));
880                 zf->wrbuf = stream->wrbuf;
881                 stream->wrbuf = buf;
882                 zf->wrstate = state;
883         }
884         stream->fdata = zf;
885         return (0);
886 }
887
888 static void
889 zfilter_fini(struct stream *stream)
890 {
891         struct zfilter *zf;
892         struct buf *zbuf;
893         z_stream *state;
894         ssize_t n;
895
896         zf = stream->fdata;
897         if (zf->rdbuf != NULL) {
898                 state = zf->rdstate;
899                 zbuf = zf->rdbuf;
900                 /*
901                  * Even if it has produced all the bytes, zlib sometimes
902                  * hasn't seen the EOF marker, so we need to call inflate()
903                  * again to make sure we have eaten all the zlib'ed bytes.
904                  */
905                 if ((zf->flags & ZFILTER_EOF) == 0) {
906                         n = zfilter_fill(stream, stream->rdbuf);
907                         assert(n == 0 && zf->flags & ZFILTER_EOF);
908                 }
909                 inflateEnd(state);
910                 free(state);
911                 buf_free(stream->rdbuf);
912                 stream->rdbuf = zbuf;
913         }
914         if (zf->wrbuf != NULL) {
915                 state = zf->wrstate;
916                 zbuf = zf->wrbuf;
917                 /*
918                  * Compress the remaining bytes in the buffer, if any,
919                  * and emit an EOF marker as appropriate.  We ignore
920                  * the error because we can't do anything about it at
921                  * this point, and it can happen if we're getting
922                  * disconnected.
923                  */
924                 (void)zfilter_flush(stream, stream->wrbuf,
925                     STREAM_FLUSH_CLOSING);
926                 deflateEnd(state);
927                 free(state);
928                 buf_free(stream->wrbuf);
929                 stream->wrbuf = zbuf;
930         }
931         free(zf);
932 }
933
934 static int
935 zfilter_flush(struct stream *stream, struct buf *buf, stream_flush_t how)
936 {
937         struct zfilter *zf;
938         struct buf *zbuf;
939         z_stream *state;
940         size_t lastin, lastout, ate, prod;
941         int done, error, flags, rv;
942
943         zf = stream->fdata;
944         state = zf->wrstate;
945         zbuf = zf->wrbuf;
946
947         if (how == STREAM_FLUSH_NORMAL)
948                 flags = Z_SYNC_FLUSH;
949         else
950                 flags = Z_FINISH;
951
952         done = 0;
953         rv = Z_OK;
954
955 again:
956         /*
957          * According to zlib.h, we should have at least 6 bytes
958          * available when using deflate() with Z_SYNC_FLUSH.
959          */
960         if ((buf_avail(zbuf) < 6 && flags == Z_SYNC_FLUSH) ||
961             rv == Z_BUF_ERROR || buf_avail(buf) == 0) {
962                 error = stream_flush_default(stream, zbuf, how);
963                 if (error)
964                         return (error);
965         }
966
967         state->next_in = (Bytef *)(buf->buf + buf->off);
968         state->avail_in = buf_count(buf);
969         state->next_out = (Bytef *)(zbuf->buf + zbuf->off + zbuf->in);
970         state->avail_out = buf_avail(zbuf);
971         lastin = state->avail_in;
972         lastout = state->avail_out;
973         rv = deflate(state, flags);
974         if (rv != Z_BUF_ERROR && rv != Z_OK && rv != Z_STREAM_END)
975                 errx(1, "deflate: %s", state->msg);
976         ate = lastin - state->avail_in;
977         prod = lastout - state->avail_out;
978         buf_less(buf, ate);
979         buf_more(zbuf, prod);
980         if ((flags == Z_SYNC_FLUSH && buf_count(buf) > 0) ||
981             (flags == Z_FINISH && rv != Z_STREAM_END) ||
982             (rv == Z_BUF_ERROR))
983                 goto again;
984
985         assert(rv == Z_OK || (rv == Z_STREAM_END && flags == Z_FINISH));
986         error = stream_flush_default(stream, zbuf, how);
987         return (error);
988 }
989
990 static ssize_t
991 zfilter_fill(struct stream *stream, struct buf *buf)
992 {
993         struct zfilter *zf;
994         struct buf *zbuf;
995         z_stream *state;
996         size_t lastin, lastout, new;
997         ssize_t n;
998         int rv;
999
1000         zf = stream->fdata;
1001         state = zf->rdstate;
1002         zbuf = zf->rdbuf;
1003
1004         assert(buf_avail(buf) > 0);
1005         if (buf_count(zbuf) == 0) {
1006                 n = stream_fill_default(stream, zbuf);
1007                 if (n <= 0)
1008                         return (n);
1009         }
1010 again:
1011         assert(buf_count(zbuf) > 0);
1012         state->next_in = (Bytef *)(zbuf->buf + zbuf->off);
1013         state->avail_in = buf_count(zbuf);
1014         state->next_out = (Bytef *)(buf->buf + buf->off + buf->in);
1015         state->avail_out = buf_avail(buf);
1016         lastin = state->avail_in;
1017         lastout = state->avail_out;
1018         rv = inflate(state, Z_SYNC_FLUSH);
1019         buf_less(zbuf, lastin - state->avail_in);
1020         new = lastout - state->avail_out;
1021         if (new == 0 && rv != Z_STREAM_END) {
1022                 n = stream_fill_default(stream, zbuf);
1023                 if (n == -1)
1024                         return (-1);
1025                 if (n == 0)
1026                         return (0);
1027                 goto again;
1028         }
1029         if (rv != Z_STREAM_END && rv != Z_OK)
1030                 errx(1, "inflate: %s", state->msg);
1031         if (rv == Z_STREAM_END)
1032                 zf->flags |= ZFILTER_EOF;
1033         buf_more(buf, new);
1034         return (new);
1035 }
1036
1037 /* The MD5 stream filter implementation. */
1038 static int
1039 md5filter_init(struct stream *stream, void *data)
1040 {
1041         struct md5filter *mf;
1042
1043         mf = xmalloc(sizeof(struct md5filter));
1044         MD5_Init(&mf->ctx);
1045         mf->md5 = data;
1046         stream->fdata = mf;
1047         return (0);
1048 }
1049
1050 static void
1051 md5filter_fini(struct stream *stream)
1052 {
1053         struct md5filter *mf;
1054
1055         mf = stream->fdata;
1056         MD5_End(mf->md5, &mf->ctx);
1057         free(stream->fdata);
1058 }
1059
1060 static ssize_t
1061 md5filter_fill(struct stream *stream, struct buf *buf)
1062 {
1063         ssize_t n;
1064
1065         assert(buf_avail(buf) > 0);
1066         n = stream_fill_default(stream, buf);
1067         return (n);
1068 }
1069
1070 static int
1071 md5filter_flush(struct stream *stream, struct buf *buf, stream_flush_t how)
1072 {
1073         struct md5filter *mf;
1074         int error;
1075
1076         mf = stream->fdata;
1077         MD5_Update(&mf->ctx, buf->buf + buf->off, buf->in);
1078         error = stream_flush_default(stream, buf, how);
1079         return (error);
1080 }