19240031aSJohn Baldwin /*- 2179fa75eSJohn Baldwin * Copyright (c) 2013 Hudson River Trading LLC 39240031aSJohn Baldwin * Written by: John H. Baldwin <jhb@FreeBSD.org> 49240031aSJohn Baldwin * All rights reserved. 59240031aSJohn Baldwin * 69240031aSJohn Baldwin * Redistribution and use in source and binary forms, with or without 79240031aSJohn Baldwin * modification, are permitted provided that the following conditions 89240031aSJohn Baldwin * are met: 99240031aSJohn Baldwin * 1. Redistributions of source code must retain the above copyright 109240031aSJohn Baldwin * notice, this list of conditions and the following disclaimer. 119240031aSJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright 129240031aSJohn Baldwin * notice, this list of conditions and the following disclaimer in the 139240031aSJohn Baldwin * documentation and/or other materials provided with the distribution. 149240031aSJohn Baldwin * 159240031aSJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 169240031aSJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 179240031aSJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 189240031aSJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 199240031aSJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 209240031aSJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 219240031aSJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 229240031aSJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 239240031aSJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 249240031aSJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 259240031aSJohn Baldwin * SUCH DAMAGE. 269240031aSJohn Baldwin */ 279240031aSJohn Baldwin 289240031aSJohn Baldwin #include <sys/cdefs.h> 299240031aSJohn Baldwin __FBSDID("$FreeBSD$"); 309240031aSJohn Baldwin 319240031aSJohn Baldwin #include "namespace.h" 329240031aSJohn Baldwin #include <assert.h> 339240031aSJohn Baldwin #include <errno.h> 349240031aSJohn Baldwin #include <limits.h> 35*c6e61550SEnji Cooper #ifdef DEBUG 36*c6e61550SEnji Cooper #include <stdint.h> 37*c6e61550SEnji Cooper #endif 389240031aSJohn Baldwin #include <stdio.h> 399240031aSJohn Baldwin #include <stdlib.h> 409240031aSJohn Baldwin #include <string.h> 419240031aSJohn Baldwin #include <wchar.h> 429240031aSJohn Baldwin #include "un-namespace.h" 439240031aSJohn Baldwin 449240031aSJohn Baldwin /* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */ 459240031aSJohn Baldwin #define FPOS_MAX OFF_MAX 469240031aSJohn Baldwin 479240031aSJohn Baldwin struct memstream { 489240031aSJohn Baldwin char **bufp; 499240031aSJohn Baldwin size_t *sizep; 509240031aSJohn Baldwin ssize_t len; 519240031aSJohn Baldwin fpos_t offset; 529240031aSJohn Baldwin }; 539240031aSJohn Baldwin 549240031aSJohn Baldwin static int 559240031aSJohn Baldwin memstream_grow(struct memstream *ms, fpos_t newoff) 569240031aSJohn Baldwin { 579240031aSJohn Baldwin char *buf; 589240031aSJohn Baldwin ssize_t newsize; 599240031aSJohn Baldwin 609240031aSJohn Baldwin if (newoff < 0 || newoff >= SSIZE_MAX) 619240031aSJohn Baldwin newsize = SSIZE_MAX - 1; 629240031aSJohn Baldwin else 639240031aSJohn Baldwin newsize = newoff; 649240031aSJohn Baldwin if (newsize > ms->len) { 659240031aSJohn Baldwin buf = realloc(*ms->bufp, newsize + 1); 669240031aSJohn Baldwin if (buf != NULL) { 679240031aSJohn Baldwin #ifdef DEBUG 689240031aSJohn Baldwin fprintf(stderr, "MS: %p growing from %zd to %zd\n", 699240031aSJohn Baldwin ms, ms->len, newsize); 709240031aSJohn Baldwin #endif 719240031aSJohn Baldwin memset(buf + ms->len + 1, 0, newsize - ms->len); 729240031aSJohn Baldwin *ms->bufp = buf; 739240031aSJohn Baldwin ms->len = newsize; 749240031aSJohn Baldwin return (1); 759240031aSJohn Baldwin } 769240031aSJohn Baldwin return (0); 779240031aSJohn Baldwin } 789240031aSJohn Baldwin return (1); 799240031aSJohn Baldwin } 809240031aSJohn Baldwin 819240031aSJohn Baldwin static void 829240031aSJohn Baldwin memstream_update(struct memstream *ms) 839240031aSJohn Baldwin { 849240031aSJohn Baldwin 859240031aSJohn Baldwin assert(ms->len >= 0 && ms->offset >= 0); 869240031aSJohn Baldwin *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset; 879240031aSJohn Baldwin } 889240031aSJohn Baldwin 899240031aSJohn Baldwin static int 909240031aSJohn Baldwin memstream_write(void *cookie, const char *buf, int len) 919240031aSJohn Baldwin { 929240031aSJohn Baldwin struct memstream *ms; 939240031aSJohn Baldwin ssize_t tocopy; 949240031aSJohn Baldwin 959240031aSJohn Baldwin ms = cookie; 969240031aSJohn Baldwin if (!memstream_grow(ms, ms->offset + len)) 979240031aSJohn Baldwin return (-1); 989240031aSJohn Baldwin tocopy = ms->len - ms->offset; 999240031aSJohn Baldwin if (len < tocopy) 1009240031aSJohn Baldwin tocopy = len; 1019240031aSJohn Baldwin memcpy(*ms->bufp + ms->offset, buf, tocopy); 1029240031aSJohn Baldwin ms->offset += tocopy; 1039240031aSJohn Baldwin memstream_update(ms); 1049240031aSJohn Baldwin #ifdef DEBUG 1059240031aSJohn Baldwin fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy); 1069240031aSJohn Baldwin #endif 1079240031aSJohn Baldwin return (tocopy); 1089240031aSJohn Baldwin } 1099240031aSJohn Baldwin 1109240031aSJohn Baldwin static fpos_t 1119240031aSJohn Baldwin memstream_seek(void *cookie, fpos_t pos, int whence) 1129240031aSJohn Baldwin { 1139240031aSJohn Baldwin struct memstream *ms; 1149240031aSJohn Baldwin #ifdef DEBUG 1159240031aSJohn Baldwin fpos_t old; 1169240031aSJohn Baldwin #endif 1179240031aSJohn Baldwin 1189240031aSJohn Baldwin ms = cookie; 1199240031aSJohn Baldwin #ifdef DEBUG 1209240031aSJohn Baldwin old = ms->offset; 1219240031aSJohn Baldwin #endif 1229240031aSJohn Baldwin switch (whence) { 1239240031aSJohn Baldwin case SEEK_SET: 1249240031aSJohn Baldwin /* _fseeko() checks for negative offsets. */ 1259240031aSJohn Baldwin assert(pos >= 0); 1269240031aSJohn Baldwin ms->offset = pos; 1279240031aSJohn Baldwin break; 1289240031aSJohn Baldwin case SEEK_CUR: 1299240031aSJohn Baldwin /* This is only called by _ftello(). */ 1309240031aSJohn Baldwin assert(pos == 0); 1319240031aSJohn Baldwin break; 1329240031aSJohn Baldwin case SEEK_END: 1339240031aSJohn Baldwin if (pos < 0) { 1349240031aSJohn Baldwin if (pos + ms->len < 0) { 1359240031aSJohn Baldwin #ifdef DEBUG 1369240031aSJohn Baldwin fprintf(stderr, 1379240031aSJohn Baldwin "MS: bad SEEK_END: pos %jd, len %zd\n", 1389240031aSJohn Baldwin (intmax_t)pos, ms->len); 1399240031aSJohn Baldwin #endif 1409240031aSJohn Baldwin errno = EINVAL; 1419240031aSJohn Baldwin return (-1); 1429240031aSJohn Baldwin } 1439240031aSJohn Baldwin } else { 1449240031aSJohn Baldwin if (FPOS_MAX - ms->len < pos) { 1459240031aSJohn Baldwin #ifdef DEBUG 1469240031aSJohn Baldwin fprintf(stderr, 1479240031aSJohn Baldwin "MS: bad SEEK_END: pos %jd, len %zd\n", 1489240031aSJohn Baldwin (intmax_t)pos, ms->len); 1499240031aSJohn Baldwin #endif 1509240031aSJohn Baldwin errno = EOVERFLOW; 1519240031aSJohn Baldwin return (-1); 1529240031aSJohn Baldwin } 1539240031aSJohn Baldwin } 1549240031aSJohn Baldwin ms->offset = ms->len + pos; 1559240031aSJohn Baldwin break; 1569240031aSJohn Baldwin } 1579240031aSJohn Baldwin memstream_update(ms); 1589240031aSJohn Baldwin #ifdef DEBUG 1599240031aSJohn Baldwin fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos, 1609240031aSJohn Baldwin whence, (intmax_t)old, (intmax_t)ms->offset); 1619240031aSJohn Baldwin #endif 1629240031aSJohn Baldwin return (ms->offset); 1639240031aSJohn Baldwin } 1649240031aSJohn Baldwin 1659240031aSJohn Baldwin static int 1669240031aSJohn Baldwin memstream_close(void *cookie) 1679240031aSJohn Baldwin { 1689240031aSJohn Baldwin 1699240031aSJohn Baldwin free(cookie); 1709240031aSJohn Baldwin return (0); 1719240031aSJohn Baldwin } 1729240031aSJohn Baldwin 1739240031aSJohn Baldwin FILE * 1749240031aSJohn Baldwin open_memstream(char **bufp, size_t *sizep) 1759240031aSJohn Baldwin { 1769240031aSJohn Baldwin struct memstream *ms; 1779240031aSJohn Baldwin int save_errno; 1789240031aSJohn Baldwin FILE *fp; 1799240031aSJohn Baldwin 1809240031aSJohn Baldwin if (bufp == NULL || sizep == NULL) { 1819240031aSJohn Baldwin errno = EINVAL; 1829240031aSJohn Baldwin return (NULL); 1839240031aSJohn Baldwin } 1849240031aSJohn Baldwin *bufp = calloc(1, 1); 1859240031aSJohn Baldwin if (*bufp == NULL) 1869240031aSJohn Baldwin return (NULL); 1879240031aSJohn Baldwin ms = malloc(sizeof(*ms)); 1889240031aSJohn Baldwin if (ms == NULL) { 1899240031aSJohn Baldwin save_errno = errno; 1909240031aSJohn Baldwin free(*bufp); 1919240031aSJohn Baldwin *bufp = NULL; 1929240031aSJohn Baldwin errno = save_errno; 1939240031aSJohn Baldwin return (NULL); 1949240031aSJohn Baldwin } 1959240031aSJohn Baldwin ms->bufp = bufp; 1969240031aSJohn Baldwin ms->sizep = sizep; 1979240031aSJohn Baldwin ms->len = 0; 1989240031aSJohn Baldwin ms->offset = 0; 1999240031aSJohn Baldwin memstream_update(ms); 2009240031aSJohn Baldwin fp = funopen(ms, NULL, memstream_write, memstream_seek, 2019240031aSJohn Baldwin memstream_close); 2029240031aSJohn Baldwin if (fp == NULL) { 2039240031aSJohn Baldwin save_errno = errno; 2049240031aSJohn Baldwin free(ms); 2059240031aSJohn Baldwin free(*bufp); 2069240031aSJohn Baldwin *bufp = NULL; 2079240031aSJohn Baldwin errno = save_errno; 2089240031aSJohn Baldwin return (NULL); 2099240031aSJohn Baldwin } 2109240031aSJohn Baldwin fwide(fp, -1); 2119240031aSJohn Baldwin return (fp); 2129240031aSJohn Baldwin } 213