diff options
author | ache <ache@FreeBSD.org> | 2001-09-02 19:10:10 +0000 |
---|---|---|
committer | ache <ache@FreeBSD.org> | 2001-09-02 19:10:10 +0000 |
commit | 245c459c3f4dcbc6da4c66aebc8879251e9af682 (patch) | |
tree | be15c0be354e09f766522b411a1ad2af5d566a99 /lib/libc/stdio | |
parent | b3ac07522908287b53a4f7e77f2e5205c4f72fb7 (diff) | |
download | FreeBSD-src-245c459c3f4dcbc6da4c66aebc8879251e9af682.zip FreeBSD-src-245c459c3f4dcbc6da4c66aebc8879251e9af682.tar.gz |
Move all stdio internal flags processing and setting out of __sread(),
__swrite() and __sseek() to higher level. According to funopen(3) they all
are just wrappers to something like standard read(2), write(2) and
lseek(2), i.e. must not touch stdio internals because they are replaceable
with any other functions knows nothing about stdio internals. See example
of funopen(3) usage in sendmail sources f.e.
NOTE: this is original stdio bug, not result of my range checkin added.
Diffstat (limited to 'lib/libc/stdio')
-rw-r--r-- | lib/libc/stdio/fdopen.c | 4 | ||||
-rw-r--r-- | lib/libc/stdio/fflush.c | 6 | ||||
-rw-r--r-- | lib/libc/stdio/fopen.c | 2 | ||||
-rw-r--r-- | lib/libc/stdio/fseek.c | 44 | ||||
-rw-r--r-- | lib/libc/stdio/ftell.c | 2 | ||||
-rw-r--r-- | lib/libc/stdio/fvwrite.c | 27 | ||||
-rw-r--r-- | lib/libc/stdio/local.h | 1 | ||||
-rw-r--r-- | lib/libc/stdio/refill.c | 9 | ||||
-rw-r--r-- | lib/libc/stdio/stdio.c | 49 |
9 files changed, 89 insertions, 55 deletions
diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c index 2e72e71..30bf5b9 100644 --- a/lib/libc/stdio/fdopen.c +++ b/lib/libc/stdio/fdopen.c @@ -78,8 +78,8 @@ fdopen(fd, mode) fp->_flags = flags; /* * If opened for appending, but underlying descriptor does not have - * O_APPEND bit set, assert __SAPP so that __swrite() will lseek to - * end before each write. + * O_APPEND bit set, assert __SAPP so that __swrite() caller + * will _sseek() to the end before write. */ if ((oflags & O_APPEND) && !(fdflags & O_APPEND)) fp->_flags |= __SAPP; diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c index 5c1eaa1..55a6a2a 100644 --- a/lib/libc/stdio/fflush.c +++ b/lib/libc/stdio/fflush.c @@ -113,9 +113,15 @@ __sflush(FILE *fp) fp->_p = p; fp->_w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size; + if (n <= 0) + return (0); + if ((fp->_flags & __SAPP) && _sseek(fp, (fpos_t)0, SEEK_END) == -1) + goto err; + fp->_flags &= ~__SOFF; /* In case FAPPEND mode is set. */ for (; n > 0; n -= t, p += t) { t = (*fp->_write)(fp->_cookie, (char *)p, n); if (t <= 0) { + err: fp->_flags |= __SERR; return (EOF); } diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c index f09fe8a..709316d 100644 --- a/lib/libc/stdio/fopen.c +++ b/lib/libc/stdio/fopen.c @@ -85,6 +85,6 @@ fopen(file, mode) * fseek and ftell.) */ if (oflags & O_APPEND) - (void) __sseek((void *)fp, (fpos_t)0, SEEK_END); + (void)_sseek(fp, (fpos_t)0, SEEK_END); return (fp); } diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c index 38a8bf5..0cbf798 100644 --- a/lib/libc/stdio/fseek.c +++ b/lib/libc/stdio/fseek.c @@ -274,7 +274,7 @@ abspos: * ensures that we only read one block, rather than two. */ curoff = target & ~(fp->_blksize - 1); - if ((*seekfn)(fp->_cookie, curoff, SEEK_SET) == POS_ERR) + if (_sseek(fp, curoff, SEEK_SET) == POS_ERR) goto dumb; fp->_r = 0; fp->_p = fp->_bf._base; @@ -295,8 +295,7 @@ abspos: * do it. Allow the seek function to change fp->_bf._base. */ dumb: - if (__sflush(fp) || - (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) + if (__sflush(fp) || _sseek(fp, (fpos_t)offset, whence) == POS_ERR) return (-1); if (ltest && fp->_offset > LONG_MAX) { fp->_flags |= __SERR; @@ -312,3 +311,42 @@ dumb: fp->_flags &= ~__SEOF; return (0); } + + +fpos_t +_sseek(fp, offset, whence) + FILE *fp; + fpos_t offset; + int whence; +{ + fpos_t ret; + int serrno, errret; + + if (fp->_seek == NULL) { + errno = ESPIPE; + return (-1); + } + serrno = errno; + errno = 0; + ret = (*fp->_seek)(fp->_cookie, offset, whence); + errret = errno; + if (errno == 0) + errno = serrno; + /* + * Disallow negative seeks per POSIX. + * It is needed here to help upper level caller + * in the cases it can't detect. + */ + if (ret < 0) { + if (errret == 0) { + fp->_flags |= __SERR; + errno = EINVAL; + } + fp->_flags &= ~__SOFF; + ret = -1; + } else { + fp->_flags |= __SOFF; + fp->_offset = ret; + } + return (ret); +} diff --git a/lib/libc/stdio/ftell.c b/lib/libc/stdio/ftell.c index e355a20..174eaa8 100644 --- a/lib/libc/stdio/ftell.c +++ b/lib/libc/stdio/ftell.c @@ -110,7 +110,7 @@ _ftello(fp, offset) if (fp->_flags & __SOFF) pos = fp->_offset; else { - pos = (*fp->_seek)(fp->_cookie, (fpos_t)0, SEEK_CUR); + pos = _sseek(fp, (fpos_t)0, SEEK_CUR); if (pos == -1) return (1); } diff --git a/lib/libc/stdio/fvwrite.c b/lib/libc/stdio/fvwrite.c index 82a49cb..efcfffb 100644 --- a/lib/libc/stdio/fvwrite.c +++ b/lib/libc/stdio/fvwrite.c @@ -64,7 +64,7 @@ __sfvwrite(fp, uio) register struct __siov *iov; register int w, s; char *nl; - int nlknown, nldist; + int nlknown, nldist, firsttime; if ((len = uio->uio_resid) == 0) return (0); @@ -86,12 +86,21 @@ __sfvwrite(fp, uio) len = iov->iov_len; \ iov++; \ } + firsttime = 1; if (fp->_flags & __SNBF) { /* * Unbuffered: write up to BUFSIZ bytes at a time. */ do { GETIOV(;); + if (firsttime) { + if ((fp->_flags & __SAPP) && + _sseek(fp, (fpos_t)0, SEEK_END) == -1) + goto err; + /* In case FAPPEND mode is set. */ + fp->_flags &= ~__SOFF; + firsttime = 0; + } w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ)); if (w <= 0) goto err; @@ -147,6 +156,14 @@ __sfvwrite(fp, uio) goto err; } else if (len >= (w = fp->_bf._size)) { /* write directly */ + if (firsttime) { + if ((fp->_flags & __SAPP) && + _sseek(fp, (fpos_t)0, SEEK_END) == -1) + goto err; + /* In case FAPPEND mode is set. */ + fp->_flags &= ~__SOFF; + firsttime = 0; + } w = (*fp->_write)(fp->_cookie, p, w); if (w <= 0) goto err; @@ -186,6 +203,14 @@ __sfvwrite(fp, uio) if (__fflush(fp)) goto err; } else if (s >= (w = fp->_bf._size)) { + if (firsttime) { + if ((fp->_flags & __SAPP) && + _sseek(fp, (fpos_t)0, SEEK_END) == -1) + goto err; + /* In case FAPPEND mode is set. */ + fp->_flags &= ~__SOFF; + firsttime = 0; + } w = (*fp->_write)(fp->_cookie, p, w); if (w <= 0) goto err; diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h index d37a540..e074273 100644 --- a/lib/libc/stdio/local.h +++ b/lib/libc/stdio/local.h @@ -46,6 +46,7 @@ * in particular, macros and private variables. */ +extern fpos_t _sseek __P((FILE *, fpos_t, int)); extern int _ftello __P((FILE *, fpos_t *)); extern int _fseeko __P((FILE *, off_t, int, int)); extern int __fflush __P((FILE *fp)); diff --git a/lib/libc/stdio/refill.c b/lib/libc/stdio/refill.c index fa46d78..2d30e81 100644 --- a/lib/libc/stdio/refill.c +++ b/lib/libc/stdio/refill.c @@ -44,6 +44,7 @@ static const char rcsid[] = #include "namespace.h" #include <errno.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include "un-namespace.h" @@ -141,10 +142,18 @@ __srefill(FILE *fp) if (fp->_r == 0) fp->_flags |= __SEOF; else { + err: fp->_r = 0; fp->_flags |= __SERR; + fp->_flags &= ~__SOFF; } return (EOF); + } else if (fp->_flags & __SOFF) { + if (fp->_offset > OFF_MAX - fp->_r) { + errno = EOVERFLOW; + goto err; + } else + fp->_offset += fp->_r; } return (0); } diff --git a/lib/libc/stdio/stdio.c b/lib/libc/stdio/stdio.c index ea8a4c1..b4bf299 100644 --- a/lib/libc/stdio/stdio.c +++ b/lib/libc/stdio/stdio.c @@ -45,7 +45,6 @@ static const char rcsid[] = #include "namespace.h" #include <errno.h> #include <fcntl.h> -#include <limits.h> #include <stdio.h> #include <unistd.h> #include "un-namespace.h" @@ -53,7 +52,6 @@ static const char rcsid[] = /* * Small standard I/O/seek/close functions. - * These maintain the `known seek offset' for seek optimisation. */ int __sread(cookie, buf, n) @@ -62,24 +60,8 @@ __sread(cookie, buf, n) int n; { register FILE *fp = cookie; - register int ret; - ret = _read(fp->_file, buf, (size_t)n); - /* if the read succeeded, update the current offset */ - if (ret >= 0) { - if (fp->_flags & __SOFF) { - if (fp->_offset > OFF_MAX - ret) { - errno = EOVERFLOW; - ret = -1; - } else { - fp->_offset += ret; - return (ret); - } - } else - return (ret); - } - fp->_flags &= ~__SOFF; - return (ret); + return(_read(fp->_file, buf, (size_t)n)); } int @@ -90,9 +72,6 @@ __swrite(cookie, buf, n) { register FILE *fp = cookie; - if (fp->_flags & __SAPP) - (void) lseek(fp->_file, (off_t)0, SEEK_END); - fp->_flags &= ~__SOFF; /* in case FAPPEND mode is set */ return (_write(fp->_file, buf, (size_t)n)); } @@ -103,32 +82,8 @@ __sseek(cookie, offset, whence) int whence; { register FILE *fp = cookie; - register off_t ret; - int serrno, errret; - serrno = errno; - errno = 0; - ret = lseek(fp->_file, (off_t)offset, whence); - errret = errno; - if (errno == 0) - errno = serrno; - /* - * Disallow negative seeks per POSIX. - * It is needed here to help upper level caller - * (fseek) in the cases it can't detect. - */ - if (ret < 0) { - if (errret == 0) { - fp->_flags |= __SERR; - errno = EINVAL; - } - fp->_flags &= ~__SOFF; - ret = -1; - } else { - fp->_flags |= __SOFF; - fp->_offset = ret; - } - return (ret); + return (lseek(fp->_file, (off_t)offset, whence)); } int |