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