1*5b486aceSchristos /* $NetBSD: funopen.c,v 1.15 2016/10/23 21:01:52 christos Exp $ */
2255db7b2Sjtc
361f28255Scgd /*-
4255db7b2Sjtc * Copyright (c) 1990, 1993
5255db7b2Sjtc * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * This code is derived from software contributed to Berkeley by
861f28255Scgd * Chris Torek.
961f28255Scgd *
1061f28255Scgd * Redistribution and use in source and binary forms, with or without
1161f28255Scgd * modification, are permitted provided that the following conditions
1261f28255Scgd * are met:
1361f28255Scgd * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd * notice, this list of conditions and the following disclaimer.
1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd * notice, this list of conditions and the following disclaimer in the
1761f28255Scgd * documentation and/or other materials provided with the distribution.
18eb7c1594Sagc * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd * may be used to endorse or promote products derived from this software
2061f28255Scgd * without specific prior written permission.
2161f28255Scgd *
2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd * SUCH DAMAGE.
3361f28255Scgd */
3461f28255Scgd
3523312f88Schristos #include <sys/cdefs.h>
3661f28255Scgd #if defined(LIBC_SCCS) && !defined(lint)
37255db7b2Sjtc #if 0
38255db7b2Sjtc static char sccsid[] = "@(#)funopen.c 8.1 (Berkeley) 6/4/93";
3923312f88Schristos #else
40*5b486aceSchristos __RCSID("$NetBSD: funopen.c,v 1.15 2016/10/23 21:01:52 christos Exp $");
41255db7b2Sjtc #endif
4261f28255Scgd #endif /* LIBC_SCCS and not lint */
4361f28255Scgd
4461f28255Scgd #include <stdio.h>
4561f28255Scgd #include <errno.h>
46de001ba2Schristos #include <stdlib.h>
47de001ba2Schristos #include <stddef.h>
483fdac2b8Sthorpej #include "reentrant.h"
4961f28255Scgd #include "local.h"
5061f28255Scgd
5161f28255Scgd 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 *))52de001ba2Schristos funopen2(const void *cookie,
53de001ba2Schristos ssize_t (*readfn)(void *, void *, size_t),
54de001ba2Schristos ssize_t (*writefn)(void *, const void *, size_t),
55526d9427Schristos off_t (*seekfn)(void *, off_t, int),
56de001ba2Schristos int (*flushfn)(void *),
57526d9427Schristos int (*closefn)(void *))
5861f28255Scgd {
59c8bafd62Sperry FILE *fp;
6061f28255Scgd int flags;
6161f28255Scgd
6261f28255Scgd if (readfn == NULL) {
6361f28255Scgd if (writefn == NULL) { /* illegal */
6461f28255Scgd errno = EINVAL;
65526d9427Schristos return NULL;
6661f28255Scgd } else
6761f28255Scgd flags = __SWR; /* write only */
6861f28255Scgd } else {
6961f28255Scgd if (writefn == NULL)
7061f28255Scgd flags = __SRD; /* read only */
7161f28255Scgd else
7261f28255Scgd flags = __SRW; /* read-write */
7361f28255Scgd }
7461f28255Scgd if ((fp = __sfp()) == NULL)
75526d9427Schristos return NULL;
7661f28255Scgd fp->_flags = flags;
7761f28255Scgd fp->_file = -1;
7803256c6eSchristos fp->_cookie = __UNCONST(cookie);
7961f28255Scgd fp->_read = readfn;
8061f28255Scgd fp->_write = writefn;
8161f28255Scgd fp->_seek = seekfn;
82de001ba2Schristos fp->_flush = flushfn;
8361f28255Scgd fp->_close = closefn;
84526d9427Schristos return fp;
8561f28255Scgd }
86de001ba2Schristos
87de001ba2Schristos typedef struct {
88de001ba2Schristos void *cookie;
89de001ba2Schristos int (*readfn)(void *, char *, int);
90de001ba2Schristos int (*writefn)(void *, const char *, int);
91de001ba2Schristos off_t (*seekfn)(void *, off_t, int);
92de001ba2Schristos int (*closefn)(void *);
93de001ba2Schristos } dookie_t;
94de001ba2Schristos
95de001ba2Schristos static ssize_t
creadfn(void * dookie,void * buf,size_t len)96de001ba2Schristos creadfn(void *dookie, void *buf, size_t len)
97de001ba2Schristos {
98de001ba2Schristos dookie_t *d = dookie;
99de001ba2Schristos if (len > INT_MAX)
100de001ba2Schristos len = INT_MAX;
101de001ba2Schristos return (*d->readfn)(d->cookie, buf, (int)len);
102de001ba2Schristos }
103de001ba2Schristos
104de001ba2Schristos static ssize_t
cwritefn(void * dookie,const void * buf,size_t len)105de001ba2Schristos cwritefn(void *dookie, const void *buf, size_t len)
106de001ba2Schristos {
107de001ba2Schristos dookie_t *d = dookie;
108de001ba2Schristos ssize_t nr;
109de001ba2Schristos size_t l = len;
110de001ba2Schristos const char *b = buf;
111de001ba2Schristos
112de001ba2Schristos while (l) {
113de001ba2Schristos size_t nw = l > INT_MAX ? INT_MAX : l;
114de001ba2Schristos nr = (*d->writefn)(d->cookie, buf, (int)nw);
115de001ba2Schristos if (nr == -1) {
116de001ba2Schristos if (len == l)
117de001ba2Schristos return -1;
118de001ba2Schristos else
119de001ba2Schristos return len - l;
120de001ba2Schristos }
121de001ba2Schristos b += nr;
122de001ba2Schristos l -= nr;
123de001ba2Schristos }
124de001ba2Schristos return len;
125de001ba2Schristos }
126de001ba2Schristos
127de001ba2Schristos static off_t
cseekfn(void * dookie,off_t off,int whence)128de001ba2Schristos cseekfn(void *dookie, off_t off, int whence)
129de001ba2Schristos {
130de001ba2Schristos dookie_t *d = dookie;
131de001ba2Schristos return (*d->seekfn)(d->cookie, off, whence);
132de001ba2Schristos }
133de001ba2Schristos
134de001ba2Schristos static int
cclosefn(void * dookie)135de001ba2Schristos cclosefn(void *dookie)
136de001ba2Schristos {
137de001ba2Schristos dookie_t *d = dookie;
138de001ba2Schristos void *c = d->cookie;
139de001ba2Schristos int (*cf)(void *) = d->closefn;
140de001ba2Schristos free(dookie);
141*5b486aceSchristos if (cf == NULL)
142*5b486aceSchristos return 0;
143de001ba2Schristos return (*cf)(c);
144de001ba2Schristos }
145de001ba2Schristos
146de001ba2Schristos 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 *))147de001ba2Schristos funopen(const void *cookie,
148de001ba2Schristos int (*readfn)(void *, char *, int),
149de001ba2Schristos int (*writefn)(void *, const char *, int),
150de001ba2Schristos off_t (*seekfn)(void *, off_t, int),
151de001ba2Schristos int (*closefn)(void *))
152de001ba2Schristos {
153de001ba2Schristos dookie_t *d;
154de001ba2Schristos FILE *fp;
155de001ba2Schristos
156de001ba2Schristos if ((d = malloc(sizeof(*d))) == NULL)
157de001ba2Schristos return NULL;
158de001ba2Schristos
159de001ba2Schristos d->cookie = __UNCONST(cookie);
160de001ba2Schristos d->readfn = readfn;
161de001ba2Schristos d->writefn = writefn;
162de001ba2Schristos d->seekfn = seekfn;
163de001ba2Schristos d->closefn = closefn;
16461a429c0Schristos fp = funopen2(d,
16561a429c0Schristos d->readfn ? creadfn : NULL,
16661a429c0Schristos d->writefn ? cwritefn : NULL,
16761a429c0Schristos d->seekfn ? cseekfn : NULL,
168*5b486aceSchristos NULL, cclosefn);
169de001ba2Schristos if (fp != NULL)
170de001ba2Schristos return fp;
171de001ba2Schristos free(d);
172de001ba2Schristos return NULL;
173de001ba2Schristos }
174