diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-12-16 13:12:22 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-12-20 10:31:53 +0100 |
commit | 95a57280ebc3996547fccd6065a5652a846d1447 (patch) | |
tree | 9a39803381927d9acf8b426ff995248455b19184 | |
parent | arm/gba: doxygen improvement (diff) | |
download | rtems-95a57280ebc3996547fccd6065a5652a846d1447.tar.bz2 |
libcsupport: Add and use rtems_libio_iovec_eval()
-rw-r--r-- | cpukit/libcsupport/include/rtems/libio_.h | 56 | ||||
-rw-r--r-- | cpukit/libcsupport/src/readv.c | 88 | ||||
-rw-r--r-- | cpukit/libcsupport/src/writev.c | 98 | ||||
-rw-r--r-- | testsuites/psxtests/psxrdwrv/psxrdwrv.scn | 8 | ||||
-rw-r--r-- | testsuites/psxtests/psxrdwrv/test.c | 33 |
5 files changed, 122 insertions, 161 deletions
diff --git a/cpukit/libcsupport/include/rtems/libio_.h b/cpukit/libcsupport/include/rtems/libio_.h index bf01cd5659..995d621f79 100644 --- a/cpukit/libcsupport/include/rtems/libio_.h +++ b/cpukit/libcsupport/include/rtems/libio_.h @@ -21,7 +21,9 @@ #ifndef _RTEMS_RTEMS_LIBIO__H #define _RTEMS_RTEMS_LIBIO__H +#include <sys/uio.h> #include <errno.h> +#include <limits.h> #include <rtems.h> #include <rtems/libio.h> @@ -839,6 +841,60 @@ static inline bool rtems_filesystem_is_parent_directory( return tokenlen == 2 && token [0] == '.' && token [1] == '.'; } +static inline ssize_t rtems_libio_iovec_eval( + int fd, + const struct iovec *iov, + int iovcnt, + uint32_t flags, + rtems_libio_t **iopp +) +{ + ssize_t total; + int v; + rtems_libio_t *iop; + + rtems_libio_check_fd( fd ); + iop = rtems_libio_iop( fd ); + rtems_libio_check_is_open( iop ); + rtems_libio_check_permissions_with_error( iop, flags, EBADF ); + + *iopp = iop; + + /* + * Argument validation on IO vector + */ + if ( iov == NULL ) + 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 ); + + /* + * 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. + */ + total = 0; + for ( v = 0 ; v < iovcnt ; ++v ) { + size_t len = iov[ v ].iov_len; + + if ( len > ( size_t ) ( SSIZE_MAX - total ) ) { + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + total += ( ssize_t ) len; + + if ( iov[ v ].iov_base == NULL ) { + rtems_set_errno_and_return_minus_one( EINVAL ); + } + } + + return total; +} + /** @} */ #ifdef __cplusplus diff --git a/cpukit/libcsupport/src/readv.c b/cpukit/libcsupport/src/readv.c index 2ff7f63767..e47f22850a 100644 --- a/cpukit/libcsupport/src/readv.c +++ b/cpukit/libcsupport/src/readv.c @@ -18,11 +18,9 @@ #include "config.h" #endif -#include <sys/types.h> #include <sys/uio.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> /** * readv() - POSIX 1003.1 - Read a Vector @@ -39,86 +37,30 @@ ssize_t readv( { ssize_t total; int v; - int bytes; rtems_libio_t *iop; - bool all_zeros; - rtems_libio_check_fd( fd ); - iop = rtems_libio_iop( fd ); - rtems_libio_check_is_open( iop ); - rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_READ, EBADF ); - - /* - * 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 ); - - /* - * 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. - */ - - all_zeros = true; - for ( total=0, v=0 ; v < iovcnt ; v++ ) { - ssize_t old; + total = rtems_libio_iovec_eval( fd, iov, iovcnt, LIBIO_FLAGS_READ, &iop ); + if ( total > 0 ) { /* - * iov[v].iov_len cannot be less than 0 because size_t is unsigned. - * So we only check for zero. + * Now process the readv(). */ - if ( iov[v].iov_base == 0 ) - rtems_set_errno_and_return_minus_one( EINVAL ); + total = 0; + for ( v = 0 ; v < iovcnt ; v++ ) { + ssize_t bytes = ( *iop->pathinfo.handlers->read_h )( + iop, + iov[ v ].iov_base, + iov[ v ].iov_len + ); - /* check for wrap */ - old = total; - total += iov[v].iov_len; - if ( total < old ) - rtems_set_errno_and_return_minus_one( EINVAL ); + if ( bytes < 0 ) + return -1; - if ( iov[v].iov_len ) - all_zeros = false; - } + total += bytes; - /* - * A readv with all zeros logically has no effect. Even though - * OpenGroup didn't address this case as they did with writev(), - * we will handle it the same way for symmetry. - */ - if ( all_zeros == true ) { - return 0; - } - - /* - * Now process the readv(). - */ - for ( total=0, v=0 ; v < iovcnt ; v++ ) { - bytes = (*iop->pathinfo.handlers->read_h)( - iop, - iov[v].iov_base, - iov[v].iov_len - ); - - if ( bytes < 0 ) - return -1; - - if ( bytes > 0 ) { - total += bytes; + if ( bytes != iov[ v ].iov_len ) + break; } - - if (bytes != iov[ v ].iov_len) - break; } return total; diff --git a/cpukit/libcsupport/src/writev.c b/cpukit/libcsupport/src/writev.c index 47605a4cd9..4a8dc735b8 100644 --- a/cpukit/libcsupport/src/writev.c +++ b/cpukit/libcsupport/src/writev.c @@ -1,5 +1,5 @@ /* - * writev() - POSIX 1003.1 - Read a Vector + * writev() - POSIX 1003.1 - Write a Vector * * OpenGroup URL: * @@ -17,11 +17,9 @@ #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, @@ -31,95 +29,31 @@ ssize_t writev( { ssize_t total; int v; - int bytes; rtems_libio_t *iop; - ssize_t old; - bool all_zeros; - rtems_libio_check_fd( fd ); - iop = rtems_libio_iop( fd ); - rtems_libio_check_is_open( iop ); - rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_WRITE, EBADF ); - - /* - * 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 ); - - /* - * 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++ ) { + total = rtems_libio_iovec_eval( fd, iov, iovcnt, LIBIO_FLAGS_WRITE, &iop ); + if ( total > 0 ) { /* - * iov[v].iov_len cannot be less than 0 because size_t is unsigned. - * So we only check for zero. + * Now process the writev(). */ - if ( iov[v].iov_base == 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; - } + total = 0; + for ( v = 0 ; v < iovcnt ; v++ ) { + ssize_t bytes = ( *iop->pathinfo.handlers->write_h )( + iop, + iov[ v ].iov_base, + iov[ v ].iov_len + ); - /* - * 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; + if ( bytes < 0 ) + return -1; - bytes = (*iop->pathinfo.handlers->write_h)( - iop, - iov[v].iov_base, - iov[v].iov_len - ); + total += bytes; - if ( bytes < 0 ) - return -1; - - if ( bytes > 0 ) { - total += bytes; + if ( bytes != iov[ v ].iov_len ) + break; } - - if (bytes != iov[ v ].iov_len) - break; } return total; } - diff --git a/testsuites/psxtests/psxrdwrv/psxrdwrv.scn b/testsuites/psxtests/psxrdwrv/psxrdwrv.scn index 26e1ea5ac9..7d070eabdd 100644 --- a/testsuites/psxtests/psxrdwrv/psxrdwrv.scn +++ b/testsuites/psxtests/psxrdwrv/psxrdwrv.scn @@ -3,16 +3,20 @@ writev bad file descriptor -- EBADF readv bad file descriptor -- EBADF writev bad iovec pointer -- EINVAL readv bad iovec pointer -- EINVAL -readv bad iovcnt of 0 -- EINVAL +writev bad iovcnt of 0 -- EINVAL readv bad iovcnt of 0 -- EINVAL writev bad iovcnt negative -- EINVAL readv bad iovcnt negative -- EINVAL writev bad iov[i].iov_base -- EINVAL readv bad iov[i].iov_base -- EINVAL writev bad iov[i].iov_len < 0 -- EINVAL -readv bad iov[i].iov_len = 0 -- EINVAL +readv bad iov[i].iov_len < 0 -- EINVAL writev iov_len total overflows -- EINVAL readv iov_len total overflows -- EINVAL +writev iov_len works with no effect -- OK +readv iov_len works with no effect -- OK +readv bad iovcnt of IOV_MAX + 1 -- EINVAL +writev bad iovcnt of IOV_MAX + 1 -- EINVAL File written using writev .. OK File read using readv .. OK *** END OF TEST PSXRDWRV *** diff --git a/testsuites/psxtests/psxrdwrv/test.c b/testsuites/psxtests/psxrdwrv/test.c index cedca900a9..0e066746a9 100644 --- a/testsuites/psxtests/psxrdwrv/test.c +++ b/testsuites/psxtests/psxrdwrv/test.c @@ -27,6 +27,7 @@ #include <utime.h> #include <string.h> #include <inttypes.h> +#include <limits.h> #include <stdio.h> #include <unistd.h> @@ -217,6 +218,7 @@ int doErrorTest(void) } fd = fileno(fp); +#ifdef __rtems__ /* writev -- bad iovec pointer */ puts("writev bad iovec pointer -- EINVAL"); rc = writev(fd, NULL, 4); @@ -236,7 +238,7 @@ int doErrorTest(void) } /* writev -- bad iovcnt 0 */ - puts("readv bad iovcnt of 0 -- EINVAL"); + puts("writev bad iovcnt of 0 -- EINVAL"); rc = writev(fd, vec, 0); if ( (rc != -1) || (errno != EINVAL) ) { printf( "writev error 3: %d=%s\n", errno, strerror(errno) ); @@ -252,6 +254,7 @@ int doErrorTest(void) fclose(fp); return FALSE; } +#endif /* __rtems__ */ /* writev -- bad iovcnt negative */ puts("writev bad iovcnt negative -- EINVAL"); @@ -271,6 +274,7 @@ int doErrorTest(void) return FALSE; } +#ifdef __rtems__ /* writev -- bad iov[i].iov_base */ vec[0].iov_base = vec; vec[0].iov_len = 100; @@ -296,6 +300,7 @@ int doErrorTest(void) fclose(fp); return FALSE; } +#endif /* __rtems__ */ /* writev -- bad iov[i].iov_len < 0 */ vec[0].iov_base = vec; @@ -310,12 +315,12 @@ int doErrorTest(void) return FALSE; } - /* readv -- bad iov[i].iov_len = 0 */ + /* readv -- bad iov[i].iov_len < 0 */ vec[0].iov_base = vec; vec[0].iov_len = 100; vec[1].iov_base = vec; vec[1].iov_len = -1024; - puts("readv bad iov[i].iov_len = 0 -- EINVAL"); + puts("readv bad iov[i].iov_len < 0 -- EINVAL"); rc = readv(fd, vec, 2); if ( (rc != -1) || (errno != EINVAL) ) { printf( "readv error 6: %d=%s\n", errno, strerror(errno) ); @@ -343,8 +348,10 @@ int doErrorTest(void) vec[0].iov_len = SIZE_MAX; vec[1].iov_base = vec; vec[1].iov_len = SIZE_MAX; + vec[2].iov_base = vec; + vec[2].iov_len = SIZE_MAX; puts("readv iov_len total overflows -- EINVAL"); - rc = readv(fd, vec, 2); + rc = readv(fd, vec, 3); if ( (rc != -1) || (errno != EINVAL) ) { printf( "read error 7: rc=%d %d=%s\n", rc, errno, strerror(errno) ); fclose(fp); @@ -377,6 +384,24 @@ int doErrorTest(void) return FALSE; } +#ifdef __rtems__ + puts("readv bad iovcnt of IOV_MAX + 1 -- EINVAL"); + rc = readv(fd, vec, IOV_MAX + 1); + if ( (rc != -1) || (errno != EINVAL) ) { + printf( "readv error 9: %d=%s\n", errno, strerror(errno) ); + fclose(fp); + return FALSE; + } + + puts("writev bad iovcnt of IOV_MAX + 1 -- EINVAL"); + rc = writev(fd, vec, IOV_MAX + 1); + if ( (rc != -1) || (errno != EINVAL) ) { + printf( "writev error 9: %d=%s\n", errno, strerror(errno) ); + fclose(fp); + return FALSE; + } +#endif /* __rtems__ */ + fclose(fp); return TRUE; } |