stream.c revision 156230
1156230Smux/*- 2156230Smux * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org> 3156230Smux * All rights reserved. 4156230Smux * 5156230Smux * Redistribution and use in source and binary forms, with or without 6156230Smux * modification, are permitted provided that the following conditions 7156230Smux * are met: 8156230Smux * 1. Redistributions of source code must retain the above copyright 9156230Smux * notice, this list of conditions and the following disclaimer. 10156230Smux * 2. Redistributions in binary form must reproduce the above copyright 11156230Smux * notice, this list of conditions and the following disclaimer in the 12156230Smux * documentation and/or other materials provided with the distribution. 13156230Smux * 14156230Smux * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15156230Smux * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16156230Smux * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17156230Smux * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18156230Smux * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19156230Smux * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20156230Smux * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21156230Smux * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22156230Smux * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23156230Smux * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24156230Smux * SUCH DAMAGE. 25156230Smux * 26156230Smux * $FreeBSD: vendor/csup/dist/contrib/csup/stream.c 156230 2006-03-03 04:11:29Z mux $ 27156230Smux */ 28156230Smux 29156230Smux#include <sys/types.h> 30156230Smux#include <sys/stat.h> 31156230Smux 32156230Smux#include <assert.h> 33156230Smux#include <zlib.h> 34156230Smux#include <err.h> 35156230Smux#include <errno.h> 36156230Smux#include <fcntl.h> 37156230Smux#include <stdarg.h> 38156230Smux#include <stdio.h> 39156230Smux#include <stdlib.h> 40156230Smux#include <string.h> 41156230Smux#include <unistd.h> 42156230Smux 43156230Smux#include "misc.h" 44156230Smux#include "stream.h" 45156230Smux 46156230Smux/* 47156230Smux * Simple stream API to make my life easier. If the fgetln() and 48156230Smux * funopen() functions were standard and if funopen() wasn't using 49156230Smux * wrong types for the function pointers, I could have just used 50156230Smux * stdio, but life sucks. 51156230Smux * 52156230Smux * For now, streams are always block-buffered. 53156230Smux */ 54156230Smux 55156230Smux/* 56156230Smux * Try to quiet warnings as much as possible with GCC while staying 57156230Smux * compatible with other compilers. 58156230Smux */ 59156230Smux#ifndef __unused 60156230Smux#if defined(__GNUC__) && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7) 61156230Smux#define __unused __attribute__((__unused__)) 62156230Smux#else 63156230Smux#define __unused 64156230Smux#endif 65156230Smux#endif 66156230Smux 67156230Smux/* 68156230Smux * Flags passed to the flush methods. 69156230Smux * 70156230Smux * STREAM_FLUSH_CLOSING is passed during the last flush call before 71156230Smux * closing a stream. This allows the zlib filter to emit the EOF 72156230Smux * marker as appropriate. In all other cases, STREAM_FLUSH_NORMAL 73156230Smux * should be passed. 74156230Smux * 75156230Smux * These flags are completely unused in the default flush method, 76156230Smux * but they are very important for the flush method of the zlib 77156230Smux * filter. 78156230Smux */ 79156230Smuxtypedef enum { 80156230Smux STREAM_FLUSH_NORMAL, 81156230Smux STREAM_FLUSH_CLOSING 82156230Smux} stream_flush_t; 83156230Smux 84156230Smux/* 85156230Smux * This is because buf_new() will always allocate size + 1 bytes, 86156230Smux * so our buffer sizes will still be power of 2 values. 87156230Smux */ 88156230Smux#define STREAM_BUFSIZ 1023 89156230Smux 90156230Smuxstruct buf { 91156230Smux char *buf; 92156230Smux size_t size; 93156230Smux size_t in; 94156230Smux size_t off; 95156230Smux}; 96156230Smux 97156230Smuxstruct stream { 98156230Smux void *cookie; 99156230Smux int fd; 100156230Smux struct buf *rdbuf; 101156230Smux struct buf *wrbuf; 102156230Smux stream_readfn_t *readfn; 103156230Smux stream_writefn_t *writefn; 104156230Smux stream_closefn_t *closefn; 105156230Smux int eof; 106156230Smux struct stream_filter *filter; 107156230Smux void *fdata; 108156230Smux}; 109156230Smux 110156230Smuxtypedef int stream_filter_initfn_t(struct stream *, void *); 111156230Smuxtypedef void stream_filter_finifn_t(struct stream *); 112156230Smuxtypedef int stream_filter_flushfn_t(struct stream *, struct buf *, 113156230Smux stream_flush_t); 114156230Smuxtypedef ssize_t stream_filter_fillfn_t(struct stream *, struct buf *); 115156230Smux 116156230Smuxstruct stream_filter { 117156230Smux stream_filter_t id; 118156230Smux stream_filter_initfn_t *initfn; 119156230Smux stream_filter_finifn_t *finifn; 120156230Smux stream_filter_fillfn_t *fillfn; 121156230Smux stream_filter_flushfn_t *flushfn; 122156230Smux}; 123156230Smux 124156230Smux/* Low-level buffer API. */ 125156230Smux#define buf_avail(buf) ((buf)->size - (buf)->off - (buf)->in) 126156230Smux#define buf_count(buf) ((buf)->in) 127156230Smux#define buf_size(buf) ((buf)->size) 128156230Smux 129156230Smuxstatic struct buf *buf_new(size_t); 130156230Smuxstatic void buf_more(struct buf *, size_t); 131156230Smuxstatic void buf_less(struct buf *, size_t); 132156230Smuxstatic void buf_free(struct buf *); 133156230Smuxstatic void buf_grow(struct buf *, size_t); 134156230Smux 135156230Smux/* Internal stream functions. */ 136156230Smuxstatic ssize_t stream_fill(struct stream *); 137156230Smuxstatic ssize_t stream_fill_default(struct stream *, struct buf *); 138156230Smuxstatic int stream_flush_int(struct stream *, stream_flush_t); 139156230Smuxstatic int stream_flush_default(struct stream *, struct buf *, 140156230Smux stream_flush_t); 141156230Smux 142156230Smux/* Filters specific functions. */ 143156230Smuxstatic struct stream_filter *stream_filter_lookup(stream_filter_t); 144156230Smuxstatic int stream_filter_init(struct stream *, void *); 145156230Smuxstatic void stream_filter_fini(struct stream *); 146156230Smux 147156230Smux/* The zlib stream filter declarations. */ 148156230Smux#define ZFILTER_EOF 1 /* Got Z_STREAM_END. */ 149156230Smux 150156230Smuxstruct zfilter { 151156230Smux int flags; 152156230Smux struct buf *rdbuf; 153156230Smux struct buf *wrbuf; 154156230Smux z_stream *rdstate; 155156230Smux z_stream *wrstate; 156156230Smux}; 157156230Smux 158156230Smuxstatic int zfilter_init(struct stream *, void *); 159156230Smuxstatic void zfilter_fini(struct stream *); 160156230Smuxstatic ssize_t zfilter_fill(struct stream *, struct buf *); 161156230Smuxstatic int zfilter_flush(struct stream *, struct buf *, 162156230Smux stream_flush_t); 163156230Smux 164156230Smux/* The MD5 stream filter. */ 165156230Smuxstruct md5filter { 166156230Smux MD5_CTX ctx; 167156230Smux char *md5; 168156230Smux}; 169156230Smux 170156230Smuxstatic int md5filter_init(struct stream *, void *); 171156230Smuxstatic void md5filter_fini(struct stream *); 172156230Smuxstatic ssize_t md5filter_fill(struct stream *, struct buf *); 173156230Smuxstatic int md5filter_flush(struct stream *, struct buf *, 174156230Smux stream_flush_t); 175156230Smux 176156230Smux/* The available stream filters. */ 177156230Smuxstruct stream_filter stream_filters[] = { 178156230Smux { 179156230Smux STREAM_FILTER_NULL, 180156230Smux NULL, 181156230Smux NULL, 182156230Smux stream_fill_default, 183156230Smux stream_flush_default 184156230Smux }, 185156230Smux { 186156230Smux STREAM_FILTER_ZLIB, 187156230Smux zfilter_init, 188156230Smux zfilter_fini, 189156230Smux zfilter_fill, 190156230Smux zfilter_flush 191156230Smux }, 192156230Smux { 193156230Smux STREAM_FILTER_MD5, 194156230Smux md5filter_init, 195156230Smux md5filter_fini, 196156230Smux md5filter_fill, 197156230Smux md5filter_flush 198156230Smux } 199156230Smux}; 200156230Smux 201156230Smux 202156230Smux/* Create a new buffer. */ 203156230Smuxstatic struct buf * 204156230Smuxbuf_new(size_t size) 205156230Smux{ 206156230Smux struct buf *buf; 207156230Smux 208156230Smux buf = xmalloc(sizeof(struct buf)); 209156230Smux /* 210156230Smux * We keep one spare byte so that stream_getln() can put a '\0' 211156230Smux * there in case the stream doesn't have an ending newline. 212156230Smux */ 213156230Smux buf->buf = xmalloc(size + 1); 214156230Smux buf->size = size; 215156230Smux buf->in = 0; 216156230Smux buf->off = 0; 217156230Smux return (buf); 218156230Smux} 219156230Smux 220156230Smux/* 221156230Smux * Grow the size of the buffer. If "need" is 0, bump its size to the 222156230Smux * next power of 2 value. Otherwise, bump it to the next power of 2 223156230Smux * value bigger than "need". 224156230Smux */ 225156230Smuxstatic void 226156230Smuxbuf_grow(struct buf *buf, size_t need) 227156230Smux{ 228156230Smux 229156230Smux if (need == 0) 230156230Smux buf->size = buf->size * 2 + 1; /* Account for the spare byte. */ 231156230Smux else { 232156230Smux assert(need > buf->size); 233156230Smux while (buf->size < need) 234156230Smux buf->size = buf->size * 2 + 1; 235156230Smux } 236156230Smux buf->buf = xrealloc(buf->buf, buf->size + 1); 237156230Smux} 238156230Smux 239156230Smux/* Make more room in the buffer if needed. */ 240156230Smuxstatic void 241156230Smuxbuf_prewrite(struct buf *buf) 242156230Smux{ 243156230Smux 244156230Smux if (buf_count(buf) == buf_size(buf)) 245156230Smux buf_grow(buf, 0); 246156230Smux if (buf_count(buf) > 0 && buf_avail(buf) == 0) { 247156230Smux memmove(buf->buf, buf->buf + buf->off, buf_count(buf)); 248156230Smux buf->off = 0; 249156230Smux } 250156230Smux} 251156230Smux 252156230Smux/* Account for "n" bytes being added in the buffer. */ 253156230Smuxstatic void 254156230Smuxbuf_more(struct buf *buf, size_t n) 255156230Smux{ 256156230Smux 257156230Smux assert(n <= buf_avail(buf)); 258156230Smux buf->in += n; 259156230Smux} 260156230Smux 261156230Smux/* Account for "n" bytes having been read in the buffer. */ 262156230Smuxstatic void 263156230Smuxbuf_less(struct buf *buf, size_t n) 264156230Smux{ 265156230Smux 266156230Smux assert(n <= buf_count(buf)); 267156230Smux buf->in -= n; 268156230Smux if (buf->in == 0) 269156230Smux buf->off = 0; 270156230Smux else 271156230Smux buf->off += n; 272156230Smux} 273156230Smux 274156230Smux/* Free a buffer. */ 275156230Smuxstatic void 276156230Smuxbuf_free(struct buf *buf) 277156230Smux{ 278156230Smux 279156230Smux free(buf->buf); 280156230Smux free(buf); 281156230Smux} 282156230Smux 283156230Smuxstatic struct stream * 284156230Smuxstream_new(stream_readfn_t *readfn, stream_writefn_t *writefn, 285156230Smux stream_closefn_t *closefn) 286156230Smux{ 287156230Smux struct stream *stream; 288156230Smux 289156230Smux stream = xmalloc(sizeof(struct stream)); 290156230Smux if (readfn == NULL && writefn == NULL) { 291156230Smux errno = EINVAL; 292156230Smux return (NULL); 293156230Smux } 294156230Smux if (readfn != NULL) 295156230Smux stream->rdbuf = buf_new(STREAM_BUFSIZ); 296156230Smux else 297156230Smux stream->rdbuf = NULL; 298156230Smux if (writefn != NULL) 299156230Smux stream->wrbuf = buf_new(STREAM_BUFSIZ); 300156230Smux else 301156230Smux stream->wrbuf = NULL; 302156230Smux stream->cookie = NULL; 303156230Smux stream->fd = -1; 304156230Smux stream->readfn = readfn; 305156230Smux stream->writefn = writefn; 306156230Smux stream->closefn = closefn; 307156230Smux stream->filter = stream_filter_lookup(STREAM_FILTER_NULL); 308156230Smux stream->fdata = NULL; 309156230Smux stream->eof = 0; 310156230Smux return (stream); 311156230Smux} 312156230Smux 313156230Smux/* Create a new stream associated with a void *. */ 314156230Smuxstruct stream * 315156230Smuxstream_open(void *cookie, stream_readfn_t *readfn, stream_writefn_t *writefn, 316156230Smux stream_closefn_t *closefn) 317156230Smux{ 318156230Smux struct stream *stream; 319156230Smux 320156230Smux stream = stream_new(readfn, writefn, closefn); 321156230Smux stream->cookie = cookie; 322156230Smux return (stream); 323156230Smux} 324156230Smux 325156230Smux/* Associate a file descriptor with a stream. */ 326156230Smuxstruct stream * 327156230Smuxstream_open_fd(int fd, stream_readfn_t *readfn, stream_writefn_t *writefn, 328156230Smux stream_closefn_t *closefn) 329156230Smux{ 330156230Smux struct stream *stream; 331156230Smux 332156230Smux stream = stream_new(readfn, writefn, closefn); 333156230Smux stream->cookie = &stream->fd; 334156230Smux stream->fd = fd; 335156230Smux return (stream); 336156230Smux} 337156230Smux 338156230Smux/* Like open() but returns a stream. */ 339156230Smuxstruct stream * 340156230Smuxstream_open_file(const char *path, int flags, ...) 341156230Smux{ 342156230Smux struct stream *stream; 343156230Smux stream_readfn_t *readfn; 344156230Smux stream_writefn_t *writefn; 345156230Smux va_list ap; 346156230Smux mode_t mode; 347156230Smux int fd; 348156230Smux 349156230Smux va_start(ap, flags); 350156230Smux if (flags & O_CREAT) { 351156230Smux /* 352156230Smux * GCC says I should not be using mode_t here since it's 353156230Smux * promoted to an int when passed through `...'. 354156230Smux */ 355156230Smux mode = va_arg(ap, int); 356156230Smux fd = open(path, flags, mode); 357156230Smux } else 358156230Smux fd = open(path, flags); 359156230Smux va_end(ap); 360156230Smux if (fd == -1) 361156230Smux return (NULL); 362156230Smux 363156230Smux flags &= O_ACCMODE; 364156230Smux if (flags == O_RDONLY) { 365156230Smux readfn = stream_read_fd; 366156230Smux writefn = NULL; 367156230Smux } else if (flags == O_WRONLY) { 368156230Smux readfn = NULL; 369156230Smux writefn = stream_write_fd; 370156230Smux } else if (flags == O_RDWR) { 371156230Smux assert(flags == O_RDWR); 372156230Smux readfn = stream_read_fd; 373156230Smux writefn = stream_write_fd; 374156230Smux } else { 375156230Smux errno = EINVAL; 376156230Smux close(fd); 377156230Smux return (NULL); 378156230Smux } 379156230Smux 380156230Smux stream = stream_open_fd(fd, readfn, writefn, stream_close_fd); 381156230Smux if (stream == NULL) 382156230Smux close(fd); 383156230Smux return (stream); 384156230Smux} 385156230Smux 386156230Smux/* Return the file descriptor associated with this stream, or -1. */ 387156230Smuxint 388156230Smuxstream_fileno(struct stream *stream) 389156230Smux{ 390156230Smux 391156230Smux return (stream->fd); 392156230Smux} 393156230Smux 394156230Smux/* Convenience read function for file descriptors. */ 395156230Smuxssize_t 396156230Smuxstream_read_fd(void *cookie, void *buf, size_t size) 397156230Smux{ 398156230Smux ssize_t nbytes; 399156230Smux int fd; 400156230Smux 401156230Smux fd = *(int *)cookie; 402156230Smux nbytes = read(fd, buf, size); 403156230Smux return (nbytes); 404156230Smux} 405156230Smux 406156230Smux/* Convenience write function for file descriptors. */ 407156230Smuxssize_t 408156230Smuxstream_write_fd(void *cookie, const void *buf, size_t size) 409156230Smux{ 410156230Smux ssize_t nbytes; 411156230Smux int fd; 412156230Smux 413156230Smux fd = *(int *)cookie; 414156230Smux nbytes = write(fd, buf, size); 415156230Smux return (nbytes); 416156230Smux} 417156230Smux 418156230Smux/* Convenience close function for file descriptors. */ 419156230Smuxint 420156230Smuxstream_close_fd(void *cookie) 421156230Smux{ 422156230Smux int fd, ret; 423156230Smux 424156230Smux fd = *(int *)cookie; 425156230Smux ret = close(fd); 426156230Smux return (ret); 427156230Smux} 428156230Smux 429156230Smux/* Read some bytes from the stream. */ 430156230Smuxssize_t 431156230Smuxstream_read(struct stream *stream, void *buf, size_t size) 432156230Smux{ 433156230Smux struct buf *rdbuf; 434156230Smux ssize_t ret; 435156230Smux size_t n; 436156230Smux 437156230Smux rdbuf = stream->rdbuf; 438156230Smux if (buf_count(rdbuf) == 0) { 439156230Smux ret = stream_fill(stream); 440156230Smux if (ret <= 0) 441156230Smux return (-1); 442156230Smux } 443156230Smux n = min(size, buf_count(rdbuf)); 444156230Smux memcpy(buf, rdbuf->buf + rdbuf->off, n); 445156230Smux buf_less(rdbuf, n); 446156230Smux return (n); 447156230Smux} 448156230Smux 449156230Smux/* 450156230Smux * Read a line from the stream and return a pointer to it. 451156230Smux * 452156230Smux * If "len" is non-NULL, the length of the string will be put into it. 453156230Smux * The pointer is only valid until the next stream API call. The line 454156230Smux * can be modified by the caller, provided he doesn't write before or 455156230Smux * after it. 456156230Smux * 457156230Smux * This is somewhat similar to the BSD fgetln() function, except that 458156230Smux * "len" can be NULL here. In that case the string is terminated by 459156230Smux * overwriting the '\n' character with a NUL character. If it's the 460156230Smux * last line in the stream and it has no ending newline, we can still 461156230Smux * add '\0' after it, because we keep one spare byte in the buffers. 462156230Smux * 463156230Smux * However, be warned that one can't handle binary lines properly 464156230Smux * without knowing the size of the string since those can contain 465156230Smux * NUL characters. 466156230Smux */ 467156230Smuxchar * 468156230Smuxstream_getln(struct stream *stream, size_t *len) 469156230Smux{ 470156230Smux struct buf *buf; 471156230Smux char *cp, *line; 472156230Smux ssize_t n; 473156230Smux size_t done, size; 474156230Smux 475156230Smux buf = stream->rdbuf; 476156230Smux if (buf_count(buf) == 0) { 477156230Smux n = stream_fill(stream); 478156230Smux if (n <= 0) 479156230Smux return (NULL); 480156230Smux } 481156230Smux cp = memchr(buf->buf + buf->off, '\n', buf_count(buf)); 482156230Smux for (done = buf_count(buf); cp == NULL; done += n) { 483156230Smux n = stream_fill(stream); 484156230Smux if (n < 0) 485156230Smux return (NULL); 486156230Smux if (n == 0) 487156230Smux /* Last line of the stream. */ 488156230Smux cp = buf->buf + buf->off + buf->in - 1; 489156230Smux else 490156230Smux cp = memchr(buf->buf + buf->off + done, '\n', 491156230Smux buf_count(buf) - done); 492156230Smux } 493156230Smux line = buf->buf + buf->off; 494156230Smux assert(cp >= line); 495156230Smux size = cp - line + 1; 496156230Smux buf_less(buf, size); 497156230Smux if (len != NULL) { 498156230Smux *len = size; 499156230Smux } else { 500156230Smux /* Terminate the string when len == NULL. */ 501156230Smux if (line[size - 1] == '\n') 502156230Smux line[size - 1] = '\0'; 503156230Smux else 504156230Smux line[size] = '\0'; 505156230Smux } 506156230Smux return (line); 507156230Smux} 508156230Smux 509156230Smux/* Write some bytes to a stream. */ 510156230Smuxssize_t 511156230Smuxstream_write(struct stream *stream, const void *src, size_t nbytes) 512156230Smux{ 513156230Smux struct buf *buf; 514156230Smux int error; 515156230Smux 516156230Smux buf = stream->wrbuf; 517156230Smux if (nbytes > buf_size(buf)) 518156230Smux buf_grow(buf, nbytes); 519156230Smux if (nbytes > buf_avail(buf)) { 520156230Smux error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); 521156230Smux if (error) 522156230Smux return (-1); 523156230Smux } 524156230Smux memcpy(buf->buf + buf->off + buf->in, src, nbytes); 525156230Smux buf_more(buf, nbytes); 526156230Smux return (nbytes); 527156230Smux} 528156230Smux 529156230Smux/* Formatted output to a stream. */ 530156230Smuxint 531156230Smuxstream_printf(struct stream *stream, const char *fmt, ...) 532156230Smux{ 533156230Smux struct buf *buf; 534156230Smux va_list ap; 535156230Smux int error, ret; 536156230Smux 537156230Smux buf = stream->wrbuf; 538156230Smuxagain: 539156230Smux va_start(ap, fmt); 540156230Smux ret = vsnprintf(buf->buf + buf->off + buf->in, buf_avail(buf), fmt, ap); 541156230Smux va_end(ap); 542156230Smux if (ret < 0) 543156230Smux return (ret); 544156230Smux if ((unsigned)ret >= buf_avail(buf)) { 545156230Smux if ((unsigned)ret >= buf_size(buf)) 546156230Smux buf_grow(buf, ret + 1); 547156230Smux if ((unsigned)ret >= buf_avail(buf)) { 548156230Smux error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); 549156230Smux if (error) 550156230Smux return (-1); 551156230Smux } 552156230Smux goto again; 553156230Smux } 554156230Smux buf_more(buf, ret); 555156230Smux return (ret); 556156230Smux} 557156230Smux 558156230Smux/* Flush the entire write buffer of the stream. */ 559156230Smuxint 560156230Smuxstream_flush(struct stream *stream) 561156230Smux{ 562156230Smux int error; 563156230Smux 564156230Smux error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); 565156230Smux return (error); 566156230Smux} 567156230Smux 568156230Smux/* Internal flush API. */ 569156230Smuxstatic int 570156230Smuxstream_flush_int(struct stream *stream, stream_flush_t how) 571156230Smux{ 572156230Smux struct buf *buf; 573156230Smux int error; 574156230Smux 575156230Smux buf = stream->wrbuf; 576156230Smux error = (*stream->filter->flushfn)(stream, buf, how); 577156230Smux assert(buf_count(buf) == 0); 578156230Smux return (error); 579156230Smux} 580156230Smux 581156230Smux/* The default flush method. */ 582156230Smuxstatic int 583156230Smuxstream_flush_default(struct stream *stream, struct buf *buf, 584156230Smux stream_flush_t __unused how) 585156230Smux{ 586156230Smux ssize_t n; 587156230Smux 588156230Smux while (buf_count(buf) > 0) { 589156230Smux do { 590156230Smux n = (*stream->writefn)(stream->cookie, 591156230Smux buf->buf + buf->off, buf_count(buf)); 592156230Smux } while (n == -1 && errno == EINTR); 593156230Smux if (n <= 0) 594156230Smux return (-1); 595156230Smux buf_less(buf, n); 596156230Smux } 597156230Smux return (0); 598156230Smux} 599156230Smux 600156230Smux/* Flush the write buffer and call fsync() on the file descriptor. */ 601156230Smuxint 602156230Smuxstream_sync(struct stream *stream) 603156230Smux{ 604156230Smux int error; 605156230Smux 606156230Smux if (stream->fd == -1) { 607156230Smux errno = EINVAL; 608156230Smux return (-1); 609156230Smux } 610156230Smux error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); 611156230Smux if (error) 612156230Smux return (-1); 613156230Smux error = fsync(stream->fd); 614156230Smux return (error); 615156230Smux} 616156230Smux 617156230Smux/* Like truncate() but on a stream. */ 618156230Smuxint 619156230Smuxstream_truncate(struct stream *stream, off_t size) 620156230Smux{ 621156230Smux int error; 622156230Smux 623156230Smux if (stream->fd == -1) { 624156230Smux errno = EINVAL; 625156230Smux return (-1); 626156230Smux } 627156230Smux error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); 628156230Smux if (error) 629156230Smux return (-1); 630156230Smux error = ftruncate(stream->fd, size); 631156230Smux return (error); 632156230Smux} 633156230Smux 634156230Smux/* Like stream_truncate() except the off_t parameter is an offset. */ 635156230Smuxint 636156230Smuxstream_truncate_rel(struct stream *stream, off_t off) 637156230Smux{ 638156230Smux struct stat sb; 639156230Smux int error; 640156230Smux 641156230Smux if (stream->fd == -1) { 642156230Smux errno = EINVAL; 643156230Smux return (-1); 644156230Smux } 645156230Smux error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); 646156230Smux if (error) 647156230Smux return (-1); 648156230Smux error = fstat(stream->fd, &sb); 649156230Smux if (error) 650156230Smux return (-1); 651156230Smux error = stream_truncate(stream, sb.st_size + off); 652156230Smux return (error); 653156230Smux} 654156230Smux 655156230Smux/* Rewind the stream. */ 656156230Smuxint 657156230Smuxstream_rewind(struct stream *stream) 658156230Smux{ 659156230Smux int error; 660156230Smux 661156230Smux if (stream->fd == -1) { 662156230Smux errno = EINVAL; 663156230Smux return (-1); 664156230Smux } 665156230Smux if (stream->rdbuf != NULL) 666156230Smux buf_less(stream->rdbuf, buf_count(stream->rdbuf)); 667156230Smux if (stream->wrbuf != NULL) { 668156230Smux error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); 669156230Smux if (error) 670156230Smux return (error); 671156230Smux } 672156230Smux error = lseek(stream->fd, 0, SEEK_SET); 673156230Smux return (error); 674156230Smux} 675156230Smux 676156230Smux/* Return EOF status. */ 677156230Smuxint 678156230Smuxstream_eof(struct stream *stream) 679156230Smux{ 680156230Smux 681156230Smux return (stream->eof); 682156230Smux} 683156230Smux 684156230Smux/* Close a stream and free any resources held by it. */ 685156230Smuxint 686156230Smuxstream_close(struct stream *stream) 687156230Smux{ 688156230Smux int error; 689156230Smux 690156230Smux if (stream == NULL) 691156230Smux return (0); 692156230Smux 693156230Smux error = 0; 694156230Smux if (stream->wrbuf != NULL) 695156230Smux error = stream_flush_int(stream, STREAM_FLUSH_CLOSING); 696156230Smux stream_filter_fini(stream); 697156230Smux if (stream->closefn != NULL) 698156230Smux /* 699156230Smux * We might overwrite a previous error from stream_flush(), 700156230Smux * but we have no choice, because wether it had worked or 701156230Smux * not, we need to close the file descriptor. 702156230Smux */ 703156230Smux error = (*stream->closefn)(stream->cookie); 704156230Smux if (stream->rdbuf != NULL) 705156230Smux buf_free(stream->rdbuf); 706156230Smux if (stream->wrbuf != NULL) 707156230Smux buf_free(stream->wrbuf); 708156230Smux free(stream); 709156230Smux return (error); 710156230Smux} 711156230Smux 712156230Smux/* The default fill method. */ 713156230Smuxstatic ssize_t 714156230Smuxstream_fill_default(struct stream *stream, struct buf *buf) 715156230Smux{ 716156230Smux ssize_t n; 717156230Smux 718156230Smux if (stream->eof) 719156230Smux return (0); 720156230Smux assert(buf_avail(buf) > 0); 721156230Smux n = (*stream->readfn)(stream->cookie, buf->buf + buf->off + buf->in, 722156230Smux buf_avail(buf)); 723156230Smux if (n < 0) 724156230Smux return (-1); 725156230Smux if (n == 0) { 726156230Smux stream->eof = 1; 727156230Smux return (0); 728156230Smux } 729156230Smux buf_more(buf, n); 730156230Smux return (n); 731156230Smux} 732156230Smux 733156230Smux/* 734156230Smux * Refill the read buffer. This function is not permitted to return 735156230Smux * without having made more bytes available, unless there was an error. 736156230Smux * Moreover, stream_fill() returns the number of bytes added. 737156230Smux */ 738156230Smuxstatic ssize_t 739156230Smuxstream_fill(struct stream *stream) 740156230Smux{ 741156230Smux struct stream_filter *filter; 742156230Smux struct buf *buf; 743156230Smux#ifndef NDEBUG 744156230Smux size_t oldcount; 745156230Smux#endif 746156230Smux ssize_t n; 747156230Smux 748156230Smux filter = stream->filter; 749156230Smux buf = stream->rdbuf; 750156230Smux buf_prewrite(buf); 751156230Smux#ifndef NDEBUG 752156230Smux oldcount = buf_count(buf); 753156230Smux#endif 754156230Smux n = (*filter->fillfn)(stream, buf); 755156230Smux assert((n > 0 && n == (signed)(buf_count(buf) - oldcount)) || 756156230Smux (n <= 0 && buf_count(buf) == oldcount)); 757156230Smux return (n); 758156230Smux} 759156230Smux 760156230Smux/* 761156230Smux * Lookup a stream filter. 762156230Smux * 763156230Smux * We are not supposed to get passed an invalid filter id, since 764156230Smux * filter ids are an enum type and we don't have invalid filter 765156230Smux * ids in the enum :-). Thus, we are not checking for out of 766156230Smux * bounds access here. If it happens, it's the caller's fault 767156230Smux * anyway. 768156230Smux */ 769156230Smuxstatic struct stream_filter * 770156230Smuxstream_filter_lookup(stream_filter_t id) 771156230Smux{ 772156230Smux struct stream_filter *filter; 773156230Smux 774156230Smux filter = stream_filters; 775156230Smux while (filter->id != id) 776156230Smux filter++; 777156230Smux return (filter); 778156230Smux} 779156230Smux 780156230Smuxstatic int 781156230Smuxstream_filter_init(struct stream *stream, void *data) 782156230Smux{ 783156230Smux struct stream_filter *filter; 784156230Smux int error; 785156230Smux 786156230Smux filter = stream->filter; 787156230Smux if (filter->initfn == NULL) 788156230Smux return (0); 789156230Smux error = (*filter->initfn)(stream, data); 790156230Smux return (error); 791156230Smux} 792156230Smux 793156230Smuxstatic void 794156230Smuxstream_filter_fini(struct stream *stream) 795156230Smux{ 796156230Smux struct stream_filter *filter; 797156230Smux 798156230Smux filter = stream->filter; 799156230Smux if (filter->finifn != NULL) 800156230Smux (*filter->finifn)(stream); 801156230Smux} 802156230Smux 803156230Smux/* 804156230Smux * Start a filter on a stream. 805156230Smux */ 806156230Smuxint 807156230Smuxstream_filter_start(struct stream *stream, stream_filter_t id, void *data) 808156230Smux{ 809156230Smux struct stream_filter *filter; 810156230Smux int error; 811156230Smux 812156230Smux filter = stream->filter; 813156230Smux if (id == filter->id) 814156230Smux return (0); 815156230Smux stream_filter_fini(stream); 816156230Smux stream->filter = stream_filter_lookup(id); 817156230Smux stream->fdata = NULL; 818156230Smux error = stream_filter_init(stream, data); 819156230Smux return (error); 820156230Smux} 821156230Smux 822156230Smux 823156230Smux/* Stop a filter, this is equivalent to setting the null filter. */ 824156230Smuxvoid 825156230Smuxstream_filter_stop(struct stream *stream) 826156230Smux{ 827156230Smux 828156230Smux stream_filter_start(stream, STREAM_FILTER_NULL, NULL); 829156230Smux} 830156230Smux 831156230Smux/* The zlib stream filter implementation. */ 832156230Smux 833156230Smux/* Take no chances with zlib... */ 834156230Smuxstatic void * 835156230Smuxzfilter_alloc(void __unused *opaque, unsigned int items, unsigned int size) 836156230Smux{ 837156230Smux 838156230Smux return (xmalloc(items * size)); 839156230Smux} 840156230Smux 841156230Smuxstatic void 842156230Smuxzfilter_free(void __unused *opaque, void *ptr) 843156230Smux{ 844156230Smux 845156230Smux free(ptr); 846156230Smux} 847156230Smux 848156230Smuxstatic int 849156230Smuxzfilter_init(struct stream *stream, void __unused *data) 850156230Smux{ 851156230Smux struct zfilter *zf; 852156230Smux struct buf *buf; 853156230Smux z_stream *state; 854156230Smux int rv; 855156230Smux 856156230Smux zf = xmalloc(sizeof(struct zfilter)); 857156230Smux memset(zf, 0, sizeof(struct zfilter)); 858156230Smux if (stream->rdbuf != NULL) { 859156230Smux state = xmalloc(sizeof(z_stream)); 860156230Smux state->zalloc = zfilter_alloc; 861156230Smux state->zfree = zfilter_free; 862156230Smux state->opaque = Z_NULL; 863156230Smux rv = inflateInit(state); 864156230Smux if (rv != Z_OK) 865156230Smux errx(1, "inflateInit: %s", state->msg); 866156230Smux buf = buf_new(buf_size(stream->rdbuf)); 867156230Smux zf->rdbuf = stream->rdbuf; 868156230Smux stream->rdbuf = buf; 869156230Smux zf->rdstate = state; 870156230Smux } 871156230Smux if (stream->wrbuf != NULL) { 872156230Smux state = xmalloc(sizeof(z_stream)); 873156230Smux state->zalloc = zfilter_alloc; 874156230Smux state->zfree = zfilter_free; 875156230Smux state->opaque = Z_NULL; 876156230Smux rv = deflateInit(state, Z_DEFAULT_COMPRESSION); 877156230Smux if (rv != Z_OK) 878156230Smux errx(1, "deflateInit: %s", state->msg); 879156230Smux buf = buf_new(buf_size(stream->wrbuf)); 880156230Smux zf->wrbuf = stream->wrbuf; 881156230Smux stream->wrbuf = buf; 882156230Smux zf->wrstate = state; 883156230Smux } 884156230Smux stream->fdata = zf; 885156230Smux return (0); 886156230Smux} 887156230Smux 888156230Smuxstatic void 889156230Smuxzfilter_fini(struct stream *stream) 890156230Smux{ 891156230Smux struct zfilter *zf; 892156230Smux struct buf *zbuf; 893156230Smux z_stream *state; 894156230Smux ssize_t n; 895156230Smux 896156230Smux zf = stream->fdata; 897156230Smux if (zf->rdbuf != NULL) { 898156230Smux state = zf->rdstate; 899156230Smux zbuf = zf->rdbuf; 900156230Smux /* 901156230Smux * Even if it has produced all the bytes, zlib sometimes 902156230Smux * hasn't seen the EOF marker, so we need to call inflate() 903156230Smux * again to make sure we have eaten all the zlib'ed bytes. 904156230Smux */ 905156230Smux if ((zf->flags & ZFILTER_EOF) == 0) { 906156230Smux n = zfilter_fill(stream, stream->rdbuf); 907156230Smux assert(n == 0 && zf->flags & ZFILTER_EOF); 908156230Smux } 909156230Smux inflateEnd(state); 910156230Smux free(state); 911156230Smux buf_free(stream->rdbuf); 912156230Smux stream->rdbuf = zbuf; 913156230Smux } 914156230Smux if (zf->wrbuf != NULL) { 915156230Smux state = zf->wrstate; 916156230Smux zbuf = zf->wrbuf; 917156230Smux /* 918156230Smux * Compress the remaining bytes in the buffer, if any, 919156230Smux * and emit an EOF marker as appropriate. We ignore 920156230Smux * the error because we can't do anything about it at 921156230Smux * this point, and it can happen if we're getting 922156230Smux * disconnected. 923156230Smux */ 924156230Smux (void)zfilter_flush(stream, stream->wrbuf, 925156230Smux STREAM_FLUSH_CLOSING); 926156230Smux deflateEnd(state); 927156230Smux free(state); 928156230Smux buf_free(stream->wrbuf); 929156230Smux stream->wrbuf = zbuf; 930156230Smux } 931156230Smux free(zf); 932156230Smux} 933156230Smux 934156230Smuxstatic int 935156230Smuxzfilter_flush(struct stream *stream, struct buf *buf, stream_flush_t how) 936156230Smux{ 937156230Smux struct zfilter *zf; 938156230Smux struct buf *zbuf; 939156230Smux z_stream *state; 940156230Smux size_t lastin, lastout, ate, prod; 941156230Smux int done, error, flags, rv; 942156230Smux 943156230Smux zf = stream->fdata; 944156230Smux state = zf->wrstate; 945156230Smux zbuf = zf->wrbuf; 946156230Smux 947156230Smux if (how == STREAM_FLUSH_NORMAL) 948156230Smux flags = Z_SYNC_FLUSH; 949156230Smux else 950156230Smux flags = Z_FINISH; 951156230Smux 952156230Smux done = 0; 953156230Smux rv = Z_OK; 954156230Smux 955156230Smuxagain: 956156230Smux /* 957156230Smux * According to zlib.h, we should have at least 6 bytes 958156230Smux * available when using deflate() with Z_SYNC_FLUSH. 959156230Smux */ 960156230Smux if ((buf_avail(zbuf) < 6 && flags == Z_SYNC_FLUSH) || 961156230Smux rv == Z_BUF_ERROR || buf_avail(buf) == 0) { 962156230Smux error = stream_flush_default(stream, zbuf, how); 963156230Smux if (error) 964156230Smux return (error); 965156230Smux } 966156230Smux 967156230Smux state->next_in = (Bytef *)(buf->buf + buf->off); 968156230Smux state->avail_in = buf_count(buf); 969156230Smux state->next_out = (Bytef *)(zbuf->buf + zbuf->off + zbuf->in); 970156230Smux state->avail_out = buf_avail(zbuf); 971156230Smux lastin = state->avail_in; 972156230Smux lastout = state->avail_out; 973156230Smux rv = deflate(state, flags); 974156230Smux if (rv != Z_BUF_ERROR && rv != Z_OK && rv != Z_STREAM_END) 975156230Smux errx(1, "deflate: %s", state->msg); 976156230Smux ate = lastin - state->avail_in; 977156230Smux prod = lastout - state->avail_out; 978156230Smux buf_less(buf, ate); 979156230Smux buf_more(zbuf, prod); 980156230Smux if ((flags == Z_SYNC_FLUSH && buf_count(buf) > 0) || 981156230Smux (flags == Z_FINISH && rv != Z_STREAM_END) || 982156230Smux (rv == Z_BUF_ERROR)) 983156230Smux goto again; 984156230Smux 985156230Smux assert(rv == Z_OK || (rv == Z_STREAM_END && flags == Z_FINISH)); 986156230Smux error = stream_flush_default(stream, zbuf, how); 987156230Smux return (error); 988156230Smux} 989156230Smux 990156230Smuxstatic ssize_t 991156230Smuxzfilter_fill(struct stream *stream, struct buf *buf) 992156230Smux{ 993156230Smux struct zfilter *zf; 994156230Smux struct buf *zbuf; 995156230Smux z_stream *state; 996156230Smux size_t lastin, lastout, new; 997156230Smux ssize_t n; 998156230Smux int rv; 999156230Smux 1000156230Smux zf = stream->fdata; 1001156230Smux state = zf->rdstate; 1002156230Smux zbuf = zf->rdbuf; 1003156230Smux 1004156230Smux assert(buf_avail(buf) > 0); 1005156230Smux if (buf_count(zbuf) == 0) { 1006156230Smux n = stream_fill_default(stream, zbuf); 1007156230Smux if (n <= 0) 1008156230Smux return (n); 1009156230Smux } 1010156230Smuxagain: 1011156230Smux assert(buf_count(zbuf) > 0); 1012156230Smux state->next_in = (Bytef *)(zbuf->buf + zbuf->off); 1013156230Smux state->avail_in = buf_count(zbuf); 1014156230Smux state->next_out = (Bytef *)(buf->buf + buf->off + buf->in); 1015156230Smux state->avail_out = buf_avail(buf); 1016156230Smux lastin = state->avail_in; 1017156230Smux lastout = state->avail_out; 1018156230Smux rv = inflate(state, Z_SYNC_FLUSH); 1019156230Smux buf_less(zbuf, lastin - state->avail_in); 1020156230Smux new = lastout - state->avail_out; 1021156230Smux if (new == 0 && rv != Z_STREAM_END) { 1022156230Smux n = stream_fill_default(stream, zbuf); 1023156230Smux if (n == -1) 1024156230Smux return (-1); 1025156230Smux if (n == 0) 1026156230Smux return (0); 1027156230Smux goto again; 1028156230Smux } 1029156230Smux if (rv != Z_STREAM_END && rv != Z_OK) 1030156230Smux errx(1, "inflate: %s", state->msg); 1031156230Smux if (rv == Z_STREAM_END) 1032156230Smux zf->flags |= ZFILTER_EOF; 1033156230Smux buf_more(buf, new); 1034156230Smux return (new); 1035156230Smux} 1036156230Smux 1037156230Smux/* The MD5 stream filter implementation. */ 1038156230Smuxstatic int 1039156230Smuxmd5filter_init(struct stream *stream, void *data) 1040156230Smux{ 1041156230Smux struct md5filter *mf; 1042156230Smux 1043156230Smux mf = xmalloc(sizeof(struct md5filter)); 1044156230Smux MD5_Init(&mf->ctx); 1045156230Smux mf->md5 = data; 1046156230Smux stream->fdata = mf; 1047156230Smux return (0); 1048156230Smux} 1049156230Smux 1050156230Smuxstatic void 1051156230Smuxmd5filter_fini(struct stream *stream) 1052156230Smux{ 1053156230Smux struct md5filter *mf; 1054156230Smux 1055156230Smux mf = stream->fdata; 1056156230Smux MD5_End(mf->md5, &mf->ctx); 1057156230Smux free(stream->fdata); 1058156230Smux} 1059156230Smux 1060156230Smuxstatic ssize_t 1061156230Smuxmd5filter_fill(struct stream *stream, struct buf *buf) 1062156230Smux{ 1063156230Smux ssize_t n; 1064156230Smux 1065156230Smux assert(buf_avail(buf) > 0); 1066156230Smux n = stream_fill_default(stream, buf); 1067156230Smux return (n); 1068156230Smux} 1069156230Smux 1070156230Smuxstatic int 1071156230Smuxmd5filter_flush(struct stream *stream, struct buf *buf, stream_flush_t how) 1072156230Smux{ 1073156230Smux struct md5filter *mf; 1074156230Smux int error; 1075156230Smux 1076156230Smux mf = stream->fdata; 1077156230Smux MD5_Update(&mf->ctx, buf->buf + buf->off, buf->in); 1078156230Smux error = stream_flush_default(stream, buf, how); 1079156230Smux return (error); 1080156230Smux} 1081