diff options
Diffstat (limited to 'usr/src/lib/libc/port/stdio/flush.c')
-rw-r--r-- | usr/src/lib/libc/port/stdio/flush.c | 199 |
1 files changed, 186 insertions, 13 deletions
diff --git a/usr/src/lib/libc/port/stdio/flush.c b/usr/src/lib/libc/port/stdio/flush.c index 7d3549ca0d..be710ccb2a 100644 --- a/usr/src/lib/libc/port/stdio/flush.c +++ b/usr/src/lib/libc/port/stdio/flush.c @@ -21,10 +21,11 @@ /* * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2020 Robert Mustacchi */ /* Copyright (c) 1988 AT&T */ -/* All Rights Reserved */ +/* All Rights Reserved */ #include "lint.h" #include "mtlib.h" @@ -42,6 +43,8 @@ #include <stddef.h> #include <errno.h> #include <fcntl.h> +#include <sys/debug.h> +#include <limits.h> #define _iob __iob @@ -376,7 +379,8 @@ rescan: lastlink = *prev = hdr; fp->_ptr = 0; fp->_base = 0; - fp->_flag = 0377; /* claim the fp by setting low 8 bits */ + /* claim the fp by setting low 8 bits */ + fp->_flag = _DEF_FLAG_MASK; if (threaded) cancel_safe_mutex_unlock(&_first_link_lock); @@ -387,11 +391,19 @@ static void isseekable(FILE *iop) { struct stat64 fstatbuf; - int save_errno; + int fd, save_errno; save_errno = errno; - if (fstat64(GET_FD(iop), &fstatbuf) != 0) { + /* + * non-FILE based STREAMS are required to declare their own seekability + * and therefore we should not try and test them below. + */ + fd = _get_fd(iop); + if (fd == -1) { + return; + } + if (fstat64(fd, &fstatbuf) != 0) { /* * when we don't know what it is we'll * do the old behaviour and flush @@ -545,8 +557,7 @@ _xflsbuf(FILE *iop) _bufsync(iop, bufend); if (n > 0) { - int fd = GET_FD(iop); - while ((num_wrote = write(fd, base, (size_t)n)) != n) { + while ((num_wrote = _xwrite(iop, base, (size_t)n)) != n) { if (num_wrote <= 0) { if (!cancel_active()) iop->_flag |= _IOERR; @@ -600,8 +611,8 @@ _fflush_l_iops(void) /* flush all buffers */ * knowing that when it is 0, it isn't allocated and * cannot be allocated while we're holding the * _first_link_lock. And when _IONBF is set (also the - * case when _flag is 0377, or alloc in progress), we - * also ignore it. + * case when _flag is 0377 -- _DEF_FLAG_MASK, or alloc in + * progress), we also ignore it. * * Ignore locked streams; it will appear as if * concurrent updates happened after fflush(NULL). Note @@ -662,7 +673,7 @@ _fflush_u(FILE *iop) /* this portion is always assumed locked */ if (!(iop->_flag & _IOWRT)) { - (void) lseek64(GET_FD(iop), -iop->_cnt, SEEK_CUR); + (void) _xseek64(iop, -iop->_cnt, SEEK_CUR); iop->_cnt = 0; /* needed for ungetc & multibyte pushbacks */ iop->_ptr = iop->_base; @@ -700,7 +711,7 @@ fclose(FILE *iop) /* Is not unbuffered and opened for read and/or write ? */ if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) res = _fflush_u(iop); - if (close(GET_FD(iop)) < 0) + if (_xclose(iop) < 0) res = EOF; if (iop->_flag & _IOMYBUF) { (void) free((char *)iop->_base - PUSHBACK); @@ -751,7 +762,7 @@ fcloseall(void) if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) (void) _fflush_u(iop); - (void) close(GET_FD(iop)); + (void) _xclose(iop); if (iop->_flag & _IOMYBUF) free((char *)iop->_base - PUSHBACK); iop->_base = NULL; @@ -781,7 +792,7 @@ close_fd(FILE *iop) /* Is not unbuffered and opened for read and/or write ? */ if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) res = _fflush_u(iop); - if (close(GET_FD(iop)) < 0) + if (_xclose(iop) < 0) res = EOF; if (iop->_flag & _IOMYBUF) { (void) free((char *)iop->_base - PUSHBACK); @@ -809,7 +820,8 @@ getiop(FILE *fp, rmutex_t *lk, mbstate_t *mb) fp->_cnt = 0; fp->_ptr = NULL; fp->_base = NULL; - fp->_flag = 0377; /* claim the fp by setting low 8 bits */ + /* claim the fp by setting low 8 bits */ + fp->_flag = _DEF_FLAG_MASK; (void) memset(mb, 0, sizeof (mbstate_t)); FUNLOCKFILE(lk); return (fp); @@ -943,3 +955,164 @@ enable_extended_FILE_stdio(int fd, int action) return (0); } #endif + +/* + * Wrappers around the various system calls that stdio needs to make on a file + * descriptor. + */ +static stdio_ops_t * +get_stdops(FILE *iop) +{ +#ifdef _LP64 + return (iop->_ops); +#else + struct xFILEdata *dat = getxfdat(iop); + return (dat->_ops); +#endif +} + +static void +set_stdops(FILE *iop, stdio_ops_t *ops) +{ +#ifdef _LP64 + ASSERT3P(iop->_ops, ==, NULL); + iop->_ops = ops; +#else + struct xFILEdata *dat = getxfdat(iop); + ASSERT3P(dat->_ops, ==, NULL); + dat->_ops = ops; +#endif + +} + +ssize_t +_xread(FILE *iop, void *buf, size_t nbytes) +{ + stdio_ops_t *ops = get_stdops(iop); + if (ops != NULL) { + return (ops->std_read(iop, buf, nbytes)); + } + + return (read(_get_fd(iop), buf, nbytes)); +} + +ssize_t +_xwrite(FILE *iop, const void *buf, size_t nbytes) +{ + stdio_ops_t *ops = get_stdops(iop); + if (ops != NULL) { + return (ops->std_write(iop, buf, nbytes)); + } + return (write(_get_fd(iop), buf, nbytes)); +} + +off_t +_xseek(FILE *iop, off_t off, int whence) +{ + stdio_ops_t *ops = get_stdops(iop); + if (ops != NULL) { + return (ops->std_seek(iop, off, whence)); + } + + return (lseek(_get_fd(iop), off, whence)); +} + +off64_t +_xseek64(FILE *iop, off64_t off, int whence) +{ + stdio_ops_t *ops = get_stdops(iop); + if (ops != NULL) { + /* + * The internal APIs only operate with an off_t. An off64_t in + * an ILP32 environment may represent a value larger than they + * can accept. As such, we try and catch such cases and error + * about it before we get there. + */ + if (off > LONG_MAX || off < LONG_MIN) { + errno = EOVERFLOW; + return (-1); + } + return (ops->std_seek(iop, off, whence)); + } + + return (lseek64(_get_fd(iop), off, whence)); +} + +int +_xclose(FILE *iop) +{ + stdio_ops_t *ops = get_stdops(iop); + if (ops != NULL) { + return (ops->std_close(iop)); + } + + return (close(_get_fd(iop))); +} + +void * +_xdata(FILE *iop) +{ + stdio_ops_t *ops = get_stdops(iop); + if (ops != NULL) { + return (ops->std_data); + } + + return (NULL); +} + +int +_xassoc(FILE *iop, fread_t readf, fwrite_t writef, fseek_t seekf, + fclose_t closef, void *data) +{ + stdio_ops_t *ops = get_stdops(iop); + + if (ops == NULL) { + ops = malloc(sizeof (*ops)); + if (ops == NULL) { + return (-1); + } + set_stdops(iop, ops); + } + + ops->std_read = readf; + ops->std_write = writef; + ops->std_seek = seekf; + ops->std_close = closef; + ops->std_data = data; + + return (0); +} + +void +_xunassoc(FILE *iop) +{ + stdio_ops_t *ops = get_stdops(iop); + if (ops == NULL) { + return; + } + set_stdops(iop, NULL); + free(ops); +} + +int +_get_fd(FILE *iop) +{ + /* + * Streams with an ops vector (currently the memory stream family) do + * not have an underlying file descriptor that we can give back to the + * user. In such cases, return -1 to explicitly make sure that they'll + * get an ebadf from things. + */ + if (get_stdops(iop) != NULL) { + return (-1); + } +#ifdef _LP64 + return (iop->_file); +#else + if (iop->__extendedfd) { + return (_file_get(iop)); + } else { + return (iop->_magic); + } +#endif +} |