Atomic IFC file writes to prevent corruption on interrupted save (#4797)

file.write() streamed directly onto the target path, so a crash mid-write
left a truncated file with dangling STEP references. Serialize to a temp
file in the same directory, then atomically rename it onto the target.

- New IfcUtil::path::atomic_rename_file: std::rename on POSIX, MoveFileExW
  with MOVEFILE_REPLACE_EXISTING on Windows. Unlike rename_file it never
  unlinks the destination first, so there is no window where it goes missing.
- Fully in C++/swig (per aothms), so the FILE_NAME header is untouched: it
  comes from the model header, not the output path (verified empirically).
- Temp lives next to the target so the rename stays on one filesystem.
- Stream is closed before the rename (Windows cannot move an open file).
- On any write error the temp is removed and the original target is intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Petru Conduraru
2026-07-07 12:49:08 +03:00
committed by Thomas Krijnen
parent b2d58d0b81
commit 4776bd7639
3 changed files with 69 additions and 5 deletions
+7
View File
@@ -37,6 +37,13 @@ namespace path {
IFC_PARSE_API bool delete_file(const std::string& filename);
IFC_PARSE_API bool rename_file(const std::string& old_filename, const std::string& new_filename);
/// Atomically renames old_filename onto new_filename, replacing an existing
/// destination in a single filesystem operation. Unlike rename_file(), the
/// destination is never unlinked before the rename, so an interruption can
/// never leave the destination missing. This requires both paths to live on
/// the same filesystem. Returns true on success.
IFC_PARSE_API bool atomic_rename_file(const std::string& old_filename, const std::string& new_filename);
#if defined(_MSC_VER) && defined(_UNICODE)
/// Uses windows.h string conversion functions