diff options
author | pquerna <pquerna@13f79535-47bb-0310-9956-ffa450edef68> | 2004-12-05 02:17:30 +0000 |
---|---|---|
committer | pquerna <pquerna@13f79535-47bb-0310-9956-ffa450edef68> | 2004-12-05 02:17:30 +0000 |
commit | b4f4f12975476cc57b8163abe0bcf937b83330f5 (patch) | |
tree | 6eb56cab80b162bb7728ad44750c68a8300fed53 | |
parent | 6ce9594ae922941baa68b477f279d4c67c0937ab (diff) | |
download | libapr-b4f4f12975476cc57b8163abe0bcf937b83330f5.tar.gz |
* file_io/unix/fullrw.c: Add apr_file_writev_full to ensure an iovec is
completely written to the file.
* include/apr_file_io.h: Define APR_MAX_IOVEC_SIZE
Add public def for apr_file_writev_full.
* file_io/unix/readwrite.c: For systems without writev, ensure that they get
the correct number of bytes written.
* test/*: Add a new test for apr_file_writev_full.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@109843 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | file_io/unix/fullrw.c | 34 | ||||
-rw-r--r-- | file_io/unix/readwrite.c | 2 | ||||
-rw-r--r-- | include/apr_file_io.h | 34 | ||||
-rw-r--r-- | test/Makefile.in | 3 | ||||
-rw-r--r-- | test/testfile.c | 37 |
6 files changed, 112 insertions, 1 deletions
@@ -1,5 +1,8 @@ Changes for APR 1.1.0 + *) Add apr_file_writev_full to ensure an entire iovec is writen to a file. + [Paul Querna] + *) apr_file_writev will now at least try to write all iovecs on platforms that do not support writev. [Paul Querna] diff --git a/file_io/unix/fullrw.c b/file_io/unix/fullrw.c index af7b70e38..5412f21af 100644 --- a/file_io/unix/fullrw.c +++ b/file_io/unix/fullrw.c @@ -60,3 +60,37 @@ APR_DECLARE(apr_status_t) apr_file_write_full(apr_file_t *thefile, return status; } + +APR_DECLARE(apr_status_t) apr_file_writev_full(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, + apr_size_t *bytes_written) +{ + apr_status_t status; + apr_size_t total = 0; + + do { + int i; + apr_size_t amt; + status = apr_file_writev(thefile, vec, nvec, &amt); + + /* We assume that writev will only write complete iovec areas. + * Incomplete writes inside a single area are not supported. + * This should be safe according to SuS v2. + */ + for(i = 0; i < nvec; i++) { + total += vec[i].iov_len; + if(total >= amt) { + vec = &vec[i+1]; + nvec -= i+1; + break; + } + } + } while (status == APR_SUCCESS && nvec > 0); + + if (bytes_written != NULL) + *bytes_written = total; + + return status; +} + diff --git a/file_io/unix/readwrite.c b/file_io/unix/readwrite.c index edd692e4b..069adfa96 100644 --- a/file_io/unix/readwrite.c +++ b/file_io/unix/readwrite.c @@ -244,6 +244,8 @@ APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iove int i, tbytes; apr_status_t rv = APR_SUCCESS; + *nbytes = 0; + for(i = 0; i < nvec; i++){ tbytes = vec[i].iov_len; rv = apr_file_write(thefile, vec[i].iov_base, &tbytes); diff --git a/include/apr_file_io.h b/include/apr_file_io.h index 44912434c..9a7b466c8 100644 --- a/include/apr_file_io.h +++ b/include/apr_file_io.h @@ -130,6 +130,22 @@ extern "C" { #define APR_FILE_ATTR_HIDDEN 0x04 /**< File is hidden */ /** @} */ +/** + * @defgroup apr_file_writev{_full} max iovec size + * @{ + */ +#if defined(DOXYGEN) +#define APR_MAX_IOVEC_SIZE 1024 /**< System dependent maximum + size of an iovec array */ +#elif defined(IOV_MAX) +#define APR_MAX_IOVEC_SIZE IOV_MAX +#elif defined(MAX_IOVEC) +#define APR_MAX_IOVEC_SIZE MAX_IOVEC +#else +#define APR_MAX_IOVEC_SIZE 1024 +#endif +/** @} */ + /** File attributes */ typedef apr_uint32_t apr_fileattrs_t; @@ -413,6 +429,24 @@ APR_DECLARE(apr_status_t) apr_file_write_full(apr_file_t *thefile, apr_size_t nbytes, apr_size_t *bytes_written); + +/** + * Write data from iovec array to the specified file, ensuring that all of the + * data is written before returning. + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @param nvec The number of elements in the struct iovec array. This must + * be smaller than APR_MAX_IOVEC_SIZE. If it isn't, the function + * will fail with APR_EINVAL. + * @param nbytes The number of bytes written. + * + * @remark apr_file_writev_full is available even if the underlying + * operating system doesn't provide writev(). + */ +APR_DECLARE(apr_status_t) apr_file_writev_full(apr_file_t *thefile, + const struct iovec *vec, + apr_size_t nvec, + apr_size_t *nbytes); /** * Write a character into the specified file. * @param ch The character to write. diff --git a/test/Makefile.in b/test/Makefile.in index df5f5acf2..ca2910074 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -31,7 +31,8 @@ LOCAL_LIBS=../lib@APR_LIBNAME@.la CLEAN_TARGETS = testfile.tmp mod_test.slo proc_child@EXEEXT@ occhild@EXEEXT@ \ readchild@EXEEXT@ tryread@EXEEXT@ sockchild@EXEEXT@ \ globalmutexchild@EXEEXT@ lfstests/large.bin \ - data/testputs.txt data/testbigfprintf.dat data/testwritev.txt + data/testputs.txt data/testbigfprintf.dat data/testwritev.txt \ + testwritev_full.txt CLEAN_SUBDIRS = internal INCDIR=../include diff --git a/test/testfile.c b/test/testfile.c index d263416c1..55907b77a 100644 --- a/test/testfile.c +++ b/test/testfile.c @@ -595,6 +595,42 @@ static void test_writev(abts_case *tc, void *data) } +static void test_writev_full(abts_case *tc, void *data) +{ + apr_file_t *f; + int nbytes; + struct iovec vec[5]; + const char *fname = "data/testwritev_full.txt"; + + APR_ASSERT_SUCCESS(tc, "open file for writing", + apr_file_open(&f, fname, + APR_WRITE|APR_CREATE|APR_TRUNCATE, + APR_OS_DEFAULT, p)); + + vec[0].iov_base = LINE1; + vec[0].iov_len = strlen(LINE1); + vec[1].iov_base = LINE2; + vec[1].iov_len = strlen(LINE2); + vec[2].iov_base = LINE1; + vec[2].iov_len = strlen(LINE1); + vec[3].iov_base = LINE1; + vec[3].iov_len = strlen(LINE1); + vec[4].iov_base = LINE2; + vec[4].iov_len = strlen(LINE2); + + APR_ASSERT_SUCCESS(tc, "writev_full of size 5 to file", + apr_file_writev_full(f, vec, 5, &nbytes)); + + ABTS_INT_EQUAL(tc, strlen(LINE1)*3 + strlen(LINE2)*2, nbytes); + + APR_ASSERT_SUCCESS(tc, "close for writing", + apr_file_close(f)); + + file_contents_equal(tc, fname, LINE1 LINE2 LINE1 LINE1 LINE2, + strlen(LINE1)*3 + strlen(LINE2)*2); + +} + static void test_truncate(abts_case *tc, void *data) { apr_status_t rv; @@ -691,6 +727,7 @@ abts_suite *testfile(abts_suite *suite) abts_run_test(suite, test_gets, NULL); abts_run_test(suite, test_puts, NULL); abts_run_test(suite, test_writev, NULL); + abts_run_test(suite, test_writev_full, NULL); abts_run_test(suite, test_bigread, NULL); abts_run_test(suite, test_mod_neg, NULL); abts_run_test(suite, test_truncate, NULL); |