1 /* Copyright (C) 1993-2021 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   return c;
137 }
libc_hidden_def(_IO_str_overflow)138 libc_hidden_def (_IO_str_overflow)
139 
140 int
141 _IO_str_underflow (FILE *fp)
142 {
143   if (fp->_IO_write_ptr > fp->_IO_read_end)
144     fp->_IO_read_end = fp->_IO_write_ptr;
145   if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
146     {
147       fp->_flags &= ~_IO_CURRENTLY_PUTTING;
148       fp->_IO_read_ptr = fp->_IO_write_ptr;
149       fp->_IO_write_ptr = fp->_IO_write_end;
150     }
151   if (fp->_IO_read_ptr < fp->_IO_read_end)
152     return *((unsigned char *) fp->_IO_read_ptr);
153   else
154     return EOF;
155 }
libc_hidden_def(_IO_str_underflow)156 libc_hidden_def (_IO_str_underflow)
157 
158 /* The size of the valid part of the buffer.  */
159 
160 ssize_t
161 _IO_str_count (FILE *fp)
162 {
163   return ((fp->_IO_write_ptr > fp->_IO_read_end
164 	   ? fp->_IO_write_ptr : fp->_IO_read_end)
165 	  - fp->_IO_read_base);
166 }
167 
168 
169 static int
enlarge_userbuf(FILE * fp,off64_t offset,int reading)170 enlarge_userbuf (FILE *fp, off64_t offset, int reading)
171 {
172   if ((ssize_t) offset <= _IO_blen (fp))
173     return 0;
174 
175   ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
176 
177   /* Try to enlarge the buffer.  */
178   if (fp->_flags & _IO_USER_BUF)
179     /* User-provided buffer.  */
180     return 1;
181 
182   size_t newsize = offset + 100;
183   char *oldbuf = fp->_IO_buf_base;
184   char *newbuf = malloc (newsize);
185   if (newbuf == NULL)
186     return 1;
187 
188   if (oldbuf != NULL)
189     {
190       memcpy (newbuf, oldbuf, _IO_blen (fp));
191       free (oldbuf);
192       /* Make sure _IO_setb won't try to delete
193 	 _IO_buf_base. */
194       fp->_IO_buf_base = NULL;
195     }
196 
197   _IO_setb (fp, newbuf, newbuf + newsize, 1);
198 
199   if (reading)
200     {
201       fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
202       fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
203       fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
204       fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
205 
206       fp->_IO_read_base = newbuf;
207       fp->_IO_read_end = fp->_IO_buf_end;
208     }
209   else
210     {
211       fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
212       fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
213       fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
214       fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
215 
216       fp->_IO_write_base = newbuf;
217       fp->_IO_write_end = fp->_IO_buf_end;
218     }
219 
220   /* Clear the area between the last write position and th
221      new position.  */
222   assert (offset >= oldend);
223   if (reading)
224     memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
225   else
226     memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
227 
228   return 0;
229 }
230 
231 static void
_IO_str_switch_to_get_mode(FILE * fp)232 _IO_str_switch_to_get_mode (FILE *fp)
233 {
234   if (_IO_in_backup (fp))
235     fp->_IO_read_base = fp->_IO_backup_base;
236   else
237     {
238       fp->_IO_read_base = fp->_IO_buf_base;
239       if (fp->_IO_write_ptr > fp->_IO_read_end)
240         fp->_IO_read_end = fp->_IO_write_ptr;
241     }
242   fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_write_ptr;
243 
244   fp->_flags &= ~_IO_CURRENTLY_PUTTING;
245 }
246 
247 off64_t
_IO_str_seekoff(FILE * fp,off64_t offset,int dir,int mode)248 _IO_str_seekoff (FILE *fp, off64_t offset, int dir, int mode)
249 {
250   off64_t new_pos;
251 
252   if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
253     mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
254 
255   bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
256 		     || _IO_in_put_mode (fp));
257   if (was_writing)
258     _IO_str_switch_to_get_mode (fp);
259 
260   if (mode == 0)
261     {
262       new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
263     }
264   else
265     {
266       ssize_t cur_size = _IO_str_count(fp);
267       new_pos = EOF;
268 
269       /* Move the get pointer, if requested. */
270       if (mode & _IOS_INPUT)
271 	{
272 	  ssize_t base;
273 	  switch (dir)
274 	    {
275 	    case _IO_seek_set:
276 	      base = 0;
277 	      break;
278 	    case _IO_seek_cur:
279 	      base = fp->_IO_read_ptr - fp->_IO_read_base;
280 	      break;
281 	    default: /* case _IO_seek_end: */
282 	      base = cur_size;
283 	      break;
284 	    }
285 	  ssize_t maxval = SSIZE_MAX - base;
286 	  if (offset < -base || offset > maxval)
287 	    {
288 	      __set_errno (EINVAL);
289 	      return EOF;
290 	    }
291 	  base += offset;
292 	  if (base > cur_size
293 	      && enlarge_userbuf (fp, base, 1) != 0)
294 	    return EOF;
295 	  fp->_IO_read_ptr = fp->_IO_read_base + base;
296 	  fp->_IO_read_end = fp->_IO_read_base + cur_size;
297 	  new_pos = base;
298 	}
299 
300       /* Move the put pointer, if requested. */
301       if (mode & _IOS_OUTPUT)
302 	{
303 	  ssize_t base;
304 	  switch (dir)
305 	    {
306 	    case _IO_seek_set:
307 	      base = 0;
308 	      break;
309 	    case _IO_seek_cur:
310 	      base = fp->_IO_write_ptr - fp->_IO_write_base;
311 	      break;
312 	    default: /* case _IO_seek_end: */
313 	      base = cur_size;
314 	      break;
315 	    }
316 	  ssize_t maxval = SSIZE_MAX - base;
317 	  if (offset < -base || offset > maxval)
318 	    {
319 	      __set_errno (EINVAL);
320 	      return EOF;
321 	    }
322 	  base += offset;
323 	  if (base > cur_size
324 	      && enlarge_userbuf (fp, base, 0) != 0)
325 	    return EOF;
326 	  fp->_IO_write_ptr = fp->_IO_write_base + base;
327 	  new_pos = base;
328 	}
329     }
330   return new_pos;
331 }
libc_hidden_def(_IO_str_seekoff)332 libc_hidden_def (_IO_str_seekoff)
333 
334 int
335 _IO_str_pbackfail (FILE *fp, int c)
336 {
337   if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
338     return EOF;
339   return _IO_default_pbackfail (fp, c);
340 }
libc_hidden_def(_IO_str_pbackfail)341 libc_hidden_def (_IO_str_pbackfail)
342 
343 void
344 _IO_str_finish (FILE *fp, int dummy)
345 {
346   if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
347     free (fp->_IO_buf_base);
348   fp->_IO_buf_base = NULL;
349 
350   _IO_default_finish (fp, 0);
351 }
352 
353 const struct _IO_jump_t _IO_str_jumps libio_vtable =
354 {
355   JUMP_INIT_DUMMY,
356   JUMP_INIT(finish, _IO_str_finish),
357   JUMP_INIT(overflow, _IO_str_overflow),
358   JUMP_INIT(underflow, _IO_str_underflow),
359   JUMP_INIT(uflow, _IO_default_uflow),
360   JUMP_INIT(pbackfail, _IO_str_pbackfail),
361   JUMP_INIT(xsputn, _IO_default_xsputn),
362   JUMP_INIT(xsgetn, _IO_default_xsgetn),
363   JUMP_INIT(seekoff, _IO_str_seekoff),
364   JUMP_INIT(seekpos, _IO_default_seekpos),
365   JUMP_INIT(setbuf, _IO_default_setbuf),
366   JUMP_INIT(sync, _IO_default_sync),
367   JUMP_INIT(doallocate, _IO_default_doallocate),
368   JUMP_INIT(read, _IO_default_read),
369   JUMP_INIT(write, _IO_default_write),
370   JUMP_INIT(seek, _IO_default_seek),
371   JUMP_INIT(close, _IO_default_close),
372   JUMP_INIT(stat, _IO_default_stat),
373   JUMP_INIT(showmanyc, _IO_default_showmanyc),
374   JUMP_INIT(imbue, _IO_default_imbue)
375 };
376