Ejemplo n.º 1
0
_IO_FILE *
__fopen_maybe_mmap (_IO_FILE *fp)
{
#ifdef _G_HAVE_MMAP
  if ((fp->_flags2 & _IO_FLAGS2_MMAP) && (fp->_flags & _IO_NO_WRITES))
    {
      /* Since this is read-only, we might be able to mmap the contents
	 directly.  We delay the decision until the first read attempt by
	 giving it a jump table containing functions that choose mmap or
	 vanilla file operations and reset the jump table accordingly.  */

      if (fp->_mode <= 0)
	_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_maybe_mmap;
      else
	_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_maybe_mmap;
      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_maybe_mmap;
    }
#endif
  return fp;
}
Ejemplo n.º 2
0
_IO_FILE *
_IO_file_setbuf_mmap (_IO_FILE *fp, char *p, _IO_ssize_t len)
{
  _IO_FILE *result;

  /* Change the function table.  */
  _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
  fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;

  /* And perform the normal operation.  */
  result = _IO_new_file_setbuf (fp, p, len);

  /* If the call failed, restore to using mmap.  */
  if (result == NULL)
    {
      _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap;
      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
    }

  return result;
}
Ejemplo n.º 3
0
attribute_compat_text_section
_IO_old_fopencookie (void *cookie, const char *mode,
		     _IO_cookie_io_functions_t io_functions)
{
  _IO_FILE *ret;

  ret = _IO_fopencookie (cookie, mode, io_functions);
  if (ret != NULL)
    _IO_JUMPS_FILE_plus (ret) = &_IO_old_cookie_jumps;

  return ret;
}
Ejemplo n.º 4
0
FILE *
freopen64 (const char *filename, const char *mode, FILE *fp)
{
  FILE *result;
  CHECK_FILE (fp, NULL);
  if (!(fp->_flags & _IO_IS_FILEBUF))
    return NULL;
  _IO_acquire_lock (fp);
  int fd = _IO_fileno (fp);
  const char *gfilename = (filename == NULL && fd >= 0
			   ? fd_to_filename (fd) : filename);
  fp->_flags2 |= _IO_FLAGS2_NOCLOSE;
  _IO_file_close_it (fp);
  _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
  if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
    fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
  result = _IO_file_fopen (fp, gfilename, mode, 0);
  fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
  if (result != NULL)
    result = __fopen_maybe_mmap (result);
  if (result != NULL)
    {
      /* unbound stream orientation */
      result->_mode = 0;

      if (fd != -1)
	{
#ifdef O_CLOEXEC
# ifndef __ASSUME_DUP3
	  int newfd;
	  if (__have_dup3 < 0)
	    newfd = -1;
	  else
	    newfd =
# endif
	      __dup3 (_IO_fileno (result), fd,
                      (result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0
                      ? O_CLOEXEC : 0);
#else
# define newfd 1
#endif

#ifndef __ASSUME_DUP3
	  if (newfd < 0)
	    {
	      if (errno == ENOSYS)
		__have_dup3 = -1;

	      __dup2 (_IO_fileno (result), fd);
	      if ((result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0)
		__fcntl (fd, F_SETFD, FD_CLOEXEC);
	    }
#endif
	  __close (_IO_fileno (result));
	  _IO_fileno (result) = fd;
	}
    }
  else if (fd != -1)
    __close (fd);
  if (filename == NULL)
    free ((char *) gfilename);
  _IO_release_lock (fp);
  return result;
}
Ejemplo n.º 5
0
FILE *
freopen (const char *filename, const char *mode, FILE *fp)
{
  FILE *result;
  CHECK_FILE (fp, NULL);
  if (!(fp->_flags & _IO_IS_FILEBUF))
    return NULL;
  _IO_acquire_lock (fp);
  int fd = _IO_fileno (fp);
  const char *gfilename = (filename == NULL && fd >= 0
			   ? fd_to_filename (fd) : filename);
  fp->_flags2 |= _IO_FLAGS2_NOCLOSE;
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
  if (&_IO_stdin_used == NULL)
    {
      /* If the shared C library is used by the application binary which
	 was linked against the older version of libio, we just use the
	 older one even for internal use to avoid trouble since a pointer
	 to the old libio may be passed into shared C library and wind
	 up here. */
      _IO_old_file_close_it (fp);
      _IO_JUMPS_FILE_plus (fp) = &_IO_old_file_jumps;
      result = _IO_old_file_fopen (fp, gfilename, mode);
    }
  else
#endif
    {
      _IO_file_close_it (fp);
      _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
      if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
	fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
      result = _IO_file_fopen (fp, gfilename, mode, 1);
      if (result != NULL)
	result = __fopen_maybe_mmap (result);
    }
  fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
  if (result != NULL)
    {
      /* unbound stream orientation */
      result->_mode = 0;

      if (fd != -1)
	{
#ifdef O_CLOEXEC
# ifndef __ASSUME_DUP3
	  int newfd;
	  if (__have_dup3 < 0)
	    newfd = -1;
	  else
	    newfd =
# endif
	      __dup3 (_IO_fileno (result), fd,
                      (result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0
                      ? O_CLOEXEC : 0);
#else
# define newfd 1
#endif

#ifndef __ASSUME_DUP3
	  if (newfd < 0)
	    {
	      if (errno == ENOSYS)
		__have_dup3 = -1;

	      __dup2 (_IO_fileno (result), fd);
	      if ((result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0)
		__fcntl (fd, F_SETFD, FD_CLOEXEC);
	    }
#endif
	  __close (_IO_fileno (result));
	  _IO_fileno (result) = fd;
	}
    }
  else if (fd != -1)
    __close (fd);
  if (filename == NULL)
    free ((char *) gfilename);

  _IO_release_lock (fp);
  return result;
}
Ejemplo n.º 6
0
static void
decide_maybe_mmap (_IO_FILE *fp)
{
  /* We use the file in read-only mode.  This could mean we can
     mmap the file and use it without any copying.  But not all
     file descriptors are for mmap-able objects and on 32-bit
     machines we don't want to map files which are too large since
     this would require too much virtual memory.  */
  struct stat64 st;

  if (_IO_SYSSTAT (fp, &st) == 0
      && S_ISREG (st.st_mode) && st.st_size != 0
      /* Limit the file size to 1MB for 32-bit machines.  */
      && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024)
      /* Sanity check.  */
      && (fp->_offset == _IO_pos_BAD || fp->_offset <= st.st_size))
    {
      /* Try to map the file.  */
      void *p;

      p = __mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED, fp->_fileno, 0);
      if (p != MAP_FAILED)
	{
	  /* OK, we managed to map the file.  Set the buffer up and use a
	     special jump table with simplified underflow functions which
	     never tries to read anything from the file.  */

	  if (__lseek64 (fp->_fileno, st.st_size, SEEK_SET) != st.st_size)
	    {
	      (void) __munmap (p, st.st_size);
	      fp->_offset = _IO_pos_BAD;
	    }
	  else
	    {
	      _IO_setb (fp, p, (char *) p + st.st_size, 0);

	      if (fp->_offset == _IO_pos_BAD)
		fp->_offset = 0;

	      _IO_setg (fp, p, p + fp->_offset, p + st.st_size);
	      fp->_offset = st.st_size;

	      if (fp->_mode <= 0)
		_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap;
	      else
		_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_mmap;
	      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;

	      return;
	    }
	}
    }

  /* We couldn't use mmap, so revert to the vanilla file operations.  */

  if (fp->_mode <= 0)
    _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
  else
    _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps;
  fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
}
Ejemplo n.º 7
0
/* Guts of underflow callback if we mmap the file.  This stats the file and
   updates the stream state to match.  In the normal case we return zero.
   If the file is no longer eligible for mmap, its jump tables are reset to
   the vanilla ones and we return nonzero.  */
static int
mmap_remap_check (_IO_FILE *fp)
{
  struct stat64 st;

  if (_IO_SYSSTAT (fp, &st) == 0
      && S_ISREG (st.st_mode) && st.st_size != 0
      /* Limit the file size to 1MB for 32-bit machines.  */
      && (sizeof (ptrdiff_t) > 4 || st.st_size < 1*1024*1024))
    {
      const size_t pagesize = __getpagesize ();
# define ROUNDED(x)	(((x) + pagesize - 1) & ~(pagesize - 1))
      if (ROUNDED (st.st_size) < ROUNDED (fp->_IO_buf_end
					  - fp->_IO_buf_base))
	{
	  /* We can trim off some pages past the end of the file.  */
	  (void) __munmap (fp->_IO_buf_base + ROUNDED (st.st_size),
			   ROUNDED (fp->_IO_buf_end - fp->_IO_buf_base)
			   - ROUNDED (st.st_size));
	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
	}
      else if (ROUNDED (st.st_size) > ROUNDED (fp->_IO_buf_end
					       - fp->_IO_buf_base))
	{
	  /* The file added some pages.  We need to remap it.  */
	  void *p;
#ifdef _G_HAVE_MREMAP
	  p = __mremap (fp->_IO_buf_base, ROUNDED (fp->_IO_buf_end
						   - fp->_IO_buf_base),
			ROUNDED (st.st_size), MREMAP_MAYMOVE);
	  if (p == MAP_FAILED)
	    {
	      (void) __munmap (fp->_IO_buf_base,
			       fp->_IO_buf_end - fp->_IO_buf_base);
	      goto punt;
	    }
#else
	  (void) __munmap (fp->_IO_buf_base,
			   fp->_IO_buf_end - fp->_IO_buf_base);
	  p = __mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED,
			fp->_fileno, 0);
	  if (p == MAP_FAILED)
	    goto punt;
#endif
	  fp->_IO_buf_base = p;
	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
	}
      else
	{
	  /* The number of pages didn't change.  */
	  fp->_IO_buf_end = fp->_IO_buf_base + st.st_size;
	}
# undef ROUNDED

      fp->_offset -= fp->_IO_read_end - fp->_IO_read_ptr;
      _IO_setg (fp, fp->_IO_buf_base,
		fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base
		? fp->_IO_buf_base + fp->_offset : fp->_IO_buf_end,
		fp->_IO_buf_end);

      /* If we are already positioned at or past the end of the file, don't
	 change the current offset.  If not, seek past what we have mapped,
	 mimicking the position left by a normal underflow reading into its
	 buffer until EOF.  */

      if (fp->_offset < fp->_IO_buf_end - fp->_IO_buf_base)
	{
	  if (__lseek64 (fp->_fileno, fp->_IO_buf_end - fp->_IO_buf_base,
			 SEEK_SET)
	      != fp->_IO_buf_end - fp->_IO_buf_base)
	    fp->_flags |= _IO_ERR_SEEN;
	  else
	    fp->_offset = fp->_IO_buf_end - fp->_IO_buf_base;
	}

      return 0;
    }
  else
    {
      /* Life is no longer good for mmap.  Punt it.  */
      (void) __munmap (fp->_IO_buf_base,
		       fp->_IO_buf_end - fp->_IO_buf_base);
    punt:
      fp->_IO_buf_base = fp->_IO_buf_end = NULL;
      _IO_setg (fp, NULL, NULL, NULL);
      if (fp->_mode <= 0)
	_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
      else
	_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps;
      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;

      return 1;
    }
}
Ejemplo n.º 8
0
_IO_FILE *
_IO_new_file_fopen (_IO_FILE *fp, const char *filename, const char *mode,
		    int is32not64)
{
  int oflags = 0, omode;
  int read_write;
  int oprot = 0666;
  int i;
  _IO_FILE *result;
#ifdef _LIBC
  const char *cs;
  const char *last_recognized;
#endif

  if (_IO_file_is_open (fp))
    return 0;
  switch (*mode)
    {
    case 'r':
      omode = O_RDONLY;
      read_write = _IO_NO_WRITES;
      break;
    case 'w':
      omode = O_WRONLY;
      oflags = O_CREAT|O_TRUNC;
      read_write = _IO_NO_READS;
      break;
    case 'a':
      omode = O_WRONLY;
      oflags = O_CREAT|O_APPEND;
      read_write = _IO_NO_READS|_IO_IS_APPENDING;
      break;
    default:
      __set_errno (EINVAL);
      return NULL;
    }
#ifdef _LIBC
  last_recognized = mode;
#endif
  for (i = 1; i < 7; ++i)
    {
      switch (*++mode)
	{
	case '\0':
	  break;
	case '+':
	  omode = O_RDWR;
	  read_write &= _IO_IS_APPENDING;
#ifdef _LIBC
	  last_recognized = mode;
#endif
	  continue;
	case 'x':
	  oflags |= O_EXCL;
#ifdef _LIBC
	  last_recognized = mode;
#endif
	  continue;
	case 'b':
#ifdef _LIBC
	  last_recognized = mode;
#endif
	  continue;
	case 'm':
	  fp->_flags2 |= _IO_FLAGS2_MMAP;
	  continue;
	case 'c':
	  fp->_flags2 |= _IO_FLAGS2_NOTCANCEL;
	  continue;
	case 'e':
#ifdef O_CLOEXEC
	  oflags |= O_CLOEXEC;
#endif
	  fp->_flags2 |= _IO_FLAGS2_CLOEXEC;
	  continue;
	default:
	  /* Ignore.  */
	  continue;
	}
      break;
    }

  result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write,
			  is32not64);

  if (result != NULL)
    {
#ifndef __ASSUME_O_CLOEXEC
      if ((fp->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 && __have_o_cloexec <= 0)
	{
	  int fd = _IO_fileno (fp);
	  if (__have_o_cloexec == 0)
	    {
	      int flags = __fcntl (fd, F_GETFD);
	      __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
	    }
	  if (__have_o_cloexec < 0)
	    __fcntl (fd, F_SETFD, FD_CLOEXEC);
	}
#endif

      /* Test whether the mode string specifies the conversion.  */
      cs = strstr (last_recognized + 1, ",ccs=");
      if (cs != NULL)
	{
	  /* Yep.  Load the appropriate conversions and set the orientation
	     to wide.  */
	  struct gconv_fcts fcts;
	  struct _IO_codecvt *cc;
	  char *endp = __strchrnul (cs + 5, ',');
	  char *ccs = malloc (endp - (cs + 5) + 3);

	  if (ccs == NULL)
	    {
	      int malloc_err = errno;  /* Whatever malloc failed with.  */
	      (void) _IO_file_close_it (fp);
	      __set_errno (malloc_err);
	      return NULL;
	    }

	  *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
	  strip (ccs, ccs);

	  if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
				   ? upstr (ccs, cs + 5) : ccs) != 0)
	    {
	      /* Something went wrong, we cannot load the conversion modules.
		 This means we cannot proceed since the user explicitly asked
		 for these.  */
	      (void) _IO_file_close_it (fp);
	      free (ccs);
	      __set_errno (EINVAL);
	      return NULL;
	    }

	  free (ccs);

	  assert (fcts.towc_nsteps == 1);
	  assert (fcts.tomb_nsteps == 1);

	  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
	  fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;

	  /* Clear the state.  We start all over again.  */
	  memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
	  memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));

	  cc = fp->_codecvt = &fp->_wide_data->_codecvt;

	  /* The functions are always the same.  */
	  *cc = __libio_codecvt;

	  cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
	  cc->__cd_in.__cd.__steps = fcts.towc;

	  cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
	  cc->__cd_in.__cd.__data[0].__internal_use = 1;
	  cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
	  cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state;

	  cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
	  cc->__cd_out.__cd.__steps = fcts.tomb;

	  cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
	  cc->__cd_out.__cd.__data[0].__internal_use = 1;
	  cc->__cd_out.__cd.__data[0].__flags
	    = __GCONV_IS_LAST | __GCONV_TRANSLIT;
	  cc->__cd_out.__cd.__data[0].__statep =
	    &result->_wide_data->_IO_state;

	  /* From now on use the wide character callback functions.  */
	  _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;

	  /* Set the mode now.  */
	  result->_mode = 1;
	}
    }

  return result;
}
Ejemplo n.º 9
0
int
_IO_fwide (_IO_FILE *fp, int mode)
{
  /* Normalize the value.  */
  mode = mode < 0 ? -1 : (mode == 0 ? 0 : 1);

#if defined SHARED && defined _LIBC \
    && SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
  if (__builtin_expect (&_IO_stdin_used == NULL, 0)
      && (fp == _IO_stdin || fp == _IO_stdout || fp == _IO_stderr))
    /* This is for a stream in the glibc 2.0 format.  */
    return -1;
#endif

  /* The orientation already has been determined.  */
  if (fp->_mode != 0
      /* Or the caller simply wants to know about the current orientation.  */
      || mode == 0)
    return fp->_mode;

  /* Set the orientation appropriately.  */
  if (mode > 0)
    {
      struct _IO_codecvt *cc = fp->_codecvt = &fp->_wide_data->_codecvt;

      fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
      fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;

      /* Get the character conversion functions based on the currently
	 selected locale for LC_CTYPE.  */
#ifdef _LIBC
      {
	/* Clear the state.  We start all over again.  */
	memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
	memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));

	struct gconv_fcts fcts;
	__wcsmbs_clone_conv (&fcts);
	assert (fcts.towc_nsteps == 1);
	assert (fcts.tomb_nsteps == 1);

	/* The functions are always the same.  */
	*cc = __libio_codecvt;

	cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
	cc->__cd_in.__cd.__steps = fcts.towc;

	cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
	cc->__cd_in.__cd.__data[0].__internal_use = 1;
	cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
	cc->__cd_in.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;

	cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
	cc->__cd_out.__cd.__steps = fcts.tomb;

	cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
	cc->__cd_out.__cd.__data[0].__internal_use = 1;
	cc->__cd_out.__cd.__data[0].__flags
	  = __GCONV_IS_LAST | __GCONV_TRANSLIT;
	cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
      }
#else
# ifdef _GLIBCPP_USE_WCHAR_T
      {
	/* Determine internal and external character sets.

	   XXX For now we make our life easy: we assume a fixed internal
	   encoding (as most sane systems have; hi HP/UX!).  If somebody
	   cares about systems which changing internal charsets they
	   should come up with a solution for the determination of the
	   currently used internal character set.  */
	const char *internal_ccs = _G_INTERNAL_CCS;
	const char *external_ccs = NULL;

#  ifdef HAVE_NL_LANGINFO
	external_ccs = nl_langinfo (CODESET);
#  endif
	if (external_ccs == NULL)
	  external_ccs = "ISO-8859-1";

	cc->__cd_in = iconv_open (internal_ccs, external_ccs);
	if (cc->__cd_in != (iconv_t) -1)
	  cc->__cd_out = iconv_open (external_ccs, internal_ccs);

	if (cc->__cd_in == (iconv_t) -1 || cc->__cd_out == (iconv_t) -1)
	  {
	    if (cc->__cd_in != (iconv_t) -1)
	      iconv_close (cc->__cd_in);
	    /* XXX */
	    abort ();
	  }
      }
# else
#  error "somehow determine this from LC_CTYPE"
# endif
#endif

      /* From now on use the wide character callback functions.  */
      _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;
    }

  /* Set the mode now.  */
  fp->_mode = mode;

  return mode;
}
Ejemplo n.º 10
0
attribute_compat_text_section
_IO_old_fdopen (int fd, const char *mode)
{
  int read_write;
  int posix_mode = 0;
  struct locked_FILE
  {
    struct _IO_FILE_complete_plus fp;
#ifdef _IO_MTSAFE_IO
    _IO_lock_t lock;
#endif
  } *new_f;
  int fd_flags;

  switch (*mode++)
    {
    case 'r':
      read_write = _IO_NO_WRITES;
      break;
    case 'w':
      read_write = _IO_NO_READS;
      break;
    case 'a':
      posix_mode = O_APPEND;
      read_write = _IO_NO_READS|_IO_IS_APPENDING;
      break;
    default:
      MAYBE_SET_EINVAL;
      return NULL;
  }
  if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+'))
    read_write &= _IO_IS_APPENDING;
#ifdef F_GETFL
  fd_flags = _IO_fcntl (fd, F_GETFL);
#ifndef O_ACCMODE
#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
#endif
  if (fd_flags == -1
      || ((fd_flags & O_ACCMODE) == O_RDONLY && !(read_write & _IO_NO_WRITES))
      || ((fd_flags & O_ACCMODE) == O_WRONLY && !(read_write & _IO_NO_READS)))
    return NULL;

  /* The May 93 draft of P1003.4/D14.1 (redesignated as 1003.1b)
     [System Application Program Interface (API) Amendment 1:
     Realtime Extensions], Rationale B.8.3.3
     Open a Stream on a File Descriptor says:

         Although not explicitly required by POSIX.1, a good
         implementation of append ("a") mode would cause the
         O_APPEND flag to be set.

     (Historical implementations [such as Solaris2] do a one-time
     seek in fdopen.)

     However, we do not turn O_APPEND off if the mode is "w" (even
     though that would seem consistent) because that would be more
     likely to break historical programs.
     */
  if ((posix_mode & O_APPEND) && !(fd_flags & O_APPEND))
    {
#ifdef F_SETFL
      if (_IO_fcntl (fd, F_SETFL, fd_flags | O_APPEND) == -1)
#endif
	return NULL;
    }
#endif

  new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
  if (new_f == NULL)
    return NULL;
#ifdef _IO_MTSAFE_IO
  new_f->fp.file._file._lock = &new_f->lock;
#endif
  _IO_old_init (&new_f->fp.file._file, 0);
  _IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps;
  _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
#if  !_IO_UNIFIED_JUMPTABLES
  new_f->fp.vtable = NULL;
#endif
  if (_IO_old_file_attach (&new_f->fp.file._file, fd) == NULL)
    {
      _IO_un_link ((struct _IO_FILE_plus *) &new_f->fp);
      free (new_f);
      return NULL;
    }
  new_f->fp.file._file._flags &= ~_IO_DELETE_DONT_CLOSE;

  _IO_mask_flags (&new_f->fp.file._file, read_write,
		  _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);

  return (_IO_FILE *) &new_f->fp;
}
Ejemplo n.º 11
0
FILE *
freopen64 (const char *filename, const char *mode, FILE *fp)
{
  FILE *result = NULL;
  char fdfilename[FD_TO_FILENAME_SIZE];

  CHECK_FILE (fp, NULL);

  _IO_acquire_lock (fp);
  /* First flush the stream (failure should be ignored).  */
  _IO_SYNC (fp);

  if (!(fp->_flags & _IO_IS_FILEBUF))
    goto end;

  int fd = _IO_fileno (fp);
  const char *gfilename
    = filename != NULL ? filename : fd_to_filename (fd, fdfilename);

  fp->_flags2 |= _IO_FLAGS2_NOCLOSE;
  _IO_file_close_it (fp);
  _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
  if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
    fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
  result = _IO_file_fopen (fp, gfilename, mode, 0);
  fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
  if (result != NULL)
    result = __fopen_maybe_mmap (result);
  if (result != NULL)
    {
      /* unbound stream orientation */
      result->_mode = 0;

      if (fd != -1 && _IO_fileno (result) != fd)
	{
	  /* At this point we have both file descriptors already allocated,
	     so __dup3 will not fail with EBADF, EINVAL, or EMFILE.  But
	     we still need to check for EINVAL and, due Linux internal
	     implementation, EBUSY.  It is because on how it internally opens
	     the file by splitting the buffer allocation operation and VFS
	     opening (a dup operation may run when a file is still pending
	     'install' on VFS).  */
	  if (__dup3 (_IO_fileno (result), fd,
		      (result->_flags2 & _IO_FLAGS2_CLOEXEC) != 0
		      ? O_CLOEXEC : 0) == -1)
	    {
	      _IO_file_close_it (result);
	      result = NULL;
	      goto end;
	    }
	  __close (_IO_fileno (result));
	  _IO_fileno (result) = fd;
	}
    }
  else if (fd != -1)
    __close (fd);

end:
  _IO_release_lock (fp);
  return result;
}