Merge pull request #4354 from milescoviello/fix/fopen-append-position

fix(libc): start append-mode streams at the end of the file
This commit is contained in:
Dean 2026-10-13 07:18:50 +13:00 committed by GitHub
commit b538b28d8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 10 additions and 1 deletions

View File

@ -30,6 +30,7 @@ struct GuestFileMode {
std::string native;
bool writes = false;
bool exclusive = false;
bool append = false;
};
static std::optional<GuestFileMode> ParseFileMode(const char* mode) {
@ -42,7 +43,7 @@ static std::optional<GuestFileMode> ParseFileMode(const char* mode) {
if (*flag == 'x') exclusive = true;
}
if (exclusive && access == 'r' && !update) return std::nullopt;
GuestFileMode result{std::string(1, access), access != 'r' || update, exclusive};
GuestFileMode result{std::string(1, access), access != 'r' || update, exclusive, access == 'a'};
if (update) result.native += '+';
#ifdef _WIN32
result.native += 'b';
@ -123,6 +124,7 @@ FileStream* APS5_VABI freopen_nid_postfix(const char* filename, const char* mode
}
}
if (stream->Reopen(path, parsed->native.c_str())) {
if (parsed->append) static_cast<void>(std::fseek(stream->GetHandle(), 0, SEEK_END));
if (!path.empty() && parsed->writes) RecordWrittenPath_nid_no_patch(path);
return stream;
}
@ -168,6 +170,7 @@ FileStream* APS5_VABI fopen_nid_postfix(const char* filename, const char* mode)
throw std::runtime_error(std::string(__func__) + ": " + FOPEN_MSG_OPEN_FAILED + ": \"" + abs_path + "\": " + reason);
}
// APS5_LOG_OUT("success: \"%s\"", abs_path.c_str());
if (parsed->append) static_cast<void>(std::fseek(handle.get(), 0, SEEK_END));
if (parsed->writes) RecordWrittenPath_nid_no_patch(fpath);
auto stream = std::make_unique<FileStream>(handle.get(), true);
handle.release();

View File

@ -295,6 +295,12 @@ static bool CheckBinaryModes() {
FileStream* stream = reopen ? freopen_nid_postfix(filename.c_str(), mode, &redirected) : fopen_nid_postfix(filename.c_str(), mode);
Require(stream != nullptr);
const bool update = std::strchr(mode, '+') != nullptr;
if (*mode == 'a') {
const bool atEnd = ftello_nid_postfix(stream) == static_cast<std::int64_t>(original.size()) &&
(!update || fgetc_nid_postfix(stream) == EOF);
if (!atEnd) std::fprintf(stderr, "%s %s: the append stream does not start at the end of the file\n", reopen ? "freopen" : "fopen", mode);
correct &= atEnd;
}
if (*mode == 'r' || (*mode == 'a' && update)) {
Require(fseeko_nid_postfix(stream, 0, SEEK_SET) == 0);
char bytes[16]{};