diff --git a/libc/src/__support/File/CMakeLists.txt b/libc/src/__support/File/CMakeLists.txt --- a/libc/src/__support/File/CMakeLists.txt +++ b/libc/src/__support/File/CMakeLists.txt @@ -25,6 +25,7 @@ .file libc.include.errno libc.include.fcntl + libc.include.stdio libc.include.sys_syscall libc.src.__support.OSUtil.osutil libc.src.errno.errno diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp --- a/libc/src/__support/File/file.cpp +++ b/libc/src/__support/File/file.cpp @@ -11,6 +11,7 @@ #include "src/__support/CPP/ArrayRef.h" #include +#include #include namespace __llvm_libc { @@ -143,6 +144,11 @@ err = true; return -1; } + } else if (prev_op == FileOp::READ && whence == SEEK_CUR) { + // More data could have been read out from the platform file than was + // required. So, we have to adjust the offset we pass to platform seek + // function. Note that read_limit >= pos is always true. + offset -= (read_limit - pos); } pos = read_limit = 0; prev_op = FileOp::SEEK; diff --git a/libc/test/src/__support/File/file_test.cpp b/libc/test/src/__support/File/file_test.cpp --- a/libc/test/src/__support/File/file_test.cpp +++ b/libc/test/src/__support/File/file_test.cpp @@ -194,6 +194,27 @@ ASSERT_EQ(f->close(), 0); } +TEST(LlvmLibcFileTest, ReadSeekCurAndRead) { + const char initial_content[] = "1234567890987654321"; + constexpr size_t FILE_BUFFER_SIZE = sizeof(initial_content); + char file_buffer[FILE_BUFFER_SIZE]; + StringFile *f = new_string_file(file_buffer, FILE_BUFFER_SIZE, 0, false, "r"); + f->reset_and_fill(initial_content, sizeof(initial_content)); + + constexpr size_t READ_SIZE = 5; + char data[READ_SIZE]; + data[READ_SIZE - 1] = '\0'; + ASSERT_EQ(f->read(data, READ_SIZE - 1), READ_SIZE - 1); + ASSERT_STREQ(data, "1234"); + ASSERT_EQ(f->seek(5, SEEK_CUR), 0); + ASSERT_EQ(f->read(data, READ_SIZE - 1), READ_SIZE - 1); + ASSERT_STREQ(data, "0987"); + ASSERT_EQ(f->seek(-5, SEEK_CUR), 0); + ASSERT_EQ(f->read(data, READ_SIZE - 1), READ_SIZE - 1); + ASSERT_STREQ(data, "9098"); + ASSERT_EQ(f->close(), 0); +} + TEST(LlvmLibcFileTest, AppendOnly) { const char initial_content[] = "1234567890987654321"; const char write_data[] = "append"; diff --git a/libc/test/src/__support/File/platform_file_test.cpp b/libc/test/src/__support/File/platform_file_test.cpp --- a/libc/test/src/__support/File/platform_file_test.cpp +++ b/libc/test/src/__support/File/platform_file_test.cpp @@ -144,6 +144,32 @@ ASSERT_EQ(file->close(), 0); } +TEST(LlvmLibcPlatformFileTest, ReadSeekCurAndRead) { + constexpr char FILENAME[] = "testdata/read_seek_cur_and_read.test"; + File *file = __llvm_libc::openfile(FILENAME, "w"); + ASSERT_FALSE(file == nullptr); + constexpr char CONTENT[] = "1234567890987654321"; + ASSERT_EQ(sizeof(CONTENT) - 1, file->write(CONTENT, sizeof(CONTENT) - 1)); + ASSERT_EQ(0, file->close()); + + file = __llvm_libc::openfile(FILENAME, "r"); + ASSERT_FALSE(file == nullptr); + + constexpr size_t READ_SIZE = 5; + char data[READ_SIZE]; + data[READ_SIZE - 1] = '\0'; + ASSERT_EQ(file->read(data, READ_SIZE - 1), READ_SIZE - 1); + ASSERT_STREQ(data, "1234"); + ASSERT_EQ(file->seek(5, SEEK_CUR), 0); + ASSERT_EQ(file->read(data, READ_SIZE - 1), READ_SIZE - 1); + ASSERT_STREQ(data, "0987"); + ASSERT_EQ(file->seek(-5, SEEK_CUR), 0); + ASSERT_EQ(file->read(data, READ_SIZE - 1), READ_SIZE - 1); + ASSERT_STREQ(data, "9098"); + + ASSERT_EQ(file->close(), 0); +} + TEST(LlvmLibcPlatformFileTest, IncorrectOperation) { constexpr char FILENAME[] = "testdata/incorrect_operation.test"; char data[1] = {123};