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