diff options
author | ivan <ivan@13f79535-47bb-0310-9956-ffa450edef68> | 2017-03-27 13:33:54 +0000 |
---|---|---|
committer | ivan <ivan@13f79535-47bb-0310-9956-ffa450edef68> | 2017-03-27 13:33:54 +0000 |
commit | 356e5599bbc356238aa2b9cecbf9addb079ed54c (patch) | |
tree | 741743640d377749686d7a6d3a4c66f3b0e89ef8 /file_io/win32/seek.c | |
parent | e078efa9f43a8bda0b5c470120e4ea93fa3f53c6 (diff) | |
download | libapr-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.c | 34 |
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; } |