Blame libio/fileops.c

Packit 6c4009
/* Copyright (C) 1993-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Written by Per Bothner <bothner@cygnus.com>.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.
Packit 6c4009
Packit 6c4009
   As a special exception, if you link the code in this file with
Packit 6c4009
   files compiled with a GNU compiler to produce an executable,
Packit 6c4009
   that does not cause the resulting executable to be covered by
Packit 6c4009
   the GNU Lesser General Public License.  This exception does not
Packit 6c4009
   however invalidate any other reasons why the executable file
Packit 6c4009
   might be covered by the GNU Lesser General Public License.
Packit 6c4009
   This exception applies to code released by its copyright holders
Packit 6c4009
   in files containing the exception.  */
Packit 6c4009
Packit 6c4009
Packit 6c4009
#include "libioP.h"
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include "../wcsmbs/wcsmbsload.h"
Packit 6c4009
#include "../iconv/gconv_charset.h"
Packit 6c4009
#include "../iconv/gconv_int.h"
Packit 6c4009
#include <shlib-compat.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
#include <kernel-features.h>
Packit 6c4009
Packit 6c4009
extern struct __gconv_trans_data __libio_translit attribute_hidden;
Packit 6c4009
Packit 6c4009
/* An fstream can be in at most one of put mode, get mode, or putback mode.
Packit 6c4009
   Putback mode is a variant of get mode.
Packit 6c4009
Packit 6c4009
   In a filebuf, there is only one current position, instead of two
Packit 6c4009
   separate get and put pointers.  In get mode, the current position
Packit 6c4009
   is that of gptr(); in put mode that of pptr().
Packit 6c4009
Packit 6c4009
   The position in the buffer that corresponds to the position
Packit 6c4009
   in external file system is normally _IO_read_end, except in putback
Packit 6c4009
   mode, when it is _IO_save_end and also when the file is in append mode,
Packit 6c4009
   since switching from read to write mode automatically sends the position in
Packit 6c4009
   the external file system to the end of file.
Packit 6c4009
   If the field _fb._offset is >= 0, it gives the offset in
Packit 6c4009
   the file as a whole corresponding to eGptr(). (?)
Packit 6c4009
Packit 6c4009
   PUT MODE:
Packit 6c4009
   If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
Packit 6c4009
   and _IO_read_base are equal to each other.  These are usually equal
Packit 6c4009
   to _IO_buf_base, though not necessarily if we have switched from
Packit 6c4009
   get mode to put mode.  (The reason is to maintain the invariant
Packit 6c4009
   that _IO_read_end corresponds to the external file position.)
Packit 6c4009
   _IO_write_base is non-NULL and usually equal to _IO_buf_base.
Packit 6c4009
   We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
Packit 6c4009
   The un-flushed character are those between _IO_write_base and _IO_write_ptr.
Packit 6c4009
Packit 6c4009
   GET MODE:
Packit 6c4009
   If a filebuf is in get or putback mode, eback() != egptr().
Packit 6c4009
   In get mode, the unread characters are between gptr() and egptr().
Packit 6c4009
   The OS file position corresponds to that of egptr().
Packit 6c4009
Packit 6c4009
   PUTBACK MODE:
Packit 6c4009
   Putback mode is used to remember "excess" characters that have
Packit 6c4009
   been sputbackc'd in a separate putback buffer.
Packit 6c4009
   In putback mode, the get buffer points to the special putback buffer.
Packit 6c4009
   The unread characters are the characters between gptr() and egptr()
Packit 6c4009
   in the putback buffer, as well as the area between save_gptr()
Packit 6c4009
   and save_egptr(), which point into the original reserve buffer.
Packit 6c4009
   (The pointers save_gptr() and save_egptr() are the values
Packit 6c4009
   of gptr() and egptr() at the time putback mode was entered.)
Packit 6c4009
   The OS position corresponds to that of save_egptr().
Packit 6c4009
Packit 6c4009
   LINE BUFFERED OUTPUT:
Packit 6c4009
   During line buffered output, _IO_write_base==base() && epptr()==base().
Packit 6c4009
   However, ptr() may be anywhere between base() and ebuf().
Packit 6c4009
   This forces a call to filebuf::overflow(int C) on every put.
Packit 6c4009
   If there is more space in the buffer, and C is not a '\n',
Packit 6c4009
   then C is inserted, and pptr() incremented.
Packit 6c4009
Packit 6c4009
   UNBUFFERED STREAMS:
Packit 6c4009
   If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
Packit 6c4009
*/
Packit 6c4009
Packit 6c4009
#define CLOSED_FILEBUF_FLAGS \
Packit 6c4009
  (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_IO_new_file_init_internal (struct _IO_FILE_plus *fp)
Packit 6c4009
{
Packit 6c4009
  /* POSIX.1 allows another file handle to be used to change the position
Packit 6c4009
     of our file descriptor.  Hence we actually don't know the actual
Packit 6c4009
     position before we do the first fseek (and until a following fflush). */
Packit 6c4009
  fp->file._offset = _IO_pos_BAD;
Packit 6c4009
  fp->file._flags |= CLOSED_FILEBUF_FLAGS;
Packit 6c4009
Packit 6c4009
  _IO_link_in (fp);
Packit 6c4009
  fp->file._fileno = -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* External version of _IO_new_file_init_internal which switches off
Packit 6c4009
   vtable validation.  */
Packit 6c4009
void
Packit 6c4009
_IO_new_file_init (struct _IO_FILE_plus *fp)
Packit 6c4009
{
Packit 6c4009
  IO_set_accept_foreign_vtables (&_IO_vtable_check);
Packit 6c4009
  _IO_new_file_init_internal (fp);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_new_file_close_it (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  int write_status;
Packit 6c4009
  if (!_IO_file_is_open (fp))
Packit 6c4009
    return EOF;
Packit 6c4009
Packit 6c4009
  if ((fp->_flags & _IO_NO_WRITES) == 0
Packit 6c4009
      && (fp->_flags & _IO_CURRENTLY_PUTTING) != 0)
Packit 6c4009
    write_status = _IO_do_flush (fp);
Packit 6c4009
  else
Packit 6c4009
    write_status = 0;
Packit 6c4009
Packit 6c4009
  _IO_unsave_markers (fp);
Packit 6c4009
Packit 6c4009
  int close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0
Packit 6c4009
		      ? _IO_SYSCLOSE (fp) : 0);
Packit 6c4009
Packit 6c4009
  /* Free buffer. */
Packit 6c4009
  if (fp->_mode > 0)
Packit 6c4009
    {
Packit 6c4009
      if (_IO_have_wbackup (fp))
Packit 6c4009
	_IO_free_wbackup_area (fp);
Packit 6c4009
      _IO_wsetb (fp, NULL, NULL, 0);
Packit 6c4009
      _IO_wsetg (fp, NULL, NULL, NULL);
Packit 6c4009
      _IO_wsetp (fp, NULL, NULL);
Packit 6c4009
    }
Packit 6c4009
  _IO_setb (fp, NULL, NULL, 0);
Packit 6c4009
  _IO_setg (fp, NULL, NULL, NULL);
Packit 6c4009
  _IO_setp (fp, NULL, NULL);
Packit 6c4009
Packit 6c4009
  _IO_un_link ((struct _IO_FILE_plus *) fp);
Packit 6c4009
  fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
Packit 6c4009
  fp->_fileno = -1;
Packit 6c4009
  fp->_offset = _IO_pos_BAD;
Packit 6c4009
Packit 6c4009
  return close_status ? close_status : write_status;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_close_it, _IO_file_close_it)
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_IO_new_file_finish (FILE *fp, int dummy)
Packit 6c4009
{
Packit 6c4009
  if (_IO_file_is_open (fp))
Packit 6c4009
    {
Packit 6c4009
      _IO_do_flush (fp);
Packit 6c4009
      if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
Packit 6c4009
	_IO_SYSCLOSE (fp);
Packit 6c4009
    }
Packit 6c4009
  _IO_default_finish (fp, 0);
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_finish, _IO_file_finish)
Packit 6c4009
Packit 6c4009
FILE *
Packit 6c4009
_IO_file_open (FILE *fp, const char *filename, int posix_mode, int prot,
Packit 6c4009
	       int read_write, int is32not64)
Packit 6c4009
{
Packit 6c4009
  int fdesc;
Packit 6c4009
  if (__glibc_unlikely (fp->_flags2 & _IO_FLAGS2_NOTCANCEL))
Packit 6c4009
    fdesc = __open_nocancel (filename,
Packit 6c4009
			     posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot);
Packit 6c4009
  else
Packit 6c4009
    fdesc = __open (filename, posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot);
Packit 6c4009
  if (fdesc < 0)
Packit 6c4009
    return NULL;
Packit 6c4009
  fp->_fileno = fdesc;
Packit 6c4009
  _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
Packit 6c4009
  /* For append mode, send the file offset to the end of the file.  Don't
Packit 6c4009
     update the offset cache though, since the file handle is not active.  */
Packit 6c4009
  if ((read_write & (_IO_IS_APPENDING | _IO_NO_READS))
Packit 6c4009
      == (_IO_IS_APPENDING | _IO_NO_READS))
Packit 6c4009
    {
Packit 6c4009
      off64_t new_pos = _IO_SYSSEEK (fp, 0, _IO_seek_end);
Packit 6c4009
      if (new_pos == _IO_pos_BAD && errno != ESPIPE)
Packit 6c4009
	{
Packit 6c4009
	  __close_nocancel (fdesc);
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  _IO_link_in ((struct _IO_FILE_plus *) fp);
Packit 6c4009
  return fp;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_file_open)
Packit 6c4009
Packit 6c4009
FILE *
Packit 6c4009
_IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,
Packit 6c4009
		    int is32not64)
Packit 6c4009
{
Packit 6c4009
  int oflags = 0, omode;
Packit 6c4009
  int read_write;
Packit 6c4009
  int oprot = 0666;
Packit 6c4009
  int i;
Packit 6c4009
  FILE *result;
Packit 6c4009
  const char *cs;
Packit 6c4009
  const char *last_recognized;
Packit 6c4009
Packit 6c4009
  if (_IO_file_is_open (fp))
Packit 6c4009
    return 0;
Packit 6c4009
  switch (*mode)
Packit 6c4009
    {
Packit 6c4009
    case 'r':
Packit 6c4009
      omode = O_RDONLY;
Packit 6c4009
      read_write = _IO_NO_WRITES;
Packit 6c4009
      break;
Packit 6c4009
    case 'w':
Packit 6c4009
      omode = O_WRONLY;
Packit 6c4009
      oflags = O_CREAT|O_TRUNC;
Packit 6c4009
      read_write = _IO_NO_READS;
Packit 6c4009
      break;
Packit 6c4009
    case 'a':
Packit 6c4009
      omode = O_WRONLY;
Packit 6c4009
      oflags = O_CREAT|O_APPEND;
Packit 6c4009
      read_write = _IO_NO_READS|_IO_IS_APPENDING;
Packit 6c4009
      break;
Packit 6c4009
    default:
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  last_recognized = mode;
Packit 6c4009
  for (i = 1; i < 7; ++i)
Packit 6c4009
    {
Packit 6c4009
      switch (*++mode)
Packit 6c4009
	{
Packit 6c4009
	case '\0':
Packit 6c4009
	  break;
Packit 6c4009
	case '+':
Packit 6c4009
	  omode = O_RDWR;
Packit 6c4009
	  read_write &= _IO_IS_APPENDING;
Packit 6c4009
	  last_recognized = mode;
Packit 6c4009
	  continue;
Packit 6c4009
	case 'x':
Packit 6c4009
	  oflags |= O_EXCL;
Packit 6c4009
	  last_recognized = mode;
Packit 6c4009
	  continue;
Packit 6c4009
	case 'b':
Packit 6c4009
	  last_recognized = mode;
Packit 6c4009
	  continue;
Packit 6c4009
	case 'm':
Packit 6c4009
	  fp->_flags2 |= _IO_FLAGS2_MMAP;
Packit 6c4009
	  continue;
Packit 6c4009
	case 'c':
Packit 6c4009
	  fp->_flags2 |= _IO_FLAGS2_NOTCANCEL;
Packit 6c4009
	  continue;
Packit 6c4009
	case 'e':
Packit 6c4009
	  oflags |= O_CLOEXEC;
Packit 6c4009
	  fp->_flags2 |= _IO_FLAGS2_CLOEXEC;
Packit 6c4009
	  continue;
Packit 6c4009
	default:
Packit 6c4009
	  /* Ignore.  */
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write,
Packit 6c4009
			  is32not64);
Packit 6c4009
Packit 6c4009
  if (result != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Test whether the mode string specifies the conversion.  */
Packit 6c4009
      cs = strstr (last_recognized + 1, ",ccs=");
Packit 6c4009
      if (cs != NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* Yep.  Load the appropriate conversions and set the orientation
Packit 6c4009
	     to wide.  */
Packit 6c4009
	  struct gconv_fcts fcts;
Packit 6c4009
	  struct _IO_codecvt *cc;
Packit 6c4009
	  char *endp = __strchrnul (cs + 5, ',');
Packit 6c4009
	  char *ccs = malloc (endp - (cs + 5) + 3);
Packit 6c4009
Packit 6c4009
	  if (ccs == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      int malloc_err = errno;  /* Whatever malloc failed with.  */
Packit 6c4009
	      (void) _IO_file_close_it (fp);
Packit 6c4009
	      __set_errno (malloc_err);
Packit 6c4009
	      return NULL;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
Packit 6c4009
	  strip (ccs, ccs);
Packit 6c4009
Packit 6c4009
	  if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
Packit 6c4009
				   ? upstr (ccs, cs + 5) : ccs) != 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* Something went wrong, we cannot load the conversion modules.
Packit 6c4009
		 This means we cannot proceed since the user explicitly asked
Packit 6c4009
		 for these.  */
Packit 6c4009
	      (void) _IO_file_close_it (fp);
Packit 6c4009
	      free (ccs);
Packit 6c4009
	      __set_errno (EINVAL);
Packit 6c4009
	      return NULL;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  free (ccs);
Packit 6c4009
Packit 6c4009
	  assert (fcts.towc_nsteps == 1);
Packit 6c4009
	  assert (fcts.tomb_nsteps == 1);
Packit 6c4009
Packit 6c4009
	  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
Packit 6c4009
	  fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
Packit 6c4009
Packit 6c4009
	  /* Clear the state.  We start all over again.  */
Packit 6c4009
	  memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
Packit 6c4009
	  memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
Packit 6c4009
Packit 6c4009
	  cc = fp->_codecvt = &fp->_wide_data->_codecvt;
Packit 6c4009
Packit 6c4009
	  cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
Packit 6c4009
	  cc->__cd_in.__cd.__steps = fcts.towc;
Packit 6c4009
Packit 6c4009
	  cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
Packit 6c4009
	  cc->__cd_in.__cd.__data[0].__internal_use = 1;
Packit 6c4009
	  cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
Packit 6c4009
	  cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
Packit 6c4009
Packit 6c4009
	  cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
Packit 6c4009
	  cc->__cd_out.__cd.__steps = fcts.tomb;
Packit 6c4009
Packit 6c4009
	  cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
Packit 6c4009
	  cc->__cd_out.__cd.__data[0].__internal_use = 1;
Packit 6c4009
	  cc->__cd_out.__cd.__data[0].__flags
Packit 6c4009
	    = __GCONV_IS_LAST | __GCONV_TRANSLIT;
Packit 6c4009
	  cc->__cd_out.__cd.__data[0].__statep =
Packit 6c4009
	    &result->_wide_data->_IO_state;
Packit 6c4009
Packit 6c4009
	  /* From now on use the wide character callback functions.  */
Packit 6c4009
	  _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;
Packit 6c4009
Packit 6c4009
	  /* Set the mode now.  */
Packit 6c4009
	  result->_mode = 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_fopen, _IO_file_fopen)
Packit 6c4009
Packit 6c4009
FILE *
Packit 6c4009
_IO_new_file_attach (FILE *fp, int fd)
Packit 6c4009
{
Packit 6c4009
  if (_IO_file_is_open (fp))
Packit 6c4009
    return NULL;
Packit 6c4009
  fp->_fileno = fd;
Packit 6c4009
  fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
Packit 6c4009
  fp->_flags |= _IO_DELETE_DONT_CLOSE;
Packit 6c4009
  /* Get the current position of the file. */
Packit 6c4009
  /* We have to do that since that may be junk. */
Packit 6c4009
  fp->_offset = _IO_pos_BAD;
Packit 6c4009
  int save_errno = errno;
Packit 6c4009
  if (_IO_SEEKOFF (fp, (off64_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT)
Packit 6c4009
      == _IO_pos_BAD && errno != ESPIPE)
Packit 6c4009
    return NULL;
Packit 6c4009
  __set_errno (save_errno);
Packit 6c4009
  return fp;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_attach, _IO_file_attach)
Packit 6c4009
Packit 6c4009
FILE *
Packit 6c4009
_IO_new_file_setbuf (FILE *fp, char *p, ssize_t len)
Packit 6c4009
{
Packit 6c4009
  if (_IO_default_setbuf (fp, p, len) == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
Packit 6c4009
    = fp->_IO_buf_base;
Packit 6c4009
  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
Packit 6c4009
  return fp;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_setbuf, _IO_file_setbuf)
Packit 6c4009
Packit 6c4009
Packit 6c4009
FILE *
Packit 6c4009
_IO_file_setbuf_mmap (FILE *fp, char *p, ssize_t len)
Packit 6c4009
{
Packit 6c4009
  FILE *result;
Packit 6c4009
Packit 6c4009
  /* Change the function table.  */
Packit 6c4009
  _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
Packit 6c4009
  fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
Packit 6c4009
Packit 6c4009
  /* And perform the normal operation.  */
Packit 6c4009
  result = _IO_new_file_setbuf (fp, p, len);
Packit 6c4009
Packit 6c4009
  /* If the call failed, restore to using mmap.  */
Packit 6c4009
  if (result == NULL)
Packit 6c4009
    {
Packit 6c4009
      _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap;
Packit 6c4009
      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t new_do_write (FILE *, const char *, size_t);
Packit 6c4009
Packit 6c4009
/* Write TO_DO bytes from DATA to FP.
Packit 6c4009
   Then mark FP as having empty buffers. */
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_new_do_write (FILE *fp, const char *data, size_t to_do)
Packit 6c4009
{
Packit 6c4009
  return (to_do == 0
Packit 6c4009
	  || (size_t) new_do_write (fp, data, to_do) == to_do) ? 0 : EOF;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_do_write, _IO_do_write)
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
new_do_write (FILE *fp, const char *data, size_t to_do)
Packit 6c4009
{
Packit 6c4009
  size_t count;
Packit 6c4009
  if (fp->_flags & _IO_IS_APPENDING)
Packit 6c4009
    /* On a system without a proper O_APPEND implementation,
Packit 6c4009
       you would need to sys_seek(0, SEEK_END) here, but is
Packit 6c4009
       not needed nor desirable for Unix- or Posix-like systems.
Packit 6c4009
       Instead, just indicate that offset (before and after) is
Packit 6c4009
       unpredictable. */
Packit 6c4009
    fp->_offset = _IO_pos_BAD;
Packit 6c4009
  else if (fp->_IO_read_end != fp->_IO_write_base)
Packit 6c4009
    {
Packit 6c4009
      off64_t new_pos
Packit 6c4009
	= _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
Packit 6c4009
      if (new_pos == _IO_pos_BAD)
Packit 6c4009
	return 0;
Packit 6c4009
      fp->_offset = new_pos;
Packit 6c4009
    }
Packit 6c4009
  count = _IO_SYSWRITE (fp, data, to_do);
Packit 6c4009
  if (fp->_cur_column && count)
Packit 6c4009
    fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;
Packit 6c4009
  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
Packit 6c4009
  fp->_IO_write_end = (fp->_mode <= 0
Packit 6c4009
		       && (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
Packit 6c4009
		       ? fp->_IO_buf_base : fp->_IO_buf_end);
Packit 6c4009
  return count;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_new_file_underflow (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  ssize_t count;
Packit 6c4009
Packit 6c4009
  /* C99 requires EOF to be "sticky".  */
Packit 6c4009
  if (fp->_flags & _IO_EOF_SEEN)
Packit 6c4009
    return EOF;
Packit 6c4009
Packit 6c4009
  if (fp->_flags & _IO_NO_READS)
Packit 6c4009
    {
Packit 6c4009
      fp->_flags |= _IO_ERR_SEEN;
Packit 6c4009
      __set_errno (EBADF);
Packit 6c4009
      return EOF;
Packit 6c4009
    }
Packit 6c4009
  if (fp->_IO_read_ptr < fp->_IO_read_end)
Packit 6c4009
    return *(unsigned char *) fp->_IO_read_ptr;
Packit 6c4009
Packit 6c4009
  if (fp->_IO_buf_base == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Maybe we already have a push back pointer.  */
Packit 6c4009
      if (fp->_IO_save_base != NULL)
Packit 6c4009
	{
Packit 6c4009
	  free (fp->_IO_save_base);
Packit 6c4009
	  fp->_flags &= ~_IO_IN_BACKUP;
Packit 6c4009
	}
Packit 6c4009
      _IO_doallocbuf (fp);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* FIXME This can/should be moved to genops ?? */
Packit 6c4009
  if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
Packit 6c4009
    {
Packit 6c4009
      /* We used to flush all line-buffered stream.  This really isn't
Packit 6c4009
	 required by any standard.  My recollection is that
Packit 6c4009
	 traditional Unix systems did this for stdout.  stderr better
Packit 6c4009
	 not be line buffered.  So we do just that here
Packit 6c4009
	 explicitly.  --drepper */
Packit 6c4009
      _IO_acquire_lock (_IO_stdout);
Packit 6c4009
Packit 6c4009
      if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
Packit 6c4009
	  == (_IO_LINKED | _IO_LINE_BUF))
Packit 6c4009
	_IO_OVERFLOW (_IO_stdout, EOF);
Packit 6c4009
Packit 6c4009
      _IO_release_lock (_IO_stdout);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  _IO_switch_to_get_mode (fp);
Packit 6c4009
Packit 6c4009
  /* This is very tricky. We have to adjust those
Packit 6c4009
     pointers before we call _IO_SYSREAD () since
Packit 6c4009
     we may longjump () out while waiting for
Packit 6c4009
     input. Those pointers may be screwed up. H.J. */
Packit 6c4009
  fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
Packit 6c4009
  fp->_IO_read_end = fp->_IO_buf_base;
Packit 6c4009
  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
Packit 6c4009
    = fp->_IO_buf_base;
Packit 6c4009
Packit 6c4009
  count = _IO_SYSREAD (fp, fp->_IO_buf_base,
Packit 6c4009
		       fp->_IO_buf_end - fp->_IO_buf_base);
Packit 6c4009
  if (count <= 0)
Packit 6c4009
    {
Packit 6c4009
      if (count == 0)
Packit 6c4009
	fp->_flags |= _IO_EOF_SEEN;
Packit 6c4009
      else
Packit 6c4009
	fp->_flags |= _IO_ERR_SEEN, count = 0;
Packit 6c4009
  }
Packit 6c4009
  fp->_IO_read_end += count;
Packit 6c4009
  if (count == 0)
Packit 6c4009
    {
Packit 6c4009
      /* If a stream is read to EOF, the calling application may switch active
Packit 6c4009
	 handles.  As a result, our offset cache would no longer be valid, so
Packit 6c4009
	 unset it.  */
Packit 6c4009
      fp->_offset = _IO_pos_BAD;
Packit 6c4009
      return EOF;
Packit 6c4009
    }
Packit 6c4009
  if (fp->_offset != _IO_pos_BAD)
Packit 6c4009
    _IO_pos_adjust (fp->_offset, count);
Packit 6c4009
  return *(unsigned char *) fp->_IO_read_ptr;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_underflow, _IO_file_underflow)
Packit 6c4009
Packit 6c4009
/* Guts of underflow callback if we mmap the file.  This stats the file and
Packit 6c4009
   updates the stream state to match.  In the normal case we return zero.
Packit 6c4009
   If the file is no longer eligible for mmap, its jump tables are reset to
Packit 6c4009
   the vanilla ones and we return nonzero.  */
Packit 6c4009
static int
Packit 6c4009
mmap_remap_check (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  struct stat64 st;
Packit 6c4009
Packit 6c4009
  if (_IO_SYSSTAT (fp, &st) == 0
Packit 6c4009
      && S_ISREG (st.st_mode) && st.st_size != 0
Packit 6c4009
      /* Limit the file size to 1MB for 32-bit machines.  */
Packit 6c4009
      && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024))
Packit 6c4009
    {
Packit 6c4009
      const size_t pagesize = __getpagesize ();
Packit 6c4009
# define ROUNDED(x)	(((x) + pagesize - 1) & ~(pagesize - 1))
Packit 6c4009
      if (ROUNDED (st.st_size) < ROUNDED (fp->_IO_buf_end
Packit 6c4009
					  - fp->_IO_buf_base))
Packit 6c4009
	{
Packit 6c4009
	  /* We can trim off some pages past the end of the file.  */
Packit 6c4009
	  (void) __munmap (fp->_IO_buf_base + ROUNDED (st.st_size),
Packit 6c4009
			   ROUNDED (fp->_IO_buf_end - fp->_IO_buf_base)
Packit 6c4009
			   - ROUNDED (st.st_size));
Packit 6c4009
	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
Packit 6c4009
	}
Packit 6c4009
      else if (ROUNDED (st.st_size) > ROUNDED (fp->_IO_buf_end
Packit 6c4009
					       - fp->_IO_buf_base))
Packit 6c4009
	{
Packit 6c4009
	  /* The file added some pages.  We need to remap it.  */
Packit 6c4009
	  void *p;
Packit 6c4009
#if _G_HAVE_MREMAP
Packit 6c4009
	  p = __mremap (fp->_IO_buf_base, ROUNDED (fp->_IO_buf_end
Packit 6c4009
						   - fp->_IO_buf_base),
Packit 6c4009
			ROUNDED (st.st_size), MREMAP_MAYMOVE);
Packit 6c4009
	  if (p == MAP_FAILED)
Packit 6c4009
	    {
Packit 6c4009
	      (void) __munmap (fp->_IO_buf_base,
Packit 6c4009
			       fp->_IO_buf_end - fp->_IO_buf_base);
Packit 6c4009
	      goto punt;
Packit 6c4009
	    }
Packit 6c4009
#else
Packit 6c4009
	  (void) __munmap (fp->_IO_buf_base,
Packit 6c4009
			   fp->_IO_buf_end - fp->_IO_buf_base);
Packit 6c4009
	  p = __mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED,
Packit 6c4009
			fp->_fileno, 0);
Packit 6c4009
	  if (p == MAP_FAILED)
Packit 6c4009
	    goto punt;
Packit 6c4009
#endif
Packit 6c4009
	  fp->_IO_buf_base = p;
Packit 6c4009
	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* The number of pages didn't change.  */
Packit 6c4009
	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
Packit 6c4009
	}
Packit 6c4009
# undef ROUNDED
Packit 6c4009
Packit 6c4009
      fp->_offset -= fp->_IO_read_end - fp->_IO_read_ptr;
Packit 6c4009
      _IO_setg (fp, fp->_IO_buf_base,
Packit 6c4009
		fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base
Packit 6c4009
		? fp->_IO_buf_base + fp->_offset : fp->_IO_buf_end,
Packit 6c4009
		fp->_IO_buf_end);
Packit 6c4009
Packit 6c4009
      /* If we are already positioned at or past the end of the file, don't
Packit 6c4009
	 change the current offset.  If not, seek past what we have mapped,
Packit 6c4009
	 mimicking the position left by a normal underflow reading into its
Packit 6c4009
	 buffer until EOF.  */
Packit 6c4009
Packit 6c4009
      if (fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base)
Packit 6c4009
	{
Packit 6c4009
	  if (__lseek64 (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base,
Packit 6c4009
			 SEEK_SET)
Packit 6c4009
	      != fp->_IO_buf_end - fp->_IO_buf_base)
Packit 6c4009
	    fp->_flags |= _IO_ERR_SEEN;
Packit 6c4009
	  else
Packit 6c4009
	    fp->_offset = fp->_IO_buf_end - fp->_IO_buf_base;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Life is no longer good for mmap.  Punt it.  */
Packit 6c4009
      (void) __munmap (fp->_IO_buf_base,
Packit 6c4009
		       fp->_IO_buf_end - fp->_IO_buf_base);
Packit 6c4009
    punt:
Packit 6c4009
      fp->_IO_buf_base = fp->_IO_buf_end = NULL;
Packit 6c4009
      _IO_setg (fp, NULL, NULL, NULL);
Packit 6c4009
      if (fp->_mode <= 0)
Packit 6c4009
	_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
Packit 6c4009
      else
Packit 6c4009
	_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps;
Packit 6c4009
      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
Packit 6c4009
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Special callback replacing the underflow callbacks if we mmap the file.  */
Packit 6c4009
int
Packit 6c4009
_IO_file_underflow_mmap (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  if (fp->_IO_read_ptr < fp->_IO_read_end)
Packit 6c4009
    return *(unsigned char *) fp->_IO_read_ptr;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (mmap_remap_check (fp)))
Packit 6c4009
    /* We punted to the regular file functions.  */
Packit 6c4009
    return _IO_UNDERFLOW (fp);
Packit 6c4009
Packit 6c4009
  if (fp->_IO_read_ptr < fp->_IO_read_end)
Packit 6c4009
    return *(unsigned char *) fp->_IO_read_ptr;
Packit 6c4009
Packit 6c4009
  fp->_flags |= _IO_EOF_SEEN;
Packit 6c4009
  return EOF;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
decide_maybe_mmap (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  /* We use the file in read-only mode.  This could mean we can
Packit 6c4009
     mmap the file and use it without any copying.  But not all
Packit 6c4009
     file descriptors are for mmap-able objects and on 32-bit
Packit 6c4009
     machines we don't want to map files which are too large since
Packit 6c4009
     this would require too much virtual memory.  */
Packit 6c4009
  struct stat64 st;
Packit 6c4009
Packit 6c4009
  if (_IO_SYSSTAT (fp, &st) == 0
Packit 6c4009
      && S_ISREG (st.st_mode) && st.st_size != 0
Packit 6c4009
      /* Limit the file size to 1MB for 32-bit machines.  */
Packit 6c4009
      && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024)
Packit 6c4009
      /* Sanity check.  */
Packit 6c4009
      && (fp->_offset == _IO_pos_BAD || fp->_offset <= st.st_size))
Packit 6c4009
    {
Packit 6c4009
      /* Try to map the file.  */
Packit 6c4009
      void *p;
Packit 6c4009
Packit 6c4009
      p = __mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED, fp->_fileno, 0);
Packit 6c4009
      if (p != MAP_FAILED)
Packit 6c4009
	{
Packit 6c4009
	  /* OK, we managed to map the file.  Set the buffer up and use a
Packit 6c4009
	     special jump table with simplified underflow functions which
Packit 6c4009
	     never tries to read anything from the file.  */
Packit 6c4009
Packit 6c4009
	  if (__lseek64 (fp->_fileno, st.st_size, SEEK_SET) != st.st_size)
Packit 6c4009
	    {
Packit 6c4009
	      (void) __munmap (p, st.st_size);
Packit 6c4009
	      fp->_offset = _IO_pos_BAD;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      _IO_setb (fp, p, (char *) p + st.st_size, 0);
Packit 6c4009
Packit 6c4009
	      if (fp->_offset == _IO_pos_BAD)
Packit 6c4009
		fp->_offset = 0;
Packit 6c4009
Packit 6c4009
	      _IO_setg (fp, p, p + fp->_offset, p + st.st_size);
Packit 6c4009
	      fp->_offset = st.st_size;
Packit 6c4009
Packit 6c4009
	      if (fp->_mode <= 0)
Packit 6c4009
		_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap;
Packit 6c4009
	      else
Packit 6c4009
		_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_mmap;
Packit 6c4009
	      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
Packit 6c4009
Packit 6c4009
	      return;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We couldn't use mmap, so revert to the vanilla file operations.  */
Packit 6c4009
Packit 6c4009
  if (fp->_mode <= 0)
Packit 6c4009
    _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
Packit 6c4009
  else
Packit 6c4009
    _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps;
Packit 6c4009
  fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_file_underflow_maybe_mmap (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  /* This is the first read attempt.  Choose mmap or vanilla operations
Packit 6c4009
     and then punt to the chosen underflow routine.  */
Packit 6c4009
  decide_maybe_mmap (fp);
Packit 6c4009
  return _IO_UNDERFLOW (fp);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_new_file_overflow (FILE *f, int ch)
Packit 6c4009
{
Packit 6c4009
  if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
Packit 6c4009
    {
Packit 6c4009
      f->_flags |= _IO_ERR_SEEN;
Packit 6c4009
      __set_errno (EBADF);
Packit 6c4009
      return EOF;
Packit 6c4009
    }
Packit 6c4009
  /* If currently reading or no buffer allocated. */
Packit 6c4009
  if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Allocate a buffer if needed. */
Packit 6c4009
      if (f->_IO_write_base == NULL)
Packit 6c4009
	{
Packit 6c4009
	  _IO_doallocbuf (f);
Packit 6c4009
	  _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
Packit 6c4009
	}
Packit 6c4009
      /* Otherwise must be currently reading.
Packit 6c4009
	 If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
Packit 6c4009
	 logically slide the buffer forwards one block (by setting the
Packit 6c4009
	 read pointers to all point at the beginning of the block).  This
Packit 6c4009
	 makes room for subsequent output.
Packit 6c4009
	 Otherwise, set the read pointers to _IO_read_end (leaving that
Packit 6c4009
	 alone, so it can continue to correspond to the external position). */
Packit 6c4009
      if (__glibc_unlikely (_IO_in_backup (f)))
Packit 6c4009
	{
Packit 6c4009
	  size_t nbackup = f->_IO_read_end - f->_IO_read_ptr;
Packit 6c4009
	  _IO_free_backup_area (f);
Packit 6c4009
	  f->_IO_read_base -= MIN (nbackup,
Packit 6c4009
				   f->_IO_read_base - f->_IO_buf_base);
Packit 6c4009
	  f->_IO_read_ptr = f->_IO_read_base;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (f->_IO_read_ptr == f->_IO_buf_end)
Packit 6c4009
	f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
Packit 6c4009
      f->_IO_write_ptr = f->_IO_read_ptr;
Packit 6c4009
      f->_IO_write_base = f->_IO_write_ptr;
Packit 6c4009
      f->_IO_write_end = f->_IO_buf_end;
Packit 6c4009
      f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
Packit 6c4009
Packit 6c4009
      f->_flags |= _IO_CURRENTLY_PUTTING;
Packit 6c4009
      if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
Packit 6c4009
	f->_IO_write_end = f->_IO_write_ptr;
Packit 6c4009
    }
Packit 6c4009
  if (ch == EOF)
Packit 6c4009
    return _IO_do_write (f, f->_IO_write_base,
Packit 6c4009
			 f->_IO_write_ptr - f->_IO_write_base);
Packit 6c4009
  if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
Packit 6c4009
    if (_IO_do_flush (f) == EOF)
Packit 6c4009
      return EOF;
Packit 6c4009
  *f->_IO_write_ptr++ = ch;
Packit 6c4009
  if ((f->_flags & _IO_UNBUFFERED)
Packit 6c4009
      || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
Packit 6c4009
    if (_IO_do_write (f, f->_IO_write_base,
Packit 6c4009
		      f->_IO_write_ptr - f->_IO_write_base) == EOF)
Packit 6c4009
      return EOF;
Packit 6c4009
  return (unsigned char) ch;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_overflow, _IO_file_overflow)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_new_file_sync (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  ssize_t delta;
Packit 6c4009
  int retval = 0;
Packit 6c4009
Packit 6c4009
  /*    char* ptr = cur_ptr(); */
Packit 6c4009
  if (fp->_IO_write_ptr > fp->_IO_write_base)
Packit 6c4009
    if (_IO_do_flush(fp)) return EOF;
Packit 6c4009
  delta = fp->_IO_read_ptr - fp->_IO_read_end;
Packit 6c4009
  if (delta != 0)
Packit 6c4009
    {
Packit 6c4009
      off64_t new_pos = _IO_SYSSEEK (fp, delta, 1);
Packit 6c4009
      if (new_pos != (off64_t) EOF)
Packit 6c4009
	fp->_IO_read_end = fp->_IO_read_ptr;
Packit 6c4009
      else if (errno == ESPIPE)
Packit 6c4009
	; /* Ignore error from unseekable devices. */
Packit 6c4009
      else
Packit 6c4009
	retval = EOF;
Packit 6c4009
    }
Packit 6c4009
  if (retval != EOF)
Packit 6c4009
    fp->_offset = _IO_pos_BAD;
Packit 6c4009
  /* FIXME: Cleanup - can this be shared? */
Packit 6c4009
  /*    setg(base(), ptr, ptr); */
Packit 6c4009
  return retval;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_sync, _IO_file_sync)
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
_IO_file_sync_mmap (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  if (fp->_IO_read_ptr != fp->_IO_read_end)
Packit 6c4009
    {
Packit 6c4009
      if (__lseek64 (fp->_fileno, fp->_IO_read_ptr - fp->_IO_buf_base,
Packit 6c4009
		     SEEK_SET)
Packit 6c4009
	  != fp->_IO_read_ptr - fp->_IO_buf_base)
Packit 6c4009
	{
Packit 6c4009
	  fp->_flags |= _IO_ERR_SEEN;
Packit 6c4009
	  return EOF;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  fp->_offset = fp->_IO_read_ptr - fp->_IO_buf_base;
Packit 6c4009
  fp->_IO_read_end = fp->_IO_read_ptr = fp->_IO_read_base;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* ftell{,o} implementation.  The only time we modify the state of the stream
Packit 6c4009
   is when we have unflushed writes.  In that case we seek to the end and
Packit 6c4009
   record that offset in the stream object.  */
Packit 6c4009
static off64_t
Packit 6c4009
do_ftell (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  off64_t result, offset = 0;
Packit 6c4009
Packit 6c4009
  /* No point looking at unflushed data if we haven't allocated buffers
Packit 6c4009
     yet.  */
Packit 6c4009
  if (fp->_IO_buf_base != NULL)
Packit 6c4009
    {
Packit 6c4009
      bool unflushed_writes = fp->_IO_write_ptr > fp->_IO_write_base;
Packit 6c4009
Packit 6c4009
      bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
Packit 6c4009
Packit 6c4009
      /* When we have unflushed writes in append mode, seek to the end of the
Packit 6c4009
	 file and record that offset.  This is the only time we change the file
Packit 6c4009
	 stream state and it is safe since the file handle is active.  */
Packit 6c4009
      if (unflushed_writes && append_mode)
Packit 6c4009
	{
Packit 6c4009
	  result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
Packit 6c4009
	  if (result == _IO_pos_BAD)
Packit 6c4009
	    return EOF;
Packit 6c4009
	  else
Packit 6c4009
	    fp->_offset = result;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Adjust for unflushed data.  */
Packit 6c4009
      if (!unflushed_writes)
Packit 6c4009
	offset -= fp->_IO_read_end - fp->_IO_read_ptr;
Packit 6c4009
      /* We don't trust _IO_read_end to represent the current file offset when
Packit 6c4009
	 writing in append mode because the value would have to be shifted to
Packit 6c4009
	 the end of the file during a flush.  Use the write base instead, along
Packit 6c4009
	 with the new offset we got above when we did a seek to the end of the
Packit 6c4009
	 file.  */
Packit 6c4009
      else if (append_mode)
Packit 6c4009
	offset += fp->_IO_write_ptr - fp->_IO_write_base;
Packit 6c4009
      /* For all other modes, _IO_read_end represents the file offset.  */
Packit 6c4009
      else
Packit 6c4009
	offset += fp->_IO_write_ptr - fp->_IO_read_end;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (fp->_offset != _IO_pos_BAD)
Packit 6c4009
    result = fp->_offset;
Packit 6c4009
  else
Packit 6c4009
    result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
Packit 6c4009
Packit 6c4009
  if (result == EOF)
Packit 6c4009
    return result;
Packit 6c4009
Packit 6c4009
  result += offset;
Packit 6c4009
Packit 6c4009
  if (result < 0)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
      return EOF;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
off64_t
Packit 6c4009
_IO_new_file_seekoff (FILE *fp, off64_t offset, int dir, int mode)
Packit 6c4009
{
Packit 6c4009
  off64_t result;
Packit 6c4009
  off64_t delta, new_offset;
Packit 6c4009
  long count;
Packit 6c4009
Packit 6c4009
  /* Short-circuit into a separate function.  We don't want to mix any
Packit 6c4009
     functionality and we don't want to touch anything inside the FILE
Packit 6c4009
     object. */
Packit 6c4009
  if (mode == 0)
Packit 6c4009
    return do_ftell (fp);
Packit 6c4009
Packit 6c4009
  /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
Packit 6c4009
     offset of the underlying file must be exact.  */
Packit 6c4009
  int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
Packit 6c4009
		       && fp->_IO_write_base == fp->_IO_write_ptr);
Packit 6c4009
Packit 6c4009
  bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
Packit 6c4009
		      || _IO_in_put_mode (fp));
Packit 6c4009
Packit 6c4009
  /* Flush unwritten characters.
Packit 6c4009
     (This may do an unneeded write if we seek within the buffer.
Packit 6c4009
     But to be able to switch to reading, we would need to set
Packit 6c4009
     egptr to pptr.  That can't be done in the current design,
Packit 6c4009
     which assumes file_ptr() is eGptr.  Anyway, since we probably
Packit 6c4009
     end up flushing when we close(), it doesn't make much difference.)
Packit 6c4009
     FIXME: simulate mem-mapped files. */
Packit 6c4009
  if (was_writing && _IO_switch_to_get_mode (fp))
Packit 6c4009
    return EOF;
Packit 6c4009
Packit 6c4009
  if (fp->_IO_buf_base == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* It could be that we already have a pushback buffer.  */
Packit 6c4009
      if (fp->_IO_read_base != NULL)
Packit 6c4009
	{
Packit 6c4009
	  free (fp->_IO_read_base);
Packit 6c4009
	  fp->_flags &= ~_IO_IN_BACKUP;
Packit 6c4009
	}
Packit 6c4009
      _IO_doallocbuf (fp);
Packit 6c4009
      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  switch (dir)
Packit 6c4009
    {
Packit 6c4009
    case _IO_seek_cur:
Packit 6c4009
      /* Adjust for read-ahead (bytes is buffer). */
Packit 6c4009
      offset -= fp->_IO_read_end - fp->_IO_read_ptr;
Packit 6c4009
Packit 6c4009
      if (fp->_offset == _IO_pos_BAD)
Packit 6c4009
	goto dumb;
Packit 6c4009
      /* Make offset absolute, assuming current pointer is file_ptr(). */
Packit 6c4009
      offset += fp->_offset;
Packit 6c4009
      if (offset < 0)
Packit 6c4009
	{
Packit 6c4009
	  __set_errno (EINVAL);
Packit 6c4009
	  return EOF;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      dir = _IO_seek_set;
Packit 6c4009
      break;
Packit 6c4009
    case _IO_seek_set:
Packit 6c4009
      break;
Packit 6c4009
    case _IO_seek_end:
Packit 6c4009
      {
Packit 6c4009
	struct stat64 st;
Packit 6c4009
	if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
Packit 6c4009
	  {
Packit 6c4009
	    offset += st.st_size;
Packit 6c4009
	    dir = _IO_seek_set;
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
	  goto dumb;
Packit 6c4009
      }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  _IO_free_backup_area (fp);
Packit 6c4009
Packit 6c4009
  /* At this point, dir==_IO_seek_set. */
Packit 6c4009
Packit 6c4009
  /* If destination is within current buffer, optimize: */
Packit 6c4009
  if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
Packit 6c4009
      && !_IO_in_backup (fp))
Packit 6c4009
    {
Packit 6c4009
      off64_t start_offset = (fp->_offset
Packit 6c4009
                              - (fp->_IO_read_end - fp->_IO_buf_base));
Packit 6c4009
      if (offset >= start_offset && offset < fp->_offset)
Packit 6c4009
	{
Packit 6c4009
	  _IO_setg (fp, fp->_IO_buf_base,
Packit 6c4009
		    fp->_IO_buf_base + (offset - start_offset),
Packit 6c4009
		    fp->_IO_read_end);
Packit 6c4009
	  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
Packit 6c4009
	  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
Packit 6c4009
	  goto resync;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (fp->_flags & _IO_NO_READS)
Packit 6c4009
    goto dumb;
Packit 6c4009
Packit 6c4009
  /* Try to seek to a block boundary, to improve kernel page management. */
Packit 6c4009
  new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
Packit 6c4009
  delta = offset - new_offset;
Packit 6c4009
  if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
Packit 6c4009
    {
Packit 6c4009
      new_offset = offset;
Packit 6c4009
      delta = 0;
Packit 6c4009
    }
Packit 6c4009
  result = _IO_SYSSEEK (fp, new_offset, 0);
Packit 6c4009
  if (result < 0)
Packit 6c4009
    return EOF;
Packit 6c4009
  if (delta == 0)
Packit 6c4009
    count = 0;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      count = _IO_SYSREAD (fp, fp->_IO_buf_base,
Packit 6c4009
			   (must_be_exact
Packit 6c4009
			    ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
Packit 6c4009
      if (count < delta)
Packit 6c4009
	{
Packit 6c4009
	  /* We weren't allowed to read, but try to seek the remainder. */
Packit 6c4009
	  offset = count == EOF ? delta : delta-count;
Packit 6c4009
	  dir = _IO_seek_cur;
Packit 6c4009
	  goto dumb;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
Packit 6c4009
	    fp->_IO_buf_base + count);
Packit 6c4009
  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
  fp->_offset = result + count;
Packit 6c4009
  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
Packit 6c4009
  return offset;
Packit 6c4009
 dumb:
Packit 6c4009
Packit 6c4009
  _IO_unsave_markers (fp);
Packit 6c4009
  result = _IO_SYSSEEK (fp, offset, dir);
Packit 6c4009
  if (result != EOF)
Packit 6c4009
    {
Packit 6c4009
      _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
Packit 6c4009
      fp->_offset = result;
Packit 6c4009
      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
    }
Packit 6c4009
  return result;
Packit 6c4009
Packit 6c4009
resync:
Packit 6c4009
  /* We need to do it since it is possible that the file offset in
Packit 6c4009
     the kernel may be changed behind our back. It may happen when
Packit 6c4009
     we fopen a file and then do a fork. One process may access the
Packit 6c4009
     file and the kernel file offset will be changed. */
Packit 6c4009
  if (fp->_offset >= 0)
Packit 6c4009
    _IO_SYSSEEK (fp, fp->_offset, 0);
Packit 6c4009
Packit 6c4009
  return offset;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_seekoff, _IO_file_seekoff)
Packit 6c4009
Packit 6c4009
off64_t
Packit 6c4009
_IO_file_seekoff_mmap (FILE *fp, off64_t offset, int dir, int mode)
Packit 6c4009
{
Packit 6c4009
  off64_t result;
Packit 6c4009
Packit 6c4009
  /* If we are only interested in the current position, calculate it and
Packit 6c4009
     return right now.  This calculation does the right thing when we are
Packit 6c4009
     using a pushback buffer, but in the usual case has the same value as
Packit 6c4009
     (fp->_IO_read_ptr - fp->_IO_buf_base).  */
Packit 6c4009
  if (mode == 0)
Packit 6c4009
    return fp->_offset - (fp->_IO_read_end - fp->_IO_read_ptr);
Packit 6c4009
Packit 6c4009
  switch (dir)
Packit 6c4009
    {
Packit 6c4009
    case _IO_seek_cur:
Packit 6c4009
      /* Adjust for read-ahead (bytes is buffer). */
Packit 6c4009
      offset += fp->_IO_read_ptr - fp->_IO_read_base;
Packit 6c4009
      break;
Packit 6c4009
    case _IO_seek_set:
Packit 6c4009
      break;
Packit 6c4009
    case _IO_seek_end:
Packit 6c4009
      offset += fp->_IO_buf_end - fp->_IO_buf_base;
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
  /* At this point, dir==_IO_seek_set. */
Packit 6c4009
Packit 6c4009
  if (offset < 0)
Packit 6c4009
    {
Packit 6c4009
      /* No negative offsets are valid.  */
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
      return EOF;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  result = _IO_SYSSEEK (fp, offset, 0);
Packit 6c4009
  if (result < 0)
Packit 6c4009
    return EOF;
Packit 6c4009
Packit 6c4009
  if (offset > fp->_IO_buf_end - fp->_IO_buf_base)
Packit 6c4009
    /* One can fseek arbitrarily past the end of the file
Packit 6c4009
       and it is meaningless until one attempts to read.
Packit 6c4009
       Leave the buffer pointers in EOF state until underflow.  */
Packit 6c4009
    _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_end, fp->_IO_buf_end);
Packit 6c4009
  else
Packit 6c4009
    /* Adjust the read pointers to match the file position,
Packit 6c4009
       but so the next read attempt will call underflow.  */
Packit 6c4009
    _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + offset,
Packit 6c4009
	      fp->_IO_buf_base + offset);
Packit 6c4009
Packit 6c4009
  fp->_offset = result;
Packit 6c4009
Packit 6c4009
  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
Packit 6c4009
Packit 6c4009
  return offset;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static off64_t
Packit 6c4009
_IO_file_seekoff_maybe_mmap (FILE *fp, off64_t offset, int dir,
Packit 6c4009
			     int mode)
Packit 6c4009
{
Packit 6c4009
  /* We only get here when we haven't tried to read anything yet.
Packit 6c4009
     So there is nothing more useful for us to do here than just
Packit 6c4009
     the underlying lseek call.  */
Packit 6c4009
Packit 6c4009
  off64_t result = _IO_SYSSEEK (fp, offset, dir);
Packit 6c4009
  if (result < 0)
Packit 6c4009
    return EOF;
Packit 6c4009
Packit 6c4009
  fp->_offset = result;
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
ssize_t
Packit 6c4009
_IO_file_read (FILE *fp, void *buf, ssize_t size)
Packit 6c4009
{
Packit 6c4009
  return (__builtin_expect (fp->_flags2 & _IO_FLAGS2_NOTCANCEL, 0)
Packit 6c4009
	  ? __read_nocancel (fp->_fileno, buf, size)
Packit 6c4009
	  : __read (fp->_fileno, buf, size));
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_file_read)
Packit 6c4009
Packit 6c4009
off64_t
Packit 6c4009
_IO_file_seek (FILE *fp, off64_t offset, int dir)
Packit 6c4009
{
Packit 6c4009
  return __lseek64 (fp->_fileno, offset, dir);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_file_seek)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_file_stat (FILE *fp, void *st)
Packit 6c4009
{
Packit 6c4009
  return __fxstat64 (_STAT_VER, fp->_fileno, (struct stat64 *) st);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_file_stat)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_file_close_mmap (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  /* In addition to closing the file descriptor we have to unmap the file.  */
Packit 6c4009
  (void) __munmap (fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base);
Packit 6c4009
  fp->_IO_buf_base = fp->_IO_buf_end = NULL;
Packit 6c4009
  /* Cancelling close should be avoided if possible since it leaves an
Packit 6c4009
     unrecoverable state behind.  */
Packit 6c4009
  return __close_nocancel (fp->_fileno);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_IO_file_close (FILE *fp)
Packit 6c4009
{
Packit 6c4009
  /* Cancelling close should be avoided if possible since it leaves an
Packit 6c4009
     unrecoverable state behind.  */
Packit 6c4009
  return __close_nocancel (fp->_fileno);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_file_close)
Packit 6c4009
Packit 6c4009
ssize_t
Packit 6c4009
_IO_new_file_write (FILE *f, const void *data, ssize_t n)
Packit 6c4009
{
Packit 6c4009
  ssize_t to_do = n;
Packit 6c4009
  while (to_do > 0)
Packit 6c4009
    {
Packit 6c4009
      ssize_t count = (__builtin_expect (f->_flags2
Packit 6c4009
                                         & _IO_FLAGS2_NOTCANCEL, 0)
Packit 6c4009
			   ? __write_nocancel (f->_fileno, data, to_do)
Packit 6c4009
			   : __write (f->_fileno, data, to_do));
Packit 6c4009
      if (count < 0)
Packit 6c4009
	{
Packit 6c4009
	  f->_flags |= _IO_ERR_SEEN;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
      to_do -= count;
Packit 6c4009
      data = (void *) ((char *) data + count);
Packit 6c4009
    }
Packit 6c4009
  n -= to_do;
Packit 6c4009
  if (f->_offset >= 0)
Packit 6c4009
    f->_offset += n;
Packit 6c4009
  return n;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
size_t
Packit 6c4009
_IO_new_file_xsputn (FILE *f, const void *data, size_t n)
Packit 6c4009
{
Packit 6c4009
  const char *s = (const char *) data;
Packit 6c4009
  size_t to_do = n;
Packit 6c4009
  int must_flush = 0;
Packit 6c4009
  size_t count = 0;
Packit 6c4009
Packit 6c4009
  if (n <= 0)
Packit 6c4009
    return 0;
Packit 6c4009
  /* This is an optimized implementation.
Packit 6c4009
     If the amount to be written straddles a block boundary
Packit 6c4009
     (or the filebuf is unbuffered), use sys_write directly. */
Packit 6c4009
Packit 6c4009
  /* First figure out how much space is available in the buffer. */
Packit 6c4009
  if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
Packit 6c4009
    {
Packit 6c4009
      count = f->_IO_buf_end - f->_IO_write_ptr;
Packit 6c4009
      if (count >= n)
Packit 6c4009
	{
Packit 6c4009
	  const char *p;
Packit 6c4009
	  for (p = s + n; p > s; )
Packit 6c4009
	    {
Packit 6c4009
	      if (*--p == '\n')
Packit 6c4009
		{
Packit 6c4009
		  count = p - s + 1;
Packit 6c4009
		  must_flush = 1;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else if (f->_IO_write_end > f->_IO_write_ptr)
Packit 6c4009
    count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
Packit 6c4009
Packit 6c4009
  /* Then fill the buffer. */
Packit 6c4009
  if (count > 0)
Packit 6c4009
    {
Packit 6c4009
      if (count > to_do)
Packit 6c4009
	count = to_do;
Packit 6c4009
      f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
Packit 6c4009
      s += count;
Packit 6c4009
      to_do -= count;
Packit 6c4009
    }
Packit 6c4009
  if (to_do + must_flush > 0)
Packit 6c4009
    {
Packit 6c4009
      size_t block_size, do_write;
Packit 6c4009
      /* Next flush the (full) buffer. */
Packit 6c4009
      if (_IO_OVERFLOW (f, EOF) == EOF)
Packit 6c4009
	/* If nothing else has to be written we must not signal the
Packit 6c4009
	   caller that everything has been written.  */
Packit 6c4009
	return to_do == 0 ? EOF : n - to_do;
Packit 6c4009
Packit 6c4009
      /* Try to maintain alignment: write a whole number of blocks.  */
Packit 6c4009
      block_size = f->_IO_buf_end - f->_IO_buf_base;
Packit 6c4009
      do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
Packit 6c4009
Packit 6c4009
      if (do_write)
Packit 6c4009
	{
Packit 6c4009
	  count = new_do_write (f, s, do_write);
Packit 6c4009
	  to_do -= count;
Packit 6c4009
	  if (count < do_write)
Packit 6c4009
	    return n - to_do;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Now write out the remainder.  Normally, this will fit in the
Packit 6c4009
	 buffer, but it's somewhat messier for line-buffered files,
Packit 6c4009
	 so we let _IO_default_xsputn handle the general case. */
Packit 6c4009
      if (to_do)
Packit 6c4009
	to_do -= _IO_default_xsputn (f, s+do_write, to_do);
Packit 6c4009
    }
Packit 6c4009
  return n - to_do;
Packit 6c4009
}
Packit 6c4009
libc_hidden_ver (_IO_new_file_xsputn, _IO_file_xsputn)
Packit 6c4009
Packit 6c4009
size_t
Packit 6c4009
_IO_file_xsgetn (FILE *fp, void *data, size_t n)
Packit 6c4009
{
Packit 6c4009
  size_t want, have;
Packit 6c4009
  ssize_t count;
Packit 6c4009
  char *s = data;
Packit 6c4009
Packit 6c4009
  want = n;
Packit 6c4009
Packit 6c4009
  if (fp->_IO_buf_base == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Maybe we already have a push back pointer.  */
Packit 6c4009
      if (fp->_IO_save_base != NULL)
Packit 6c4009
	{
Packit 6c4009
	  free (fp->_IO_save_base);
Packit 6c4009
	  fp->_flags &= ~_IO_IN_BACKUP;
Packit 6c4009
	}
Packit 6c4009
      _IO_doallocbuf (fp);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  while (want > 0)
Packit 6c4009
    {
Packit 6c4009
      have = fp->_IO_read_end - fp->_IO_read_ptr;
Packit 6c4009
      if (want <= have)
Packit 6c4009
	{
Packit 6c4009
	  memcpy (s, fp->_IO_read_ptr, want);
Packit 6c4009
	  fp->_IO_read_ptr += want;
Packit 6c4009
	  want = 0;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  if (have > 0)
Packit 6c4009
	    {
Packit 6c4009
	      s = __mempcpy (s, fp->_IO_read_ptr, have);
Packit 6c4009
	      want -= have;
Packit 6c4009
	      fp->_IO_read_ptr += have;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Check for backup and repeat */
Packit 6c4009
	  if (_IO_in_backup (fp))
Packit 6c4009
	    {
Packit 6c4009
	      _IO_switch_to_main_get_area (fp);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* If we now want less than a buffer, underflow and repeat
Packit 6c4009
	     the copy.  Otherwise, _IO_SYSREAD directly to
Packit 6c4009
	     the user buffer. */
Packit 6c4009
	  if (fp->_IO_buf_base
Packit 6c4009
	      && want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base))
Packit 6c4009
	    {
Packit 6c4009
	      if (__underflow (fp) == EOF)
Packit 6c4009
		break;
Packit 6c4009
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* These must be set before the sysread as we might longjmp out
Packit 6c4009
	     waiting for input. */
Packit 6c4009
	  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
	  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
Packit 6c4009
Packit 6c4009
	  /* Try to maintain alignment: read a whole number of blocks.  */
Packit 6c4009
	  count = want;
Packit 6c4009
	  if (fp->_IO_buf_base)
Packit 6c4009
	    {
Packit 6c4009
	      size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base;
Packit 6c4009
	      if (block_size >= 128)
Packit 6c4009
		count -= want % block_size;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  count = _IO_SYSREAD (fp, s, count);
Packit 6c4009
	  if (count <= 0)
Packit 6c4009
	    {
Packit 6c4009
	      if (count == 0)
Packit 6c4009
		fp->_flags |= _IO_EOF_SEEN;
Packit 6c4009
	      else
Packit 6c4009
		fp->_flags |= _IO_ERR_SEEN;
Packit 6c4009
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  s += count;
Packit 6c4009
	  want -= count;
Packit 6c4009
	  if (fp->_offset != _IO_pos_BAD)
Packit 6c4009
	    _IO_pos_adjust (fp->_offset, count);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return n - want;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_IO_file_xsgetn)
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
_IO_file_xsgetn_mmap (FILE *fp, void *data, size_t n)
Packit 6c4009
{
Packit 6c4009
  size_t have;
Packit 6c4009
  char *read_ptr = fp->_IO_read_ptr;
Packit 6c4009
  char *s = (char *) data;
Packit 6c4009
Packit 6c4009
  have = fp->_IO_read_end - fp->_IO_read_ptr;
Packit 6c4009
Packit 6c4009
  if (have < n)
Packit 6c4009
    {
Packit 6c4009
      if (__glibc_unlikely (_IO_in_backup (fp)))
Packit 6c4009
	{
Packit 6c4009
	  s = __mempcpy (s, read_ptr, have);
Packit 6c4009
	  n -= have;
Packit 6c4009
	  _IO_switch_to_main_get_area (fp);
Packit 6c4009
	  read_ptr = fp->_IO_read_ptr;
Packit 6c4009
	  have = fp->_IO_read_end - fp->_IO_read_ptr;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (have < n)
Packit 6c4009
	{
Packit 6c4009
	  /* Check that we are mapping all of the file, in case it grew.  */
Packit 6c4009
	  if (__glibc_unlikely (mmap_remap_check (fp)))
Packit 6c4009
	    /* We punted mmap, so complete with the vanilla code.  */
Packit 6c4009
	    return s - (char *) data + _IO_XSGETN (fp, data, n);
Packit 6c4009
Packit 6c4009
	  read_ptr = fp->_IO_read_ptr;
Packit 6c4009
	  have = fp->_IO_read_end - read_ptr;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (have < n)
Packit 6c4009
    fp->_flags |= _IO_EOF_SEEN;
Packit 6c4009
Packit 6c4009
  if (have != 0)
Packit 6c4009
    {
Packit 6c4009
      have = MIN (have, n);
Packit 6c4009
      s = __mempcpy (s, read_ptr, have);
Packit 6c4009
      fp->_IO_read_ptr = read_ptr + have;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return s - (char *) data;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
_IO_file_xsgetn_maybe_mmap (FILE *fp, void *data, size_t n)
Packit 6c4009
{
Packit 6c4009
  /* We only get here if this is the first attempt to read something.
Packit 6c4009
     Decide which operations to use and then punt to the chosen one.  */
Packit 6c4009
Packit 6c4009
  decide_maybe_mmap (fp);
Packit 6c4009
  return _IO_XSGETN (fp, data, n);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
versioned_symbol (libc, _IO_new_do_write, _IO_do_write, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_attach, _IO_file_attach, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_close_it, _IO_file_close_it, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_finish, _IO_file_finish, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_fopen, _IO_file_fopen, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_init, _IO_file_init, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_setbuf, _IO_file_setbuf, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_sync, _IO_file_sync, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_overflow, _IO_file_overflow, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_seekoff, _IO_file_seekoff, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_underflow, _IO_file_underflow, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_write, _IO_file_write, GLIBC_2_1);
Packit 6c4009
versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1);
Packit 6c4009
Packit 6c4009
const struct _IO_jump_t _IO_file_jumps libio_vtable =
Packit 6c4009
{
Packit 6c4009
  JUMP_INIT_DUMMY,
Packit 6c4009
  JUMP_INIT(finish, _IO_file_finish),
Packit 6c4009
  JUMP_INIT(overflow, _IO_file_overflow),
Packit 6c4009
  JUMP_INIT(underflow, _IO_file_underflow),
Packit 6c4009
  JUMP_INIT(uflow, _IO_default_uflow),
Packit 6c4009
  JUMP_INIT(pbackfail, _IO_default_pbackfail),
Packit 6c4009
  JUMP_INIT(xsputn, _IO_file_xsputn),
Packit 6c4009
  JUMP_INIT(xsgetn, _IO_file_xsgetn),
Packit 6c4009
  JUMP_INIT(seekoff, _IO_new_file_seekoff),
Packit 6c4009
  JUMP_INIT(seekpos, _IO_default_seekpos),
Packit 6c4009
  JUMP_INIT(setbuf, _IO_new_file_setbuf),
Packit 6c4009
  JUMP_INIT(sync, _IO_new_file_sync),
Packit 6c4009
  JUMP_INIT(doallocate, _IO_file_doallocate),
Packit 6c4009
  JUMP_INIT(read, _IO_file_read),
Packit 6c4009
  JUMP_INIT(write, _IO_new_file_write),
Packit 6c4009
  JUMP_INIT(seek, _IO_file_seek),
Packit 6c4009
  JUMP_INIT(close, _IO_file_close),
Packit 6c4009
  JUMP_INIT(stat, _IO_file_stat),
Packit 6c4009
  JUMP_INIT(showmanyc, _IO_default_showmanyc),
Packit 6c4009
  JUMP_INIT(imbue, _IO_default_imbue)
Packit 6c4009
};
Packit 6c4009
libc_hidden_data_def (_IO_file_jumps)
Packit 6c4009
Packit 6c4009
const struct _IO_jump_t _IO_file_jumps_mmap libio_vtable =
Packit 6c4009
{
Packit 6c4009
  JUMP_INIT_DUMMY,
Packit 6c4009
  JUMP_INIT(finish, _IO_file_finish),
Packit 6c4009
  JUMP_INIT(overflow, _IO_file_overflow),
Packit 6c4009
  JUMP_INIT(underflow, _IO_file_underflow_mmap),
Packit 6c4009
  JUMP_INIT(uflow, _IO_default_uflow),
Packit 6c4009
  JUMP_INIT(pbackfail, _IO_default_pbackfail),
Packit 6c4009
  JUMP_INIT(xsputn, _IO_new_file_xsputn),
Packit 6c4009
  JUMP_INIT(xsgetn, _IO_file_xsgetn_mmap),
Packit 6c4009
  JUMP_INIT(seekoff, _IO_file_seekoff_mmap),
Packit 6c4009
  JUMP_INIT(seekpos, _IO_default_seekpos),
Packit 6c4009
  JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
Packit 6c4009
  JUMP_INIT(sync, _IO_file_sync_mmap),
Packit 6c4009
  JUMP_INIT(doallocate, _IO_file_doallocate),
Packit 6c4009
  JUMP_INIT(read, _IO_file_read),
Packit 6c4009
  JUMP_INIT(write, _IO_new_file_write),
Packit 6c4009
  JUMP_INIT(seek, _IO_file_seek),
Packit 6c4009
  JUMP_INIT(close, _IO_file_close_mmap),
Packit 6c4009
  JUMP_INIT(stat, _IO_file_stat),
Packit 6c4009
  JUMP_INIT(showmanyc, _IO_default_showmanyc),
Packit 6c4009
  JUMP_INIT(imbue, _IO_default_imbue)
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
const struct _IO_jump_t _IO_file_jumps_maybe_mmap libio_vtable =
Packit 6c4009
{
Packit 6c4009
  JUMP_INIT_DUMMY,
Packit 6c4009
  JUMP_INIT(finish, _IO_file_finish),
Packit 6c4009
  JUMP_INIT(overflow, _IO_file_overflow),
Packit 6c4009
  JUMP_INIT(underflow, _IO_file_underflow_maybe_mmap),
Packit 6c4009
  JUMP_INIT(uflow, _IO_default_uflow),
Packit 6c4009
  JUMP_INIT(pbackfail, _IO_default_pbackfail),
Packit 6c4009
  JUMP_INIT(xsputn, _IO_new_file_xsputn),
Packit 6c4009
  JUMP_INIT(xsgetn, _IO_file_xsgetn_maybe_mmap),
Packit 6c4009
  JUMP_INIT(seekoff, _IO_file_seekoff_maybe_mmap),
Packit 6c4009
  JUMP_INIT(seekpos, _IO_default_seekpos),
Packit 6c4009
  JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
Packit 6c4009
  JUMP_INIT(sync, _IO_new_file_sync),
Packit 6c4009
  JUMP_INIT(doallocate, _IO_file_doallocate),
Packit 6c4009
  JUMP_INIT(read, _IO_file_read),
Packit 6c4009
  JUMP_INIT(write, _IO_new_file_write),
Packit 6c4009
  JUMP_INIT(seek, _IO_file_seek),
Packit 6c4009
  JUMP_INIT(close, _IO_file_close),
Packit 6c4009
  JUMP_INIT(stat, _IO_file_stat),
Packit 6c4009
  JUMP_INIT(showmanyc, _IO_default_showmanyc),
Packit 6c4009
  JUMP_INIT(imbue, _IO_default_imbue)
Packit 6c4009
};