diff options
Diffstat (limited to 'cpukit/libcsupport/src/writev.c')
-rw-r--r-- | cpukit/libcsupport/src/writev.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/cpukit/libcsupport/src/writev.c b/cpukit/libcsupport/src/writev.c new file mode 100644 index 0000000000..c032f9f6bc --- /dev/null +++ b/cpukit/libcsupport/src/writev.c @@ -0,0 +1,126 @@ +/* + * writev() - POSIX 1003.1 - Read a Vector + * + * OpenGroup URL: + * + * http://www.opengroup.org/onlinepubs/009695399/functions/writev.html + * + * COPYRIGHT (c) 1989-2007. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/uio.h> + +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +ssize_t writev( + int fd, + const struct iovec *iov, + int iovcnt +) +{ + ssize_t total; + int v; + int bytes; + rtems_libio_t *iop; + ssize_t old; + boolean all_zeros; + + rtems_libio_check_fd( fd ); + iop = rtems_libio_iop( fd ); + rtems_libio_check_is_open( iop ); + rtems_libio_check_permissions( iop, LIBIO_FLAGS_WRITE ); + + /* + * Argument validation on IO vector + */ + if ( !iov ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( iovcnt <= 0 ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( iovcnt > IOV_MAX ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( !iop->handlers->write_h ) + rtems_set_errno_and_return_minus_one( ENOTSUP ); + + /* + * OpenGroup says that you are supposed to return EINVAL if the + * sum of the iov_len values in the iov array would overflow a + * ssize_t. + * + * Also we would like to ensure that no IO is performed if there + * are obvious errors in the iovec. So this extra loop ensures + * that we do not do anything if there is an argument error. + * + * In addition,the OpenGroup specification says that if all the + * iov_len entries are zero, then the call has no effect. So + * this loop does that check as well and sets "all-zero" appropriately. + * The variable "all_zero" is used as an early exit point before + * entering the write loop. + */ + all_zeros = TRUE; + for ( old=0, total=0, v=0 ; v < iovcnt ; v++ ) { + + if ( !iov[v].iov_base ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( iov[v].iov_len < 0 ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + if ( iov[v].iov_len ) + all_zeros = FALSE; + + /* check for wrap */ + old = total; + total += iov[v].iov_len; + if ( total < old || total > SSIZE_MAX ) + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* + * A writev with all zeros is supposed to have no effect per OpenGroup. + */ + if ( all_zeros == TRUE ) { + return 0; + } + + /* + * Now process the writev(). + */ + for ( total=0, v=0 ; v < iovcnt ; v++ ) { + /* all zero lengths has no effect */ + if ( iov[v].iov_len == 0 ) + continue; + + bytes = (*iop->handlers->write_h)( iop, iov[v].iov_base, iov[v].iov_len ); + + if ( bytes < 0 ) + return -1; + + if ( bytes > 0 ) { + iop->offset += bytes; + total += bytes; + } + + if (bytes != iov[ v ].iov_len) + break; + } + + return total; +} + |