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 <assert.h>
28 #include "strfile.h"
29 #include "libioP.h"
30 #include <string.h>
31 #include <stdio_ext.h>
32 
33 void
_IO_str_init_static_internal(_IO_strfile * sf,char * ptr,size_t size,char * pstart)34 _IO_str_init_static_internal (_IO_strfile *sf, char *ptr, size_t size,
35 			      char *pstart)
36 {
37   FILE *fp = &sf->_sbf._f;
38   char *end;
39 
40   if (size == 0)
41     end = __rawmemchr (ptr, '\0');
42   else if ((size_t) ptr + size > (size_t) ptr)
43     end = ptr + size;
44   else
45     end = (char *) -1;
46   _IO_setb (fp, ptr, end, 0);
47 
48   fp->_IO_write_base = ptr;
49   fp->_IO_read_base = ptr;
50   fp->_IO_read_ptr = ptr;
51   if (pstart)
52     {
53       fp->_IO_write_ptr = pstart;
54       fp->_IO_write_end = end;
55       fp->_IO_read_end = pstart;
56     }
57   else
58     {
59       fp->_IO_write_ptr = ptr;
60       fp->_IO_write_end = ptr;
61       fp->_IO_read_end = end;
62     }
63   /* A null _allocate_buffer function flags the strfile as being static. */
64   sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0;
65 }
66 
67 void
_IO_str_init_static(_IO_strfile * sf,char * ptr,int size,char * pstart)68 _IO_str_init_static (_IO_strfile *sf, char *ptr, int size, char *pstart)
69 {
70   return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
71 }
72 
73 void
_IO_str_init_readonly(_IO_strfile * sf,const char * ptr,int size)74 _IO_str_init_readonly (_IO_strfile *sf, const char *ptr, int size)
75 {
76   _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
77   sf->_sbf._f._flags |= _IO_NO_WRITES;
78 }
79 
80 int
_IO_str_overflow(FILE * fp,int c)81 _IO_str_overflow (FILE *fp, int c)
82 {
83   int flush_only = c == EOF;
84   size_t pos;
85   if (fp->_flags & _IO_NO_WRITES)
86       return flush_only ? 0 : EOF;
87   if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
88     {
89       fp->_flags |= _IO_CURRENTLY_PUTTING;
90       fp->_IO_write_ptr = fp->_IO_read_ptr;
91       fp->_IO_read_ptr = fp->_IO_read_end;
92     }
93   pos = fp->_IO_write_ptr - fp->_IO_write_base;
94   if (pos >= (size_t) (_IO_blen (fp) + flush_only))
95     {
96       if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
97 	return EOF;
98       else
99 	{
100 	  char *new_buf;
101 	  char *old_buf = fp->_IO_buf_base;
102 	  size_t old_blen = _IO_blen (fp);
103 	  size_t new_size = 2 * old_blen + 100;
104 	  if (new_size < old_blen)
105 	    return EOF;
106 	  new_buf = malloc (new_size);
107 	  if (new_buf == NULL)
108 	    {
109 	      /*	  __ferror(fp) = 1; */
110 	      return EOF;
111 	    }
112 	  if (old_buf)
113 	    {
114 	      memcpy (new_buf, old_buf, old_blen);
115 	      free (old_buf);
116 	      /* Make sure _IO_setb won't try to delete _IO_buf_base. */
117 	      fp->_IO_buf_base = NULL;
118 	    }
119 	  memset (new_buf + old_blen, '\0', new_size - old_blen);
120 
121 	  _IO_setb (fp, new_buf, new_buf + new_size, 1);
122 	  fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
123 	  fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
124 	  fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
125 	  fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
126 
127 	  fp->_IO_write_base = new_buf;
128 	  fp->_IO_write_end = fp->_IO_buf_end;
129 	}
130     }
131 
132   if (!flush_only)
133     *fp->_IO_write_ptr++ = (unsigned char) c;
134   if (fp->_IO_write_ptr > fp->_IO_read_end)
135     fp->_IO_read_end = fp->_IO_write_ptr;
136   if (flush_only)
137     return 0;
138   else
139     return c;
140 }
libc_hidden_def(_IO_str_overflow)141 libc_hidden_def (_IO_str_overflow)
142 
143 int
144 _IO_str_underflow (FILE *fp)
145 {
146   if (fp->_IO_write_ptr > fp->_IO_read_end)
147     fp->_IO_read_end = fp->_IO_write_ptr;
148   if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
149     {
150       fp->_flags &= ~_IO_CURRENTLY_PUTTING;
151       fp->_IO_read_ptr = fp->_IO_write_ptr;
152       fp->_IO_write_ptr = fp->_IO_write_end;
153     }
154   if (fp->_IO_read_ptr < fp->_IO_read_end)
155     return *((unsigned char *) fp->_IO_read_ptr);
156   else
157     return EOF;
158 }
libc_hidden_def(_IO_str_underflow)159 libc_hidden_def (_IO_str_underflow)
160 
161 /* The size of the valid part of the buffer.  */
162 
163 ssize_t
164 _IO_str_count (FILE *fp)
165 {
166   return ((fp->_IO_write_ptr > fp->_IO_read_end
167 	   ? fp->_IO_write_ptr : fp->_IO_read_end)
168 	  - fp->_IO_read_base);
169 }
170 
171 
172 static int
enlarge_userbuf(FILE * fp,off64_t offset,int reading)173 enlarge_userbuf (FILE *fp, off64_t offset, int reading)
174 {
175   if ((ssize_t) offset <= _IO_blen (fp))
176     return 0;
177 
178   ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
179 
180   /* Try to enlarge the buffer.  */
181   if (fp->_flags & _IO_USER_BUF)
182     /* User-provided buffer.  */
183     return 1;
184 
185   size_t newsize = offset + 100;
186   char *oldbuf = fp->_IO_buf_base;
187   char *newbuf = malloc (newsize);
188   if (newbuf == NULL)
189     return 1;
190 
191   if (oldbuf != NULL)
192     {
193       memcpy (newbuf, oldbuf, _IO_blen (fp));
194       free (oldbuf);
195       /* Make sure _IO_setb won't try to delete
196 	 _IO_buf_base. */
197       fp->_IO_buf_base = NULL;
198     }
199 
200   _IO_setb (fp, newbuf, newbuf + newsize, 1);
201 
202   if (reading)
203     {
204       fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
205       fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
206       fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
207       fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
208 
209       fp->_IO_read_base = newbuf;
210       fp->_IO_read_end = fp->_IO_buf_end;
211     }
212   else
213     {
214       fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
215       fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
216       fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
217       fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
218 
219       fp->_IO_write_base = newbuf;
220       fp->_IO_write_end = fp->_IO_buf_end;
221     }
222 
223   /* Clear the area between the last write position and th
224      new position.  */
225   assert (offset >= oldend);
226   if (reading)
227     memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
228   else
229     memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
230 
231   return 0;
232 }
233 
234 static void
_IO_str_switch_to_get_mode(FILE * fp)235 _IO_str_switch_to_get_mode (FILE *fp)
236 {
237   if (_IO_in_backup (fp))
238     fp->_IO_read_base = fp->_IO_backup_base;
239   else
240     {
241       fp->_IO_read_base = fp->_IO_buf_base;
242       if (fp->_IO_write_ptr > fp->_IO_read_end)
243         fp->_IO_read_end = fp->_IO_write_ptr;
244     }
245   fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_write_ptr;
246 
247   fp->_flags &= ~_IO_CURRENTLY_PUTTING;
248 }
249 
250 off64_t
_IO_str_seekoff(FILE * fp,off64_t offset,int dir,int mode)251 _IO_str_seekoff (FILE *fp, off64_t offset, int dir, int mode)
252 {
253   off64_t new_pos;
254 
255   if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
256     mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
257 
258   bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
259 		     || _IO_in_put_mode (fp));
260   if (was_writing)
261     _IO_str_switch_to_get_mode (fp);
262 
263   if (mode == 0)
264     {
265       new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
266     }
267   else
268     {
269       ssize_t cur_size = _IO_str_count(fp);
270       new_pos = EOF;
271 
272       /* Move the get pointer, if requested. */
273       if (mode & _IOS_INPUT)
274 	{
275 	  ssize_t base;
276 	  switch (dir)
277 	    {
278 	    case _IO_seek_set:
279 	      base = 0;
280 	      break;
281 	    case _IO_seek_cur:
282 	      base = fp->_IO_read_ptr - fp->_IO_read_base;
283 	      break;
284 	    default: /* case _IO_seek_end: */
285 	      base = cur_size;
286 	      break;
287 	    }
288 	  ssize_t maxval = SSIZE_MAX - base;
289 	  if (offset < -base || offset > maxval)
290 	    {
291 	      __set_errno (EINVAL);
292 	      return EOF;
293 	    }
294 	  base += offset;
295 	  if (base > cur_size
296 	      && enlarge_userbuf (fp, base, 1) != 0)
297 	    return EOF;
298 	  fp->_IO_read_ptr = fp->_IO_read_base + base;
299 	  fp->_IO_read_end = fp->_IO_read_base + cur_size;
300 	  new_pos = base;
301 	}
302 
303       /* Move the put pointer, if requested. */
304       if (mode & _IOS_OUTPUT)
305 	{
306 	  ssize_t base;
307 	  switch (dir)
308 	    {
309 	    case _IO_seek_set:
310 	      base = 0;
311 	      break;
312 	    case _IO_seek_cur:
313 	      base = fp->_IO_write_ptr - fp->_IO_write_base;
314 	      break;
315 	    default: /* case _IO_seek_end: */
316 	      base = cur_size;
317 	      break;
318 	    }
319 	  ssize_t maxval = SSIZE_MAX - base;
320 	  if (offset < -base || offset > maxval)
321 	    {
322 	      __set_errno (EINVAL);
323 	      return EOF;
324 	    }
325 	  base += offset;
326 	  if (base > cur_size
327 	      && enlarge_userbuf (fp, base, 0) != 0)
328 	    return EOF;
329 	  fp->_IO_write_ptr = fp->_IO_write_base + base;
330 	  new_pos = base;
331 	}
332     }
333   return new_pos;
334 }
libc_hidden_def(_IO_str_seekoff)335 libc_hidden_def (_IO_str_seekoff)
336 
337 int
338 _IO_str_pbackfail (FILE *fp, int c)
339 {
340   if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
341     return EOF;
342   return _IO_default_pbackfail (fp, c);
343 }
libc_hidden_def(_IO_str_pbackfail)344 libc_hidden_def (_IO_str_pbackfail)
345 
346 void
347 _IO_str_finish (FILE *fp, int dummy)
348 {
349   if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
350     free (fp->_IO_buf_base);
351   fp->_IO_buf_base = NULL;
352 
353   _IO_default_finish (fp, 0);
354 }
355 
356 const struct _IO_jump_t _IO_str_jumps libio_vtable =
357 {
358   JUMP_INIT_DUMMY,
359   JUMP_INIT(finish, _IO_str_finish),
360   JUMP_INIT(overflow, _IO_str_overflow),
361   JUMP_INIT(underflow, _IO_str_underflow),
362   JUMP_INIT(uflow, _IO_default_uflow),
363   JUMP_INIT(pbackfail, _IO_str_pbackfail),
364   JUMP_INIT(xsputn, _IO_default_xsputn),
365   JUMP_INIT(xsgetn, _IO_default_xsgetn),
366   JUMP_INIT(seekoff, _IO_str_seekoff),
367   JUMP_INIT(seekpos, _IO_default_seekpos),
368   JUMP_INIT(setbuf, _IO_default_setbuf),
369   JUMP_INIT(sync, _IO_default_sync),
370   JUMP_INIT(doallocate, _IO_default_doallocate),
371   JUMP_INIT(read, _IO_default_read),
372   JUMP_INIT(write, _IO_default_write),
373   JUMP_INIT(seek, _IO_default_seek),
374   JUMP_INIT(close, _IO_default_close),
375   JUMP_INIT(stat, _IO_default_stat),
376   JUMP_INIT(showmanyc, _IO_default_showmanyc),
377   JUMP_INIT(imbue, _IO_default_imbue)
378 };
379