summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpquerna <pquerna@13f79535-47bb-0310-9956-ffa450edef68>2004-12-05 02:17:30 +0000
committerpquerna <pquerna@13f79535-47bb-0310-9956-ffa450edef68>2004-12-05 02:17:30 +0000
commitb4f4f12975476cc57b8163abe0bcf937b83330f5 (patch)
tree6eb56cab80b162bb7728ad44750c68a8300fed53
parent6ce9594ae922941baa68b477f279d4c67c0937ab (diff)
downloadlibapr-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--CHANGES3
-rw-r--r--file_io/unix/fullrw.c34
-rw-r--r--file_io/unix/readwrite.c2
-rw-r--r--include/apr_file_io.h34
-rw-r--r--test/Makefile.in3
-rw-r--r--test/testfile.c37
6 files changed, 112 insertions, 1 deletions
diff --git a/CHANGES b/CHANGES
index 169d94810..51e310842 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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);