1*d35e2a8fSmillert /* $OpenBSD: fmemopen.c,v 1.5 2020/08/17 16:17:39 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 */
33*d35e2a8fSmillert int append; /* open for append */
341b5be6a0Smpi };
351b5be6a0Smpi
361b5be6a0Smpi static int
fmemopen_read(void * v,char * b,int l)371b5be6a0Smpi fmemopen_read(void *v, char *b, int l)
381b5be6a0Smpi {
391b5be6a0Smpi struct state *st = v;
401b5be6a0Smpi int i;
411b5be6a0Smpi
421b5be6a0Smpi for (i = 0; i < l && i + st->pos < st->len; i++)
431b5be6a0Smpi b[i] = st->string[st->pos + i];
441b5be6a0Smpi st->pos += i;
451b5be6a0Smpi
461b5be6a0Smpi return (i);
471b5be6a0Smpi }
481b5be6a0Smpi
491b5be6a0Smpi static int
fmemopen_write(void * v,const char * b,int l)501b5be6a0Smpi fmemopen_write(void *v, const char *b, int l)
511b5be6a0Smpi {
521b5be6a0Smpi struct state *st = v;
531b5be6a0Smpi int i;
541b5be6a0Smpi
55*d35e2a8fSmillert if (st->append)
56*d35e2a8fSmillert st->pos = st->len;
57*d35e2a8fSmillert
581b5be6a0Smpi for (i = 0; i < l && i + st->pos < st->size; i++)
591b5be6a0Smpi st->string[st->pos + i] = b[i];
601b5be6a0Smpi st->pos += i;
611b5be6a0Smpi
621b5be6a0Smpi if (st->pos >= st->len) {
631b5be6a0Smpi st->len = st->pos;
641b5be6a0Smpi
6503222a19Smpi if (st->len < st->size)
661b5be6a0Smpi st->string[st->len] = '\0';
6703222a19Smpi else if (!st->update)
6803222a19Smpi st->string[st->size - 1] = '\0';
691b5be6a0Smpi }
701b5be6a0Smpi
711b5be6a0Smpi return (i);
721b5be6a0Smpi }
731b5be6a0Smpi
741b5be6a0Smpi static fpos_t
fmemopen_seek(void * v,fpos_t off,int whence)7503222a19Smpi fmemopen_seek(void *v, fpos_t off, int whence)
761b5be6a0Smpi {
771b5be6a0Smpi struct state *st = v;
7803222a19Smpi ssize_t base = 0;
791b5be6a0Smpi
801b5be6a0Smpi switch (whence) {
811b5be6a0Smpi case SEEK_SET:
821b5be6a0Smpi break;
831b5be6a0Smpi case SEEK_CUR:
8403222a19Smpi base = st->pos;
851b5be6a0Smpi break;
861b5be6a0Smpi case SEEK_END:
8703222a19Smpi base = st->len;
881b5be6a0Smpi break;
8903222a19Smpi }
9003222a19Smpi
9103222a19Smpi if (off > st->size - base || off < -base) {
9203222a19Smpi errno = EOVERFLOW;
931b5be6a0Smpi return (-1);
941b5be6a0Smpi }
951b5be6a0Smpi
9603222a19Smpi st->pos = base + off;
971b5be6a0Smpi
9803222a19Smpi return (st->pos);
991b5be6a0Smpi }
1001b5be6a0Smpi
1011b5be6a0Smpi static int
fmemopen_close(void * v)1021b5be6a0Smpi fmemopen_close(void *v)
1031b5be6a0Smpi {
1041b5be6a0Smpi free(v);
1051b5be6a0Smpi
1061b5be6a0Smpi return (0);
1071b5be6a0Smpi }
1081b5be6a0Smpi
1091b5be6a0Smpi static int
fmemopen_close_free(void * v)1101b5be6a0Smpi fmemopen_close_free(void *v)
1111b5be6a0Smpi {
1121b5be6a0Smpi struct state *st = v;
1131b5be6a0Smpi
1141b5be6a0Smpi free(st->string);
1151b5be6a0Smpi free(st);
1161b5be6a0Smpi
1171b5be6a0Smpi return (0);
1181b5be6a0Smpi }
1191b5be6a0Smpi
1201b5be6a0Smpi FILE *
fmemopen(void * buf,size_t size,const char * mode)1211b5be6a0Smpi fmemopen(void *buf, size_t size, const char *mode)
1221b5be6a0Smpi {
1231b5be6a0Smpi struct state *st;
1241b5be6a0Smpi FILE *fp;
1251b5be6a0Smpi int flags, oflags;
1261b5be6a0Smpi
1271b5be6a0Smpi if (size == 0) {
1281b5be6a0Smpi errno = EINVAL;
1291b5be6a0Smpi return (NULL);
1301b5be6a0Smpi }
1311b5be6a0Smpi
1321b5be6a0Smpi if ((flags = __sflags(mode, &oflags)) == 0) {
1331b5be6a0Smpi errno = EINVAL;
1341b5be6a0Smpi return (NULL);
1351b5be6a0Smpi }
1361b5be6a0Smpi
1371b5be6a0Smpi if (buf == NULL && ((oflags & O_RDWR) == 0)) {
1381b5be6a0Smpi errno = EINVAL;
1391b5be6a0Smpi return (NULL);
1401b5be6a0Smpi }
1411b5be6a0Smpi
1421b5be6a0Smpi if ((st = malloc(sizeof(*st))) == NULL)
1431b5be6a0Smpi return (NULL);
1441b5be6a0Smpi
1451b5be6a0Smpi if ((fp = __sfp()) == NULL) {
1461b5be6a0Smpi free(st);
1471b5be6a0Smpi return (NULL);
1481b5be6a0Smpi }
1491b5be6a0Smpi
1501b5be6a0Smpi st->pos = 0;
151ac593df8Smillert st->len = (oflags & O_TRUNC) ? 0 : size;
1521b5be6a0Smpi st->size = size;
15303222a19Smpi st->update = oflags & O_RDWR;
154*d35e2a8fSmillert st->append = oflags & O_APPEND;
1551b5be6a0Smpi
1561b5be6a0Smpi if (buf == NULL) {
1571b5be6a0Smpi if ((st->string = malloc(size)) == NULL) {
1581b5be6a0Smpi free(st);
1591b5be6a0Smpi fp->_flags = 0;
1601b5be6a0Smpi return (NULL);
1611b5be6a0Smpi }
1621b5be6a0Smpi *st->string = '\0';
1631b5be6a0Smpi } else {
1641b5be6a0Smpi st->string = (char *)buf;
1651b5be6a0Smpi
1661b5be6a0Smpi if (oflags & O_TRUNC)
1671b5be6a0Smpi *st->string = '\0';
1681b5be6a0Smpi
1691b5be6a0Smpi if (oflags & O_APPEND) {
1701b5be6a0Smpi char *p;
1711b5be6a0Smpi
1721b5be6a0Smpi if ((p = memchr(st->string, '\0', size)) != NULL)
1731b5be6a0Smpi st->pos = st->len = (p - st->string);
1741b5be6a0Smpi else
1751b5be6a0Smpi st->pos = st->len = size;
1761b5be6a0Smpi }
1771b5be6a0Smpi }
1781b5be6a0Smpi
1791b5be6a0Smpi fp->_flags = (short)flags;
1801b5be6a0Smpi fp->_file = -1;
181*d35e2a8fSmillert fp->_cookie = st;
1821b5be6a0Smpi fp->_read = (flags & __SWR) ? NULL : fmemopen_read;
1831b5be6a0Smpi fp->_write = (flags & __SRD) ? NULL : fmemopen_write;
1841b5be6a0Smpi fp->_seek = fmemopen_seek;
1851b5be6a0Smpi fp->_close = (buf == NULL) ? fmemopen_close_free : fmemopen_close;
1861b5be6a0Smpi
1871b5be6a0Smpi return (fp);
1881b5be6a0Smpi }
1899b9d2a55Sguenther DEF_WEAK(fmemopen);
190