fix(daemon): replace the embedded daemon even when the old binary is locked
When a newer wallet build embeds a newer daemon, extractEmbeddedResources() detects the size change and tries to overwrite dragonxd.exe in the daemon dir — but the write is a plain truncating ofstream, which fails silently if the file is locked. A running (or just-killed, handle-not-yet-released) daemon locks the .exe on Windows (and Linux returns ETXTBSY), so the stale binary was kept and the wallet kept launching the old daemon version. If the direct write fails, move the stale binary aside to "<name>.old" (renaming a running/locked executable is permitted on both Windows and Linux — the running process keeps the moved copy) and write the fresh one at the original path. A best-effort pass removes leftover .old files once the old process has exited. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -274,8 +274,30 @@ static bool extractResource(const EmbeddedResource* res, const std::string& dest
|
|||||||
// Write file
|
// Write file
|
||||||
std::ofstream file(destPath, std::ios::binary);
|
std::ofstream file(destPath, std::ios::binary);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
DEBUG_LOGF("[ERROR] Failed to open %s for writing\n", destPath.c_str());
|
// The destination may be locked because the previous daemon is still using the binary:
|
||||||
return false;
|
// Windows locks a running .exe against truncation, Linux returns ETXTBSY. Both platforms
|
||||||
|
// DO allow renaming/moving such a file — the running process keeps the moved copy — so move
|
||||||
|
// the stale binary aside and write a fresh one at the original path.
|
||||||
|
std::error_code ec;
|
||||||
|
if (std::filesystem::exists(destPath)) {
|
||||||
|
std::string sidelined = destPath + ".old";
|
||||||
|
std::filesystem::remove(sidelined, ec); // clear any leftover from a prior swap
|
||||||
|
ec.clear();
|
||||||
|
std::filesystem::rename(destPath, sidelined, ec);
|
||||||
|
if (!ec) {
|
||||||
|
file.clear();
|
||||||
|
file.open(destPath, std::ios::binary);
|
||||||
|
if (file)
|
||||||
|
DEBUG_LOGF("[INFO] Replaced in-use %s (old copy moved to .old)\n", destPath.c_str());
|
||||||
|
} else {
|
||||||
|
DEBUG_LOGF("[WARN] Could not move stale %s aside: %s\n",
|
||||||
|
destPath.c_str(), ec.message().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!file) {
|
||||||
|
DEBUG_LOGF("[ERROR] Failed to open %s for writing\n", destPath.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file.write(reinterpret_cast<const char*>(res->data), res->size);
|
file.write(reinterpret_cast<const char*>(res->data), res->size);
|
||||||
@@ -413,7 +435,18 @@ bool extractEmbeddedResources()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Best-effort cleanup of any ".old" binaries left behind by a previous in-use replacement.
|
||||||
|
// Once the old daemon/xmrig process has exited, the file is no longer locked and removes cleanly;
|
||||||
|
// if it's still running, the remove fails harmlessly and we retry on the next startup.
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
for (const char* name : { RESOURCE_DRAGONXD, RESOURCE_XMRIG }) {
|
||||||
|
std::filesystem::remove(daemonDir + pathSep + name + std::string(".old"), ec);
|
||||||
|
ec.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user