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