Blame libio/strops.c

Packit Service 82fcde
/* Copyright (C) 1993-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.
Packit Service 82fcde
Packit Service 82fcde
   As a special exception, if you link the code in this file with
Packit Service 82fcde
   files compiled with a GNU compiler to produce an executable,
Packit Service 82fcde
   that does not cause the resulting executable to be covered by
Packit Service 82fcde
   the GNU Lesser General Public License.  This exception does not
Packit Service 82fcde
   however invalidate any other reasons why the executable file
Packit Service 82fcde
   might be covered by the GNU Lesser General Public License.
Packit Service 82fcde
   This exception applies to code released by its copyright holders
Packit Service 82fcde
   in files containing the exception.  */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include "strfile.h"
Packit Service 82fcde
#include "libioP.h"
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <stdio_ext.h>
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_IO_str_init_static_internal (_IO_strfile *sf, char *ptr, size_t size,
Packit Service 82fcde
			      char *pstart)
Packit Service 82fcde
{
Packit Service 82fcde
  FILE *fp = &sf->_sbf._f;
Packit Service 82fcde
  char *end;
Packit Service 82fcde
Packit Service 82fcde
  if (size == 0)
Packit Service 82fcde
    end = __rawmemchr (ptr, '\0');
Packit Service 82fcde
  else if ((size_t) ptr + size > (size_t) ptr)
Packit Service 82fcde
    end = ptr + size;
Packit Service 82fcde
  else
Packit Service 82fcde
    end = (char *) -1;
Packit Service 82fcde
  _IO_setb (fp, ptr, end, 0);
Packit Service 82fcde
Packit Service 82fcde
  fp->_IO_write_base = ptr;
Packit Service 82fcde
  fp->_IO_read_base = ptr;
Packit Service 82fcde
  fp->_IO_read_ptr = ptr;
Packit Service 82fcde
  if (pstart)
Packit Service 82fcde
    {
Packit Service 82fcde
      fp->_IO_write_ptr = pstart;
Packit Service 82fcde
      fp->_IO_write_end = end;
Packit Service 82fcde
      fp->_IO_read_end = pstart;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      fp->_IO_write_ptr = ptr;
Packit Service 82fcde
      fp->_IO_write_end = ptr;
Packit Service 82fcde
      fp->_IO_read_end = end;
Packit Service 82fcde
    }
Packit Service 82fcde
  /* A null _allocate_buffer function flags the strfile as being static. */
Packit Service 82fcde
  sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_IO_str_init_static (_IO_strfile *sf, char *ptr, int size, char *pstart)
Packit Service 82fcde
{
Packit Service 82fcde
  return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_IO_str_init_readonly (_IO_strfile *sf, const char *ptr, int size)
Packit Service 82fcde
{
Packit Service 82fcde
  _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
Packit Service 82fcde
  sf->_sbf._f._flags |= _IO_NO_WRITES;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
_IO_str_overflow (FILE *fp, int c)
Packit Service 82fcde
{
Packit Service 82fcde
  int flush_only = c == EOF;
Packit Service 82fcde
  size_t pos;
Packit Service 82fcde
  if (fp->_flags & _IO_NO_WRITES)
Packit Service 82fcde
      return flush_only ? 0 : EOF;
Packit Service 82fcde
  if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
Packit Service 82fcde
    {
Packit Service 82fcde
      fp->_flags |= _IO_CURRENTLY_PUTTING;
Packit Service 82fcde
      fp->_IO_write_ptr = fp->_IO_read_ptr;
Packit Service 82fcde
      fp->_IO_read_ptr = fp->_IO_read_end;
Packit Service 82fcde
    }
Packit Service 82fcde
  pos = fp->_IO_write_ptr - fp->_IO_write_base;
Packit Service 82fcde
  if (pos >= (size_t) (_IO_blen (fp) + flush_only))
Packit Service 82fcde
    {
Packit Service 82fcde
      if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
Packit Service 82fcde
	return EOF;
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  char *new_buf;
Packit Service 82fcde
	  char *old_buf = fp->_IO_buf_base;
Packit Service 82fcde
	  size_t old_blen = _IO_blen (fp);
Packit Service 82fcde
	  size_t new_size = 2 * old_blen + 100;
Packit Service 82fcde
	  if (new_size < old_blen)
Packit Service 82fcde
	    return EOF;
Packit Service 82fcde
	  new_buf = malloc (new_size);
Packit Service 82fcde
	  if (new_buf == NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /*	  __ferror(fp) = 1; */
Packit Service 82fcde
	      return EOF;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  if (old_buf)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      memcpy (new_buf, old_buf, old_blen);
Packit Service 82fcde
	      free (old_buf);
Packit Service 82fcde
	      /* Make sure _IO_setb won't try to delete _IO_buf_base. */
Packit Service 82fcde
	      fp->_IO_buf_base = NULL;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  memset (new_buf + old_blen, '\0', new_size - old_blen);
Packit Service 82fcde
Packit Service 82fcde
	  _IO_setb (fp, new_buf, new_buf + new_size, 1);
Packit Service 82fcde
	  fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
Packit Service 82fcde
	  fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
Packit Service 82fcde
	  fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
Packit Service 82fcde
	  fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
Packit Service 82fcde
Packit Service 82fcde
	  fp->_IO_write_base = new_buf;
Packit Service 82fcde
	  fp->_IO_write_end = fp->_IO_buf_end;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (!flush_only)
Packit Service 82fcde
    *fp->_IO_write_ptr++ = (unsigned char) c;
Packit Service 82fcde
  if (fp->_IO_write_ptr > fp->_IO_read_end)
Packit Service 82fcde
    fp->_IO_read_end = fp->_IO_write_ptr;
Packit Service 82fcde
  return c;
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_IO_str_overflow)
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
_IO_str_underflow (FILE *fp)
Packit Service 82fcde
{
Packit Service 82fcde
  if (fp->_IO_write_ptr > fp->_IO_read_end)
Packit Service 82fcde
    fp->_IO_read_end = fp->_IO_write_ptr;
Packit Service 82fcde
  if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
Packit Service 82fcde
    {
Packit Service 82fcde
      fp->_flags &= ~_IO_CURRENTLY_PUTTING;
Packit Service 82fcde
      fp->_IO_read_ptr = fp->_IO_write_ptr;
Packit Service 82fcde
      fp->_IO_write_ptr = fp->_IO_write_end;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (fp->_IO_read_ptr < fp->_IO_read_end)
Packit Service 82fcde
    return *((unsigned char *) fp->_IO_read_ptr);
Packit Service 82fcde
  else
Packit Service 82fcde
    return EOF;
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_IO_str_underflow)
Packit Service 82fcde
Packit Service 82fcde
/* The size of the valid part of the buffer.  */
Packit Service 82fcde
Packit Service 82fcde
ssize_t
Packit Service 82fcde
_IO_str_count (FILE *fp)
Packit Service 82fcde
{
Packit Service 82fcde
  return ((fp->_IO_write_ptr > fp->_IO_read_end
Packit Service 82fcde
	   ? fp->_IO_write_ptr : fp->_IO_read_end)
Packit Service 82fcde
	  - fp->_IO_read_base);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
enlarge_userbuf (FILE *fp, off64_t offset, int reading)
Packit Service 82fcde
{
Packit Service 82fcde
  if ((ssize_t) offset <= _IO_blen (fp))
Packit Service 82fcde
    return 0;
Packit Service 82fcde
Packit Service 82fcde
  ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
Packit Service 82fcde
Packit Service 82fcde
  /* Try to enlarge the buffer.  */
Packit Service 82fcde
  if (fp->_flags & _IO_USER_BUF)
Packit Service 82fcde
    /* User-provided buffer.  */
Packit Service 82fcde
    return 1;
Packit Service 82fcde
Packit Service 82fcde
  size_t newsize = offset + 100;
Packit Service 82fcde
  char *oldbuf = fp->_IO_buf_base;
Packit Service 82fcde
  char *newbuf = malloc (newsize);
Packit Service 82fcde
  if (newbuf == NULL)
Packit Service 82fcde
    return 1;
Packit Service 82fcde
Packit Service 82fcde
  if (oldbuf != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      memcpy (newbuf, oldbuf, _IO_blen (fp));
Packit Service 82fcde
      free (oldbuf);
Packit Service 82fcde
      /* Make sure _IO_setb won't try to delete
Packit Service 82fcde
	 _IO_buf_base. */
Packit Service 82fcde
      fp->_IO_buf_base = NULL;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  _IO_setb (fp, newbuf, newbuf + newsize, 1);
Packit Service 82fcde
Packit Service 82fcde
  if (reading)
Packit Service 82fcde
    {
Packit Service 82fcde
      fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
Packit Service 82fcde
      fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
Packit Service 82fcde
      fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
Packit Service 82fcde
      fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
Packit Service 82fcde
Packit Service 82fcde
      fp->_IO_read_base = newbuf;
Packit Service 82fcde
      fp->_IO_read_end = fp->_IO_buf_end;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
Packit Service 82fcde
      fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
Packit Service 82fcde
      fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
Packit Service 82fcde
      fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
Packit Service 82fcde
Packit Service 82fcde
      fp->_IO_write_base = newbuf;
Packit Service 82fcde
      fp->_IO_write_end = fp->_IO_buf_end;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Clear the area between the last write position and th
Packit Service 82fcde
     new position.  */
Packit Service 82fcde
  assert (offset >= oldend);
Packit Service 82fcde
  if (reading)
Packit Service 82fcde
    memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
Packit Service 82fcde
  else
Packit Service 82fcde
    memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
_IO_str_switch_to_get_mode (FILE *fp)
Packit Service 82fcde
{
Packit Service 82fcde
  if (_IO_in_backup (fp))
Packit Service 82fcde
    fp->_IO_read_base = fp->_IO_backup_base;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      fp->_IO_read_base = fp->_IO_buf_base;
Packit Service 82fcde
      if (fp->_IO_write_ptr > fp->_IO_read_end)
Packit Service 82fcde
        fp->_IO_read_end = fp->_IO_write_ptr;
Packit Service 82fcde
    }
Packit Service 82fcde
  fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_write_ptr;
Packit Service 82fcde
Packit Service 82fcde
  fp->_flags &= ~_IO_CURRENTLY_PUTTING;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
off64_t
Packit Service 82fcde
_IO_str_seekoff (FILE *fp, off64_t offset, int dir, int mode)
Packit Service 82fcde
{
Packit Service 82fcde
  off64_t new_pos;
Packit Service 82fcde
Packit Service 82fcde
  if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
Packit Service 82fcde
    mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
Packit Service 82fcde
Packit Service 82fcde
  bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
Packit Service 82fcde
		     || _IO_in_put_mode (fp));
Packit Service 82fcde
  if (was_writing)
Packit Service 82fcde
    _IO_str_switch_to_get_mode (fp);
Packit Service 82fcde
Packit Service 82fcde
  if (mode == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      ssize_t cur_size = _IO_str_count(fp);
Packit Service 82fcde
      new_pos = EOF;
Packit Service 82fcde
Packit Service 82fcde
      /* Move the get pointer, if requested. */
Packit Service 82fcde
      if (mode & _IOS_INPUT)
Packit Service 82fcde
	{
Packit Service 82fcde
	  ssize_t base;
Packit Service 82fcde
	  switch (dir)
Packit Service 82fcde
	    {
Packit Service 82fcde
	    case _IO_seek_set:
Packit Service 82fcde
	      base = 0;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    case _IO_seek_cur:
Packit Service 82fcde
	      base = fp->_IO_read_ptr - fp->_IO_read_base;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    default: /* case _IO_seek_end: */
Packit Service 82fcde
	      base = cur_size;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  ssize_t maxval = SSIZE_MAX - base;
Packit Service 82fcde
	  if (offset < -base || offset > maxval)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      __set_errno (EINVAL);
Packit Service 82fcde
	      return EOF;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  base += offset;
Packit Service 82fcde
	  if (base > cur_size
Packit Service 82fcde
	      && enlarge_userbuf (fp, base, 1) != 0)
Packit Service 82fcde
	    return EOF;
Packit Service 82fcde
	  fp->_IO_read_ptr = fp->_IO_read_base + base;
Packit Service 82fcde
	  fp->_IO_read_end = fp->_IO_read_base + cur_size;
Packit Service 82fcde
	  new_pos = base;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* Move the put pointer, if requested. */
Packit Service 82fcde
      if (mode & _IOS_OUTPUT)
Packit Service 82fcde
	{
Packit Service 82fcde
	  ssize_t base;
Packit Service 82fcde
	  switch (dir)
Packit Service 82fcde
	    {
Packit Service 82fcde
	    case _IO_seek_set:
Packit Service 82fcde
	      base = 0;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    case _IO_seek_cur:
Packit Service 82fcde
	      base = fp->_IO_write_ptr - fp->_IO_write_base;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    default: /* case _IO_seek_end: */
Packit Service 82fcde
	      base = cur_size;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  ssize_t maxval = SSIZE_MAX - base;
Packit Service 82fcde
	  if (offset < -base || offset > maxval)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      __set_errno (EINVAL);
Packit Service 82fcde
	      return EOF;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  base += offset;
Packit Service 82fcde
	  if (base > cur_size
Packit Service 82fcde
	      && enlarge_userbuf (fp, base, 0) != 0)
Packit Service 82fcde
	    return EOF;
Packit Service 82fcde
	  fp->_IO_write_ptr = fp->_IO_write_base + base;
Packit Service 82fcde
	  new_pos = base;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
  return new_pos;
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_IO_str_seekoff)
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
_IO_str_pbackfail (FILE *fp, int c)
Packit Service 82fcde
{
Packit Service 82fcde
  if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
Packit Service 82fcde
    return EOF;
Packit Service 82fcde
  return _IO_default_pbackfail (fp, c);
Packit Service 82fcde
}
Packit Service 82fcde
libc_hidden_def (_IO_str_pbackfail)
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_IO_str_finish (FILE *fp, int dummy)
Packit Service 82fcde
{
Packit Service 82fcde
  if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
Packit Service 82fcde
    free (fp->_IO_buf_base);
Packit Service 82fcde
  fp->_IO_buf_base = NULL;
Packit Service 82fcde
Packit Service 82fcde
  _IO_default_finish (fp, 0);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
const struct _IO_jump_t _IO_str_jumps libio_vtable =
Packit Service 82fcde
{
Packit Service 82fcde
  JUMP_INIT_DUMMY,
Packit Service 82fcde
  JUMP_INIT(finish, _IO_str_finish),
Packit Service 82fcde
  JUMP_INIT(overflow, _IO_str_overflow),
Packit Service 82fcde
  JUMP_INIT(underflow, _IO_str_underflow),
Packit Service 82fcde
  JUMP_INIT(uflow, _IO_default_uflow),
Packit Service 82fcde
  JUMP_INIT(pbackfail, _IO_str_pbackfail),
Packit Service 82fcde
  JUMP_INIT(xsputn, _IO_default_xsputn),
Packit Service 82fcde
  JUMP_INIT(xsgetn, _IO_default_xsgetn),
Packit Service 82fcde
  JUMP_INIT(seekoff, _IO_str_seekoff),
Packit Service 82fcde
  JUMP_INIT(seekpos, _IO_default_seekpos),
Packit Service 82fcde
  JUMP_INIT(setbuf, _IO_default_setbuf),
Packit Service 82fcde
  JUMP_INIT(sync, _IO_default_sync),
Packit Service 82fcde
  JUMP_INIT(doallocate, _IO_default_doallocate),
Packit Service 82fcde
  JUMP_INIT(read, _IO_default_read),
Packit Service 82fcde
  JUMP_INIT(write, _IO_default_write),
Packit Service 82fcde
  JUMP_INIT(seek, _IO_default_seek),
Packit Service 82fcde
  JUMP_INIT(close, _IO_default_close),
Packit Service 82fcde
  JUMP_INIT(stat, _IO_default_stat),
Packit Service 82fcde
  JUMP_INIT(showmanyc, _IO_default_showmanyc),
Packit Service 82fcde
  JUMP_INIT(imbue, _IO_default_imbue)
Packit Service 82fcde
};