summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbojan <bojan@13f79535-47bb-0310-9956-ffa450edef68>2007-05-11 02:11:25 +0000
committerbojan <bojan@13f79535-47bb-0310-9956-ffa450edef68>2007-05-11 02:11:25 +0000
commit567718da876063aeb57ae5d884c7799f762e66ec (patch)
treeec42b4e701e7a9e40503b21e78678e477b43028e
parent0054746b016c46cf445f3023ad8b37e7a6495424 (diff)
downloadlibapr-567718da876063aeb57ae5d884c7799f762e66ec.tar.gz
The file pointer position must be recalculated and set when writev()ing to a
buffered file. Fix by Davi Arnaut for bug #40963 git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@537066 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--file_io/unix/readwrite.c9
-rw-r--r--test/testfile.c39
2 files changed, 48 insertions, 0 deletions
diff --git a/file_io/unix/readwrite.c b/file_io/unix/readwrite.c
index 3511846d9..412d7c8ba 100644
--- a/file_io/unix/readwrite.c
+++ b/file_io/unix/readwrite.c
@@ -252,6 +252,15 @@ APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iove
if (rv != APR_SUCCESS) {
return rv;
}
+ if (thefile->direction == 0) {
+ /* Position file pointer for writing at the offset we are
+ * logically reading from
+ */
+ apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
+ if (offset != thefile->filePtr)
+ lseek(thefile->filedes, offset, SEEK_SET);
+ thefile->bufpos = thefile->dataRead = 0;
+ }
}
#ifdef HAVE_WRITEV
diff --git a/test/testfile.c b/test/testfile.c
index df63d081f..9f24dcc54 100644
--- a/test/testfile.c
+++ b/test/testfile.c
@@ -715,6 +715,44 @@ static void test_writev_buffered(abts_case *tc, void *data)
strlen(TESTSTR) + strlen(LINE1) + strlen(LINE2));
}
+static void test_writev_buffered_seek(abts_case *tc, void *data)
+{
+ apr_file_t *f;
+ apr_status_t rv;
+ apr_off_t off = 0;
+ struct iovec vec[3];
+ apr_size_t nbytes = strlen(TESTSTR);
+ char *str = apr_pcalloc(p, nbytes+1);
+ const char *fname = "data/testwritev_buffered.dat";
+
+ APR_ASSERT_SUCCESS(tc, "open file for writing",
+ apr_file_open(&f, fname,
+ APR_WRITE | APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT, p));
+
+ rv = apr_file_read(f, str, &nbytes);
+ ABTS_STR_EQUAL(tc, TESTSTR, str);
+ APR_ASSERT_SUCCESS(tc, "buffered seek", apr_file_seek(f, APR_SET, &off));
+
+ 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 = TESTSTR;
+ vec[2].iov_len = strlen(TESTSTR);
+
+ APR_ASSERT_SUCCESS(tc, "writev of size 2 to file",
+ apr_file_writev(f, vec, 3, &nbytes));
+
+ APR_ASSERT_SUCCESS(tc, "close for writing",
+ apr_file_close(f));
+
+ file_contents_equal(tc, fname, LINE1 LINE2 TESTSTR,
+ strlen(LINE1) + strlen(LINE2) + strlen(TESTSTR));
+
+ APR_ASSERT_SUCCESS(tc, "remove file", apr_file_remove(fname, p));
+}
+
static void test_truncate(abts_case *tc, void *data)
{
apr_status_t rv;
@@ -941,6 +979,7 @@ abts_suite *testfile(abts_suite *suite)
abts_run_test(suite, test_writev, NULL);
abts_run_test(suite, test_writev_full, NULL);
abts_run_test(suite, test_writev_buffered, NULL);
+ abts_run_test(suite, test_writev_buffered_seek, NULL);
abts_run_test(suite, test_bigread, NULL);
abts_run_test(suite, test_mod_neg, NULL);
abts_run_test(suite, test_truncate, NULL);