1*ac593df8Smillert /* $OpenBSD: fmemopen.c,v 1.4 2020/08/14 12:00:33 millert Exp $ */ 203222a19Smpi 31b5be6a0Smpi /* 41b5be6a0Smpi * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> 51b5be6a0Smpi * Copyright (c) 2009 Ted Unangst 61b5be6a0Smpi * 71b5be6a0Smpi * Permission to use, copy, modify, and distribute this software for any 81b5be6a0Smpi * purpose with or without fee is hereby granted, provided that the above 91b5be6a0Smpi * copyright notice and this permission notice appear in all copies. 101b5be6a0Smpi * 111b5be6a0Smpi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 121b5be6a0Smpi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 131b5be6a0Smpi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 141b5be6a0Smpi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 151b5be6a0Smpi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 161b5be6a0Smpi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 171b5be6a0Smpi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 181b5be6a0Smpi */ 191b5be6a0Smpi 201b5be6a0Smpi #include <errno.h> 211b5be6a0Smpi #include <fcntl.h> 221b5be6a0Smpi #include <stdio.h> 231b5be6a0Smpi #include <stdlib.h> 2403222a19Smpi #include <string.h> 251b5be6a0Smpi #include "local.h" 261b5be6a0Smpi 271b5be6a0Smpi struct state { 281b5be6a0Smpi char *string; /* actual stream */ 291b5be6a0Smpi size_t pos; /* current position */ 301b5be6a0Smpi size_t size; /* allocated size */ 311b5be6a0Smpi size_t len; /* length of the data */ 3203222a19Smpi int update; /* open for update */ 331b5be6a0Smpi }; 341b5be6a0Smpi 351b5be6a0Smpi static int 361b5be6a0Smpi fmemopen_read(void *v, char *b, int l) 371b5be6a0Smpi { 381b5be6a0Smpi struct state *st = v; 391b5be6a0Smpi int i; 401b5be6a0Smpi 411b5be6a0Smpi for (i = 0; i < l && i + st->pos < st->len; i++) 421b5be6a0Smpi b[i] = st->string[st->pos + i]; 431b5be6a0Smpi st->pos += i; 441b5be6a0Smpi 451b5be6a0Smpi return (i); 461b5be6a0Smpi } 471b5be6a0Smpi 481b5be6a0Smpi static int 491b5be6a0Smpi fmemopen_write(void *v, const char *b, int l) 501b5be6a0Smpi { 511b5be6a0Smpi struct state *st = v; 521b5be6a0Smpi int i; 531b5be6a0Smpi 541b5be6a0Smpi for (i = 0; i < l && i + st->pos < st->size; i++) 551b5be6a0Smpi st->string[st->pos + i] = b[i]; 561b5be6a0Smpi st->pos += i; 571b5be6a0Smpi 581b5be6a0Smpi if (st->pos >= st->len) { 591b5be6a0Smpi st->len = st->pos; 601b5be6a0Smpi 6103222a19Smpi if (st->len < st->size) 621b5be6a0Smpi st->string[st->len] = '\0'; 6303222a19Smpi else if (!st->update) 6403222a19Smpi st->string[st->size - 1] = '\0'; 651b5be6a0Smpi } 661b5be6a0Smpi 671b5be6a0Smpi return (i); 681b5be6a0Smpi } 691b5be6a0Smpi 701b5be6a0Smpi static fpos_t 7103222a19Smpi fmemopen_seek(void *v, fpos_t off, int whence) 721b5be6a0Smpi { 731b5be6a0Smpi struct state *st = v; 7403222a19Smpi ssize_t base = 0; 751b5be6a0Smpi 761b5be6a0Smpi switch (whence) { 771b5be6a0Smpi case SEEK_SET: 781b5be6a0Smpi break; 791b5be6a0Smpi case SEEK_CUR: 8003222a19Smpi base = st->pos; 811b5be6a0Smpi break; 821b5be6a0Smpi case SEEK_END: 8303222a19Smpi base = st->len; 841b5be6a0Smpi break; 8503222a19Smpi } 8603222a19Smpi 8703222a19Smpi if (off > st->size - base || off < -base) { 8803222a19Smpi errno = EOVERFLOW; 891b5be6a0Smpi return (-1); 901b5be6a0Smpi } 911b5be6a0Smpi 9203222a19Smpi st->pos = base + off; 931b5be6a0Smpi 9403222a19Smpi return (st->pos); 951b5be6a0Smpi } 961b5be6a0Smpi 971b5be6a0Smpi static int 981b5be6a0Smpi fmemopen_close(void *v) 991b5be6a0Smpi { 1001b5be6a0Smpi free(v); 1011b5be6a0Smpi 1021b5be6a0Smpi return (0); 1031b5be6a0Smpi } 1041b5be6a0Smpi 1051b5be6a0Smpi static int 1061b5be6a0Smpi fmemopen_close_free(void *v) 1071b5be6a0Smpi { 1081b5be6a0Smpi struct state *st = v; 1091b5be6a0Smpi 1101b5be6a0Smpi free(st->string); 1111b5be6a0Smpi free(st); 1121b5be6a0Smpi 1131b5be6a0Smpi return (0); 1141b5be6a0Smpi } 1151b5be6a0Smpi 1161b5be6a0Smpi FILE * 1171b5be6a0Smpi fmemopen(void *buf, size_t size, const char *mode) 1181b5be6a0Smpi { 1191b5be6a0Smpi struct state *st; 1201b5be6a0Smpi FILE *fp; 1211b5be6a0Smpi int flags, oflags; 1221b5be6a0Smpi 1231b5be6a0Smpi if (size == 0) { 1241b5be6a0Smpi errno = EINVAL; 1251b5be6a0Smpi return (NULL); 1261b5be6a0Smpi } 1271b5be6a0Smpi 1281b5be6a0Smpi if ((flags = __sflags(mode, &oflags)) == 0) { 1291b5be6a0Smpi errno = EINVAL; 1301b5be6a0Smpi return (NULL); 1311b5be6a0Smpi } 1321b5be6a0Smpi 1331b5be6a0Smpi if (buf == NULL && ((oflags & O_RDWR) == 0)) { 1341b5be6a0Smpi errno = EINVAL; 1351b5be6a0Smpi return (NULL); 1361b5be6a0Smpi } 1371b5be6a0Smpi 1381b5be6a0Smpi if ((st = malloc(sizeof(*st))) == NULL) 1391b5be6a0Smpi return (NULL); 1401b5be6a0Smpi 1411b5be6a0Smpi if ((fp = __sfp()) == NULL) { 1421b5be6a0Smpi free(st); 1431b5be6a0Smpi return (NULL); 1441b5be6a0Smpi } 1451b5be6a0Smpi 1461b5be6a0Smpi st->pos = 0; 147*ac593df8Smillert st->len = (oflags & O_TRUNC) ? 0 : size; 1481b5be6a0Smpi st->size = size; 14903222a19Smpi st->update = oflags & O_RDWR; 1501b5be6a0Smpi 1511b5be6a0Smpi if (buf == NULL) { 1521b5be6a0Smpi if ((st->string = malloc(size)) == NULL) { 1531b5be6a0Smpi free(st); 1541b5be6a0Smpi fp->_flags = 0; 1551b5be6a0Smpi return (NULL); 1561b5be6a0Smpi } 1571b5be6a0Smpi *st->string = '\0'; 1581b5be6a0Smpi } else { 1591b5be6a0Smpi st->string = (char *)buf; 1601b5be6a0Smpi 1611b5be6a0Smpi if (oflags & O_TRUNC) 1621b5be6a0Smpi *st->string = '\0'; 1631b5be6a0Smpi 1641b5be6a0Smpi if (oflags & O_APPEND) { 1651b5be6a0Smpi char *p; 1661b5be6a0Smpi 1671b5be6a0Smpi if ((p = memchr(st->string, '\0', size)) != NULL) 1681b5be6a0Smpi st->pos = st->len = (p - st->string); 1691b5be6a0Smpi else 1701b5be6a0Smpi st->pos = st->len = size; 1711b5be6a0Smpi } 1721b5be6a0Smpi } 1731b5be6a0Smpi 1741b5be6a0Smpi fp->_flags = (short)flags; 1751b5be6a0Smpi fp->_file = -1; 1761b5be6a0Smpi fp->_cookie = (void *)st; 1771b5be6a0Smpi fp->_read = (flags & __SWR) ? NULL : fmemopen_read; 1781b5be6a0Smpi fp->_write = (flags & __SRD) ? NULL : fmemopen_write; 1791b5be6a0Smpi fp->_seek = fmemopen_seek; 1801b5be6a0Smpi fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close; 1811b5be6a0Smpi 1821b5be6a0Smpi return (fp); 1831b5be6a0Smpi } 1849b9d2a55Sguenther DEF_WEAK(fmemopen); 185