Fix the package fs seam: UTF-8 paths, GetUserFileName pickers, exclusive-create landing, rollback arm/disarm
Both pickers now ride GetUserFileName (mode 0/1); the "no save picker" premise was false. Landing uses O_EXCL so the create is the existence check, not a TOCTOU pair.
This commit is contained in:
@@ -1,34 +1,45 @@
|
||||
// package_rollback.cpp — see package_rollback.h. The rollback delete below runs
|
||||
// under the ONE carve-out from prune's exclusive file-deletion authority, stated at
|
||||
// src/shell/persist/prune_fs.cpp:5-11; it satisfies that discriminator by
|
||||
// construction — every recorded path was created by this journal's own
|
||||
// writeLandedFile, and the abandoned index mutation means nothing ever referenced it.
|
||||
// package_rollback.cpp — see package_rollback.h. The rollback delete below runs under
|
||||
// the ONE carve-out from prune's exclusive file-deletion authority, stated at
|
||||
// src/shell/persist/prune_fs.cpp:5-11. That discriminator has two clauses and this
|
||||
// journal makes only the FIRST structural: "did this call create it" is guaranteed by
|
||||
// recording exclusively-created paths, but "did anything ever reference it" is a
|
||||
// claim about the caller's ordering — hence markIndexCommitted(), which the import
|
||||
// verb must fire at the index commit so a later rollback() refuses instead of
|
||||
// deleting indexed files.
|
||||
|
||||
#include "shell/package/package_rollback.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "shell/package/package_path.h"
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
bool LandedFileJournal::writeLandedFile(const std::string& absPath,
|
||||
bool LandedFileJournal::writeLandedFile(const std::string& destPath,
|
||||
const PayloadBuffer& payload) {
|
||||
if (payload.empty()) return false;
|
||||
if (indexCommitted_) return false;
|
||||
|
||||
std::error_code ec;
|
||||
if (fs::exists(absPath, ec) || ec) return false;
|
||||
PackageFileWriter writer(absPath);
|
||||
if (!writer.appendPayload(payload)) return false; // dtor aborts; temp removed
|
||||
if (!writer.commit()) return false;
|
||||
const fs::path resolved = fs::absolute(utf8Path(destPath), ec);
|
||||
if (ec) return false;
|
||||
const std::string absPath = resolved.u8string();
|
||||
|
||||
if (!writeFileExclusive(absPath, payload)) return false;
|
||||
paths_.push_back(absPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
RollbackResult LandedFileJournal::rollback() {
|
||||
RollbackResult result;
|
||||
if (indexCommitted_) {
|
||||
result.refused = true;
|
||||
return result;
|
||||
}
|
||||
for (const std::string& path : paths_) {
|
||||
std::error_code ec;
|
||||
const bool removed = fs::remove(path, ec);
|
||||
const bool removed = fs::remove(utf8Path(path), ec);
|
||||
if (removed) ++result.deletedCount;
|
||||
else if (ec) ++result.failedCount;
|
||||
else ++result.alreadyAbsentCount; // no error, nothing there
|
||||
|
||||
Reference in New Issue
Block a user