summaryrefslogtreecommitdiff
path: root/file_io/win32/seek.c
diff options
context:
space:
mode:
authorivan <ivan@13f79535-47bb-0310-9956-ffa450edef68>2017-03-27 13:33:54 +0000
committerivan <ivan@13f79535-47bb-0310-9956-ffa450edef68>2017-03-27 13:33:54 +0000
commit356e5599bbc356238aa2b9cecbf9addb079ed54c (patch)
tree741743640d377749686d7a6d3a4c66f3b0e89ef8 /file_io/win32/seek.c
parente078efa9f43a8bda0b5c470120e4ea93fa3f53c6 (diff)
downloadlibapr-356e5599bbc356238aa2b9cecbf9addb079ed54c.tar.gz
Fix two issues with apr_file_trunc() for buffered files:
- The Win32 implementation incorrectly flushes the buffered writes _after_ truncating a file. Such files will have unexpected data written after the position at which they should've been truncated. PR 51017. (Under Unix, this issue has been fixed in r1044440) - Both Win32 and Unix implementations incorrectly keep the data read into a buffer after the file is truncated. Thus, reading from a file after apr_file_trunc() can return invalid data from the previous file offset. * file_io/win32/seek.c (apr_file_trunc): Flush the write buffer or discard the read buffer before truncating. Propely update the internal file offset (filePtr) and the eof_hit marker. * file_io/unix/seek.c (apr_file_trunc): Discard the read buffer before truncating. * test/testfile.c (test_file_trunc): Extend the checks. Factor out part of this test... (test_file_trunc_buffered_write): ...into this new test. (test_file_trunc_buffered_write2, test_file_trunc_buffered_read): New tests. (testfile): Run the new tests. Patch by: Evgeny Kotkov <evgeny.kotkov {at} visualsvn.com> git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1788929 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'file_io/win32/seek.c')
-rw-r--r--file_io/win32/seek.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/file_io/win32/seek.c b/file_io/win32/seek.c
index b412fd4cb..afe6edb00 100644
--- a/file_io/win32/seek.c
+++ b/file_io/win32/seek.c
@@ -161,17 +161,43 @@ APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *thefile, apr_off_t offset)
LONG offhi = (LONG)(offset >> 32);
DWORD rc;
+ if (thefile->buffered) {
+ if (thefile->direction == 1) {
+ /* Figure out what needs to be flushed. Don't flush the part
+ * of the write buffer that will get truncated anyway.
+ */
+ if (offset < thefile->filePtr) {
+ thefile->bufpos = 0;
+ }
+ else if (offset < thefile->filePtr + (apr_off_t)thefile->bufpos) {
+ thefile->bufpos = offset - thefile->filePtr;
+ }
+
+ if (thefile->bufpos != 0) {
+ rv = apr_file_flush(thefile);
+ if (rv != APR_SUCCESS)
+ return rv;
+ }
+ }
+ else if (thefile->direction == 0) {
+ /* Discard the read buffer, as we are about to reposition
+ * ourselves to the end of file.
+ */
+ thefile->bufpos = 0;
+ thefile->dataRead = 0;
+ }
+ }
+
rc = SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN);
if (rc == 0xFFFFFFFF)
if ((rv = apr_get_os_error()) != APR_SUCCESS)
return rv;
+ thefile->filePtr = offset;
+ /* Don't report EOF until the next read. */
+ thefile->eof_hit = 0;
if (!SetEndOfFile(thefile->filehand))
return apr_get_os_error();
- if (thefile->buffered) {
- return setptr(thefile, offset);
- }
-
return APR_SUCCESS;
}