mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
fix(windows): retain runtime authority after cleanup failure
This commit is contained in:
@@ -57,7 +57,9 @@ without this lane reports Windows native controls as unavailable.
|
||||
deduplicated using Windows ordinal comparison, preserving their native Unicode
|
||||
semantics and caller-selected values.
|
||||
- Cleanup walks locked directory objects, removes files by handle, and unlinks
|
||||
reparse entries without traversing their targets. Normal close, cancellation,
|
||||
reparse entries without traversing their targets. Failed removal retains the
|
||||
root and ancestor leases for retry; a partially removed runtime accepts only
|
||||
cleanup, and its registry entry remains until removal succeeds. Normal close, cancellation,
|
||||
startup failure, and timeout release provider resources. Abrupt owner death
|
||||
kills the owned job; it can leave private runtime files for later operator
|
||||
cleanup and does not claim transactional deletion after a crash.
|
||||
|
||||
@@ -86,6 +86,7 @@ struct Runtime : Resource {
|
||||
std::vector<Handle> parents;
|
||||
Handle directory;
|
||||
std::vector<Handle> immutableFiles;
|
||||
bool closing = false;
|
||||
// Main-thread admission is single-flight; only the accepted copy owns the
|
||||
// atomic cancellation flag consumed by its async worker. ERROR_BUSY rejects
|
||||
// another copy before it can reset that flag or replace pending ownership.
|
||||
|
||||
@@ -328,14 +328,11 @@ static void disposeSnapshot(Runtime& root, Handle& file, const std::wstring& pat
|
||||
|
||||
void closeRuntime(Runtime& root) {
|
||||
if (root.closed) return;
|
||||
root.closing = true;
|
||||
// Windows keeps the bearer descriptor and snapshot leases until this owner
|
||||
// cleanup. POSIX removes its consumed descriptor earlier. Abrupt owner death
|
||||
// closes process jobs but cannot run this walk, so private files can remain.
|
||||
root.immutableFiles.clear();
|
||||
struct ReleaseRuntime {
|
||||
Runtime& root;
|
||||
~ReleaseRuntime() { root.directory.reset(); root.parents.clear(); root.closed = true; }
|
||||
} release{root};
|
||||
// Each traversed directory stays locked against replacement. Reparse entries
|
||||
// are unlinked as objects; their targets are never enumerated or deleted.
|
||||
struct Frame {
|
||||
@@ -380,6 +377,10 @@ void closeRuntime(Runtime& root) {
|
||||
frames.push_back(std::make_unique<Frame>(std::move(child), path));
|
||||
else dispose(child.get(), path);
|
||||
}
|
||||
// Failed walks retain the root's identity leases for a later cleanup retry.
|
||||
root.directory.reset();
|
||||
root.parents.clear();
|
||||
root.closed = true;
|
||||
}
|
||||
|
||||
struct SnapshotWork {
|
||||
@@ -528,6 +529,7 @@ napi_value filesystemCall(napi_env env, const std::wstring& operation, const std
|
||||
return result;
|
||||
}
|
||||
auto& root = static_cast<Runtime&>(resource(env, args[0], Kind::Runtime));
|
||||
require(!root.closing || operation == L"runtime_close", "Runtime cleanup is pending", root.path, ERROR_BUSY);
|
||||
if (operation == L"runtime_snapshot_cancel") { root.snapshotCancelled.store(true); return null(env); }
|
||||
require(!root.snapshotPending, "Runtime snapshot is still pending", root.path, ERROR_BUSY);
|
||||
// Reject overlapping operations before snapshot() resets cancellation. The
|
||||
|
||||
Reference in New Issue
Block a user