From e7b257687548726747a5be4765460de4eccc2915 Mon Sep 17 00:00:00 2001 From: guenther Date: Mon, 12 Aug 2024 20:53:09 +0000 Subject: [PATCH] Make exit(), fclose(), fflush(), and freopen() comply with POSIX-2008 requirements for setting the underlying file position when flushing read-mode streams, and make an fseek()-after-fflush() not change the underlying file position. Much testing, review, and assistance from tb@ ok tb@ millert@ --- lib/libc/stdio/fclose.3 | 13 +++++---- lib/libc/stdio/fclose.c | 4 +-- lib/libc/stdio/fflush.3 | 28 +++++++++++++----- lib/libc/stdio/fflush.c | 62 ++++++++++++++++++++++++++-------------- lib/libc/stdio/freopen.c | 7 ++--- lib/libc/stdio/fseek.c | 9 ++++-- lib/libc/stdio/ftell.c | 5 ++-- lib/libc/stdlib/exit.3 | 11 ++++--- 8 files changed, 88 insertions(+), 51 deletions(-) diff --git a/lib/libc/stdio/fclose.3 b/lib/libc/stdio/fclose.3 index b1f7c536b0a..cedcaed15ed 100644 --- a/lib/libc/stdio/fclose.3 +++ b/lib/libc/stdio/fclose.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: fclose.3,v 1.9 2015/11/04 21:30:13 tedu Exp $ +.\" $OpenBSD: fclose.3,v 1.10 2024/08/12 20:53:09 guenther Exp $ .\" .\" Copyright (c) 1990, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -31,7 +31,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd $Mdocdate: November 4 2015 $ +.Dd $Mdocdate: August 12 2024 $ .Dt FCLOSE 3 .Os .Sh NAME @@ -47,8 +47,11 @@ The function dissociates the named .Fa stream from its underlying file or set of functions. -If the stream was being used for output, any buffered data is written -first, using +If the stream was being used for output then any buffered data is written +first, +while if the stream was being used for input then the underlying +file position may be updated, +as if via .Xr fflush 3 . .Sh RETURN VALUES Upon successful completion 0 is returned. @@ -83,7 +86,7 @@ or The .Fn fclose function conforms to -.St -ansiC . +.St -p1003.1-2024 . .Sh HISTORY The .Fn fclose diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c index 4bd162abc84..07026faccd4 100644 --- a/lib/libc/stdio/fclose.c +++ b/lib/libc/stdio/fclose.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fclose.c,v 1.10 2015/08/31 02:53:57 guenther Exp $ */ +/* $OpenBSD: fclose.c,v 1.11 2024/08/12 20:53:09 guenther Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -47,7 +47,7 @@ fclose(FILE *fp) } FLOCKFILE(fp); WCIO_FREE(fp); - r = fp->_flags & __SWR ? __sflush(fp) : 0; + r = __sflush(fp); if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) r = EOF; if (fp->_flags & __SMBF) diff --git a/lib/libc/stdio/fflush.3 b/lib/libc/stdio/fflush.3 index 677d087c817..1e1c7803942 100644 --- a/lib/libc/stdio/fflush.3 +++ b/lib/libc/stdio/fflush.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: fflush.3,v 1.13 2019/09/07 10:28:27 schwarze Exp $ +.\" $OpenBSD: fflush.3,v 1.14 2024/08/12 20:53:09 guenther Exp $ .\" .\" Copyright (c) 1990, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -31,7 +31,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd $Mdocdate: September 7 2019 $ +.Dd $Mdocdate: August 12 2024 $ .Dt FFLUSH 3 .Os .Sh NAME @@ -50,6 +50,20 @@ The function forces a write of all buffered data for the given output or update .Fa stream via the stream's underlying write function. +If +.Fa stream +is a stream opened for reading with +.Xr fdopen 3 , +.Xr fopen 3 , +or +.Xr freopen 3 +of a seekable file and it is not already at EOF then +.Fn fflush +sets the seek position of the file to the file position of the +stream and discards any text pushed back by via +.Xr ungetc 3 +or +.Xr ungetwc 3 . The open status of the stream is unaffected. .Pp If the @@ -70,7 +84,9 @@ For input streams this discards any input read from the underlying object but not yet obtained via .Xr getc 3 ; this includes any text pushed back via -.Xr ungetc 3 . +.Xr ungetc 3 +or +.Xr ungetwc 3 . .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, @@ -82,9 +98,7 @@ is set to indicate the error. .Bl -tag -width Er .It Bq Er EBADF .Fa stream -is not an open stream or, in the case of -.Fn fflush , -not a stream open for writing. +is not an open stream. .El .Pp The function @@ -102,7 +116,7 @@ for any of the errors specified for the routine The .Fn fflush function conforms to -.St -ansiC . +.St -p1003.1-2024 . .Sh HISTORY A predecessor .Fn flush diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c index fd1a4b3504b..5888e2364c8 100644 --- a/lib/libc/stdio/fflush.c +++ b/lib/libc/stdio/fflush.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fflush.c,v 1.9 2015/08/31 02:53:57 guenther Exp $ */ +/* $OpenBSD: fflush.c,v 1.10 2024/08/12 20:53:09 guenther Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -33,6 +33,7 @@ #include #include +#include #include "local.h" /* Flush a single file, or (if fp is NULL) all files. */ @@ -44,11 +45,7 @@ fflush(FILE *fp) if (fp == NULL) return (_fwalk(__sflush_locked)); FLOCKFILE(fp); - if ((fp->_flags & (__SWR | __SRW)) == 0) { - errno = EBADF; - r = EOF; - } else - r = __sflush(fp); + r = __sflush(fp); FUNLOCKFILE(fp); return (r); } @@ -58,30 +55,51 @@ int __sflush(FILE *fp) { unsigned char *p; + fpos_t off; int n, t; t = fp->_flags; - if ((t & __SWR) == 0) - return (0); + if (t & __SWR) { + if ((p = fp->_bf._base) == NULL) + return (0); - if ((p = fp->_bf._base) == NULL) - return (0); + n = fp->_p - p; /* write this much */ - n = fp->_p - p; /* write this much */ + /* + * Set these immediately to avoid problems with longjmp and to + * allow exchange buffering (via setvbuf) in user write + * function. + */ + fp->_p = p; + fp->_w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size; - /* - * Set these immediately to avoid problems with longjmp and to allow - * exchange buffering (via setvbuf) in user write function. - */ - fp->_p = p; - fp->_w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size; + for (; n > 0; n -= t, p += t) { + t = (*fp->_write)(fp->_cookie, (char *)p, n); + if (t <= 0) { + fp->_flags |= __SERR; + return (EOF); + } + } + } else if ((t & __SRD) && !(t & __SEOF)) { + if (fp->_seek != __sseek || fp->_file < 0) { + errno = EBADF; + return EOF; + } - for (; n > 0; n -= t, p += t) { - t = (*fp->_write)(fp->_cookie, (char *)p, n); - if (t <= 0) { - fp->_flags |= __SERR; - return (EOF); + off = fp->_r; + if (HASUB(fp)) { + off += fp->_ur; + FREEUB(fp); } + if (t & __SOFF) { + off = fp->_offset - off; + __sseek(fp->_cookie, off, SEEK_SET); + } else if (off != 0) + __sseek(fp->_cookie, -off, SEEK_CUR); + + WCIO_FREE(fp); + fp->_p = fp->_bf._base; + fp->_r = 0; } return (0); } diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c index 65065e54d7d..2b82300c0b2 100644 --- a/lib/libc/stdio/freopen.c +++ b/lib/libc/stdio/freopen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: freopen.c,v 1.17 2019/06/29 16:12:21 deraadt Exp $ */ +/* $OpenBSD: freopen.c,v 1.18 2024/08/12 20:53:09 guenther Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -75,9 +75,8 @@ freopen(const char *file, const char *mode, FILE *fp) isopen = 0; wantfd = -1; } else { - /* flush the stream; ANSI doesn't require this. */ - if (fp->_flags & __SWR) - (void) __sflush(fp); + /* flush the stream; POSIX, not ANSI, requires this. */ + (void) __sflush(fp); /* if close is NULL, closing is a no-op, hence pointless */ isopen = fp->_close != NULL; if ((wantfd = fp->_file) < 0 && isopen) { diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c index 18c530138a6..a65867d3f46 100644 --- a/lib/libc/stdio/fseek.c +++ b/lib/libc/stdio/fseek.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fseek.c,v 1.14 2022/05/14 05:06:32 guenther Exp $ */ +/* $OpenBSD: fseek.c,v 1.15 2024/08/12 20:53:09 guenther Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -116,7 +116,8 @@ fseeko(FILE *fp, off_t offset, int whence) /* * Can only optimise if: * reading (and not reading-and-writing); - * not unbuffered; and + * not unbuffered; + * not immediately after an fflush(); and * this is a `regular' Unix file (and hence seekfn==__sseek). * We must check __NBF first, because it is possible to have __NBF * and __SOPT both set. @@ -125,6 +126,8 @@ fseeko(FILE *fp, off_t offset, int whence) __smakebuf(fp); if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT)) goto dumb; + if (fp->_r == 0 && (fp->_p == NULL || fp->_p == fp->_bf._base)) + goto dumb; if ((fp->_flags & __SOPT) == 0) { if (seekfn != __sseek || fp->_file < 0 || fstat(fp->_file, &st) == -1 || @@ -228,7 +231,7 @@ fseeko(FILE *fp, off_t offset, int whence) * do it. Allow the seek function to change fp->_bf._base. */ dumb: - if (__sflush(fp) || + if (((fp->_flags & __SWR) && __sflush(fp)) || (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) { FUNLOCKFILE(fp); return (EOF); diff --git a/lib/libc/stdio/ftell.c b/lib/libc/stdio/ftell.c index a75ebbbaad7..69e1f0d6ef9 100644 --- a/lib/libc/stdio/ftell.c +++ b/lib/libc/stdio/ftell.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ftell.c,v 1.11 2015/08/31 02:53:57 guenther Exp $ */ +/* $OpenBSD: ftell.c,v 1.12 2024/08/12 20:53:09 guenther Exp $ */ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -55,7 +55,8 @@ ftello(FILE *fp) * adjust for buffered bytes. */ FLOCKFILE(fp); - __sflush(fp); /* may adjust seek offset on append stream */ + if (fp->_flags & __SWR) + __sflush(fp); /* may adjust seek offset on append stream */ if (fp->_flags & __SOFF) pos = fp->_offset; else { diff --git a/lib/libc/stdlib/exit.3 b/lib/libc/stdlib/exit.3 index a1c43780d65..5e006e53f40 100644 --- a/lib/libc/stdlib/exit.3 +++ b/lib/libc/stdlib/exit.3 @@ -29,9 +29,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $OpenBSD: exit.3,v 1.16 2014/11/30 21:21:59 schwarze Exp $ +.\" $OpenBSD: exit.3,v 1.17 2024/08/12 20:53:09 guenther Exp $ .\" -.Dd $Mdocdate: November 30 2014 $ +.Dd $Mdocdate: August 12 2024 $ .Dt EXIT 3 .Os .Sh NAME @@ -54,9 +54,7 @@ Call the functions registered with the .Xr atexit 3 function, in the reverse order of their registration. .It -Flush all open output streams. -.It -Close all open streams. +Flush and close all open streams. .It Unlink all files created with the .Xr tmpfile 3 @@ -79,6 +77,7 @@ function never returns. .Sh SEE ALSO .Xr _exit 2 , .Xr atexit 3 , +.Xr fflush 3 , .Xr intro 3 , .Xr sysexits 3 , .Xr tmpfile 3 @@ -86,7 +85,7 @@ function never returns. The .Fn exit function conforms to -.St -isoC-99 . +.St -p1003.1-2024 . .Sh HISTORY An .Fn exit -- 2.20.1