summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/stdio/fopen.337
-rw-r--r--lib/libc/stdio/freopen.c59
2 files changed, 94 insertions, 2 deletions
diff --git a/lib/libc/stdio/fopen.3 b/lib/libc/stdio/fopen.3
index eb39376..1508e59 100644
--- a/lib/libc/stdio/fopen.3
+++ b/lib/libc/stdio/fopen.3
@@ -36,7 +36,7 @@
.\" @(#)fopen.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd June 4, 1993
+.Dd January 26, 2003
.Dt FOPEN 3
.Os
.Sh NAME
@@ -158,6 +158,41 @@ The
argument is used just as in the
.Fn fopen
function.
+.Pp
+If the
+.Fa path
+argument is
+.Dv NULL ,
+.Fn freopen
+attempts to re-open the file associated with
+.Fa stream
+with a new mode.
+The new mode must be compatible with the mode that the stream was originally
+opened with:
+.Bl -bullet -offset indent
+.It
+Streams originally opened with mode
+.Dq Li r
+can only be reopened with that same mode.
+.It
+Streams originally opened with mode
+.Dq Li a
+can be reopened with the same mode, or mode
+.Dq Li w .
+.It
+Streams originally opened with mode
+.Dq Li w
+can be reopened with the same mode, or mode
+.Dq Li a .
+.It
+Streams originally opened with mode
+.Dq Li r+ ,
+.Dq Li w+ ,
+or
+.Dq Li a+
+can be reopened with any mode.
+.El
+.Pp
The primary use of the
.Fn freopen
function
diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c
index a22dedd..66794dd 100644
--- a/lib/libc/stdio/freopen.c
+++ b/lib/libc/stdio/freopen.c
@@ -64,7 +64,7 @@ freopen(file, mode, fp)
FILE *fp;
{
int f;
- int flags, isopen, oflags, sverrno, wantfd;
+ int dflags, flags, isopen, oflags, sverrno, wantfd;
if ((flags = __sflags(mode, &oflags)) == 0) {
(void) fclose(fp);
@@ -77,6 +77,59 @@ freopen(file, mode, fp)
__sinit();
/*
+ * If the filename is a NULL pointer, the caller is asking us to
+ * re-open the same file with a different mode. We allow this only
+ * if the modes are compatible.
+ */
+ if (file == NULL) {
+ /* See comment below regarding freopen() of closed files. */
+ if (fp->_flags == 0) {
+ FUNLOCKFILE(fp);
+ errno = EINVAL;
+ return (NULL);
+ }
+ if ((dflags = _fcntl(fp->_file, F_GETFL)) < 0) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ if ((dflags & O_ACCMODE) != O_RDWR && (dflags & O_ACCMODE) !=
+ (oflags & O_ACCMODE)) {
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = EINVAL;
+ return (NULL);
+ }
+ if ((oflags ^ dflags) & O_APPEND) {
+ dflags &= ~O_APPEND;
+ dflags |= oflags & O_APPEND;
+ if (_fcntl(fp->_file, F_SETFL, dflags) < 0) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ }
+ if (oflags & O_TRUNC)
+ ftruncate(fp->_file, 0);
+ if (_fseeko(fp, 0, oflags & O_APPEND ? SEEK_END : SEEK_SET,
+ 0) < 0 && errno != ESPIPE) {
+ sverrno = errno;
+ fclose(fp);
+ FUNLOCKFILE(fp);
+ errno = sverrno;
+ return (NULL);
+ }
+ f = fp->_file;
+ isopen = 0;
+ wantfd = -1;
+ goto finish;
+ }
+
+ /*
* There are actually programs that depend on being able to "freopen"
* descriptors that weren't originally open. Keep this from breaking.
* Remember whether the stream was open to begin with, and which file
@@ -112,6 +165,7 @@ freopen(file, mode, fp)
}
sverrno = errno;
+finish:
/*
* Finish closing fp. Even if the open succeeded above, we cannot
* keep fp->_base: it may be the wrong size. This loses the effect
@@ -134,6 +188,9 @@ freopen(file, mode, fp)
FREELB(fp);
fp->_lb._size = 0;
fp->_extra->orientation = 0;
+ memset(&fp->_extra->state, 0, sizeof(fp->_extra->state));
+ memset(&fp->_extra->cstate, 0, sizeof(fp->_extra->cstate));
+ fp->_extra->cstatepos = 0;
if (f < 0) { /* did not get it after all */
fp->_flags = 0; /* set it free */
OpenPOWER on IntegriCloud