Keep Replacing a Read-Only Config and Include What the Helpers Need Everywhere

The config was always replaced by a rename, never written in place, so
the write helper's refusal of a read-only target, right for the presets
it mirrors, stopped a read-only OrcaSlicer.conf from ever being saved
again. The helper takes an explicit opt-in to replace such a file, and
the two config save variants share one writer that uses it.

The identity helper's stat headers were included only under the Linux
guard, which the Linux-only build never noticed; they are included on
every platform now. A temporary the longer name pushes past the path
limit is written in place like one refused for permissions, the rename
retry that waits for a Windows reader runs on Windows only, a failing
stat in the sweep skips that entry rather than ending the sweep, and the
rename fallback no longer stats the target it is about to remove.
This commit is contained in:
Hanif Koh
2026-09-24 21:32:30 +08:00
parent 758b802dec
commit dda6646c49
5 changed files with 77 additions and 57 deletions
+19
View File
@@ -111,6 +111,25 @@ TEST_CASE("write_file_atomically refuses a read-only target and leaves it untouc
REQUIRE(content == "pinned");
}
TEST_CASE("write_file_atomically replaces a read-only target when asked to", "[Utils]") {
#ifndef _WIN32
if (::geteuid() == 0)
SKIP("a read-only file does not stop root");
#endif
ScopedTemporaryDir dir;
const boost::filesystem::path target = dir.path() / "pinned.json";
REQUIRE_FALSE(write_file_atomically(target.string(), "pinned"));
boost::filesystem::permissions(target, boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read);
const std::error_code ec = write_file_atomically(target.string(), "replaced", false, /*replace_read_only=*/true);
boost::filesystem::permissions(target, boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read);
REQUIRE_FALSE(ec);
std::string content;
load_string_file(target, content);
REQUIRE(content == "replaced");
}
TEST_CASE("write_file_atomically keeps bytes intact in binary mode", "[Utils]") {
ScopedTemporaryDir dir;
const boost::filesystem::path target = dir.path() / "blob.bin";