diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 5f0b3b499..47f0e30f2 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,5 +1,25 @@ 2007-07-13 Eric Blake + Fix fflush issues. + * libc/stdio/fflush.c (_fflush_r): New function. + (fflush): Fix reentrancy and large offset behavior. + * libc/include/stdio.h (_fflush_r): Add prototype. + * libc/stdio/fclose.c (_fclose_r): All fflush callers changed. + * libc/stdio/freopen.c (_freopen_r): Likewise. + * libc/stdio/fseek.c (_fseek_r): Likewise. + * libc/stdio/ftell.c (_ftell_r): Likewise. + * libc/stdio/fvwrite.c (__sfvwrite_r): Likewise. + * libc/stdio/refill.c (__srefill_r): Likewise. + * libc/stdio/setvbuf.c (setvbuf): Likewise. + * libc/stdio/ungetc.c (_ungetc_r): Likewise. + * libc/stdio/vfprintf.c (__sbprintf): Likewise. + * libc/stdio/wbuf.c (__swbuf_r): Likewise. + * libc/stdio64/freopen64.c (_freopen64_r): Likewise. + * libc/stdio64/fseeko64.c (_fseeko64_r): Likewise. Defer to + 32-bit version if not large file. + * libc/stdio64/ftello64.c (_ftello64_r): Likewise. + * libc/stdio64/tmpfile64.c (_tmpfile64_r): Avoid compile warning. + Documentation updates. * libc/stdio/ungetc.c: Document ungetc. * libc/stdio/Makefile.am (CHEWOUT_FILES): Sort, match current list diff --git a/newlib/libc/include/stdio.h b/newlib/libc/include/stdio.h index babb1c3c5..b387a4455 100644 --- a/newlib/libc/include/stdio.h +++ b/newlib/libc/include/stdio.h @@ -348,12 +348,13 @@ int _EXFUN(_dprintf_r, (struct _reent *, int, const char *, ...) int _EXFUN(_fclose_r, (struct _reent *, FILE *)); int _EXFUN(_fcloseall_r, (struct _reent *)); FILE * _EXFUN(_fdopen_r, (struct _reent *, int, const char *)); -FILE * _EXFUN(_fopen_r, (struct _reent *, const char *, const char *)); +int _EXFUN(_fflush_r, (struct _reent *, FILE *)); char * _EXFUN(_fgets_r, (struct _reent *, char *, int, FILE *)); int _EXFUN(_fiprintf_r, (struct _reent *, FILE *, const char *, ...) _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); int _EXFUN(_fiscanf_r, (struct _reent *, FILE *, const char *, ...) _ATTRIBUTE ((__format__ (__scanf__, 3, 4)))); +FILE * _EXFUN(_fopen_r, (struct _reent *, const char *, const char *)); int _EXFUN(_fprintf_r, (struct _reent *, FILE *, const char *, ...) _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); int _EXFUN(_fputc_r, (struct _reent *, int, FILE *)); diff --git a/newlib/libc/stdio/fclose.c b/newlib/libc/stdio/fclose.c index 18cddf0c8..a14a63f3f 100644 --- a/newlib/libc/stdio/fclose.c +++ b/newlib/libc/stdio/fclose.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1990, 2007 The Regents of the University of California. + * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -89,7 +89,7 @@ _DEFUN(_fclose_r, (rptr, fp), /* Unconditionally flush to allow special handling for seekable read files to reposition file to last byte processed as opposed to last byte read ahead into the buffer. */ - r = fflush (fp); + r = _fflush_r (rptr, fp); if (fp->_close != NULL && fp->_close (rptr, fp->_cookie) < 0) r = EOF; if (fp->_flags & __SMBF) diff --git a/newlib/libc/stdio/fflush.c b/newlib/libc/stdio/fflush.c index d375d9509..24bd6c10e 100644 --- a/newlib/libc/stdio/fflush.c +++ b/newlib/libc/stdio/fflush.c @@ -26,10 +26,7 @@ ANSI_SYNOPSIS #include int fflush(FILE *<[fp]>); -TRAD_SYNOPSIS - #include - int fflush(<[fp]>) - FILE *<[fp]>; + int _fflush_r(struct _reent *<[reent]>, FILE *<[fp]>); DESCRIPTION The <> output functions can buffer output before delivering it @@ -41,32 +38,41 @@ or stream identified by <[fp]>) to the host system. If <[fp]> is <>, <> delivers pending output from all open files. +Additionally, if <[fp]> is a seekable input stream visiting a file +descriptor, set the position of the file descriptor to match next +unread byte, useful for obeying POSIX semantics when ending a process +without consuming all input from the stream. + +The alternate function <<_fflush_r>> is a reentrant version, where the +extra argument <[reent]> is a pointer to a reentrancy structure, and +<[fp]> must not be NULL. + RETURNS <> returns <<0>> unless it encounters a write error; in that situation, it returns <>. PORTABILITY -ANSI C requires <>. +ANSI C requires <>. The behavior on input streams is only +specified by POSIX, and not all implementations follow POSIX rules. No supporting OS subroutines are required. */ #include <_ansi.h> #include +#include #include "local.h" /* Flush a single file, or (if fp is NULL) all files. */ int -_DEFUN(fflush, (fp), +_DEFUN(_fflush_r, (ptr, fp), + struct _reent *ptr _AND register FILE * fp) { register unsigned char *p; register int n, t; - if (fp == NULL) - return _fwalk (_GLOBAL_REENT, fflush); - #ifdef _REENT_SMALL /* For REENT_SMALL platforms, it is possible we are being called for the first time on a std stream. This std @@ -83,15 +89,13 @@ _DEFUN(fflush, (fp), return 0; #endif /* _REENT_SMALL */ - CHECK_INIT (_REENT, fp); + CHECK_INIT (ptr, fp); _flockfile (fp); t = fp->_flags; if ((t & __SWR) == 0) { - _fpos_t _EXFUN((*seekfn), (struct _reent *, _PTR, _fpos_t, int)); - /* For a read stream, an fflush causes the next seek to be unoptimized (i.e. forces a system-level seek). This conforms to the POSIX and SUSv3 standards. */ @@ -104,22 +108,38 @@ _DEFUN(fflush, (fp), this seek to be deferred until necessary, but we choose to do it here to make the change simpler, more contained, and less likely to miss a code scenario. */ - if ((fp->_r > 0 || fp->_ur > 0) && (seekfn = fp->_seek) != NULL) - { - _fpos_t curoff; + if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL) + { + int tmp; +#ifdef __LARGE64_FILES + _fpos64_t curoff; +#else + _fpos_t curoff; +#endif - /* Get the physical position we are at in the file. */ - if (fp->_flags & __SOFF) - curoff = fp->_offset; - else - { - /* We don't know current physical offset, so ask for it. */ - curoff = seekfn (_REENT, fp->_cookie, (_fpos_t) 0, SEEK_CUR); - if (curoff == -1L) - { - _funlockfile (fp); - return 0; - } + /* Get the physical position we are at in the file. */ + if (fp->_flags & __SOFF) + curoff = fp->_offset; + else + { + /* We don't know current physical offset, so ask for it. + Only ESPIPE is ignorable. */ +#ifdef __LARGE64_FILES + if (fp->_flags & __SL64) + curoff = fp->_seek64 (ptr, fp->_cookie, 0, SEEK_CUR); + else +#endif + curoff = fp->_seek (ptr, fp->_cookie, 0, SEEK_CUR); + if (curoff == -1L) + { + int result = EOF; + if (ptr->_errno == ESPIPE) + result = 0; + else + fp->_flags |= __SERR; + _funlockfile (fp); + return result; + } } if (fp->_flags & __SRD) { @@ -129,17 +149,29 @@ _DEFUN(fflush, (fp), if (HASUB (fp)) curoff -= fp->_ur; } - /* Now physically seek to after byte last read. */ - if (seekfn (_REENT, fp->_cookie, curoff, SEEK_SET) != -1) - { - /* Seek successful. We can clear read buffer now. */ - fp->_flags &= ~__SNPT; - fp->_r = 0; - fp->_p = fp->_bf._base; - if (fp->_flags & __SOFF) - fp->_offset = curoff; - } - } + /* Now physically seek to after byte last read. */ +#ifdef __LARGE64_FILES + if (fp->_flags & __SL64) + tmp = (fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET) == curoff); + else +#endif + tmp = (fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET) == curoff); + if (tmp) + { + /* Seek successful. We can clear read buffer now. */ + fp->_flags &= ~__SNPT; + fp->_r = 0; + fp->_p = fp->_bf._base; + if (fp->_flags & __SOFF) + fp->_offset = curoff; + } + else + { + fp->_flags |= __SERR; + _funlockfile (fp); + return EOF; + } + } _funlockfile (fp); return 0; } @@ -161,7 +193,7 @@ _DEFUN(fflush, (fp), while (n > 0) { - t = fp->_write (_REENT, fp->_cookie, (char *) p, n); + t = fp->_write (ptr, fp->_cookie, (char *) p, n); if (t <= 0) { fp->_flags |= __SERR; @@ -174,3 +206,17 @@ _DEFUN(fflush, (fp), _funlockfile (fp); return 0; } + +#ifndef _REENT_ONLY + +int +_DEFUN(fflush, (fp), + register FILE * fp) +{ + if (fp == NULL) + return _fwalk_reent (_GLOBAL_REENT, _fflush_r); + + return _fflush_r (_REENT, fp); +} + +#endif /* _REENT_ONLY */ diff --git a/newlib/libc/stdio/freopen.c b/newlib/libc/stdio/freopen.c index f6d658c63..247f8c6ad 100644 --- a/newlib/libc/stdio/freopen.c +++ b/newlib/libc/stdio/freopen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1990, 2006, 2007 The Regents of the University of California. + * Copyright (c) 1990, 2007 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -124,7 +124,7 @@ _DEFUN(_freopen_r, (ptr, file, mode, fp), else { if (fp->_flags & __SWR) - fflush (fp); + _fflush_r (ptr, fp); /* * If close is NULL, closing is a no-op, hence pointless. * If file is NULL, the file should not be closed. diff --git a/newlib/libc/stdio/fseek.c b/newlib/libc/stdio/fseek.c index 028c62a3f..569bad742 100644 --- a/newlib/libc/stdio/fseek.c +++ b/newlib/libc/stdio/fseek.c @@ -145,7 +145,7 @@ _DEFUN(_fseek_r, (ptr, fp, offset, whence), if (fp->_flags & __SAPP && fp->_flags & __SWR) { /* So flush the buffer and seek to the end. */ - fflush (fp); + _fflush_r (ptr, fp); } /* Have to be able to seek. */ @@ -170,7 +170,7 @@ _DEFUN(_fseek_r, (ptr, fp, offset, whence), * we have to first find the current stream offset a la * ftell (see ftell for details). */ - fflush (fp); /* may adjust seek offset on append stream */ + _fflush_r (ptr, fp); /* may adjust seek offset on append stream */ if (fp->_flags & __SOFF) curoff = fp->_offset; else @@ -356,7 +356,8 @@ _DEFUN(_fseek_r, (ptr, fp, offset, whence), */ dumb: - if (fflush (fp) || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) + if (_fflush_r (ptr, fp) + || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) { _funlockfile (fp); return EOF; diff --git a/newlib/libc/stdio/ftell.c b/newlib/libc/stdio/ftell.c index b77879d73..2aa10b2c7 100644 --- a/newlib/libc/stdio/ftell.c +++ b/newlib/libc/stdio/ftell.c @@ -120,7 +120,7 @@ _DEFUN(_ftell_r, (ptr, fp), /* Find offset of underlying I/O object, then adjust for buffered bytes. */ - fflush(fp); /* may adjust seek offset on append stream */ + _fflush_r (ptr, fp); /* may adjust seek offset on append stream */ if (fp->_flags & __SOFF) pos = fp->_offset; else diff --git a/newlib/libc/stdio/fvwrite.c b/newlib/libc/stdio/fvwrite.c index 75fc8347b..d3878dc17 100644 --- a/newlib/libc/stdio/fvwrite.c +++ b/newlib/libc/stdio/fvwrite.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1990, 2006, 2007 The Regents of the University of California. + * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -185,7 +185,7 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio), COPY (w); /* fp->_w -= w; *//* unneeded */ fp->_p += w; - if (fflush (fp)) + if (_fflush_r (ptr, fp)) goto err; } else if (len >= (w = fp->_bf._size)) @@ -235,7 +235,7 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio), COPY (w); /* fp->_w -= w; */ fp->_p += w; - if (fflush (fp)) + if (_fflush_r (ptr, fp)) goto err; } else if (s >= (w = fp->_bf._size)) @@ -254,7 +254,7 @@ _DEFUN(__sfvwrite_r, (ptr, fp, uio), if ((nldist -= w) == 0) { /* copied the newline: flush and forget */ - if (fflush (fp)) + if (_fflush_r (ptr, fp)) goto err; nlknown = 0; } diff --git a/newlib/libc/stdio/refill.c b/newlib/libc/stdio/refill.c index f4644ce96..6b329a852 100644 --- a/newlib/libc/stdio/refill.c +++ b/newlib/libc/stdio/refill.c @@ -65,7 +65,7 @@ _DEFUN(__srefill_r, (ptr, fp), /* switch to reading */ if (fp->_flags & __SWR) { - if (fflush (fp)) + if (_fflush_r (ptr, fp)) return EOF; fp->_flags &= ~__SWR; fp->_w = 0; diff --git a/newlib/libc/stdio/setvbuf.c b/newlib/libc/stdio/setvbuf.c index 561f68b54..583a081f4 100644 --- a/newlib/libc/stdio/setvbuf.c +++ b/newlib/libc/stdio/setvbuf.c @@ -126,7 +126,7 @@ _DEFUN(setvbuf, (fp, buf, mode, size), * non buffer flags, and clear malloc flag. */ - _CAST_VOID fflush (fp); + _fflush_r (_REENT, fp); fp->_r = 0; fp->_lbfsize = 0; if (fp->_flags & __SMBF) diff --git a/newlib/libc/stdio/ungetc.c b/newlib/libc/stdio/ungetc.c index 59834ded7..d65cddab6 100644 --- a/newlib/libc/stdio/ungetc.c +++ b/newlib/libc/stdio/ungetc.c @@ -143,7 +143,7 @@ _DEFUN(_ungetc_r, (rptr, c, fp), } if (fp->_flags & __SWR) { - if (fflush (fp)) + if (_fflush_r (rptr, fp)) { _funlockfile (fp); return EOF; diff --git a/newlib/libc/stdio/vfprintf.c b/newlib/libc/stdio/vfprintf.c index 0c1a47bb6..5bbd7594f 100644 --- a/newlib/libc/stdio/vfprintf.c +++ b/newlib/libc/stdio/vfprintf.c @@ -212,7 +212,7 @@ _DEFUN(__sbprintf, (rptr, fp, fmt, ap), /* do the work, then copy any error status */ ret = _VFPRINTF_R (rptr, &fake, fmt, ap); - if (ret >= 0 && fflush(&fake)) + if (ret >= 0 && _fflush_r (rptr, &fake)) ret = EOF; if (fake._flags & __SERR) fp->_flags |= __SERR; diff --git a/newlib/libc/stdio/wbuf.c b/newlib/libc/stdio/wbuf.c index ea8f64d8d..bd7f15d9b 100644 --- a/newlib/libc/stdio/wbuf.c +++ b/newlib/libc/stdio/wbuf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1990, 2007 The Regents of the University of California. + * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -74,14 +74,14 @@ _DEFUN(__swbuf_r, (ptr, c, fp), n = fp->_p - fp->_bf._base; if (n >= fp->_bf._size) { - if (fflush (fp)) + if (_fflush_r (ptr, fp)) return EOF; n = 0; } fp->_w--; *fp->_p++ = c; if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n')) - if (fflush (fp)) + if (_fflush_r (ptr, fp)) return EOF; return c; } diff --git a/newlib/libc/stdio64/freopen64.c b/newlib/libc/stdio64/freopen64.c index 0362407e9..866d8c943 100644 --- a/newlib/libc/stdio64/freopen64.c +++ b/newlib/libc/stdio64/freopen64.c @@ -124,7 +124,7 @@ _DEFUN (_freopen64_r, (ptr, file, mode, fp), else { if (fp->_flags & __SWR) - fflush (fp); + _fflush_r (ptr, fp); /* * If close is NULL, closing is a no-op, hence pointless. * If file is NULL, the file should not be closed. diff --git a/newlib/libc/stdio64/fseeko64.c b/newlib/libc/stdio64/fseeko64.c index fe07bfe2d..280484e62 100644 --- a/newlib/libc/stdio64/fseeko64.c +++ b/newlib/libc/stdio64/fseeko64.c @@ -111,11 +111,22 @@ _DEFUN (_fseeko64_r, (ptr, fp, offset, whence), struct stat64 st; int havepos; + /* Only do 64-bit seek on large file. */ + if (!(fp->_flags & __SL64)) + { + if ((_off_t) offset != offset) + { + ptr->_errno = EOVERFLOW; + return EOF; + } + return (_off64_t) _fseeko_r (ptr, fp, offset, whence); + } + /* Make sure stdio is set up. */ CHECK_INIT (ptr, fp); - _flockfile(fp); + _flockfile (fp); curoff = fp->_offset; @@ -125,12 +136,12 @@ _DEFUN (_fseeko64_r, (ptr, fp, offset, whence), if (fp->_flags & __SAPP && fp->_flags & __SWR) { /* So flush the buffer and seek to the end. */ - fflush (fp); + _fflush_r (ptr, fp); } /* Have to be able to seek. */ - if ((seekfn = fp->_seek64) == NULL || !(fp->_flags & __SL64)) + if ((seekfn = fp->_seek64) == NULL) { ptr->_errno = ESPIPE; /* ??? */ _funlockfile(fp); @@ -150,7 +161,7 @@ _DEFUN (_fseeko64_r, (ptr, fp, offset, whence), * we have to first find the current stream offset a la * ftell (see ftell for details). */ - fflush(fp); /* may adjust seek offset on append stream */ + _fflush_r (ptr, fp); /* may adjust seek offset on append stream */ if (fp->_flags & __SOFF) curoff = fp->_offset; else @@ -323,7 +334,8 @@ _DEFUN (_fseeko64_r, (ptr, fp, offset, whence), */ dumb: - if (fflush (fp) || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) + if (_fflush_r (ptr, fp) + || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) { _funlockfile(fp); return EOF; diff --git a/newlib/libc/stdio64/ftello64.c b/newlib/libc/stdio64/ftello64.c index b596d3234..2fdfb784e 100644 --- a/newlib/libc/stdio64/ftello64.c +++ b/newlib/libc/stdio64/ftello64.c @@ -91,6 +91,10 @@ _DEFUN (_ftello64_r, (ptr, fp), { _fpos64_t pos; + /* Only do 64-bit tell on large file. */ + if (!(fp->_flags & __SL64)) + return (_off64_t) _ftello_r (ptr, fp); + /* Ensure stdio is set up. */ CHECK_INIT (ptr, fp); @@ -106,7 +110,7 @@ _DEFUN (_ftello64_r, (ptr, fp), /* Find offset of underlying I/O object, then adjust for buffered bytes. */ - fflush(fp); /* may adjust seek offset on append stream */ + _fflush_r (ptr, fp); /* may adjust seek offset on append stream */ if (fp->_flags & __SOFF) pos = fp->_offset; else diff --git a/newlib/libc/stdio64/tmpfile64.c b/newlib/libc/stdio64/tmpfile64.c index 511606c78..98a7d7817 100644 --- a/newlib/libc/stdio64/tmpfile64.c +++ b/newlib/libc/stdio64/tmpfile64.c @@ -48,6 +48,7 @@ Supporting OS subroutines required: <>, <>, <>, */ #include +#include #include #include #include