From 428889a68d67aa4e110b7de9346474e27a4f3ab9 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 19 May 2024 19:35:47 +0300 Subject: [PATCH 1/4] removed + from bad chars in filenames Signed-off-by: Trial97 --- launcher/FileSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index 70704e1d3..22d1ae60c 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -801,7 +801,7 @@ QString NormalizePath(QString path) } } -static const QString BAD_PATH_CHARS = "\"?<>:;*|!+\r\n"; +static const QString BAD_PATH_CHARS = "\"?<>:;*|!\r\n"; static const QString BAD_FILENAME_CHARS = BAD_PATH_CHARS + "\\/"; QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) From a7a1b2876569704e842d942976ce39061ee5e899 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 30 May 2024 13:49:23 +0300 Subject: [PATCH 2/4] improve invalid path name Signed-off-by: Trial97 --- launcher/FileSystem.cpp | 89 +++++++++++++++++-- launcher/MMCZip.cpp | 2 - launcher/minecraft/Library.cpp | 1 + .../flame/FlameInstanceCreationTask.cpp | 2 - launcher/modplatform/flame/FlameModIndex.cpp | 2 - .../modrinth/ModrinthInstanceCreationTask.cpp | 2 - .../modrinth/ModrinthPackIndex.cpp | 2 - launcher/net/HttpMetaCache.cpp | 2 - 8 files changed, 82 insertions(+), 20 deletions(-) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index 22d1ae60c..72df9368a 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -74,6 +74,7 @@ #include #include #else +#include #include #endif @@ -801,25 +802,97 @@ QString NormalizePath(QString path) } } -static const QString BAD_PATH_CHARS = "\"?<>:;*|!\r\n"; -static const QString BAD_FILENAME_CHARS = BAD_PATH_CHARS + "\\/"; +QString removeDuplicates(QString a) +{ + auto b = a.split(""); + b.removeDuplicates(); + return b.join(""); +} + +QString getFileSystemType(const QString& path) +{ + QString fileSystemType; + +#ifdef Q_OS_WIN + wchar_t volume[MAX_PATH + 1] = { 0 }; + if (GetVolumeInformationW((LPCWSTR)path.utf16(), nullptr, 0, nullptr, nullptr, nullptr, volume, MAX_PATH)) { + fileSystemType = QString::fromWCharArray(volume); + } +#elif defined(Q_OS_UNIX) + struct statvfs buf; + if (statvfs(path.toUtf8().constData(), &buf) == 0) { + switch (buf.f_type) { + case 0x4d44: // "MSDOS" + fileSystemType = "FAT32"; + break; + case 0x5346544e: // "NTFS" + fileSystemType = "NTFS"; + break; + case 0x4244: // "HFS+" or "H+" on some systems + case 0x482b: // "HFS+" or "H+" on some systems + fileSystemType = "HFS+"; + break; + case 0x41465342: // "APFS" + fileSystemType = "APFS"; + break; + case 0x65735546: // "exFAT" + fileSystemType = "exFAT"; + break; + default: + break; + } + } +#endif + + return fileSystemType; +} + +static const QString BAD_WIN_CHARS = "\"?<>:*|\r\n"; + +static const QString BAD_FAT32_CHARS = "<>:\"|?*+.,;=[]!"; +static const QString BAD_NTFS_CHARS = "<>:\"|?*"; +static const QString BAD_HFS_CHARS = ":"; +static const QString BAD_EXFAT_CHARS = "<>:\"|?*"; + +static const QString BAD_FILENAME_CHARS = + removeDuplicates(BAD_WIN_CHARS + BAD_FAT32_CHARS + BAD_NTFS_CHARS + BAD_HFS_CHARS + BAD_EXFAT_CHARS) + "\\/"; QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) { for (int i = 0; i < string.length(); i++) if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i))) string[i] = replaceWith; - return string; } -QString RemoveInvalidPathChars(QString string, QChar replaceWith) +QString RemoveInvalidPathChars(QString path, QChar replaceWith) { - for (int i = 0; i < string.length(); i++) - if (string.at(i) < ' ' || BAD_PATH_CHARS.contains(string.at(i))) - string[i] = replaceWith; + QString invalidChars; +#ifdef Q_OS_WIN + invalidChars = BAD_WIN_CHARS; +#endif - return string; + QString fileSystemType = getFileSystemType(QFileInfo(path).absolutePath()); + + if (fileSystemType == "FAT32") { + invalidChars += BAD_FAT32_CHARS; + } else if (fileSystemType == "NTFS") { + invalidChars += BAD_NTFS_CHARS; + } else if (fileSystemType == "HFS+" || fileSystemType == "APFS") { + invalidChars += BAD_HFS_CHARS; + } else if (fileSystemType == "exFAT") { + invalidChars += BAD_EXFAT_CHARS; + } + + if (invalidChars.size() != 0) { + for (int i = 0; i < path.length(); i++) { + if (path.at(i) < ' ' || invalidChars.contains(path.at(i))) { + path[i] = replaceWith; + } + } + } + + return path; } QString DirNameFromString(QString string, QString inDir) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 9a5ae7a9d..9acde90e1 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -288,9 +288,7 @@ std::optional extractSubDir(QuaZip* zip, const QString& subdir, con do { QString file_name = zip->getCurrentFileName(); -#ifdef Q_OS_WIN file_name = FS::RemoveInvalidPathChars(file_name); -#endif if (!file_name.startsWith(subdir)) continue; diff --git a/launcher/minecraft/Library.cpp b/launcher/minecraft/Library.cpp index 2c3f2035f..4e30f72d1 100644 --- a/launcher/minecraft/Library.cpp +++ b/launcher/minecraft/Library.cpp @@ -51,6 +51,7 @@ void Library::getApplicableFiles(const RuntimeContext& runtimeContext, { bool local = isLocal(); auto actualPath = [&](QString relPath) { + relPath = FS::RemoveInvalidPathChars(relPath); QFileInfo out(FS::PathCombine(storagePrefix(), relPath)); if (local && !overridePath.isEmpty()) { QString fileName = out.fileName(); diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index a1f10c156..003203879 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -538,9 +538,7 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop) } for (const auto& result : results) { auto fileName = result.fileName; -#ifdef Q_OS_WIN fileName = FS::RemoveInvalidPathChars(fileName); -#endif auto relpath = FS::PathCombine(result.targetFolder, fileName); if (!result.required && !selectedOptionalMods.contains(relpath)) { diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index 83a28fa2b..1ca9237f4 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -139,9 +139,7 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) -> file.version = Json::requireString(obj, "displayName"); file.downloadUrl = Json::ensureString(obj, "downloadUrl"); file.fileName = Json::requireString(obj, "fileName"); -#ifdef Q_OS_WIN file.fileName = FS::RemoveInvalidPathChars(file.fileName); -#endif ModPlatform::IndexedVersionType::VersionType ver_type; switch (Json::requireInteger(obj, "releaseType")) { diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index e92489999..cbb8e8e67 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -241,9 +241,7 @@ bool ModrinthCreationTask::createInstance() for (auto file : m_files) { auto fileName = file.path; -#ifdef Q_OS_WIN fileName = FS::RemoveInvalidPathChars(fileName); -#endif auto file_path = FS::PathCombine(root_modpack_path, fileName); if (!root_modpack_url.isParentOf(QUrl::fromLocalFile(file_path))) { // This means we somehow got out of the root folder, so abort here to prevent exploits diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 4671a330d..6c3df0902 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -227,9 +227,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t if (parent.contains("url")) { file.downloadUrl = Json::requireString(parent, "url"); file.fileName = Json::requireString(parent, "filename"); -#ifdef Q_OS_WIN file.fileName = FS::RemoveInvalidPathChars(file.fileName); -#endif file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1); auto hash_list = Json::requireObject(parent, "hashes"); diff --git a/launcher/net/HttpMetaCache.cpp b/launcher/net/HttpMetaCache.cpp index 648155412..d8b1c7636 100644 --- a/launcher/net/HttpMetaCache.cpp +++ b/launcher/net/HttpMetaCache.cpp @@ -84,9 +84,7 @@ auto HttpMetaCache::getEntry(QString base, QString resource_path) -> MetaEntryPt auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag) -> MetaEntryPtr { -#ifdef Q_OS_WIN resource_path = FS::RemoveInvalidPathChars(resource_path); -#endif auto entry = getEntry(base, resource_path); // it's not present? generate a default stale entry if (!entry) { From 44a16c1ca1c340d3f7641fa12b0ffe59cdf92992 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 30 May 2024 14:20:35 +0300 Subject: [PATCH 3/4] fix CI Signed-off-by: Trial97 --- launcher/FileSystem.cpp | 84 +++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 53 deletions(-) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index 72df9368a..3ded638ae 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -74,7 +74,6 @@ #include #include #else -#include #include #endif @@ -809,53 +808,13 @@ QString removeDuplicates(QString a) return b.join(""); } -QString getFileSystemType(const QString& path) -{ - QString fileSystemType; - -#ifdef Q_OS_WIN - wchar_t volume[MAX_PATH + 1] = { 0 }; - if (GetVolumeInformationW((LPCWSTR)path.utf16(), nullptr, 0, nullptr, nullptr, nullptr, volume, MAX_PATH)) { - fileSystemType = QString::fromWCharArray(volume); - } -#elif defined(Q_OS_UNIX) - struct statvfs buf; - if (statvfs(path.toUtf8().constData(), &buf) == 0) { - switch (buf.f_type) { - case 0x4d44: // "MSDOS" - fileSystemType = "FAT32"; - break; - case 0x5346544e: // "NTFS" - fileSystemType = "NTFS"; - break; - case 0x4244: // "HFS+" or "H+" on some systems - case 0x482b: // "HFS+" or "H+" on some systems - fileSystemType = "HFS+"; - break; - case 0x41465342: // "APFS" - fileSystemType = "APFS"; - break; - case 0x65735546: // "exFAT" - fileSystemType = "exFAT"; - break; - default: - break; - } - } -#endif - - return fileSystemType; -} - static const QString BAD_WIN_CHARS = "\"?<>:*|\r\n"; -static const QString BAD_FAT32_CHARS = "<>:\"|?*+.,;=[]!"; +static const QString BAD_FAT_CHARS = "<>:\"|?*+.,;=[]!"; static const QString BAD_NTFS_CHARS = "<>:\"|?*"; static const QString BAD_HFS_CHARS = ":"; -static const QString BAD_EXFAT_CHARS = "<>:\"|?*"; -static const QString BAD_FILENAME_CHARS = - removeDuplicates(BAD_WIN_CHARS + BAD_FAT32_CHARS + BAD_NTFS_CHARS + BAD_HFS_CHARS + BAD_EXFAT_CHARS) + "\\/"; +static const QString BAD_FILENAME_CHARS = removeDuplicates(BAD_WIN_CHARS + BAD_FAT_CHARS + BAD_NTFS_CHARS + BAD_HFS_CHARS) + "\\/"; QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) { @@ -872,16 +831,35 @@ QString RemoveInvalidPathChars(QString path, QChar replaceWith) invalidChars = BAD_WIN_CHARS; #endif - QString fileSystemType = getFileSystemType(QFileInfo(path).absolutePath()); - - if (fileSystemType == "FAT32") { - invalidChars += BAD_FAT32_CHARS; - } else if (fileSystemType == "NTFS") { - invalidChars += BAD_NTFS_CHARS; - } else if (fileSystemType == "HFS+" || fileSystemType == "APFS") { - invalidChars += BAD_HFS_CHARS; - } else if (fileSystemType == "exFAT") { - invalidChars += BAD_EXFAT_CHARS; + switch (statFS(path).fsType) { + case FilesystemType::FAT: + invalidChars += BAD_FAT_CHARS; + break; + case FilesystemType::NTFS: + invalidChars += BAD_NTFS_CHARS; + break; + // case FilesystemType::REFS: + // case FilesystemType::EXT: + // case FilesystemType::EXT_2_OLD: + // case FilesystemType::EXT_2_3_4: + // case FilesystemType::XFS: + // case FilesystemType::BTRFS: + // case FilesystemType::NFS: + // case FilesystemType::ZFS: + case FilesystemType::APFS: + /* fallthrough */ + case FilesystemType::HFS: + /* fallthrough */ + case FilesystemType::HFSPLUS: + /* fallthrough */ + case FilesystemType::HFSX: + invalidChars += BAD_HFS_CHARS; + break; + // case FilesystemType::FUSEBLK: + // case FilesystemType::F2FS: + // case FilesystemType::UNKNOWN: + default: + break; } if (invalidChars.size() != 0) { From d1286bbe909bb51b74ab266ed190682d38e29776 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 30 May 2024 21:54:32 +0300 Subject: [PATCH 4/4] add some comments Signed-off-by: Trial97 --- launcher/FileSystem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index 3ded638ae..7a34e8a5d 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -831,14 +831,16 @@ QString RemoveInvalidPathChars(QString path, QChar replaceWith) invalidChars = BAD_WIN_CHARS; #endif + // the null character is ignored in this check as it was not a problem until now switch (statFS(path).fsType) { case FilesystemType::FAT: invalidChars += BAD_FAT_CHARS; break; case FilesystemType::NTFS: + /* fallthrough */ + case FilesystemType::REFS: // similar to NTFS(should be available only on windows) invalidChars += BAD_NTFS_CHARS; break; - // case FilesystemType::REFS: // case FilesystemType::EXT: // case FilesystemType::EXT_2_OLD: // case FilesystemType::EXT_2_3_4: