1247411Sjhb/*- 2247411Sjhb * Copyright (c) 2013 Advanced Computing Technologies LLC 3247411Sjhb * Written by: John H. Baldwin <jhb@FreeBSD.org> 4247411Sjhb * All rights reserved. 5247411Sjhb * 6247411Sjhb * Redistribution and use in source and binary forms, with or without 7247411Sjhb * modification, are permitted provided that the following conditions 8247411Sjhb * are met: 9247411Sjhb * 1. Redistributions of source code must retain the above copyright 10247411Sjhb * notice, this list of conditions and the following disclaimer. 11247411Sjhb * 2. Redistributions in binary form must reproduce the above copyright 12247411Sjhb * notice, this list of conditions and the following disclaimer in the 13247411Sjhb * documentation and/or other materials provided with the distribution. 14247411Sjhb * 15247411Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16247411Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17247411Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18247411Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19247411Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20247411Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21247411Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22247411Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23247411Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24247411Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25247411Sjhb * SUCH DAMAGE. 26247411Sjhb */ 27247411Sjhb 28247411Sjhb#include <sys/cdefs.h> 29247411Sjhb__FBSDID("$FreeBSD$"); 30247411Sjhb 31247411Sjhb#include "namespace.h" 32247411Sjhb#include <assert.h> 33247411Sjhb#include <errno.h> 34247411Sjhb#include <limits.h> 35247411Sjhb#include <stdio.h> 36247411Sjhb#include <stdlib.h> 37247411Sjhb#include <string.h> 38247411Sjhb#include <wchar.h> 39247411Sjhb#include "un-namespace.h" 40247411Sjhb 41247411Sjhb/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */ 42247411Sjhb#define FPOS_MAX OFF_MAX 43247411Sjhb 44247411Sjhbstruct memstream { 45247411Sjhb char **bufp; 46247411Sjhb size_t *sizep; 47247411Sjhb ssize_t len; 48247411Sjhb fpos_t offset; 49247411Sjhb}; 50247411Sjhb 51247411Sjhbstatic int 52247411Sjhbmemstream_grow(struct memstream *ms, fpos_t newoff) 53247411Sjhb{ 54247411Sjhb char *buf; 55247411Sjhb ssize_t newsize; 56247411Sjhb 57247411Sjhb if (newoff < 0 || newoff >= SSIZE_MAX) 58247411Sjhb newsize = SSIZE_MAX - 1; 59247411Sjhb else 60247411Sjhb newsize = newoff; 61247411Sjhb if (newsize > ms->len) { 62247411Sjhb buf = realloc(*ms->bufp, newsize + 1); 63247411Sjhb if (buf != NULL) { 64247411Sjhb#ifdef DEBUG 65247411Sjhb fprintf(stderr, "MS: %p growing from %zd to %zd\n", 66247411Sjhb ms, ms->len, newsize); 67247411Sjhb#endif 68247411Sjhb memset(buf + ms->len + 1, 0, newsize - ms->len); 69247411Sjhb *ms->bufp = buf; 70247411Sjhb ms->len = newsize; 71247411Sjhb return (1); 72247411Sjhb } 73247411Sjhb return (0); 74247411Sjhb } 75247411Sjhb return (1); 76247411Sjhb} 77247411Sjhb 78247411Sjhbstatic void 79247411Sjhbmemstream_update(struct memstream *ms) 80247411Sjhb{ 81247411Sjhb 82247411Sjhb assert(ms->len >= 0 && ms->offset >= 0); 83247411Sjhb *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset; 84247411Sjhb} 85247411Sjhb 86247411Sjhbstatic int 87247411Sjhbmemstream_write(void *cookie, const char *buf, int len) 88247411Sjhb{ 89247411Sjhb struct memstream *ms; 90247411Sjhb ssize_t tocopy; 91247411Sjhb 92247411Sjhb ms = cookie; 93247411Sjhb if (!memstream_grow(ms, ms->offset + len)) 94247411Sjhb return (-1); 95247411Sjhb tocopy = ms->len - ms->offset; 96247411Sjhb if (len < tocopy) 97247411Sjhb tocopy = len; 98247411Sjhb memcpy(*ms->bufp + ms->offset, buf, tocopy); 99247411Sjhb ms->offset += tocopy; 100247411Sjhb memstream_update(ms); 101247411Sjhb#ifdef DEBUG 102247411Sjhb fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy); 103247411Sjhb#endif 104247411Sjhb return (tocopy); 105247411Sjhb} 106247411Sjhb 107247411Sjhbstatic fpos_t 108247411Sjhbmemstream_seek(void *cookie, fpos_t pos, int whence) 109247411Sjhb{ 110247411Sjhb struct memstream *ms; 111247411Sjhb#ifdef DEBUG 112247411Sjhb fpos_t old; 113247411Sjhb#endif 114247411Sjhb 115247411Sjhb ms = cookie; 116247411Sjhb#ifdef DEBUG 117247411Sjhb old = ms->offset; 118247411Sjhb#endif 119247411Sjhb switch (whence) { 120247411Sjhb case SEEK_SET: 121247411Sjhb /* _fseeko() checks for negative offsets. */ 122247411Sjhb assert(pos >= 0); 123247411Sjhb ms->offset = pos; 124247411Sjhb break; 125247411Sjhb case SEEK_CUR: 126247411Sjhb /* This is only called by _ftello(). */ 127247411Sjhb assert(pos == 0); 128247411Sjhb break; 129247411Sjhb case SEEK_END: 130247411Sjhb if (pos < 0) { 131247411Sjhb if (pos + ms->len < 0) { 132247411Sjhb#ifdef DEBUG 133247411Sjhb fprintf(stderr, 134247411Sjhb "MS: bad SEEK_END: pos %jd, len %zd\n", 135247411Sjhb (intmax_t)pos, ms->len); 136247411Sjhb#endif 137247411Sjhb errno = EINVAL; 138247411Sjhb return (-1); 139247411Sjhb } 140247411Sjhb } else { 141247411Sjhb if (FPOS_MAX - ms->len < pos) { 142247411Sjhb#ifdef DEBUG 143247411Sjhb fprintf(stderr, 144247411Sjhb "MS: bad SEEK_END: pos %jd, len %zd\n", 145247411Sjhb (intmax_t)pos, ms->len); 146247411Sjhb#endif 147247411Sjhb errno = EOVERFLOW; 148247411Sjhb return (-1); 149247411Sjhb } 150247411Sjhb } 151247411Sjhb ms->offset = ms->len + pos; 152247411Sjhb break; 153247411Sjhb } 154247411Sjhb memstream_update(ms); 155247411Sjhb#ifdef DEBUG 156247411Sjhb fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos, 157247411Sjhb whence, (intmax_t)old, (intmax_t)ms->offset); 158247411Sjhb#endif 159247411Sjhb return (ms->offset); 160247411Sjhb} 161247411Sjhb 162247411Sjhbstatic int 163247411Sjhbmemstream_close(void *cookie) 164247411Sjhb{ 165247411Sjhb 166247411Sjhb free(cookie); 167247411Sjhb return (0); 168247411Sjhb} 169247411Sjhb 170247411SjhbFILE * 171247411Sjhbopen_memstream(char **bufp, size_t *sizep) 172247411Sjhb{ 173247411Sjhb struct memstream *ms; 174247411Sjhb int save_errno; 175247411Sjhb FILE *fp; 176247411Sjhb 177247411Sjhb if (bufp == NULL || sizep == NULL) { 178247411Sjhb errno = EINVAL; 179247411Sjhb return (NULL); 180247411Sjhb } 181247411Sjhb *bufp = calloc(1, 1); 182247411Sjhb if (*bufp == NULL) 183247411Sjhb return (NULL); 184247411Sjhb ms = malloc(sizeof(*ms)); 185247411Sjhb if (ms == NULL) { 186247411Sjhb save_errno = errno; 187247411Sjhb free(*bufp); 188247411Sjhb *bufp = NULL; 189247411Sjhb errno = save_errno; 190247411Sjhb return (NULL); 191247411Sjhb } 192247411Sjhb ms->bufp = bufp; 193247411Sjhb ms->sizep = sizep; 194247411Sjhb ms->len = 0; 195247411Sjhb ms->offset = 0; 196247411Sjhb memstream_update(ms); 197247411Sjhb fp = funopen(ms, NULL, memstream_write, memstream_seek, 198247411Sjhb memstream_close); 199247411Sjhb if (fp == NULL) { 200247411Sjhb save_errno = errno; 201247411Sjhb free(ms); 202247411Sjhb free(*bufp); 203247411Sjhb *bufp = NULL; 204247411Sjhb errno = save_errno; 205247411Sjhb return (NULL); 206247411Sjhb } 207247411Sjhb fwide(fp, -1); 208247411Sjhb return (fp); 209247411Sjhb} 210