summaryrefslogtreecommitdiff
path: root/Libraries/LibC
diff options
context:
space:
mode:
authorSergey Bugaev <bugaevc@serenityos.org>2020-05-22 19:35:47 +0300
committerAndreas Kling <kling@serenityos.org>2020-05-22 18:58:36 +0200
commitf03e4520853b55af87cfeb4a5b50b620ccd3bb52 (patch)
treea9d1bb8c3359b835e842bf8f090b4f9429d3a9ec /Libraries/LibC
parent799f6f4ec63e13f2407a6fa1920136553d2e1635 (diff)
downloadserenity-f03e4520853b55af87cfeb4a5b50b620ccd3bb52.zip
LibC: Sync file position when dropping read ahead buffer
When we flush a FILE, we behave differently depending on whether we reading from the file or writing to it: * If we're writing, we actually write out the buffered data. * If we're reading, we just drop the buffered (read ahead) data. After flushing, there should be no additional buffered state stdio keeps about a FILE, compared to what is true about the underlying file. This includes file position (offset). When flushing writes, this is taken care of automatically, but dropping the buffer is not enough to achieve that when reading. This commit fixes that by seeking back explicitly in that case. One way the problem manifested itself was upon fseek(SEEK_CUR) calls, as the position of the underlying file was oftentimes different to the logical position of the FILE. Since FILE::seek() already calls FILE::flush() prior to actually modifying the position, fixing FILE::flush() to sync the positions is enough to fix that issue.
Diffstat (limited to 'Libraries/LibC')
-rw-r--r--Libraries/LibC/stdio.cpp27
1 files changed, 27 insertions, 0 deletions
diff --git a/Libraries/LibC/stdio.cpp b/Libraries/LibC/stdio.cpp
index e59fe96891..0bd0f0e679 100644
--- a/Libraries/LibC/stdio.cpp
+++ b/Libraries/LibC/stdio.cpp
@@ -92,6 +92,7 @@ private:
bool may_use() const { return m_ungotten || m_mode != _IONBF; }
bool is_not_empty() const { return m_ungotten || !m_empty; }
+ size_t buffered_size() const;
const u8* begin_dequeue(size_t& available_size) const;
void did_dequeue(size_t actual_size);
@@ -172,7 +173,20 @@ bool FILE::flush()
}
if (m_mode & O_RDONLY) {
// When open for reading, just drop the buffered data.
+ size_t had_buffered = m_buffer.buffered_size();
m_buffer.drop();
+ // Attempt to reset the underlying file position to what the user
+ // expects.
+ int rc = lseek(m_fd, -had_buffered, SEEK_CUR);
+ if (rc < 0) {
+ if (errno == ESPIPE) {
+ // We can't set offset on this file; oh well, the user will just
+ // have to cope.
+ errno = 0;
+ } else {
+ return false;
+ }
+ }
}
return true;
@@ -440,6 +454,19 @@ void FILE::Buffer::drop()
m_ungotten = false;
}
+size_t FILE::Buffer::buffered_size() const
+{
+ // Note: does not include the ungetc() buffer.
+
+ if (m_empty)
+ return 0;
+
+ if (m_begin < m_end)
+ return m_end - m_begin;
+ else
+ return m_capacity - (m_begin - m_end);
+}
+
const u8* FILE::Buffer::begin_dequeue(size_t& available_size) const
{
if (m_ungotten) {