aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-03-02 16:42:02 -0600
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-03-02 16:42:02 -0600
commitd08372153cf1479dff11995af56070ff2a52f71d (patch)
treec398c46b6fc3de465bde84223e0da55b41a2e140
parent378d4cdf1501c5ff186f311a2edcdc85a2e03e30 (diff)
Restore game directory permissions after each run
In rare cases (crashes, unclean Wine shutdown), game files can end up read-only. As a precaution, restore owner rwx permissions on all files in the game directory after every run, right after FUSE unmount. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
-rw-r--r--src/src/organizercore.cpp17
1 files changed, 17 insertions, 0 deletions
diff --git a/src/src/organizercore.cpp b/src/src/organizercore.cpp
index 6e95d7e..b7878ce 100644
--- a/src/src/organizercore.cpp
+++ b/src/src/organizercore.cpp
@@ -47,6 +47,7 @@
#include <nak_ffi.h>
#endif
+#include <filesystem>
#include <QApplication>
#include <QCoreApplication>
#include <QDialog>
@@ -2337,6 +2338,22 @@ void OrganizerCore::afterRun(const QFileInfo& binary, DWORD exitCode)
// USVFS is only active while a hooked process is running.
m_USVFS.unmount();
+ // Restore write permissions on the game directory. In rare cases
+ // (crashes, unclean Wine shutdown) file permissions can be changed to
+ // read-only, preventing subsequent launches from working.
+ {
+ const QString gameDir = managedGame()->gameDirectory().absolutePath();
+ namespace fs = std::filesystem;
+ std::error_code ec;
+ for (auto it = fs::recursive_directory_iterator(
+ gameDir.toStdString(), fs::directory_options::skip_permission_denied);
+ it != fs::recursive_directory_iterator(); ++it) {
+ fs::permissions(it->path(),
+ fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec,
+ fs::perm_options::add, ec);
+ }
+ }
+
if (m_CurrentProfile != nullptr) {
const QString prefixPathStr = resolveWinePrefixPath(m_Settings, managedGame());
if (!prefixPathStr.isEmpty()) {