patch for freopen(NULL,...)

Jeff Johnston jjohnstn@redhat.com
Mon Jan 9 17:54:00 GMT 2006


Patch checked in with minor modifications.  A check was required for 
HAVE_FCNTL before using _fcntl_r.  I also initialized e which was 
generating a warning message because of the new if clause.

-- Jeff J.

Eric Blake wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> POSIX states that freopen(NULL,...) should attempt to change the mode of
> the existing underlying file descriptor, with an implementation-defined
> list of valid changes, rather than closing the underlying file descriptor:
> http://www.opengroup.org/onlinepubs/009695399/functions/freopen.html.
> 
> Currently, newlib freopen(NULL) blindly calls open(NULL), which in the
> worst case causes a core dump for violating the POSIX interface of open,
> and in the best case violates POSIX for returning EFAULT instead of EBADF
> (if open has the extension of returning EFAULT).  Even though POSIX allows
> an implementation the cop-out of always returning EBADF when filename is
> NULL, it is more useful to provide a non-trivial implementation: this
> feature of freopen is useful for changing append vs. seek status on files
> open for writing; and on cygwin it is useful for changing binary vs. text
> modes.  In fact, coreutils 5.93 now uses the idiom freopen(NULL, "rb",
> stdin) to ensure that stdin is in binary mode (I have patched the cygwin
> release of coreutils 5.93 to use a replacement freopen, but think the
> patch belongs better in newlib itself).
> 
> Some notes about this patch: __SCLE is currently only defined for cygwin,
> and cygwin documents that fcntl(F_SETFL) does not alter binary/text mode,
> and that setmode() should not be called on ttys.  Also, POSIX states that
> freopen may return EBADF when filename was NULL but the conversion cannot
> be performed; and since I know of no easy way to change the mode of an
> open file descriptor from O_RDONLY to O_WRONLY, my patch has the
> implementation-defined limitation that freopen(NULL) will only succeed if
> the access mode (read, write, or read-write) is unchanged.
> 
> 2005-12-26  Eric Blake  <ebb9@byu.net>
> 
> 	* libc/stdio/freopen.c (_freopen_r): Accept NULL filename.
> 	* libc/stdio64/freopen64.c (_freopen64_r): Likewise.
> 
> - --
> Life is short - so eat dessert first!
> 
> Eric Blake             ebb9@byu.net
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.1 (Cygwin)
> Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
> Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
> 
> iD8DBQFDsBXX84KuGfSFAYARAiJdAJ0UGksI1Bhu/AZ5BaPz7BPCJ7nJEACeLF6c
> Vy1KK8RbAacnrDFmEelx66s=
> =PMcl
> -----END PGP SIGNATURE-----
> 
> 
> ------------------------------------------------------------------------
> 
> Index: libc/stdio/freopen.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio/freopen.c,v
> retrieving revision 1.12
> diff -u -p -r1.12 freopen.c
> --- libc/stdio/freopen.c	8 Feb 2005 01:33:16 -0000	1.12
> +++ libc/stdio/freopen.c	26 Dec 2005 15:45:50 -0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 1990 The Regents of the University of California.
> + * Copyright (c) 1990, 2005 The Regents of the University of California.
>   * All rights reserved.
>   *
>   * Redistribution and use in source and binary forms are permitted
> @@ -55,6 +55,11 @@ it).
>  
>  <[file]> and <[mode]> are used just as in <<fopen>>.
>  
> +If <[file]> is <<NULL>>, the underlying stream is modified rather than
> +closed.  The file cannot change access mode (for example, if it was
> +previously read-only, <[mode]> must be "r", "rb", or "rt"), but can
> +change status such as append or binary mode.
> +
>  RETURNS
>  If successful, the result is the same as the argument <[fp]>.  If the
>  file cannot be opened as specified, the result is <<NULL>>.
> @@ -70,6 +75,7 @@ Supporting OS subroutines required: <<cl
>  #include <reent.h>
>  #include <time.h>
>  #include <stdio.h>
> +#include <errno.h>
>  #include <fcntl.h>
>  #include <stdlib.h>
>  #include <sys/lock.h>
> @@ -117,17 +123,51 @@ _DEFUN(_freopen_r, (ptr, file, mode, fp)
>      {
>        if (fp->_flags & __SWR)
>  	_CAST_VOID fflush (fp);
> -      /* if close is NULL, closing is a no-op, hence pointless */
> -      if (fp->_close != NULL)
> +      /*
> +       * If close is NULL, closing is a no-op, hence pointless.
> +       * If file is NULL, the file should not be closed.
> +       */
> +      if (fp->_close != NULL && file != NULL)
>  	_CAST_VOID (*fp->_close) (fp->_cookie);
>      }
>  
>    /*
> -   * Now get a new descriptor to refer to the new file.
> +   * Now get a new descriptor to refer to the new file, or reuse the
> +   * existing file descriptor if file is NULL.
>     */
>  
> -  f = _open_r (ptr, (char *) file, oflags, 0666);
> -  e = ptr->_errno;
> +  if (file != NULL)
> +    {
> +      f = _open_r (ptr, (char *) file, oflags, 0666);
> +      e = ptr->_errno;
> +    }
> +  else
> +    {
> +      /*
> +       * Reuse the file descriptor, but only if the access mode is
> +       * unchanged.  F_SETFL correctly ignores creation flags.
> +       */
> +      f = fp->_file;
> +      if ((oflags = _fcntl_r (ptr, f, F_GETFL, 0)) == -1
> +          || ((oflags ^ flags) & O_ACCMODE) != 0
> +          || _fcntl_r (ptr, f, F_SETFL, flags) == -1)
> +        f = -1;
> +#ifdef __SCLE
> +      /*
> +       * F_SETFL doesn't change textmode.  Don't mess with modes of ttys.
> +       */
> +      if (0 <= f && ! _isatty (f)
> +          && setmode (f, flags & (O_BINARY | O_TEXT)) == -1)
> +        f = -1;
> +#endif
> +
> +      if (f < 0)
> +        {
> +          e = EBADF;
> +          if (fp->_close != NULL)
> +            _CAST_VOID (*fp->_close) (fp->_cookie);
> +        }
> +    }
>  
>    /*
>     * Finish closing fp.  Even if the open succeeded above,
> Index: libc/stdio64/freopen64.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdio64/freopen64.c,v
> retrieving revision 1.7
> diff -u -p -r1.7 freopen64.c
> --- libc/stdio64/freopen64.c	8 Feb 2005 01:33:17 -0000	1.7
> +++ libc/stdio64/freopen64.c	26 Dec 2005 15:45:50 -0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 1990 The Regents of the University of California.
> + * Copyright (c) 1990, 2005 The Regents of the University of California.
>   * All rights reserved.
>   *
>   * Redistribution and use in source and binary forms are permitted
> @@ -55,6 +55,11 @@ it).
>  
>  <[file]> and <[mode]> are used just as in <<fopen>>.
>  
> +If <[file]> is <<NULL>>, the underlying stream is modified rather than
> +closed.  The file cannot change access mode (for example, if it was
> +previously read-only, <[mode]> must be "r", "rb", or "rt"), but can
> +change status such as append or binary mode.
> +
>  RETURNS
>  If successful, the result is the same as the argument <[fp]>.  If the
>  file cannot be opened as specified, the result is <<NULL>>.
> @@ -68,6 +73,7 @@ Supporting OS subroutines required: <<cl
>  
>  #include <time.h>
>  #include <stdio.h>
> +#include <errno.h>
>  #include <fcntl.h>
>  #include <stdlib.h>
>  #include <sys/lock.h>
> @@ -117,17 +123,51 @@ _DEFUN (_freopen64_r, (ptr, file, mode, 
>      {
>        if (fp->_flags & __SWR)
>  	(void) fflush (fp);
> -      /* if close is NULL, closing is a no-op, hence pointless */
> -      if (fp->_close != NULL)
> +      /*
> +       * If close is NULL, closing is a no-op, hence pointless.
> +       * If file is NULL, the file should not be closed.
> +       */
> +      if (fp->_close != NULL && file != NULL)
>  	(void) (*fp->_close) (fp->_cookie);
>      }
>  
>    /*
> -   * Now get a new descriptor to refer to the new file.
> +   * Now get a new descriptor to refer to the new file, or reuse the
> +   * existing file descriptor if file is NULL.
>     */
>  
> -  f = _open64_r (ptr, (char *) file, oflags, 0666);
> -  e = ptr->_errno;
> +  if (file != NULL)
> +    {
> +      f = _open64_r (ptr, (char *) file, oflags, 0666);
> +      e = ptr->_errno;
> +    }
> +  else
> +    {
> +      /*
> +       * Reuse the file descriptor, but only if the access mode is
> +       * unchanged.  F_SETFL correctly ignores creation flags.
> +       */
> +      f = fp->_file;
> +      if ((oflags = _fcntl_r (ptr, f, F_GETFL, 0)) == -1
> +          || ((oflags ^ flags) & O_ACCMODE) != 0
> +          || _fcntl_r (ptr, f, F_SETFL, flags) == -1)
> +        f = -1;
> +#ifdef __SCLE
> +      /*
> +       * F_SETFL doesn't change textmode.  Don't mess with modes of ttys.
> +       */
> +      if (0 <= f && ! _isatty (f)
> +          && setmode (f, flags & (O_BINARY | O_TEXT)) == -1)
> +        f = -1;
> +#endif
> +
> +      if (f < 0)
> +        {
> +          e = EBADF;
> +          if (fp->_close != NULL)
> +            (void) (*fp->_close) (fp->_cookie);
> +        }
> +    }
>  
>    /*
>     * Finish closing fp.  Even if the open succeeded above,




More information about the Newlib mailing list