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.
This commit is contained in:
parent
9c552a1fd7
commit
924888f977
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=82807
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ _fseeko(fp, offset, whence, ltest)
|
||||
* 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 @@ _fseeko(fp, offset, whence, ltest)
|
||||
* 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 @@ _fseeko(fp, offset, whence, ltest)
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user