skip QSaveFile temprary files
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com> (cherry picked from commit 562c3013269dbb9cad411f58ded333dee1aea158)
This commit is contained in:
parent
25eaa4eba6
commit
51a71d0471
@ -1883,3 +1883,26 @@ const QString Application::javaPath()
|
||||
{
|
||||
return m_settings->get("JavaDir").toString();
|
||||
}
|
||||
|
||||
void Application::addQSavePath(QString path)
|
||||
{
|
||||
QMutexLocker locker(&m_qsaveResourcesMutex);
|
||||
m_qsaveResources.insert(path);
|
||||
}
|
||||
|
||||
void Application::removeQSavePath(QString path)
|
||||
{
|
||||
QMutexLocker locker(&m_qsaveResourcesMutex);
|
||||
m_qsaveResources.remove(path);
|
||||
}
|
||||
|
||||
bool Application::checkQSavePath(QString path)
|
||||
{
|
||||
QMutexLocker locker(&m_qsaveResourcesMutex);
|
||||
for (auto r : m_qsaveResources) {
|
||||
if (path.contains(r)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
@ -42,6 +42,8 @@
|
||||
#include <QDebug>
|
||||
#include <QFlag>
|
||||
#include <QIcon>
|
||||
#include <QMutex>
|
||||
#include <QSet>
|
||||
#include <QUrl>
|
||||
#include <memory>
|
||||
|
||||
@ -303,4 +305,13 @@ class Application : public QApplication {
|
||||
QList<QUrl> m_urlsToImport;
|
||||
QString m_instanceIdToShowWindowOf;
|
||||
std::unique_ptr<QFile> logFile;
|
||||
|
||||
public:
|
||||
void addQSavePath(QString);
|
||||
void removeQSavePath(QString);
|
||||
bool checkQSavePath(QString);
|
||||
|
||||
private:
|
||||
QSet<QString> m_qsaveResources;
|
||||
mutable QMutex m_qsaveResourcesMutex;
|
||||
};
|
||||
|
@ -30,6 +30,7 @@ set(CORE_SOURCES
|
||||
StringUtils.cpp
|
||||
QVariantUtils.h
|
||||
RuntimeContext.h
|
||||
PSaveFile.h
|
||||
|
||||
# Basic instance manipulation tasks (derived from InstanceTask)
|
||||
InstanceCreationTask.h
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QSaveFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QStorageInfo>
|
||||
#include <QTextStream>
|
||||
@ -54,6 +53,7 @@
|
||||
#include <system_error>
|
||||
|
||||
#include "DesktopServices.h"
|
||||
#include "PSaveFile.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#if defined Q_OS_WIN32
|
||||
@ -191,8 +191,8 @@ void ensureExists(const QDir& dir)
|
||||
void write(const QString& filename, const QByteArray& data)
|
||||
{
|
||||
ensureExists(QFileInfo(filename).dir());
|
||||
QSaveFile file(filename);
|
||||
if (!file.open(QSaveFile::WriteOnly)) {
|
||||
PSaveFile file(filename);
|
||||
if (!file.open(PSaveFile::WriteOnly)) {
|
||||
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||
}
|
||||
if (data.size() != file.write(data)) {
|
||||
@ -213,8 +213,8 @@ void appendSafe(const QString& filename, const QByteArray& data)
|
||||
buffer = QByteArray();
|
||||
}
|
||||
buffer.append(data);
|
||||
QSaveFile file(filename);
|
||||
if (!file.open(QSaveFile::WriteOnly)) {
|
||||
PSaveFile file(filename);
|
||||
if (!file.open(PSaveFile::WriteOnly)) {
|
||||
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||
}
|
||||
if (buffer.size() != file.write(buffer)) {
|
||||
@ -971,8 +971,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
||||
if (!args.empty())
|
||||
argstring = " \"" + args.join("\" \"") + "\"";
|
||||
|
||||
stream << "#!/bin/bash"
|
||||
<< "\n";
|
||||
stream << "#!/bin/bash" << "\n";
|
||||
stream << "\"" << target << "\" " << argstring << "\n";
|
||||
|
||||
stream.flush();
|
||||
@ -1016,12 +1015,9 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
||||
if (!args.empty())
|
||||
argstring = " '" + args.join("' '") + "'";
|
||||
|
||||
stream << "[Desktop Entry]"
|
||||
<< "\n";
|
||||
stream << "Type=Application"
|
||||
<< "\n";
|
||||
stream << "Categories=Game;ActionGame;AdventureGame;Simulation"
|
||||
<< "\n";
|
||||
stream << "[Desktop Entry]" << "\n";
|
||||
stream << "Type=Application" << "\n";
|
||||
stream << "Categories=Game;ActionGame;AdventureGame;Simulation" << "\n";
|
||||
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
|
||||
stream << "Name=" << name.toLocal8Bit() << "\n";
|
||||
if (!icon.isEmpty()) {
|
||||
|
70
launcher/PSaveFile.h
Normal file
70
launcher/PSaveFile.h
Normal file
@ -0,0 +1,70 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QSaveFile>
|
||||
#include "Application.h"
|
||||
|
||||
#if defined(LAUNCHER_APPLICATION)
|
||||
|
||||
/* PSaveFile
|
||||
* A class that mimics QSaveFile for Windows.
|
||||
*
|
||||
* When reading resources, we need to avoid accessing temporary files
|
||||
* generated by QSaveFile. If we start reading such a file, we may
|
||||
* inadvertently keep it open while QSaveFile is trying to remove it,
|
||||
* or we might detect the file just before it is removed, leading to
|
||||
* race conditions and errors.
|
||||
*
|
||||
* Unfortunately, QSaveFile doesn't provide a way to retrieve the
|
||||
* temporary file name or to set a specific template for the temporary
|
||||
* file name it uses. By default, QSaveFile appends a `.XXXXXX` suffix
|
||||
* to the original file name, where the `XXXXXX` part is dynamically
|
||||
* generated to ensure uniqueness.
|
||||
*
|
||||
* This class acts like a lock by adding and removing the target file
|
||||
* name into/from a global string set, helping to manage access to
|
||||
* files during critical operations.
|
||||
*
|
||||
* Note: Please do not use the `setFileName` function directly, as it
|
||||
* is not virtual and cannot be overridden.
|
||||
*/
|
||||
class PSaveFile : public QSaveFile {
|
||||
public:
|
||||
PSaveFile(const QString& name) : QSaveFile(name)
|
||||
{
|
||||
if (auto app = APPLICATION_DYN) {
|
||||
app->addQSavePath(name + ".");
|
||||
}
|
||||
}
|
||||
PSaveFile(const QString& name, QObject* parent) : QSaveFile(name, parent)
|
||||
{
|
||||
if (auto app = APPLICATION_DYN) {
|
||||
app->addQSavePath(name + ".");
|
||||
}
|
||||
}
|
||||
virtual ~PSaveFile()
|
||||
{
|
||||
if (auto app = APPLICATION_DYN) {
|
||||
app->removeQSavePath(fileName() + ".");
|
||||
}
|
||||
}
|
||||
};
|
||||
#else
|
||||
#define PSaveFile QSaveFile
|
||||
#endif
|
@ -38,7 +38,6 @@
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QSaveFile>
|
||||
#include <QString>
|
||||
|
||||
#include <FileSystem.h>
|
||||
@ -57,6 +56,7 @@
|
||||
#include <optional>
|
||||
|
||||
#include "FileSystem.h"
|
||||
#include "PSaveFile.h"
|
||||
|
||||
using std::nullopt;
|
||||
using std::optional;
|
||||
@ -183,7 +183,7 @@ bool putLevelDatDataToFS(const QFileInfo& file, QByteArray& data)
|
||||
if (fullFilePath.isNull()) {
|
||||
return false;
|
||||
}
|
||||
QSaveFile f(fullFilePath);
|
||||
PSaveFile f(fullFilePath);
|
||||
if (!f.open(QIODevice::WriteOnly)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Application.h"
|
||||
#include "FileSystem.h"
|
||||
#include "minecraft/mod/Resource.h"
|
||||
|
||||
@ -52,6 +53,9 @@ class BasicFolderLoadTask : public Task {
|
||||
m_dir.refresh();
|
||||
for (auto entry : m_dir.entryInfoList()) {
|
||||
auto filePath = entry.absoluteFilePath();
|
||||
if (auto app = APPLICATION_DYN; app && app->checkQSavePath(filePath)) {
|
||||
continue;
|
||||
}
|
||||
auto newFilePath = FS::getUniqueResourceName(filePath);
|
||||
if (newFilePath != filePath) {
|
||||
FS::move(filePath, newFilePath);
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include "ModFolderLoadTask.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "FileSystem.h"
|
||||
#include "minecraft/mod/MetadataHandler.h"
|
||||
|
||||
@ -65,6 +66,9 @@ void ModFolderLoadTask::executeTask()
|
||||
m_mods_dir.refresh();
|
||||
for (auto entry : m_mods_dir.entryInfoList()) {
|
||||
auto filePath = entry.absoluteFilePath();
|
||||
if (auto app = APPLICATION_DYN; app && app->checkQSavePath(filePath)) {
|
||||
continue;
|
||||
}
|
||||
auto newFilePath = FS::getUniqueResourceName(filePath);
|
||||
if (newFilePath != filePath) {
|
||||
FS::move(filePath, newFilePath);
|
||||
|
@ -72,7 +72,7 @@ auto stringEntry(toml::table table, QString entry_name) -> QString
|
||||
{
|
||||
auto node = table[StringUtils::toStdString(entry_name)];
|
||||
if (!node) {
|
||||
qCritical() << "Failed to read str property '" + entry_name + "' in mod metadata.";
|
||||
qWarning() << "Failed to read str property '" + entry_name + "' in mod metadata.";
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ auto intEntry(toml::table table, QString entry_name) -> int
|
||||
{
|
||||
auto node = table[StringUtils::toStdString(entry_name)];
|
||||
if (!node) {
|
||||
qCritical() << "Failed to read int property '" + entry_name + "' in mod metadata.";
|
||||
qWarning() << "Failed to read int property '" + entry_name + "' in mod metadata.";
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ Task::State FileSink::init(QNetworkRequest& request)
|
||||
}
|
||||
|
||||
wroteAnyData = false;
|
||||
m_output_file.reset(new QSaveFile(m_filename));
|
||||
m_output_file.reset(new PSaveFile(m_filename));
|
||||
if (!m_output_file->open(QIODevice::WriteOnly)) {
|
||||
qCCritical(taskNetLogC) << "Could not open " + m_filename + " for writing";
|
||||
return Task::State::Failed;
|
||||
|
@ -35,8 +35,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSaveFile>
|
||||
|
||||
#include "PSaveFile.h"
|
||||
#include "Sink.h"
|
||||
|
||||
namespace Net {
|
||||
@ -60,6 +59,6 @@ class FileSink : public Sink {
|
||||
protected:
|
||||
QString m_filename;
|
||||
bool wroteAnyData = false;
|
||||
std::unique_ptr<QSaveFile> m_output_file;
|
||||
std::unique_ptr<PSaveFile> m_output_file;
|
||||
};
|
||||
} // namespace Net
|
||||
|
@ -39,7 +39,6 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QSaveFile>
|
||||
#include <QStringList>
|
||||
#include <QTemporaryFile>
|
||||
#include <QTextStream>
|
||||
|
@ -51,7 +51,6 @@
|
||||
#include <icons/IconList.h>
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <QSaveFile>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStack>
|
||||
#include <functional>
|
||||
|
Loading…
Reference in New Issue
Block a user