1*9240031aSJohn Baldwin /*- 2*9240031aSJohn Baldwin * Copyright (c) 2013 Advanced Computing Technologies LLC 3*9240031aSJohn Baldwin * Written by: John H. Baldwin <jhb@FreeBSD.org> 4*9240031aSJohn Baldwin * All rights reserved. 5*9240031aSJohn Baldwin * 6*9240031aSJohn Baldwin * Redistribution and use in source and binary forms, with or without 7*9240031aSJohn Baldwin * modification, are permitted provided that the following conditions 8*9240031aSJohn Baldwin * are met: 9*9240031aSJohn Baldwin * 1. Redistributions of source code must retain the above copyright 10*9240031aSJohn Baldwin * notice, this list of conditions and the following disclaimer. 11*9240031aSJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright 12*9240031aSJohn Baldwin * notice, this list of conditions and the following disclaimer in the 13*9240031aSJohn Baldwin * documentation and/or other materials provided with the distribution. 14*9240031aSJohn Baldwin * 15*9240031aSJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*9240031aSJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*9240031aSJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*9240031aSJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*9240031aSJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*9240031aSJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*9240031aSJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*9240031aSJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*9240031aSJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*9240031aSJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*9240031aSJohn Baldwin * SUCH DAMAGE. 26*9240031aSJohn Baldwin */ 27*9240031aSJohn Baldwin 28*9240031aSJohn Baldwin #include <sys/cdefs.h> 29*9240031aSJohn Baldwin __FBSDID("$FreeBSD$"); 30*9240031aSJohn Baldwin 31*9240031aSJohn Baldwin #include "namespace.h" 32*9240031aSJohn Baldwin #include <assert.h> 33*9240031aSJohn Baldwin #include <errno.h> 34*9240031aSJohn Baldwin #include <limits.h> 35*9240031aSJohn Baldwin #include <stdio.h> 36*9240031aSJohn Baldwin #include <stdlib.h> 37*9240031aSJohn Baldwin #include <string.h> 38*9240031aSJohn Baldwin #include <wchar.h> 39*9240031aSJohn Baldwin #include "un-namespace.h" 40*9240031aSJohn Baldwin 41*9240031aSJohn Baldwin /* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */ 42*9240031aSJohn Baldwin #define FPOS_MAX OFF_MAX 43*9240031aSJohn Baldwin 44*9240031aSJohn Baldwin struct memstream { 45*9240031aSJohn Baldwin char **bufp; 46*9240031aSJohn Baldwin size_t *sizep; 47*9240031aSJohn Baldwin ssize_t len; 48*9240031aSJohn Baldwin fpos_t offset; 49*9240031aSJohn Baldwin }; 50*9240031aSJohn Baldwin 51*9240031aSJohn Baldwin static int 52*9240031aSJohn Baldwin memstream_grow(struct memstream *ms, fpos_t newoff) 53*9240031aSJohn Baldwin { 54*9240031aSJohn Baldwin char *buf; 55*9240031aSJohn Baldwin ssize_t newsize; 56*9240031aSJohn Baldwin 57*9240031aSJohn Baldwin if (newoff < 0 || newoff >= SSIZE_MAX) 58*9240031aSJohn Baldwin newsize = SSIZE_MAX - 1; 59*9240031aSJohn Baldwin else 60*9240031aSJohn Baldwin newsize = newoff; 61*9240031aSJohn Baldwin if (newsize > ms->len) { 62*9240031aSJohn Baldwin buf = realloc(*ms->bufp, newsize + 1); 63*9240031aSJohn Baldwin if (buf != NULL) { 64*9240031aSJohn Baldwin #ifdef DEBUG 65*9240031aSJohn Baldwin fprintf(stderr, "MS: %p growing from %zd to %zd\n", 66*9240031aSJohn Baldwin ms, ms->len, newsize); 67*9240031aSJohn Baldwin #endif 68*9240031aSJohn Baldwin memset(buf + ms->len + 1, 0, newsize - ms->len); 69*9240031aSJohn Baldwin *ms->bufp = buf; 70*9240031aSJohn Baldwin ms->len = newsize; 71*9240031aSJohn Baldwin return (1); 72*9240031aSJohn Baldwin } 73*9240031aSJohn Baldwin return (0); 74*9240031aSJohn Baldwin } 75*9240031aSJohn Baldwin return (1); 76*9240031aSJohn Baldwin } 77*9240031aSJohn Baldwin 78*9240031aSJohn Baldwin static void 79*9240031aSJohn Baldwin memstream_update(struct memstream *ms) 80*9240031aSJohn Baldwin { 81*9240031aSJohn Baldwin 82*9240031aSJohn Baldwin assert(ms->len >= 0 && ms->offset >= 0); 83*9240031aSJohn Baldwin *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset; 84*9240031aSJohn Baldwin } 85*9240031aSJohn Baldwin 86*9240031aSJohn Baldwin static int 87*9240031aSJohn Baldwin memstream_write(void *cookie, const char *buf, int len) 88*9240031aSJohn Baldwin { 89*9240031aSJohn Baldwin struct memstream *ms; 90*9240031aSJohn Baldwin ssize_t tocopy; 91*9240031aSJohn Baldwin 92*9240031aSJohn Baldwin ms = cookie; 93*9240031aSJohn Baldwin if (!memstream_grow(ms, ms->offset + len)) 94*9240031aSJohn Baldwin return (-1); 95*9240031aSJohn Baldwin tocopy = ms->len - ms->offset; 96*9240031aSJohn Baldwin if (len < tocopy) 97*9240031aSJohn Baldwin tocopy = len; 98*9240031aSJohn Baldwin memcpy(*ms->bufp + ms->offset, buf, tocopy); 99*9240031aSJohn Baldwin ms->offset += tocopy; 100*9240031aSJohn Baldwin memstream_update(ms); 101*9240031aSJohn Baldwin #ifdef DEBUG 102*9240031aSJohn Baldwin fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy); 103*9240031aSJohn Baldwin #endif 104*9240031aSJohn Baldwin return (tocopy); 105*9240031aSJohn Baldwin } 106*9240031aSJohn Baldwin 107*9240031aSJohn Baldwin static fpos_t 108*9240031aSJohn Baldwin memstream_seek(void *cookie, fpos_t pos, int whence) 109*9240031aSJohn Baldwin { 110*9240031aSJohn Baldwin struct memstream *ms; 111*9240031aSJohn Baldwin #ifdef DEBUG 112*9240031aSJohn Baldwin fpos_t old; 113*9240031aSJohn Baldwin #endif 114*9240031aSJohn Baldwin 115*9240031aSJohn Baldwin ms = cookie; 116*9240031aSJohn Baldwin #ifdef DEBUG 117*9240031aSJohn Baldwin old = ms->offset; 118*9240031aSJohn Baldwin #endif 119*9240031aSJohn Baldwin switch (whence) { 120*9240031aSJohn Baldwin case SEEK_SET: 121*9240031aSJohn Baldwin /* _fseeko() checks for negative offsets. */ 122*9240031aSJohn Baldwin assert(pos >= 0); 123*9240031aSJohn Baldwin ms->offset = pos; 124*9240031aSJohn Baldwin break; 125*9240031aSJohn Baldwin case SEEK_CUR: 126*9240031aSJohn Baldwin /* This is only called by _ftello(). */ 127*9240031aSJohn Baldwin assert(pos == 0); 128*9240031aSJohn Baldwin break; 129*9240031aSJohn Baldwin case SEEK_END: 130*9240031aSJohn Baldwin if (pos < 0) { 131*9240031aSJohn Baldwin if (pos + ms->len < 0) { 132*9240031aSJohn Baldwin #ifdef DEBUG 133*9240031aSJohn Baldwin fprintf(stderr, 134*9240031aSJohn Baldwin "MS: bad SEEK_END: pos %jd, len %zd\n", 135*9240031aSJohn Baldwin (intmax_t)pos, ms->len); 136*9240031aSJohn Baldwin #endif 137*9240031aSJohn Baldwin errno = EINVAL; 138*9240031aSJohn Baldwin return (-1); 139*9240031aSJohn Baldwin } 140*9240031aSJohn Baldwin } else { 141*9240031aSJohn Baldwin if (FPOS_MAX - ms->len < pos) { 142*9240031aSJohn Baldwin #ifdef DEBUG 143*9240031aSJohn Baldwin fprintf(stderr, 144*9240031aSJohn Baldwin "MS: bad SEEK_END: pos %jd, len %zd\n", 145*9240031aSJohn Baldwin (intmax_t)pos, ms->len); 146*9240031aSJohn Baldwin #endif 147*9240031aSJohn Baldwin errno = EOVERFLOW; 148*9240031aSJohn Baldwin return (-1); 149*9240031aSJohn Baldwin } 150*9240031aSJohn Baldwin } 151*9240031aSJohn Baldwin ms->offset = ms->len + pos; 152*9240031aSJohn Baldwin break; 153*9240031aSJohn Baldwin } 154*9240031aSJohn Baldwin memstream_update(ms); 155*9240031aSJohn Baldwin #ifdef DEBUG 156*9240031aSJohn Baldwin fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos, 157*9240031aSJohn Baldwin whence, (intmax_t)old, (intmax_t)ms->offset); 158*9240031aSJohn Baldwin #endif 159*9240031aSJohn Baldwin return (ms->offset); 160*9240031aSJohn Baldwin } 161*9240031aSJohn Baldwin 162*9240031aSJohn Baldwin static int 163*9240031aSJohn Baldwin memstream_close(void *cookie) 164*9240031aSJohn Baldwin { 165*9240031aSJohn Baldwin 166*9240031aSJohn Baldwin free(cookie); 167*9240031aSJohn Baldwin return (0); 168*9240031aSJohn Baldwin } 169*9240031aSJohn Baldwin 170*9240031aSJohn Baldwin FILE * 171*9240031aSJohn Baldwin open_memstream(char **bufp, size_t *sizep) 172*9240031aSJohn Baldwin { 173*9240031aSJohn Baldwin struct memstream *ms; 174*9240031aSJohn Baldwin int save_errno; 175*9240031aSJohn Baldwin FILE *fp; 176*9240031aSJohn Baldwin 177*9240031aSJohn Baldwin if (bufp == NULL || sizep == NULL) { 178*9240031aSJohn Baldwin errno = EINVAL; 179*9240031aSJohn Baldwin return (NULL); 180*9240031aSJohn Baldwin } 181*9240031aSJohn Baldwin *bufp = calloc(1, 1); 182*9240031aSJohn Baldwin if (*bufp == NULL) 183*9240031aSJohn Baldwin return (NULL); 184*9240031aSJohn Baldwin ms = malloc(sizeof(*ms)); 185*9240031aSJohn Baldwin if (ms == NULL) { 186*9240031aSJohn Baldwin save_errno = errno; 187*9240031aSJohn Baldwin free(*bufp); 188*9240031aSJohn Baldwin *bufp = NULL; 189*9240031aSJohn Baldwin errno = save_errno; 190*9240031aSJohn Baldwin return (NULL); 191*9240031aSJohn Baldwin } 192*9240031aSJohn Baldwin ms->bufp = bufp; 193*9240031aSJohn Baldwin ms->sizep = sizep; 194*9240031aSJohn Baldwin ms->len = 0; 195*9240031aSJohn Baldwin ms->offset = 0; 196*9240031aSJohn Baldwin memstream_update(ms); 197*9240031aSJohn Baldwin fp = funopen(ms, NULL, memstream_write, memstream_seek, 198*9240031aSJohn Baldwin memstream_close); 199*9240031aSJohn Baldwin if (fp == NULL) { 200*9240031aSJohn Baldwin save_errno = errno; 201*9240031aSJohn Baldwin free(ms); 202*9240031aSJohn Baldwin free(*bufp); 203*9240031aSJohn Baldwin *bufp = NULL; 204*9240031aSJohn Baldwin errno = save_errno; 205*9240031aSJohn Baldwin return (NULL); 206*9240031aSJohn Baldwin } 207*9240031aSJohn Baldwin fwide(fp, -1); 208*9240031aSJohn Baldwin return (fp); 209*9240031aSJohn Baldwin } 210