1 /* Copyright (C) 1993-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.
17 
18    As a special exception, if you link the code in this file with
19    files compiled with a GNU compiler to produce an executable,
20    that does not cause the resulting executable to be covered by
21    the GNU Lesser General Public License.  This exception does not
22    however invalidate any other reasons why the executable file
23    might be covered by the GNU Lesser General Public License.
24    This exception applies to code released by its copyright holders
25    in files containing the exception.  */
26 
27 #include <libioP.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <shlib-compat.h>
31 
32 static ssize_t
_IO_cookie_read(FILE * fp,void * buf,ssize_t size)33 _IO_cookie_read (FILE *fp, void *buf, ssize_t size)
34 {
35   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
36   cookie_read_function_t *read_cb = cfile->__io_functions.read;
37 #ifdef PTR_DEMANGLE
38   PTR_DEMANGLE (read_cb);
39 #endif
40 
41   if (read_cb == NULL)
42     return -1;
43 
44   return read_cb (cfile->__cookie, buf, size);
45 }
46 
47 static ssize_t
_IO_cookie_write(FILE * fp,const void * buf,ssize_t size)48 _IO_cookie_write (FILE *fp, const void *buf, ssize_t size)
49 {
50   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
51   cookie_write_function_t *write_cb = cfile->__io_functions.write;
52 #ifdef PTR_DEMANGLE
53   PTR_DEMANGLE (write_cb);
54 #endif
55 
56   if (write_cb == NULL)
57     {
58       fp->_flags |= _IO_ERR_SEEN;
59       return 0;
60     }
61 
62   ssize_t n = write_cb (cfile->__cookie, buf, size);
63   if (n < size)
64     fp->_flags |= _IO_ERR_SEEN;
65 
66   return n;
67 }
68 
69 static off64_t
_IO_cookie_seek(FILE * fp,off64_t offset,int dir)70 _IO_cookie_seek (FILE *fp, off64_t offset, int dir)
71 {
72   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
73   cookie_seek_function_t *seek_cb = cfile->__io_functions.seek;
74 #ifdef PTR_DEMANGLE
75   PTR_DEMANGLE (seek_cb);
76 #endif
77 
78   return ((seek_cb == NULL
79 	   || (seek_cb (cfile->__cookie, &offset, dir)
80 	       == -1)
81 	   || offset == (off64_t) -1)
82 	  ? _IO_pos_BAD : offset);
83 }
84 
85 static int
_IO_cookie_close(FILE * fp)86 _IO_cookie_close (FILE *fp)
87 {
88   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
89   cookie_close_function_t *close_cb = cfile->__io_functions.close;
90 #ifdef PTR_DEMANGLE
91   PTR_DEMANGLE (close_cb);
92 #endif
93 
94   if (close_cb == NULL)
95     return 0;
96 
97   return close_cb (cfile->__cookie);
98 }
99 
100 
101 static off64_t
_IO_cookie_seekoff(FILE * fp,off64_t offset,int dir,int mode)102 _IO_cookie_seekoff (FILE *fp, off64_t offset, int dir, int mode)
103 {
104   /* We must force the fileops code to always use seek to determine
105      the position.  */
106   fp->_offset = _IO_pos_BAD;
107   return _IO_file_seekoff (fp, offset, dir, mode);
108 }
109 
110 
111 static const struct _IO_jump_t _IO_cookie_jumps libio_vtable = {
112   JUMP_INIT_DUMMY,
113   JUMP_INIT(finish, _IO_file_finish),
114   JUMP_INIT(overflow, _IO_file_overflow),
115   JUMP_INIT(underflow, _IO_file_underflow),
116   JUMP_INIT(uflow, _IO_default_uflow),
117   JUMP_INIT(pbackfail, _IO_default_pbackfail),
118   JUMP_INIT(xsputn, _IO_file_xsputn),
119   JUMP_INIT(xsgetn, _IO_default_xsgetn),
120   JUMP_INIT(seekoff, _IO_cookie_seekoff),
121   JUMP_INIT(seekpos, _IO_default_seekpos),
122   JUMP_INIT(setbuf, _IO_file_setbuf),
123   JUMP_INIT(sync, _IO_file_sync),
124   JUMP_INIT(doallocate, _IO_file_doallocate),
125   JUMP_INIT(read, _IO_cookie_read),
126   JUMP_INIT(write, _IO_cookie_write),
127   JUMP_INIT(seek, _IO_cookie_seek),
128   JUMP_INIT(close, _IO_cookie_close),
129   JUMP_INIT(stat, _IO_default_stat),
130   JUMP_INIT(showmanyc, _IO_default_showmanyc),
131   JUMP_INIT(imbue, _IO_default_imbue),
132 };
133 
134 
135 /* Copy the callbacks from SOURCE to *TARGET, with pointer
136    mangling.  */
137 static void
set_callbacks(cookie_io_functions_t * target,cookie_io_functions_t source)138 set_callbacks (cookie_io_functions_t *target,
139 	       cookie_io_functions_t source)
140 {
141 #ifdef PTR_MANGLE
142   PTR_MANGLE (source.read);
143   PTR_MANGLE (source.write);
144   PTR_MANGLE (source.seek);
145   PTR_MANGLE (source.close);
146 #endif
147   *target = source;
148 }
149 
150 void
_IO_cookie_init(struct _IO_cookie_file * cfile,int read_write,void * cookie,cookie_io_functions_t io_functions)151 _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write,
152 		 void *cookie, cookie_io_functions_t io_functions)
153 {
154   _IO_init_internal (&cfile->__fp.file, 0);
155   _IO_JUMPS (&cfile->__fp) = &_IO_cookie_jumps;
156 
157   cfile->__cookie = cookie;
158   set_callbacks (&cfile->__io_functions, io_functions);
159 
160   _IO_new_file_init_internal (&cfile->__fp);
161 
162   _IO_mask_flags (&cfile->__fp.file, read_write,
163 		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
164 
165   cfile->__fp.file._flags2 |= _IO_FLAGS2_NEED_LOCK;
166 
167   /* We use a negative number different from -1 for _fileno to mark that
168      this special stream is not associated with a real file, but still has
169      to be treated as such.  */
170   cfile->__fp.file._fileno = -2;
171 }
172 
173 
174 FILE *
_IO_fopencookie(void * cookie,const char * mode,cookie_io_functions_t io_functions)175 _IO_fopencookie (void *cookie, const char *mode,
176 		 cookie_io_functions_t io_functions)
177 {
178   int read_write;
179   struct locked_FILE
180   {
181     struct _IO_cookie_file cfile;
182 #ifdef _IO_MTSAFE_IO
183     _IO_lock_t lock;
184 #endif
185   } *new_f;
186 
187   switch (*mode++)
188     {
189     case 'r':
190       read_write = _IO_NO_WRITES;
191       break;
192     case 'w':
193       read_write = _IO_NO_READS;
194       break;
195     case 'a':
196       read_write = _IO_NO_READS|_IO_IS_APPENDING;
197       break;
198     default:
199       __set_errno (EINVAL);
200       return NULL;
201   }
202   if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+'))
203     read_write &= _IO_IS_APPENDING;
204 
205   new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
206   if (new_f == NULL)
207     return NULL;
208 #ifdef _IO_MTSAFE_IO
209   new_f->cfile.__fp.file._lock = &new_f->lock;
210 #endif
211 
212   _IO_cookie_init (&new_f->cfile, read_write, cookie, io_functions);
213 
214   return (FILE *) &new_f->cfile.__fp;
215 }
216 
217 versioned_symbol (libc, _IO_fopencookie, fopencookie, GLIBC_2_2);
218 
219 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
220 
221 static off64_t
222 attribute_compat_text_section
_IO_old_cookie_seek(FILE * fp,off64_t offset,int dir)223 _IO_old_cookie_seek (FILE *fp, off64_t offset, int dir)
224 {
225   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
226   int (*seek_cb) (FILE *, off_t, int)
227     = (int (*) (FILE *, off_t, int)) cfile->__io_functions.seek;
228 #ifdef PTR_DEMANGLE
229   PTR_DEMANGLE (seek_cb);
230 #endif
231 
232   if (seek_cb == NULL)
233     return _IO_pos_BAD;
234 
235   int ret = seek_cb (cfile->__cookie, offset, dir);
236 
237   return (ret == -1) ? _IO_pos_BAD : ret;
238 }
239 
240 static const struct _IO_jump_t _IO_old_cookie_jumps libio_vtable = {
241   JUMP_INIT_DUMMY,
242   JUMP_INIT(finish, _IO_file_finish),
243   JUMP_INIT(overflow, _IO_file_overflow),
244   JUMP_INIT(underflow, _IO_file_underflow),
245   JUMP_INIT(uflow, _IO_default_uflow),
246   JUMP_INIT(pbackfail, _IO_default_pbackfail),
247   JUMP_INIT(xsputn, _IO_file_xsputn),
248   JUMP_INIT(xsgetn, _IO_default_xsgetn),
249   JUMP_INIT(seekoff, _IO_cookie_seekoff),
250   JUMP_INIT(seekpos, _IO_default_seekpos),
251   JUMP_INIT(setbuf, _IO_file_setbuf),
252   JUMP_INIT(sync, _IO_file_sync),
253   JUMP_INIT(doallocate, _IO_file_doallocate),
254   JUMP_INIT(read, _IO_cookie_read),
255   JUMP_INIT(write, _IO_cookie_write),
256   JUMP_INIT(seek, _IO_old_cookie_seek),
257   JUMP_INIT(close, _IO_cookie_close),
258   JUMP_INIT(stat, _IO_default_stat),
259   JUMP_INIT(showmanyc, _IO_default_showmanyc),
260   JUMP_INIT(imbue, _IO_default_imbue),
261 };
262 
263 FILE *
264 attribute_compat_text_section
_IO_old_fopencookie(void * cookie,const char * mode,cookie_io_functions_t io_functions)265 _IO_old_fopencookie (void *cookie, const char *mode,
266 		     cookie_io_functions_t io_functions)
267 {
268   FILE *ret;
269 
270   ret = _IO_fopencookie (cookie, mode, io_functions);
271   if (ret != NULL)
272     _IO_JUMPS_FILE_plus (ret) = &_IO_old_cookie_jumps;
273 
274   return ret;
275 }
276 
277 compat_symbol (libc, _IO_old_fopencookie, fopencookie, GLIBC_2_0);
278 
279 #endif
280