(root)/
glibc-2.38/
libio/
strops.c
       1  /* Copyright (C) 1993-2023 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
      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 = strchr (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
      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
      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
      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  }
     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  }
     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
     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
     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
     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  }
     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  }
     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  }