Initial implementation of the C99 feature whereby calling freopen() with

a NULL filename argument allows a stream's mode to be changed. At the
moment it just recycles the old file descriptor instead of storing the
filename somewhere and using that to reopen the file, as the standard
seems to require. Strictly conforming C99 applications probably can't
tell the difference but POSIX ones can.

PR:		46791
This commit is contained in:
Tim J. Robbins 2003-01-26 10:01:59 +00:00
parent bbe7088205
commit c297498757
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=109871
2 changed files with 94 additions and 2 deletions

View File

@ -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

View File

@ -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);
@ -76,6 +76,59 @@ freopen(file, mode, fp)
if (!__sdidinit)
__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.
@ -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 */