19240031aSJohn Baldwin /*- 2*179fa75eSJohn 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> 359240031aSJohn Baldwin #include <stdio.h> 369240031aSJohn Baldwin #include <stdlib.h> 379240031aSJohn Baldwin #include <string.h> 389240031aSJohn Baldwin #include <wchar.h> 399240031aSJohn Baldwin #include "un-namespace.h" 409240031aSJohn Baldwin 419240031aSJohn Baldwin /* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */ 429240031aSJohn Baldwin #define FPOS_MAX OFF_MAX 439240031aSJohn Baldwin 449240031aSJohn Baldwin struct memstream { 459240031aSJohn Baldwin char **bufp; 469240031aSJohn Baldwin size_t *sizep; 479240031aSJohn Baldwin ssize_t len; 489240031aSJohn Baldwin fpos_t offset; 499240031aSJohn Baldwin }; 509240031aSJohn Baldwin 519240031aSJohn Baldwin static int 529240031aSJohn Baldwin memstream_grow(struct memstream *ms, fpos_t newoff) 539240031aSJohn Baldwin { 549240031aSJohn Baldwin char *buf; 559240031aSJohn Baldwin ssize_t newsize; 569240031aSJohn Baldwin 579240031aSJohn Baldwin if (newoff < 0 || newoff >= SSIZE_MAX) 589240031aSJohn Baldwin newsize = SSIZE_MAX - 1; 599240031aSJohn Baldwin else 609240031aSJohn Baldwin newsize = newoff; 619240031aSJohn Baldwin if (newsize > ms->len) { 629240031aSJohn Baldwin buf = realloc(*ms->bufp, newsize + 1); 639240031aSJohn Baldwin if (buf != NULL) { 649240031aSJohn Baldwin #ifdef DEBUG 659240031aSJohn Baldwin fprintf(stderr, "MS: %p growing from %zd to %zd\n", 669240031aSJohn Baldwin ms, ms->len, newsize); 679240031aSJohn Baldwin #endif 689240031aSJohn Baldwin memset(buf + ms->len + 1, 0, newsize - ms->len); 699240031aSJohn Baldwin *ms->bufp = buf; 709240031aSJohn Baldwin ms->len = newsize; 719240031aSJohn Baldwin return (1); 729240031aSJohn Baldwin } 739240031aSJohn Baldwin return (0); 749240031aSJohn Baldwin } 759240031aSJohn Baldwin return (1); 769240031aSJohn Baldwin } 779240031aSJohn Baldwin 789240031aSJohn Baldwin static void 799240031aSJohn Baldwin memstream_update(struct memstream *ms) 809240031aSJohn Baldwin { 819240031aSJohn Baldwin 829240031aSJohn Baldwin assert(ms->len >= 0 && ms->offset >= 0); 839240031aSJohn Baldwin *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset; 849240031aSJohn Baldwin } 859240031aSJohn Baldwin 869240031aSJohn Baldwin static int 879240031aSJohn Baldwin memstream_write(void *cookie, const char *buf, int len) 889240031aSJohn Baldwin { 899240031aSJohn Baldwin struct memstream *ms; 909240031aSJohn Baldwin ssize_t tocopy; 919240031aSJohn Baldwin 929240031aSJohn Baldwin ms = cookie; 939240031aSJohn Baldwin if (!memstream_grow(ms, ms->offset + len)) 949240031aSJohn Baldwin return (-1); 959240031aSJohn Baldwin tocopy = ms->len - ms->offset; 969240031aSJohn Baldwin if (len < tocopy) 979240031aSJohn Baldwin tocopy = len; 989240031aSJohn Baldwin memcpy(*ms->bufp + ms->offset, buf, tocopy); 999240031aSJohn Baldwin ms->offset += tocopy; 1009240031aSJohn Baldwin memstream_update(ms); 1019240031aSJohn Baldwin #ifdef DEBUG 1029240031aSJohn Baldwin fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy); 1039240031aSJohn Baldwin #endif 1049240031aSJohn Baldwin return (tocopy); 1059240031aSJohn Baldwin } 1069240031aSJohn Baldwin 1079240031aSJohn Baldwin static fpos_t 1089240031aSJohn Baldwin memstream_seek(void *cookie, fpos_t pos, int whence) 1099240031aSJohn Baldwin { 1109240031aSJohn Baldwin struct memstream *ms; 1119240031aSJohn Baldwin #ifdef DEBUG 1129240031aSJohn Baldwin fpos_t old; 1139240031aSJohn Baldwin #endif 1149240031aSJohn Baldwin 1159240031aSJohn Baldwin ms = cookie; 1169240031aSJohn Baldwin #ifdef DEBUG 1179240031aSJohn Baldwin old = ms->offset; 1189240031aSJohn Baldwin #endif 1199240031aSJohn Baldwin switch (whence) { 1209240031aSJohn Baldwin case SEEK_SET: 1219240031aSJohn Baldwin /* _fseeko() checks for negative offsets. */ 1229240031aSJohn Baldwin assert(pos >= 0); 1239240031aSJohn Baldwin ms->offset = pos; 1249240031aSJohn Baldwin break; 1259240031aSJohn Baldwin case SEEK_CUR: 1269240031aSJohn Baldwin /* This is only called by _ftello(). */ 1279240031aSJohn Baldwin assert(pos == 0); 1289240031aSJohn Baldwin break; 1299240031aSJohn Baldwin case SEEK_END: 1309240031aSJohn Baldwin if (pos < 0) { 1319240031aSJohn Baldwin if (pos + ms->len < 0) { 1329240031aSJohn Baldwin #ifdef DEBUG 1339240031aSJohn Baldwin fprintf(stderr, 1349240031aSJohn Baldwin "MS: bad SEEK_END: pos %jd, len %zd\n", 1359240031aSJohn Baldwin (intmax_t)pos, ms->len); 1369240031aSJohn Baldwin #endif 1379240031aSJohn Baldwin errno = EINVAL; 1389240031aSJohn Baldwin return (-1); 1399240031aSJohn Baldwin } 1409240031aSJohn Baldwin } else { 1419240031aSJohn Baldwin if (FPOS_MAX - ms->len < pos) { 1429240031aSJohn Baldwin #ifdef DEBUG 1439240031aSJohn Baldwin fprintf(stderr, 1449240031aSJohn Baldwin "MS: bad SEEK_END: pos %jd, len %zd\n", 1459240031aSJohn Baldwin (intmax_t)pos, ms->len); 1469240031aSJohn Baldwin #endif 1479240031aSJohn Baldwin errno = EOVERFLOW; 1489240031aSJohn Baldwin return (-1); 1499240031aSJohn Baldwin } 1509240031aSJohn Baldwin } 1519240031aSJohn Baldwin ms->offset = ms->len + pos; 1529240031aSJohn Baldwin break; 1539240031aSJohn Baldwin } 1549240031aSJohn Baldwin memstream_update(ms); 1559240031aSJohn Baldwin #ifdef DEBUG 1569240031aSJohn Baldwin fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos, 1579240031aSJohn Baldwin whence, (intmax_t)old, (intmax_t)ms->offset); 1589240031aSJohn Baldwin #endif 1599240031aSJohn Baldwin return (ms->offset); 1609240031aSJohn Baldwin } 1619240031aSJohn Baldwin 1629240031aSJohn Baldwin static int 1639240031aSJohn Baldwin memstream_close(void *cookie) 1649240031aSJohn Baldwin { 1659240031aSJohn Baldwin 1669240031aSJohn Baldwin free(cookie); 1679240031aSJohn Baldwin return (0); 1689240031aSJohn Baldwin } 1699240031aSJohn Baldwin 1709240031aSJohn Baldwin FILE * 1719240031aSJohn Baldwin open_memstream(char **bufp, size_t *sizep) 1729240031aSJohn Baldwin { 1739240031aSJohn Baldwin struct memstream *ms; 1749240031aSJohn Baldwin int save_errno; 1759240031aSJohn Baldwin FILE *fp; 1769240031aSJohn Baldwin 1779240031aSJohn Baldwin if (bufp == NULL || sizep == NULL) { 1789240031aSJohn Baldwin errno = EINVAL; 1799240031aSJohn Baldwin return (NULL); 1809240031aSJohn Baldwin } 1819240031aSJohn Baldwin *bufp = calloc(1, 1); 1829240031aSJohn Baldwin if (*bufp == NULL) 1839240031aSJohn Baldwin return (NULL); 1849240031aSJohn Baldwin ms = malloc(sizeof(*ms)); 1859240031aSJohn Baldwin if (ms == NULL) { 1869240031aSJohn Baldwin save_errno = errno; 1879240031aSJohn Baldwin free(*bufp); 1889240031aSJohn Baldwin *bufp = NULL; 1899240031aSJohn Baldwin errno = save_errno; 1909240031aSJohn Baldwin return (NULL); 1919240031aSJohn Baldwin } 1929240031aSJohn Baldwin ms->bufp = bufp; 1939240031aSJohn Baldwin ms->sizep = sizep; 1949240031aSJohn Baldwin ms->len = 0; 1959240031aSJohn Baldwin ms->offset = 0; 1969240031aSJohn Baldwin memstream_update(ms); 1979240031aSJohn Baldwin fp = funopen(ms, NULL, memstream_write, memstream_seek, 1989240031aSJohn Baldwin memstream_close); 1999240031aSJohn Baldwin if (fp == NULL) { 2009240031aSJohn Baldwin save_errno = errno; 2019240031aSJohn Baldwin free(ms); 2029240031aSJohn Baldwin free(*bufp); 2039240031aSJohn Baldwin *bufp = NULL; 2049240031aSJohn Baldwin errno = save_errno; 2059240031aSJohn Baldwin return (NULL); 2069240031aSJohn Baldwin } 2079240031aSJohn Baldwin fwide(fp, -1); 2089240031aSJohn Baldwin return (fp); 2099240031aSJohn Baldwin } 210