diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-23 16:09:59 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-23 16:09:59 -0500 |
| commit | 96a6ba196c72e955c3db822d93da38fce8cd7045 (patch) | |
| tree | 3fcc40e939bd609c4cb7b84f05e85875dde64fc6 /libs/uibase/src/filesystemutilities.cpp | |
| parent | 6b9f0876cfbf6f8c723c86ec941ee70933aa883f (diff) | |
Fix VFS rmdir, prefix/launch issues, add version + beta channel
- VFS: add mo2_rmdir + OverwriteManager::removeDirectory so Wrye Bash
shutil.rmtree stops failing with WinError 267 (issue #47).
- FileRenamer: case-insensitive fallback via new resolvePathCaseInsensitive
walks each path component; bulk hide in Conflict tab no longer dies with
a misleading "Input/output error" when DirectoryEntry normalised parent
dir case (issue #54). formatSystemMessage stops aliasing Windows error
code 5 to errno 5 (EIO).
- Versioning: FLUORINE_VERSION_* + fluorine_build_info.h generated from
CMake; Linux createVersionInfo returns Fluorine's version. About dialog
shows Fluorine version + MO2 engine + commit. Beta builds stamp
"<semver>B<yyyymmddhhmm>" (issue #51).
- CI: ci.yml determines channel from ref (v* tags = stable, main = beta),
publishes a rolling `beta` GitHub release whose body carries a
machine-parseable fluorine-meta block (timestamp, commit) for the
in-app updater.
- Updater: new FluorineUpdater polls GitHub API on startup, compares
against embedded metadata, notifies on new release without auto-install.
Channel toggle piggybacks on the existing "beta versions" checkbox.
- Bethesda plugins: determineMyGamesPath no longer creates
Documents/My Games/<GameName> for every possible title at plugin load;
only games with a detected install path get their dirs created
(issue #55).
- Starfield: dataDirectory() on Linux now points at <game>/Data instead
of My Games/Starfield/Data so the single FUSE mount lands where SFSE
loads plugins; My Games Data becomes a secondary symlinked mapping
(issue #56).
- Prefix resolution: prefer Fluorine config, then explicit
fluorine/prefix_path, then legacy Settings/* keys (with a warning) so
auto-detected Heroic/Bottles prefixes can't silently override a user-
configured Fluorine prefix (issue #52). compatDataPathFromPrefix no
longer hands Proton the wrong parent dir for plain wine prefixes.
- xrandr: ensureXrandrInstalled back-fills the helper for existing SLR
installs, prefix init runs it before wineboot, SLR wrap exposes
xrandr-bin via --filesystem= and prepends PATH inside the container
(issue #49).
- Process tracking: drop the wineserver-as-last-resort fallback that made
MO2 hang on Proton's session manager after game exit. Rescan the prefix
for matching game executables instead (covers reparented launcher
children like f4se_loader → Fallout4.exe). Unlock button now kills
wineserver for the prefix (SIGTERM then SIGKILL on timeout).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'libs/uibase/src/filesystemutilities.cpp')
| -rw-r--r-- | libs/uibase/src/filesystemutilities.cpp | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/libs/uibase/src/filesystemutilities.cpp b/libs/uibase/src/filesystemutilities.cpp index b027f5f..ba05699 100644 --- a/libs/uibase/src/filesystemutilities.cpp +++ b/libs/uibase/src/filesystemutilities.cpp @@ -95,4 +95,61 @@ QString resolveFileCaseInsensitive(const QString& path) #endif } +QString resolvePathCaseInsensitive(const QString& path) +{ +#ifdef _WIN32 + return QDir::cleanPath(path); +#else + const QString clean = QDir::cleanPath(path); + if (QFileInfo::exists(clean)) { + return clean; + } + + // Walk each component and match case-insensitively against the real + // filesystem. Stops as soon as a component has no case-insensitive match; + // returns the cleaned input in that case. + const QString prefix = clean.startsWith('/') ? QStringLiteral("/") : QString(); + const QStringList parts = + clean.split('/', Qt::SkipEmptyParts); + + QString current = prefix; + for (int i = 0; i < parts.size(); ++i) { + const QString& want = parts[i]; + const QString next = current.isEmpty() ? want : current + '/' + want; + + if (QFileInfo::exists(next)) { + current = next; + continue; + } + + QDir dir(current.isEmpty() ? QStringLiteral(".") : current); + if (!dir.exists()) { + return clean; + } + + const QDir::Filters filters = (i + 1 < parts.size()) + ? (QDir::Dirs | QDir::NoDotAndDotDot | + QDir::Hidden | QDir::System) + : (QDir::Dirs | QDir::Files | + QDir::NoDotAndDotDot | QDir::Hidden | + QDir::System); + + bool matched = false; + for (const QString& entry : dir.entryList(filters)) { + if (entry.compare(want, Qt::CaseInsensitive) == 0) { + current = current.isEmpty() ? entry : current + '/' + entry; + matched = true; + break; + } + } + + if (!matched) { + return clean; + } + } + + return current; +#endif +} + } // namespace MOBase |
