diff options
-rw-r--r-- | lib/libc/stdio/fopen.3 | 37 | ||||
-rw-r--r-- | lib/libc/stdio/freopen.c | 59 |
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 */ |