fix: resolve relative paths for atomic write target (#1564)
Some checks failed
Sync Labels / sync-labels (push) Has been cancelled
Update Issues / update-issues (push) Has been cancelled
Release / Settings (push) Has been cancelled
Release / release (push) Has been cancelled
Release / Compute latest release flag (push) Has been cancelled
Release / Update docs (push) Has been cancelled
Release / Update docker image (push) Has been cancelled
Release / Build (push) Has been cancelled
Release / Artifacts (push) Has been cancelled
Release / Update NPM (push) Has been cancelled

Fixes #1383

This solves an edge case where the target path of an atomic write is
a relative path without a directory part.
In this case, the temporary file was written to the system's tempdir
before, which may then fail the atomic rename as the tempdir often
is on a different device such as tmpfs.
This commit is contained in:
Niklas Korz
2026-03-22 20:19:21 +01:00
committed by GitHub
parent bd1648389b
commit 90a392ed8a

View File

@@ -74,7 +74,19 @@ bool DeleteLocalFile(const char* file_name) {
bool WriteLocalFileAtomically(const char* file_name,
const std::string& contents) {
const auto file_path = std::filesystem::u8path(file_name);
std::error_code ec;
// To atomically move the temporary file to the target location after write,
// they must be on the same device. For relative paths without a directory
// part, the parent path is empty, which fails TempFilePath's empty directory
// path check, thus falling back to /tmp that is on a potentially different
// device. We prevent this by resolving the absolute file path.
const auto file_path =
std::filesystem::absolute(std::filesystem::u8path(file_name), ec);
if (ec) {
LOG(ERROR) << "Failed to resolve file path '" << file_name
<< "', error: " << ec;
return false;
}
const auto dir_path = file_path.parent_path();
std::string temp_file_name;
@@ -83,7 +95,6 @@ bool WriteLocalFileAtomically(const char* file_name,
if (!File::WriteStringToFile(temp_file_name.c_str(), contents))
return false;
std::error_code ec;
auto temp_file_path = std::filesystem::u8path(temp_file_name);
std::filesystem::rename(temp_file_path, file_name, ec);
if (ec) {