1*f14fb602SLionel Sambuc /* $NetBSD: funopen.c,v 1.14 2012/03/28 15:21:11 christos Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras * Copyright (c) 1990, 1993
52fe8fb19SBen Gras * The Regents of the University of California. All rights reserved.
62fe8fb19SBen Gras *
72fe8fb19SBen Gras * This code is derived from software contributed to Berkeley by
82fe8fb19SBen Gras * Chris Torek.
92fe8fb19SBen Gras *
102fe8fb19SBen Gras * Redistribution and use in source and binary forms, with or without
112fe8fb19SBen Gras * modification, are permitted provided that the following conditions
122fe8fb19SBen Gras * are met:
132fe8fb19SBen Gras * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer in the
172fe8fb19SBen Gras * documentation and/or other materials provided with the distribution.
182fe8fb19SBen Gras * 3. Neither the name of the University nor the names of its contributors
192fe8fb19SBen Gras * may be used to endorse or promote products derived from this software
202fe8fb19SBen Gras * without specific prior written permission.
212fe8fb19SBen Gras *
222fe8fb19SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232fe8fb19SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242fe8fb19SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252fe8fb19SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262fe8fb19SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272fe8fb19SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282fe8fb19SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292fe8fb19SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302fe8fb19SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312fe8fb19SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322fe8fb19SBen Gras * SUCH DAMAGE.
332fe8fb19SBen Gras */
342fe8fb19SBen Gras
352fe8fb19SBen Gras #include <sys/cdefs.h>
362fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
372fe8fb19SBen Gras #if 0
382fe8fb19SBen Gras static char sccsid[] = "@(#)funopen.c 8.1 (Berkeley) 6/4/93";
392fe8fb19SBen Gras #else
40*f14fb602SLionel Sambuc __RCSID("$NetBSD: funopen.c,v 1.14 2012/03/28 15:21:11 christos Exp $");
412fe8fb19SBen Gras #endif
422fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
432fe8fb19SBen Gras
442fe8fb19SBen Gras #include <stdio.h>
452fe8fb19SBen Gras #include <errno.h>
46*f14fb602SLionel Sambuc #include <stdlib.h>
47*f14fb602SLionel Sambuc #include <stddef.h>
482fe8fb19SBen Gras #include "reentrant.h"
492fe8fb19SBen Gras #include "local.h"
502fe8fb19SBen Gras
512fe8fb19SBen Gras FILE *
funopen2(const void * cookie,ssize_t (* readfn)(void *,void *,size_t),ssize_t (* writefn)(void *,const void *,size_t),off_t (* seekfn)(void *,off_t,int),int (* flushfn)(void *),int (* closefn)(void *))52*f14fb602SLionel Sambuc funopen2(const void *cookie,
53*f14fb602SLionel Sambuc ssize_t (*readfn)(void *, void *, size_t),
54*f14fb602SLionel Sambuc ssize_t (*writefn)(void *, const void *, size_t),
55*f14fb602SLionel Sambuc off_t (*seekfn)(void *, off_t, int),
56*f14fb602SLionel Sambuc int (*flushfn)(void *),
57*f14fb602SLionel Sambuc int (*closefn)(void *))
582fe8fb19SBen Gras {
592fe8fb19SBen Gras FILE *fp;
602fe8fb19SBen Gras int flags;
612fe8fb19SBen Gras
622fe8fb19SBen Gras if (readfn == NULL) {
632fe8fb19SBen Gras if (writefn == NULL) { /* illegal */
642fe8fb19SBen Gras errno = EINVAL;
65*f14fb602SLionel Sambuc return NULL;
662fe8fb19SBen Gras } else
672fe8fb19SBen Gras flags = __SWR; /* write only */
682fe8fb19SBen Gras } else {
692fe8fb19SBen Gras if (writefn == NULL)
702fe8fb19SBen Gras flags = __SRD; /* read only */
712fe8fb19SBen Gras else
722fe8fb19SBen Gras flags = __SRW; /* read-write */
732fe8fb19SBen Gras }
742fe8fb19SBen Gras if ((fp = __sfp()) == NULL)
75*f14fb602SLionel Sambuc return NULL;
762fe8fb19SBen Gras fp->_flags = flags;
772fe8fb19SBen Gras fp->_file = -1;
782fe8fb19SBen Gras fp->_cookie = __UNCONST(cookie);
792fe8fb19SBen Gras fp->_read = readfn;
802fe8fb19SBen Gras fp->_write = writefn;
812fe8fb19SBen Gras fp->_seek = seekfn;
82*f14fb602SLionel Sambuc fp->_flush = flushfn;
832fe8fb19SBen Gras fp->_close = closefn;
84*f14fb602SLionel Sambuc return fp;
85*f14fb602SLionel Sambuc }
86*f14fb602SLionel Sambuc
87*f14fb602SLionel Sambuc typedef struct {
88*f14fb602SLionel Sambuc void *cookie;
89*f14fb602SLionel Sambuc int (*readfn)(void *, char *, int);
90*f14fb602SLionel Sambuc int (*writefn)(void *, const char *, int);
91*f14fb602SLionel Sambuc off_t (*seekfn)(void *, off_t, int);
92*f14fb602SLionel Sambuc int (*closefn)(void *);
93*f14fb602SLionel Sambuc } dookie_t;
94*f14fb602SLionel Sambuc
95*f14fb602SLionel Sambuc static ssize_t
creadfn(void * dookie,void * buf,size_t len)96*f14fb602SLionel Sambuc creadfn(void *dookie, void *buf, size_t len)
97*f14fb602SLionel Sambuc {
98*f14fb602SLionel Sambuc dookie_t *d = dookie;
99*f14fb602SLionel Sambuc if (len > INT_MAX)
100*f14fb602SLionel Sambuc len = INT_MAX;
101*f14fb602SLionel Sambuc return (*d->readfn)(d->cookie, buf, (int)len);
102*f14fb602SLionel Sambuc }
103*f14fb602SLionel Sambuc
104*f14fb602SLionel Sambuc static ssize_t
cwritefn(void * dookie,const void * buf,size_t len)105*f14fb602SLionel Sambuc cwritefn(void *dookie, const void *buf, size_t len)
106*f14fb602SLionel Sambuc {
107*f14fb602SLionel Sambuc dookie_t *d = dookie;
108*f14fb602SLionel Sambuc ssize_t nr;
109*f14fb602SLionel Sambuc size_t l = len;
110*f14fb602SLionel Sambuc const char *b = buf;
111*f14fb602SLionel Sambuc
112*f14fb602SLionel Sambuc while (l) {
113*f14fb602SLionel Sambuc size_t nw = l > INT_MAX ? INT_MAX : l;
114*f14fb602SLionel Sambuc nr = (*d->writefn)(d->cookie, buf, (int)nw);
115*f14fb602SLionel Sambuc if (nr == -1) {
116*f14fb602SLionel Sambuc if (len == l)
117*f14fb602SLionel Sambuc return -1;
118*f14fb602SLionel Sambuc else
119*f14fb602SLionel Sambuc return len - l;
120*f14fb602SLionel Sambuc }
121*f14fb602SLionel Sambuc b += nr;
122*f14fb602SLionel Sambuc l -= nr;
123*f14fb602SLionel Sambuc }
124*f14fb602SLionel Sambuc return len;
125*f14fb602SLionel Sambuc }
126*f14fb602SLionel Sambuc
127*f14fb602SLionel Sambuc static off_t
cseekfn(void * dookie,off_t off,int whence)128*f14fb602SLionel Sambuc cseekfn(void *dookie, off_t off, int whence)
129*f14fb602SLionel Sambuc {
130*f14fb602SLionel Sambuc dookie_t *d = dookie;
131*f14fb602SLionel Sambuc return (*d->seekfn)(d->cookie, off, whence);
132*f14fb602SLionel Sambuc }
133*f14fb602SLionel Sambuc
134*f14fb602SLionel Sambuc static int
cclosefn(void * dookie)135*f14fb602SLionel Sambuc cclosefn(void *dookie)
136*f14fb602SLionel Sambuc {
137*f14fb602SLionel Sambuc dookie_t *d = dookie;
138*f14fb602SLionel Sambuc void *c = d->cookie;
139*f14fb602SLionel Sambuc int (*cf)(void *) = d->closefn;
140*f14fb602SLionel Sambuc free(dookie);
141*f14fb602SLionel Sambuc return (*cf)(c);
142*f14fb602SLionel Sambuc }
143*f14fb602SLionel Sambuc
144*f14fb602SLionel Sambuc FILE *
funopen(const void * cookie,int (* readfn)(void *,char *,int),int (* writefn)(void *,const char *,int),off_t (* seekfn)(void *,off_t,int),int (* closefn)(void *))145*f14fb602SLionel Sambuc funopen(const void *cookie,
146*f14fb602SLionel Sambuc int (*readfn)(void *, char *, int),
147*f14fb602SLionel Sambuc int (*writefn)(void *, const char *, int),
148*f14fb602SLionel Sambuc off_t (*seekfn)(void *, off_t, int),
149*f14fb602SLionel Sambuc int (*closefn)(void *))
150*f14fb602SLionel Sambuc {
151*f14fb602SLionel Sambuc dookie_t *d;
152*f14fb602SLionel Sambuc FILE *fp;
153*f14fb602SLionel Sambuc
154*f14fb602SLionel Sambuc if ((d = malloc(sizeof(*d))) == NULL)
155*f14fb602SLionel Sambuc return NULL;
156*f14fb602SLionel Sambuc
157*f14fb602SLionel Sambuc d->cookie = __UNCONST(cookie);
158*f14fb602SLionel Sambuc d->readfn = readfn;
159*f14fb602SLionel Sambuc d->writefn = writefn;
160*f14fb602SLionel Sambuc d->seekfn = seekfn;
161*f14fb602SLionel Sambuc d->closefn = closefn;
162*f14fb602SLionel Sambuc fp = funopen2(d,
163*f14fb602SLionel Sambuc d->readfn ? creadfn : NULL,
164*f14fb602SLionel Sambuc d->writefn ? cwritefn : NULL,
165*f14fb602SLionel Sambuc d->seekfn ? cseekfn : NULL,
166*f14fb602SLionel Sambuc NULL,
167*f14fb602SLionel Sambuc d->closefn ? cclosefn : NULL);
168*f14fb602SLionel Sambuc if (fp != NULL)
169*f14fb602SLionel Sambuc return fp;
170*f14fb602SLionel Sambuc free(d);
171*f14fb602SLionel Sambuc return NULL;
1722fe8fb19SBen Gras }
173