From 838687fb2ec0965cb270cf311d796edfd7adaca7 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Mon, 23 Mar 2026 00:36:50 +0500 Subject: [PATCH] fix: log error if file open/commit fails Signed-off-by: Octol1ttle --- launcher/Application.cpp | 11 +++++----- launcher/FileSystem.cpp | 6 +++--- launcher/archive/ArchiveWriter.cpp | 2 +- launcher/minecraft/AssetsUtils.cpp | 2 +- launcher/minecraft/ProfileUtils.cpp | 4 ++-- launcher/minecraft/ShortcutUtils.cpp | 6 +++--- launcher/minecraft/auth/AccountList.cpp | 6 +++--- .../minecraft/mod/tasks/LocalModParseTask.cpp | 2 +- .../atlauncher/ATLPackInstallTask.cpp | 2 +- .../modplatform/helpers/OverrideUtils.cpp | 4 ++-- .../legacy_ftb/PackInstallTask.cpp | 2 +- .../modrinth/ModrinthPackExportTask.cpp | 4 ++-- launcher/modplatform/packwiz/Packwiz.cpp | 2 +- .../technic/TechnicPackProcessor.cpp | 2 +- launcher/net/FileSink.cpp | 20 +++++++++++++------ launcher/net/HttpMetaCache.cpp | 2 +- launcher/screenshots/ImgurUpload.cpp | 2 +- launcher/translations/POTranslator.cpp | 2 +- launcher/ui/dialogs/AboutDialog.cpp | 4 ++-- .../updater/prismupdater/PrismUpdater.cpp | 5 +++-- tests/Library_test.cpp | 2 +- tests/MojangVersionFormat_test.cpp | 4 ++-- tests/Version_test.cpp | 2 +- 23 files changed, 54 insertions(+), 44 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 960b4cc4e..7af39b55e 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -514,12 +514,13 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) logFile = std::unique_ptr(new QFile(logBase.arg(0))); if (!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { showFatalErrorMessage("The launcher data folder is not writable!", - QString("The launcher couldn't create a log file - the data folder is not writable.\n" + QString("The launcher couldn't create a log file - %1.\n" "\n" "Make sure you have write permissions to the data folder.\n" - "(%1)\n" + "(%2)\n" "\n" "The launcher cannot continue until you fix this problem.") + .arg(logFile->errorString()) .arg(dataPath)); return; } @@ -626,11 +627,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) if (check.write(payload) == payload.size()) { check.close(); } else { - qWarning() << "Could not write into" << liveCheckFile << "!"; + qWarning() << "Could not write into" << liveCheckFile << "error:" << check.errorString(); check.remove(); // also closes file! } } else { - qWarning() << "Could not open" << liveCheckFile << "for writing!"; + qWarning() << "Could not open" << liveCheckFile << "for writing:" << check.errorString(); } } @@ -1955,7 +1956,7 @@ bool Application::handleDataMigration(const QString& currentData, auto setDoNotMigrate = [&nomigratePath] { QFile file(nomigratePath); if (!file.open(QIODevice::WriteOnly)) { - qWarning() << "setDoNotMigrate failed; Failed to open file '" << file.fileName() << "' for writing!"; + qWarning() << "setDoNotMigrate failed; Failed to open file" << file.fileName() << "for writing:" << file.errorString(); } }; diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index b7125a162..f53c9343e 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -954,7 +954,7 @@ QString createShortcut(QString destination, QString target, QStringList args, QS return QString(); } if (!info.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Failed to open file" << info.fileName() << "for writing!"; + qWarning() << "Failed to open file" << info.fileName() << "for writing:" << info.errorString(); return QString(); } @@ -965,7 +965,7 @@ QString createShortcut(QString destination, QString target, QStringList args, QS QFile f(exec); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Failed to open file" << f.fileName() << "for writing!"; + qWarning() << "Failed to open file" << f.fileName() << "for writing:" << f.errorString(); return QString(); } QTextStream stream(&f); @@ -1010,7 +1010,7 @@ QString createShortcut(QString destination, QString target, QStringList args, QS destination += ".desktop"; QFile f(destination); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Failed to open file '" << f.fileName() << "' for writing!"; + qWarning() << "Failed to open file" << f.fileName() << "for writing:" << f.errorString(); return QString(); } QTextStream stream(&f); diff --git a/launcher/archive/ArchiveWriter.cpp b/launcher/archive/ArchiveWriter.cpp index 8436e5486..43dbe4dbd 100644 --- a/launcher/archive/ArchiveWriter.cpp +++ b/launcher/archive/ArchiveWriter.cpp @@ -174,7 +174,7 @@ bool ArchiveWriter::addFile(const QString& fileName, const QString& fileDest) if (fileInfo.isFile() && !fileInfo.isSymLink()) { QFile file(fileInfo.absoluteFilePath()); if (!file.open(QIODevice::ReadOnly)) { - qCritical() << "Failed to open file:" << fileInfo.filePath(); + qCritical() << "Failed to open file:" << fileInfo.filePath() << "error:" << file.errorString(); return false; } diff --git a/launcher/minecraft/AssetsUtils.cpp b/launcher/minecraft/AssetsUtils.cpp index 8185f9dc9..37d02b5c1 100644 --- a/launcher/minecraft/AssetsUtils.cpp +++ b/launcher/minecraft/AssetsUtils.cpp @@ -104,7 +104,7 @@ bool loadAssetsIndexJson(const QString& assetsId, const QString& path, AssetsInd // Try to open the file and fail if we can't. // TODO: We should probably report this error to the user. if (!file.open(QIODevice::ReadOnly)) { - qCritical() << "Failed to read assets index file" << path; + qCritical() << "Failed to read assets index file" << path << "error:" << file.errorString(); return false; } index.id = assetsId; diff --git a/launcher/minecraft/ProfileUtils.cpp b/launcher/minecraft/ProfileUtils.cpp index b0b9122e3..ae6326953 100644 --- a/launcher/minecraft/ProfileUtils.cpp +++ b/launcher/minecraft/ProfileUtils.cpp @@ -144,13 +144,13 @@ bool saveJsonFile(const QJsonDocument& doc, const QString& filename) auto data = doc.toJson(); QSaveFile jsonFile(filename); if (!jsonFile.open(QIODevice::WriteOnly)) { + qWarning() << "Couldn't open" << filename << "for writing:" << jsonFile.errorString(); jsonFile.cancelWriting(); - qWarning() << "Couldn't open" << filename << "for writing"; return false; } jsonFile.write(data); if (!jsonFile.commit()) { - qWarning() << "Couldn't save" << filename; + qWarning() << "Couldn't save" << filename << "error:" << jsonFile.errorString(); return false; } return true; diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp index ec4ebb31a..b719e3142 100644 --- a/launcher/minecraft/ShortcutUtils.cpp +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -71,7 +71,7 @@ bool createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) QFile iconFile(iconPath); if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application: %1").arg(iconFile.errorString())); return false; } @@ -101,7 +101,7 @@ bool createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) QFile iconFile(iconPath); if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut: %1").arg(iconFile.errorString())); return false; } bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG"); @@ -127,7 +127,7 @@ bool createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) QFile iconFile(iconPath); if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut: %1").arg(iconFile.errorString())); return false; } bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO"); diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index f9988b2fc..ac27b6bbc 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -450,7 +450,7 @@ bool AccountList::loadList() // Try to open the file and fail if we can't. // TODO: We should probably report this error to the user. if (!file.open(QIODevice::ReadOnly)) { - qCritical() << QString("Failed to read the account list file (%1).").arg(m_listFilePath).toUtf8(); + qCritical() << QString("Failed to read the account list file %1 (%2).").arg(m_listFilePath).arg(file.errorString()).toUtf8(); return false; } @@ -567,7 +567,7 @@ bool AccountList::saveList() // Try to open the file and fail if we can't. // TODO: We should probably report this error to the user. if (!file.open(QIODevice::WriteOnly)) { - qCritical() << QString("Failed to read the account list file (%1).").arg(m_listFilePath).toUtf8(); + qCritical() << QString("Failed to save the account list file %1 (%2).").arg(m_listFilePath).arg(file.errorString()).toUtf8(); return false; } @@ -578,7 +578,7 @@ bool AccountList::saveList() qDebug() << "Saved account list to" << m_listFilePath; return true; } else { - qDebug() << "Failed to save accounts to" << m_listFilePath; + qDebug() << "Failed to save accounts to" << m_listFilePath << "error:" << file.errorString(); return false; } } diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index 6755b320a..74c311676 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -751,7 +751,7 @@ bool loadIconFile(const Mod& mod, QPixmap* pixmap) if (icon_info.exists() && icon_info.isFile()) { QFile icon(icon_info.filePath()); if (!icon.open(QIODevice::ReadOnly)) { - return png_invalid("failed to open file " + icon_info.filePath()); + return png_invalid("failed to open file " + icon_info.filePath() + " " + icon.errorString()); } auto data = icon.readAll(); diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp index ada1f2296..7a7365fbc 100644 --- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp +++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp @@ -618,7 +618,7 @@ bool PackInstallTask::createPackComponent(QString instanceRoot, PackProfile* pro QFile file(patchFileName); if (!file.open(QFile::WriteOnly)) { - qCritical() << "Error opening" << file.fileName() << "for reading:" << file.errorString(); + qCritical() << "Error opening" << file.fileName() << "for writing:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); diff --git a/launcher/modplatform/helpers/OverrideUtils.cpp b/launcher/modplatform/helpers/OverrideUtils.cpp index d5958a59d..e64b30ffe 100644 --- a/launcher/modplatform/helpers/OverrideUtils.cpp +++ b/launcher/modplatform/helpers/OverrideUtils.cpp @@ -16,7 +16,7 @@ void createOverrides(const QString& name, const QString& parent_folder, const QS QFile file(file_path); if (!file.open(QFile::WriteOnly)) { - qWarning() << "Failed to open file '" << file.fileName() << "' for writing!"; + qWarning() << "Failed to open file" << file.fileName() << "for writing:" << file.errorString(); return; } @@ -47,7 +47,7 @@ QStringList readOverrides(const QString& name, const QString& parent_folder) QStringList previous_overrides; if (!file.open(QFile::ReadOnly)) { - qWarning() << "Failed to open file '" << file.fileName() << "' for reading!"; + qWarning() << "Failed to open file" << file.fileName() << "for reading:" << file.errorString(); return previous_overrides; } diff --git a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp index 06c180fcd..8220676fc 100644 --- a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp +++ b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp @@ -169,7 +169,7 @@ void PackInstallTask::install() break; } } else { - qWarning() << "Failed to open file '" << packJson.fileName() << "' for reading!"; + qWarning() << "Failed to open file" << packJson.fileName() << "for reading:" << packJson.errorString(); } } diff --git a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp index 97410117b..9a972bc85 100644 --- a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp @@ -108,13 +108,13 @@ void ModrinthPackExportTask::collectHashes() QFile openFile(file.absoluteFilePath()); if (!openFile.open(QFile::ReadOnly)) { - qWarning() << "Could not open" << file << "for hashing"; + qWarning() << "Could not open" << file << "for hashing:" << openFile.errorString(); continue; } const QByteArray data = openFile.readAll(); if (openFile.error() != QFileDevice::NoError) { - qWarning() << "Could not read" << file; + qWarning() << "Could not read" << file << "error:" << openFile.errorString(); continue; } auto sha512 = Hashing::hash(data, Hashing::Algorithm::Sha512); diff --git a/launcher/modplatform/packwiz/Packwiz.cpp b/launcher/modplatform/packwiz/Packwiz.cpp index b0f69f05c..4b3d75169 100644 --- a/launcher/modplatform/packwiz/Packwiz.cpp +++ b/launcher/modplatform/packwiz/Packwiz.cpp @@ -190,7 +190,7 @@ void V1::updateModIndex(const QDir& index_dir, Mod& mod) } if (!index_file.open(QIODevice::ReadWrite)) { - qCritical() << QString("Could not open file %1!").arg(normalized_fname); + qCritical() << "Could not open file" << normalized_fname << "error:" << index_file.errorString(); return; } diff --git a/launcher/modplatform/technic/TechnicPackProcessor.cpp b/launcher/modplatform/technic/TechnicPackProcessor.cpp index e114398c4..858f4ae6b 100644 --- a/launcher/modplatform/technic/TechnicPackProcessor.cpp +++ b/launcher/modplatform/technic/TechnicPackProcessor.cpp @@ -117,7 +117,7 @@ void Technic::TechnicPackProcessor::run(SettingsObject* globalSettings, } else if (QFile::exists(versionJson)) { QFile file(versionJson); if (!file.open(QIODevice::ReadOnly)) { - emit failed(tr("Unable to open \"version.json\"!")); + emit failed(tr("Unable to open \"version.json\": %1").arg(file.errorString())); return; } data = file.readAll(); diff --git a/launcher/net/FileSink.cpp b/launcher/net/FileSink.cpp index f61dd527d..47838f62c 100644 --- a/launcher/net/FileSink.cpp +++ b/launcher/net/FileSink.cpp @@ -58,8 +58,9 @@ Task::State FileSink::init(QNetworkRequest& request) m_wroteAnyData = false; m_output_file.reset(new PSaveFile(m_filename)); if (!m_output_file->open(QIODevice::WriteOnly)) { - qCCritical(taskNetLogC) << "Could not open " + m_filename + " for writing"; - m_fail_reason = "Could not open file"; + const auto error = QString("Could not open %1 for writing: %2").arg(m_filename).arg(m_output_file->errorString()); + qCCritical(taskNetLogC) << error; + m_fail_reason = error; return Task::State::Failed; } @@ -72,11 +73,17 @@ Task::State FileSink::init(QNetworkRequest& request) Task::State FileSink::write(QByteArray& data) { if (!writeAllValidators(data) || m_output_file->write(data) != data.size()) { - qCCritical(taskNetLogC) << "Failed writing into " + m_filename; + QString error = QString("Failed writing into %1: %2").arg(m_filename); + if (m_output_file->error() == QFileDevice::NoError) { + error = error.arg("Validators failed"); + } else { + error = error.arg(m_output_file->errorString()); + } + qCCritical(taskNetLogC) << error; + m_fail_reason = error; m_output_file->cancelWriting(); m_output_file.reset(); m_wroteAnyData = false; - m_fail_reason = "Failed to write validators"; return Task::State::Failed; } @@ -116,9 +123,10 @@ Task::State FileSink::finalize(QNetworkReply& reply) // nothing went wrong... if (!m_output_file->commit()) { - qCCritical(taskNetLogC) << "Failed to commit changes to" << m_filename; + const auto error = QString("Failed to commit changes to %1: %2").arg(m_filename).arg(m_output_file->errorString()); + qCCritical(taskNetLogC) << error; + m_fail_reason = error; m_output_file->cancelWriting(); - m_fail_reason = "Failed to commit changes"; return Task::State::Failed; } } diff --git a/launcher/net/HttpMetaCache.cpp b/launcher/net/HttpMetaCache.cpp index 9ad9fdf43..6b81bfe0d 100644 --- a/launcher/net/HttpMetaCache.cpp +++ b/launcher/net/HttpMetaCache.cpp @@ -113,7 +113,7 @@ auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString ex if (file_last_changed != entry->m_local_changed_timestamp) { QFile input(real_path); if (!input.open(QIODevice::ReadOnly)) { - qWarning() << "Failed to open file '" << input.fileName() << "' for reading!"; + qWarning() << "Failed to open file" << input.fileName() << "for reading:" << input.errorString(); return staleEntry(base, resource_path); } QString md5sum = QCryptographicHash::hash(input.readAll(), QCryptographicHash::Md5).toHex().constData(); diff --git a/launcher/screenshots/ImgurUpload.cpp b/launcher/screenshots/ImgurUpload.cpp index f553bc774..e6ba372ed 100644 --- a/launcher/screenshots/ImgurUpload.cpp +++ b/launcher/screenshots/ImgurUpload.cpp @@ -52,7 +52,7 @@ QNetworkReply* ImgurUpload::getReply(QNetworkRequest& request) auto file = new QFile(m_fileInfo.absoluteFilePath(), this); if (!file->open(QFile::ReadOnly)) { - emitFailed(); + emitFailed(tr("Could not open file %1 for reading: %2").arg(m_fileInfo.absoluteFilePath()).arg(file->errorString())); return nullptr; } diff --git a/launcher/translations/POTranslator.cpp b/launcher/translations/POTranslator.cpp index e4e2573c6..458ebd230 100644 --- a/launcher/translations/POTranslator.cpp +++ b/launcher/translations/POTranslator.cpp @@ -133,7 +133,7 @@ void POTranslatorPrivate::reload() { QFile file(filename); if (!file.open(QFile::OpenMode::enum_type::ReadOnly | QFile::OpenMode::enum_type::Text)) { - qDebug() << "Failed to open PO file:" << filename; + qDebug() << "Failed to open PO file:" << filename << "error:" << file.errorString(); return; } diff --git a/launcher/ui/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp index 6052e94a9..da42ae2b4 100644 --- a/launcher/ui/dialogs/AboutDialog.cpp +++ b/launcher/ui/dialogs/AboutDialog.cpp @@ -48,7 +48,7 @@ QString getCreditsHtml() { QFile dataFile(":/documents/credits.html"); if (!dataFile.open(QIODevice::ReadOnly)) { - qWarning() << "Failed to open file '" << dataFile.fileName() << "' for reading!"; + qWarning() << "Failed to open file" << dataFile.fileName() << "for reading:" << dataFile.errorString(); return {}; } QString fileContent = QString::fromUtf8(dataFile.readAll()); @@ -66,7 +66,7 @@ QString getLicenseHtml() dataFile.close(); return output; } else { - qWarning() << "Failed to open file '" << dataFile.fileName() << "' for reading!"; + qWarning() << "Failed to open file" << dataFile.fileName() << "for reading:" << dataFile.errorString(); return QString(); } } diff --git a/launcher/updater/prismupdater/PrismUpdater.cpp b/launcher/updater/prismupdater/PrismUpdater.cpp index a9369d62b..11e92efcd 100644 --- a/launcher/updater/prismupdater/PrismUpdater.cpp +++ b/launcher/updater/prismupdater/PrismUpdater.cpp @@ -184,12 +184,13 @@ PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, ar logFile = std::unique_ptr(new QFile(logBase.arg(0))); if (!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { showFatalErrorMessage(tr("The launcher data folder is not writable!"), - tr("The updater couldn't create a log file - the data folder is not writable.\n" + tr("The updater couldn't create a log file - %1.\n" "\n" "Make sure you have write permissions to the data folder.\n" - "(%1)\n" + "(%2)\n" "\n" "The updater cannot continue until you fix this problem.") + .arg(logFile->errorString()) .arg(m_dataPath)); return; } diff --git a/tests/Library_test.cpp b/tests/Library_test.cpp index 4649bfe1b..73b6bf4a2 100644 --- a/tests/Library_test.cpp +++ b/tests/Library_test.cpp @@ -49,7 +49,7 @@ class LibraryTest : public QObject { { QFile jsonFile(path); if (!jsonFile.open(QIODevice::ReadOnly)) { - qCritical() << "Failed to open file" << jsonFile.fileName() << "for reading!"; + qCritical() << "Failed to open file" << jsonFile.fileName() << "for reading:" << jsonFile.errorString(); return LibraryPtr(); } auto data = jsonFile.readAll(); diff --git a/tests/MojangVersionFormat_test.cpp b/tests/MojangVersionFormat_test.cpp index d55c6561e..385b75bb8 100644 --- a/tests/MojangVersionFormat_test.cpp +++ b/tests/MojangVersionFormat_test.cpp @@ -10,7 +10,7 @@ class MojangVersionFormatTest : public QObject { { QFile jsonFile(path); if (!jsonFile.open(QIODevice::ReadOnly)) { - qWarning() << "Failed to open file '" << jsonFile.fileName() << "' for reading!"; + qWarning() << "Failed to open file" << jsonFile.fileName() << "for reading:" << jsonFile.errorString(); return QJsonDocument(); } auto data = jsonFile.readAll(); @@ -21,7 +21,7 @@ class MojangVersionFormatTest : public QObject { { QFile jsonFile(file); if (!jsonFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qCritical() << "Failed to open file '" << jsonFile.fileName() << "' for writing!"; + qCritical() << "Failed to open file" << jsonFile.fileName() << "for writing:" << jsonFile.errorString(); return; } auto data = doc.toJson(QJsonDocument::Indented); diff --git a/tests/Version_test.cpp b/tests/Version_test.cpp index 541355b70..f3bdfec14 100644 --- a/tests/Version_test.cpp +++ b/tests/Version_test.cpp @@ -107,7 +107,7 @@ class VersionTest : public QObject { QFile vector_file{ test_vector_dir.absoluteFilePath("test_vectors.txt") }; if (!vector_file.open(QFile::OpenModeFlag::ReadOnly)) { - qCritical() << "Failed to open file '" << vector_file.fileName() << "' for reading!"; + qCritical() << "Failed to open file" << vector_file.fileName() << "for reading:" << vector_file.errorString(); return; }