summaryrefslogtreecommitdiffstats
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rw-r--r--application/MainWindow.cpp2
-rw-r--r--application/MultiMC.cpp162
-rw-r--r--application/MultiMC.h3
3 files changed, 156 insertions, 11 deletions
diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp
index 933c4dbc..8c827806 100644
--- a/application/MainWindow.cpp
+++ b/application/MainWindow.cpp
@@ -992,7 +992,7 @@ void MainWindow::downloadUpdates(GoUpdate::Status status)
// If the task succeeds, install the updates.
if (updateDlg.exec(&updateTask))
{
- MMC->installUpdates(updateTask.updateFilesDir());
+ MMC->installUpdates(updateTask.updateFilesDir(), updateTask.operations());
}
else
{
diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp
index 67b50b40..a21455f0 100644
--- a/application/MultiMC.cpp
+++ b/application/MultiMC.cpp
@@ -583,7 +583,69 @@ std::shared_ptr<JavaVersionList> MultiMC::javalist()
return m_javalist;
}
-void MultiMC::installUpdates(const QString updateFilesDir)
+// from <sys/stat.h>
+#ifndef S_IRUSR
+#define __S_IREAD 0400 /* Read by owner. */
+#define __S_IWRITE 0200 /* Write by owner. */
+#define __S_IEXEC 0100 /* Execute by owner. */
+#define S_IRUSR __S_IREAD /* Read by owner. */
+#define S_IWUSR __S_IWRITE /* Write by owner. */
+#define S_IXUSR __S_IEXEC /* Execute by owner. */
+
+#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */
+#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */
+#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */
+
+#define S_IROTH (S_IRGRP >> 3) /* Read by others. */
+#define S_IWOTH (S_IWGRP >> 3) /* Write by others. */
+#define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */
+#endif
+static QFile::Permissions unixModeToPermissions(const int mode)
+{
+ QFile::Permissions perms;
+
+ if (mode & S_IRUSR)
+ {
+ perms |= QFile::ReadUser;
+ }
+ if (mode & S_IWUSR)
+ {
+ perms |= QFile::WriteUser;
+ }
+ if (mode & S_IXUSR)
+ {
+ perms |= QFile::ExeUser;
+ }
+
+ if (mode & S_IRGRP)
+ {
+ perms |= QFile::ReadGroup;
+ }
+ if (mode & S_IWGRP)
+ {
+ perms |= QFile::WriteGroup;
+ }
+ if (mode & S_IXGRP)
+ {
+ perms |= QFile::ExeGroup;
+ }
+
+ if (mode & S_IROTH)
+ {
+ perms |= QFile::ReadOther;
+ }
+ if (mode & S_IWOTH)
+ {
+ perms |= QFile::WriteOther;
+ }
+ if (mode & S_IXOTH)
+ {
+ perms |= QFile::ExeOther;
+ }
+ return perms;
+}
+
+void MultiMC::installUpdates(const QString updateFilesDir, GoUpdate::OperationList operations)
{
qDebug() << "Installing updates.";
#ifdef WINDOWS
@@ -596,14 +658,96 @@ void MultiMC::installUpdates(const QString updateFilesDir)
#error Unsupported operating system.
#endif
- QStringList args;
- args << "--install-dir" << root();
- args << "--package-dir" << updateFilesDir;
- args << "--script" << PathCombine(updateFilesDir, "file_list.xml");
- args << "--wait" << QString::number(applicationPid());
- args << "--finish-cmd" << finishCmd;
- args << "--finish-dir" << dataPath;
- qDebug() << "Running updater with args" << args.join(" ");
+ QString backupPath = PathCombine(root(), "update-backup");
+ QString trashPath = PathCombine(root(), "update-trash");
+ if(!ensureFolderPathExists(backupPath))
+ {
+ qWarning() << "couldn't create folder" << backupPath;
+ return;
+ }
+ if(!ensureFolderPathExists(trashPath))
+ {
+ qWarning() << "couldn't create folder" << trashPath;
+ return;
+ }
+ struct BackupEntry
+ {
+ QString orig;
+ QString backup;
+ };
+ QList <BackupEntry> backups;
+ QList <BackupEntry> trashcan;
+ for(auto op: operations)
+ {
+ switch(op.type)
+ {
+ case GoUpdate::Operation::OP_COPY:
+ {
+ QFileInfo replaced (PathCombine(root(), op.dest));
+ if(replaced.exists())
+ {
+ QString backupFilePath = PathCombine(backupPath, replaced.completeBaseName());
+ QFile::rename(replaced.absoluteFilePath(), backupFilePath);
+ BackupEntry be;
+ be.orig = replaced.absoluteFilePath();
+ be.backup = backupFilePath;
+ backups.append(be);
+ }
+ QFile::copy(op.file, replaced.absoluteFilePath());
+ QFile::setPermissions(replaced.absoluteFilePath(), unixModeToPermissions(op.mode));
+ }
+ break;
+ case GoUpdate::Operation::OP_DELETE:
+ {
+ QString trashFilePath = PathCombine(backupPath, op.file);
+ QString origFilePath = PathCombine(root(), op.file);
+ if(QFile::exists(origFilePath))
+ {
+ QFile::rename(origFilePath, trashFilePath);
+ BackupEntry be;
+ be.orig = origFilePath;
+ be.backup = trashFilePath;
+ trashcan.append(be);
+ }
+ }
+ break;
+ }
+ }
+
+ // try to start the new binary
+ qint64 pid = -1;
+ auto args = qApp->arguments();
+ args.removeFirst();
+ QProcess::startDetached(finishCmd, args, QDir::currentPath(), &pid);
+ // failed to start... ?
+ if(pid == -1)
+ {
+ goto FAILED;
+ }
+ // now clean up the backed up stuff.
+ for(auto backup:backups)
+ {
+ QFile::remove(backup.backup);
+ }
+ for(auto backup:trashcan)
+ {
+ QFile::remove(backup.backup);
+ }
+ qApp->quit();
+ return;
+
+FAILED:
+ // if the above failed, roll back changes
+ for(auto backup:backups)
+ {
+ QFile::remove(backup.orig);
+ QFile::rename(backup.backup, backup.orig);
+ }
+ for(auto backup:trashcan)
+ {
+ QFile::rename(backup.backup, backup.orig);
+ }
+ // and do nothing
}
void MultiMC::setIconTheme(const QString& name)
diff --git a/application/MultiMC.h b/application/MultiMC.h
index f815b8e4..9edf0596 100644
--- a/application/MultiMC.h
+++ b/application/MultiMC.h
@@ -6,6 +6,7 @@
#include <QFlag>
#include <QIcon>
#include <QDateTime>
+#include <updater/GoUpdate.h>
class QFile;
class MinecraftVersionList;
@@ -105,7 +106,7 @@ public:
}
// APPLICATION ONLY
- void installUpdates(const QString updateFilesDir);
+ void installUpdates(const QString updateFilesDir, GoUpdate::OperationList operations);
/*!
* Opens a json file using either a system default editor, or, if note empty, the editor