]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/csup/stream.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.bin / 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         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 *
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
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
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
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
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
292 buf_free(struct buf *buf)
293 {
294
295         free(buf->buf);
296         free(buf);
297 }
298
299 static struct stream *
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 *
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 *
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 *
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
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 *
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
428 stream_fileno(struct stream *stream)
429 {
430
431         return (stream->fd);
432 }
433
434 /* Convenience read function for character buffers. */
435 ssize_t
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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 *
952 zfilter_alloc(void __unused *opaque, unsigned int items, unsigned int size)
953 {
954
955         return (xmalloc(items * size));
956 }
957
958 static void
959 zfilter_free(void __unused *opaque, void *ptr)
960 {
961
962         free(ptr);
963 }
964
965 static int
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
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
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
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
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
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
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
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
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