xref: /dflybsd-src/lib/libc/stdio/fopencookie.c (revision 54fa87ff9f63f867b4a3b601a4c97bccdd65ea07)
1a765cedfSAntonio Huete Jimenez /*
2a765cedfSAntonio Huete Jimenez  * Copyright (c) 2016, EMC / Isilon Storage Division
3a765cedfSAntonio Huete Jimenez  * All rights reserved.
4a765cedfSAntonio Huete Jimenez  *
5a765cedfSAntonio Huete Jimenez  * Redistribution and use in source and binary forms, with or without
6a765cedfSAntonio Huete Jimenez  * modification, are permitted provided that the following conditions
7a765cedfSAntonio Huete Jimenez  * are met:
8a765cedfSAntonio Huete Jimenez  * 1. Redistributions of source code must retain the above copyright
9a765cedfSAntonio Huete Jimenez  *    notice, this list of conditions and the following disclaimer.
10a765cedfSAntonio Huete Jimenez  * 2. Redistributions in binary form must reproduce the above copyright
11a765cedfSAntonio Huete Jimenez  *    notice, this list of conditions and the following disclaimer in the
12a765cedfSAntonio Huete Jimenez  *    documentation and/or other materials provided with the distribution.
13a765cedfSAntonio Huete Jimenez  *
14a765cedfSAntonio Huete Jimenez  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
15a765cedfSAntonio Huete Jimenez  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16a765cedfSAntonio Huete Jimenez  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17a765cedfSAntonio Huete Jimenez  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
18a765cedfSAntonio Huete Jimenez  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19a765cedfSAntonio Huete Jimenez  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20a765cedfSAntonio Huete Jimenez  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21a765cedfSAntonio Huete Jimenez  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22a765cedfSAntonio Huete Jimenez  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23a765cedfSAntonio Huete Jimenez  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24a765cedfSAntonio Huete Jimenez  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25a765cedfSAntonio Huete Jimenez  */
26a765cedfSAntonio Huete Jimenez 
27a765cedfSAntonio Huete Jimenez #include <sys/cdefs.h>
28a765cedfSAntonio Huete Jimenez __FBSDID("$FreeBSD$");
29a765cedfSAntonio Huete Jimenez 
30a765cedfSAntonio Huete Jimenez #include <sys/fcntl.h>
31a765cedfSAntonio Huete Jimenez 
32a765cedfSAntonio Huete Jimenez #include <errno.h>
33a765cedfSAntonio Huete Jimenez #include <stdio.h>
34a765cedfSAntonio Huete Jimenez #include <stdlib.h>
35a765cedfSAntonio Huete Jimenez 
36a765cedfSAntonio Huete Jimenez #include "local.h"
37a765cedfSAntonio Huete Jimenez 
38a765cedfSAntonio Huete Jimenez struct fopencookie_thunk {
39a765cedfSAntonio Huete Jimenez 	void			*foc_cookie;
40a765cedfSAntonio Huete Jimenez 	cookie_io_functions_t	foc_io;
41a765cedfSAntonio Huete Jimenez };
42a765cedfSAntonio Huete Jimenez 
43a765cedfSAntonio Huete Jimenez static int _fopencookie_read(void *, char *, int);
44a765cedfSAntonio Huete Jimenez static int _fopencookie_write(void *, const char *, int);
45a765cedfSAntonio Huete Jimenez static fpos_t _fopencookie_seek(void *, fpos_t, int);
46a765cedfSAntonio Huete Jimenez static int _fopencookie_close(void *);
47a765cedfSAntonio Huete Jimenez 
48a765cedfSAntonio Huete Jimenez FILE *
fopencookie(void * cookie,const char * mode,cookie_io_functions_t io_funcs)49a765cedfSAntonio Huete Jimenez fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs)
50a765cedfSAntonio Huete Jimenez {
51a765cedfSAntonio Huete Jimenez 	int (*readfn)(void *, char *, int);
52a765cedfSAntonio Huete Jimenez 	int (*writefn)(void *, const char *, int);
53a765cedfSAntonio Huete Jimenez 	struct fopencookie_thunk *thunk;
54a765cedfSAntonio Huete Jimenez 	FILE *fp;
55a765cedfSAntonio Huete Jimenez 	int flags, oflags;
56a765cedfSAntonio Huete Jimenez 
57a765cedfSAntonio Huete Jimenez 	if ((flags = __sflags(mode, &oflags)) == 0)
58a765cedfSAntonio Huete Jimenez 		return (NULL);
59a765cedfSAntonio Huete Jimenez 
60a765cedfSAntonio Huete Jimenez 	thunk = malloc(sizeof(*thunk));
61a765cedfSAntonio Huete Jimenez 	if (thunk == NULL)
62a765cedfSAntonio Huete Jimenez 		return (NULL);
63a765cedfSAntonio Huete Jimenez 
64a765cedfSAntonio Huete Jimenez 	thunk->foc_cookie = cookie;
65a765cedfSAntonio Huete Jimenez 	thunk->foc_io = io_funcs;
66a765cedfSAntonio Huete Jimenez 
67a765cedfSAntonio Huete Jimenez 	readfn = _fopencookie_read;
68a765cedfSAntonio Huete Jimenez 	writefn = _fopencookie_write;
69a765cedfSAntonio Huete Jimenez 	if (flags == __SWR)
70a765cedfSAntonio Huete Jimenez 		readfn = NULL;
71a765cedfSAntonio Huete Jimenez 	else if (flags == __SRD)
72a765cedfSAntonio Huete Jimenez 		writefn = NULL;
73a765cedfSAntonio Huete Jimenez 
74a765cedfSAntonio Huete Jimenez 	fp = funopen(thunk, readfn, writefn, _fopencookie_seek,
75a765cedfSAntonio Huete Jimenez 	    _fopencookie_close);
76a765cedfSAntonio Huete Jimenez 	if (fp == NULL) {
77a765cedfSAntonio Huete Jimenez 		free(thunk);
78a765cedfSAntonio Huete Jimenez 		return (NULL);
79a765cedfSAntonio Huete Jimenez 	}
80a765cedfSAntonio Huete Jimenez 
81a765cedfSAntonio Huete Jimenez 	if ((oflags & O_APPEND) != 0)
82a765cedfSAntonio Huete Jimenez 		fp->pub._flags |= __SAPP;
83a765cedfSAntonio Huete Jimenez 
84a765cedfSAntonio Huete Jimenez 	return (fp);
85a765cedfSAntonio Huete Jimenez }
86a765cedfSAntonio Huete Jimenez 
87a765cedfSAntonio Huete Jimenez static int
_fopencookie_read(void * cookie,char * buf,int size)88a765cedfSAntonio Huete Jimenez _fopencookie_read(void *cookie, char *buf, int size)
89a765cedfSAntonio Huete Jimenez {
90a765cedfSAntonio Huete Jimenez 	struct fopencookie_thunk *thunk;
91a765cedfSAntonio Huete Jimenez 
92a765cedfSAntonio Huete Jimenez 	thunk = cookie;
93a765cedfSAntonio Huete Jimenez 
94a765cedfSAntonio Huete Jimenez 	/* Reads from a stream with NULL read return EOF. */
95a765cedfSAntonio Huete Jimenez 	if (thunk->foc_io.read == NULL)
96a765cedfSAntonio Huete Jimenez 		return (0);
97a765cedfSAntonio Huete Jimenez 
98a765cedfSAntonio Huete Jimenez 	return ((int)thunk->foc_io.read(thunk->foc_cookie, buf, (size_t)size));
99a765cedfSAntonio Huete Jimenez }
100a765cedfSAntonio Huete Jimenez 
101a765cedfSAntonio Huete Jimenez static int
_fopencookie_write(void * cookie,const char * buf,int size)102a765cedfSAntonio Huete Jimenez _fopencookie_write(void *cookie, const char *buf, int size)
103a765cedfSAntonio Huete Jimenez {
104a765cedfSAntonio Huete Jimenez 	struct fopencookie_thunk *thunk;
105a765cedfSAntonio Huete Jimenez 
106a765cedfSAntonio Huete Jimenez 	thunk = cookie;
107a765cedfSAntonio Huete Jimenez 
108a765cedfSAntonio Huete Jimenez 	/* Writes to a stream with NULL write discard data. */
109a765cedfSAntonio Huete Jimenez 	if (thunk->foc_io.write == NULL)
110a765cedfSAntonio Huete Jimenez 		return (size);
111a765cedfSAntonio Huete Jimenez 
112a765cedfSAntonio Huete Jimenez 	return ((int)thunk->foc_io.write(thunk->foc_cookie, buf,
113a765cedfSAntonio Huete Jimenez 		(size_t)size));
114a765cedfSAntonio Huete Jimenez }
115a765cedfSAntonio Huete Jimenez 
116a765cedfSAntonio Huete Jimenez static fpos_t
_fopencookie_seek(void * cookie,fpos_t offset,int whence)117a765cedfSAntonio Huete Jimenez _fopencookie_seek(void *cookie, fpos_t offset, int whence)
118a765cedfSAntonio Huete Jimenez {
119a765cedfSAntonio Huete Jimenez 	struct fopencookie_thunk *thunk;
120*54fa87ffSSascha Wildner 	off_t off64;
121a765cedfSAntonio Huete Jimenez 	int res;
122a765cedfSAntonio Huete Jimenez 
123a765cedfSAntonio Huete Jimenez 	switch (whence) {
124a765cedfSAntonio Huete Jimenez 	case SEEK_SET:
125a765cedfSAntonio Huete Jimenez 	case SEEK_CUR:
126a765cedfSAntonio Huete Jimenez 	case SEEK_END:
127a765cedfSAntonio Huete Jimenez 		break;
128a765cedfSAntonio Huete Jimenez 	default:
129a765cedfSAntonio Huete Jimenez 		/* fopencookie(3) only allows these three seek modes. */
130a765cedfSAntonio Huete Jimenez 		errno = EINVAL;
131a765cedfSAntonio Huete Jimenez 		return (-1);
132a765cedfSAntonio Huete Jimenez 	}
133a765cedfSAntonio Huete Jimenez 
134a765cedfSAntonio Huete Jimenez 	thunk = cookie;
135a765cedfSAntonio Huete Jimenez 
136a765cedfSAntonio Huete Jimenez 	/*
137a765cedfSAntonio Huete Jimenez 	 * If seek is NULL, it is not possible to perform seek operations on
138a765cedfSAntonio Huete Jimenez 	 * the stream.
139a765cedfSAntonio Huete Jimenez 	 */
140a765cedfSAntonio Huete Jimenez 	if (thunk->foc_io.seek == NULL) {
141a765cedfSAntonio Huete Jimenez 		errno = ENOTSUP;
142a765cedfSAntonio Huete Jimenez 		return (-1);
143a765cedfSAntonio Huete Jimenez 	}
144a765cedfSAntonio Huete Jimenez 
145*54fa87ffSSascha Wildner 	off64 = (off_t)offset;
146a765cedfSAntonio Huete Jimenez 	res = thunk->foc_io.seek(thunk->foc_cookie, &off64, whence);
147a765cedfSAntonio Huete Jimenez 	if (res < 0)
148a765cedfSAntonio Huete Jimenez 		return (res);
149a765cedfSAntonio Huete Jimenez 
150a765cedfSAntonio Huete Jimenez 	return ((fpos_t)off64);
151a765cedfSAntonio Huete Jimenez }
152a765cedfSAntonio Huete Jimenez 
153a765cedfSAntonio Huete Jimenez static int
_fopencookie_close(void * cookie)154a765cedfSAntonio Huete Jimenez _fopencookie_close(void *cookie)
155a765cedfSAntonio Huete Jimenez {
156a765cedfSAntonio Huete Jimenez 	struct fopencookie_thunk *thunk;
157a765cedfSAntonio Huete Jimenez 	int ret, serrno;
158a765cedfSAntonio Huete Jimenez 
159a765cedfSAntonio Huete Jimenez 	ret = 0;
160a765cedfSAntonio Huete Jimenez 	thunk = cookie;
161a765cedfSAntonio Huete Jimenez 	if (thunk->foc_io.close != NULL)
162a765cedfSAntonio Huete Jimenez 		ret = thunk->foc_io.close(thunk->foc_cookie);
163a765cedfSAntonio Huete Jimenez 
164a765cedfSAntonio Huete Jimenez 	serrno = errno;
165a765cedfSAntonio Huete Jimenez 	free(thunk);
166a765cedfSAntonio Huete Jimenez 	errno = serrno;
167a765cedfSAntonio Huete Jimenez 	return (ret);
168a765cedfSAntonio Huete Jimenez }
169