The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
fopencookie.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** Wrap funopen to provide an fopencookie compatible interface on systems that don't support it
18  *
19  * @file src/lib/util/fopencookie.c
20  *
21  * @copyright 2019 The FreeRADIUS server project
22  * @copyright 2019 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23  */
24 RCSID("$Id: 348c07f011aa98ac101bfca7ec5a73628297a13d $")
25 
26 #ifndef HAVE_FOPENCOOKIE
27 #include <freeradius-devel/util/talloc.h>
28 #include <stdio.h>
29 #include "fopencookie.h"
30 
31 #define NEED_READ 0x01
32 #define NEED_WRITE 0x02
33 #define NEED_SEEK 0x04
34 
35 /** Holds the fopencookie function pointers plus the funopen cookie
36  *
37  */
38 typedef struct {
39  void *cookie; //!< Original cookie passed to fopencookie
40  cookie_io_functions_t io_funcs; //!< Fopencookie callbacks (which we wrap)
42 
43 
44 /** Wrap fopencookie read function
45  *
46  */
47 static int _read(void *c, char *buf, int n)
48 {
49  fr_funopen_cookie_t *oc = talloc_get_type_abort(c, fr_funopen_cookie_t);
50 
51  return (int)oc->io_funcs.read(oc->cookie, buf, (size_t)n);
52 }
53 
54 /** Wrap fopencookie write function
55  *
56  */
57 static int _write(void *c, const char *buf, int n)
58 {
59  fr_funopen_cookie_t *oc = talloc_get_type_abort(c, fr_funopen_cookie_t);
60 
61  return (int)oc->io_funcs.write(oc->cookie, buf, (size_t)n);
62 }
63 
64 /** Wrap fopencookie seek function
65  *
66  */
67 static fpos_t _seek(void *c, fpos_t offset, int whence)
68 {
69  fr_funopen_cookie_t *oc = talloc_get_type_abort(c, fr_funopen_cookie_t);
70  int ret;
71 
72  /*
73  * fopencookie seek cb should return
74  * and update offset to be the new position,
75  * or not zero and leave offset untouched.
76  *
77  * funopen seek cb should return -1 for an error
78  * or the new offset on success.
79  */
80  ret = oc->io_funcs.seek(oc->cookie, (off64_t *)&offset, whence);
81  if (ret != 0) return -1;
82 
83  return offset;
84 }
85 
86 /** Wrap fopencookie close function and free our fr_funopen_cookie_t
87  *
88  */
89 static int _close(void *c)
90 {
91  fr_funopen_cookie_t *oc = talloc_get_type_abort(c, fr_funopen_cookie_t);
92  int ret = oc->io_funcs.close ? oc->io_funcs.close(oc->cookie) : 0;
93 
94  talloc_free(oc);
95 
96  return ret;
97 }
98 
99 FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs)
100 {
102  int need = 0;
103  FILE *f;
104  char const *p;
105 
106  /*
107  * Process mode string as described by `man fopen`
108  */
109  for (p = mode; *p != '\0'; p++) {
110  switch (*p) {
111  case 'r':
112  need |= NEED_READ;
113 
114  if (p[1] == 'b') p++; /* Skip binary */
115  if (p[1] == '+') {
116  p++;
117  need |= NEED_WRITE;
118  continue;
119  }
120  continue;
121 
122  case 'w':
123  need |= NEED_WRITE;
124 
125  if (p[1] == 'b') p++; /* Skip binary */
126  if (p[1] == '+') {
127  p++;
128  need |= NEED_READ;
129  continue;
130  }
131  continue;
132 
133  case 'a':
134  need |= (NEED_SEEK | NEED_WRITE);
135 
136  if (p[1] == 'b') p++; /* Skip binary */
137  if (p[1] == '+') {
138  p++;
139  need |= NEED_READ;
140  continue;
141  }
142  continue;
143 
144  /*
145  * 'b' is also allowed as the last char
146  */
147  case 'b':
148  if (p[1] != '\0') {
149  invalid_arg:
150  errno = EINVAL;
151  return NULL;
152  }
153  continue; /* Loop will exit next iteration */
154 
155  default:
156  goto invalid_arg;
157  }
158  }
159 
160  if ((need & NEED_READ) && !io_funcs.read) goto invalid_arg;
161  if ((need & NEED_WRITE) && !io_funcs.write) goto invalid_arg;
162  if ((need & NEED_SEEK) && !io_funcs.seek) goto invalid_arg;
163 
164  oc = talloc_zero(NULL, fr_funopen_cookie_t);
165  if (!oc) {
166  errno = ENOMEM;
167  return NULL;
168  }
169 
170  oc->io_funcs = io_funcs;
171  oc->cookie = cookie;
172 
173  f = funopen(oc,
174  oc->io_funcs.read ? _read : NULL,
175  oc->io_funcs.write ? _write : NULL,
176  oc->io_funcs.seek ? _seek : NULL,
177  _close);
178  if (!f) {
179  talloc_free(oc);
180  return NULL;
181  }
182 
183  if (need & NEED_SEEK) {
184  if (fseek(f, 0L, SEEK_END) < 0) {
185  fclose(f);
186  talloc_free(oc);
187  return NULL;
188  }
189  }
190 
191  return f;
192 }
193 #endif
int n
Definition: acutest.h:577
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
static int _write(void *c, const char *buf, int n)
Wrap fopencookie write function.
Definition: fopencookie.c:57
#define NEED_READ
Definition: fopencookie.c:31
static int _close(void *c)
Wrap fopencookie close function and free our fr_funopen_cookie_t.
Definition: fopencookie.c:89
static fpos_t _seek(void *c, fpos_t offset, int whence)
Wrap fopencookie seek function.
Definition: fopencookie.c:67
void * cookie
Original cookie passed to fopencookie.
Definition: fopencookie.c:39
static int _read(void *c, char *buf, int n)
Wrap fopencookie read function.
Definition: fopencookie.c:47
#define NEED_SEEK
Definition: fopencookie.c:33
#define NEED_WRITE
Definition: fopencookie.c:32
cookie_io_functions_t io_funcs
Fopencookie callbacks (which we wrap)
Definition: fopencookie.c:40
FILE * fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs)
Definition: fopencookie.c:99
Provide missing types for fopencookie on systems that don't support it.
cookie_close_function_t close
Definition: fopencookie.h:55
cookie_seek_function_t seek
Definition: fopencookie.h:54
cookie_read_function_t read
Definition: fopencookie.h:52
cookie_write_function_t write
Definition: fopencookie.h:53
talloc_free(reap)