Skip to content

Commit

Permalink
feat(symlinks&hardlinks): linkup copy dialog
Browse files Browse the repository at this point in the history
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
  • Loading branch information
Ryex committed Feb 8, 2023
1 parent 3897d49 commit 306f741
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 26 deletions.
5 changes: 2 additions & 3 deletions launcher/FileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ void create_link::runPrivlaged(const QString& offset)
qint64 byteswritten = clientConnection->write(block);
bool bytesflushed = clientConnection->flush();
qDebug() << "block flushed" << byteswritten << bytesflushed;
//clientConnection->disconnectFromServer();

});

qDebug() << "Listening on pipe" << serverName;
Expand All @@ -437,7 +437,6 @@ void create_link::runPrivlaged(const QString& offset)

}


void ExternalLinkFileProcess::runLinkFile() {
QString fileLinkExe = PathCombine(QCoreApplication::instance()->applicationDirPath(), BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink");
QString params = "-s " + m_server;
Expand All @@ -463,7 +462,7 @@ void ExternalLinkFileProcess::runLinkFile() {
ShExecInfo.lpFile = programNameWin;
ShExecInfo.lpParameters = paramsWin;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_NORMAL;
ShExecInfo.nShow = SW_HIDE;
ShExecInfo.hInstApp = NULL;

ShellExecuteEx(&ShExecInfo);
Expand Down
9 changes: 7 additions & 2 deletions launcher/FileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,16 +211,21 @@ class create_link : public QObject {

bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }

int totalLinked() { return m_linked; }


void runPrivlaged() { runPrivlaged(QString()); }
void runPrivlaged(const QString& offset);

int totalLinked() { return m_linked; }
QList<LinkResult> getResults() { return m_path_results; }


signals:
void fileLinked(const QString& srcName, const QString& dstName);
void linkFailed(const QString& srcName, const QString& dstName, const QString& err_msg, int err_value);
void finishedPrivlaged(bool gotResults);
void finished();
void finishedPrivlaged(bool gotResults);


private:
bool operator()(const QString& offset, bool dryRun = false);
Expand Down
8 changes: 4 additions & 4 deletions launcher/InstanceCopyPrefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ bool InstanceCopyPrefs::isUseHardLinksEnabled() const
return useHardLinks;
}

bool InstanceCopyPrefs::isLinkWorldsEnabled() const
bool InstanceCopyPrefs::isDontLinkSavesEnabled() const
{
return linkWorlds;
return dontLinkSaves;
}

// ======= Setters =======
Expand Down Expand Up @@ -159,7 +159,7 @@ void InstanceCopyPrefs::enableUseHardLinks(bool b)
useHardLinks = b;
}

void InstanceCopyPrefs::enableLinkWorlds(bool b)
void InstanceCopyPrefs::enableDontLinkSaves(bool b)
{
linkWorlds = b;
dontLinkSaves = b;
}
6 changes: 3 additions & 3 deletions launcher/InstanceCopyPrefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct InstanceCopyPrefs {
[[nodiscard]] bool isCopyScreenshotsEnabled() const;
[[nodiscard]] bool isLinkFilesEnabled() const;
[[nodiscard]] bool isUseHardLinksEnabled() const;
[[nodiscard]] bool isLinkWorldsEnabled() const;
[[nodiscard]] bool isDontLinkSavesEnabled() const;
// Setters
void enableCopySaves(bool b);
void enableKeepPlaytime(bool b);
Expand All @@ -33,7 +33,7 @@ struct InstanceCopyPrefs {
void enableCopyScreenshots(bool b);
void enableLinkFiles(bool b);
void enableUseHardLinks(bool b);
void enableLinkWorlds(bool b);
void enableDontLinkSaves(bool b);

protected: // data
bool copySaves = true;
Expand All @@ -46,5 +46,5 @@ struct InstanceCopyPrefs {
bool copyScreenshots = true;
bool linkFiles = false;
bool useHardLinks = false;
bool linkWorlds = true;
bool dontLinkSaves = false;
};
73 changes: 69 additions & 4 deletions launcher/InstanceCopyTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyP
m_keepPlaytime = prefs.isKeepPlaytimeEnabled();

QString filters = prefs.getSelectedFiltersAsRegex();

m_useLinks = prefs.isLinkFilesEnabled();
m_useHardLinks = prefs.isUseHardLinksEnabled();
m_copySaves = prefs.isDontLinkSavesEnabled() && prefs.isCopySavesEnabled();

if (!filters.isEmpty())
{
// Set regex filter:
Expand All @@ -25,11 +30,71 @@ void InstanceCopyTask::executeTask()
{
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));

m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this]{
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
folderCopy.followSymlinks(false).matcher(m_matcher.get());
auto copySaves = [&](){
FS::copy savesCopy(FS::PathCombine(m_origInstance->instanceRoot(), "saves") , FS::PathCombine(m_stagingPath, "saves"));
savesCopy.followSymlinks(false);

return savesCopy();
};

m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this, copySaves]{
if (m_useLinks) {
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
folderLink.linkRecursively(true).useHardLinks(m_useHardLinks).matcher(m_matcher.get());

bool there_were_errors = false;

if(!folderLink()){
#if defined Q_OS_WIN32
if (!m_useHardLinks) {
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";

qDebug() << "atempting to run with privelage";

QEventLoop loop;
bool got_priv_results = false;

connect(&folderLink, &FS::create_link::finishedPrivlaged, this, [&](bool gotResults){
if (!gotResults) {
qDebug() << "Privlaged run exited without results!";
}
got_priv_results = gotResults;
loop.quit();
});
folderLink.runPrivlaged();

loop.exec(); // wait for the finished signal

for (auto result : folderLink.getResults()) {
if (result.err_value != 0) {
there_were_errors = true;
}
}

if (m_copySaves) {
there_were_errors |= !copySaves();
}

return got_priv_results && !there_were_errors;
} else {
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
}
#else
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
#endif return false;
}

if (m_copySaves) {
there_were_errors |= !copySaves();
}

return !there_were_errors;
} else {
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
folderCopy.followSymlinks(false).matcher(m_matcher.get());

return folderCopy();
return folderCopy();
}
});
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
Expand Down
3 changes: 3 additions & 0 deletions launcher/InstanceCopyTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ class InstanceCopyTask : public InstanceTask
QFutureWatcher<bool> m_copyFutureWatcher;
std::unique_ptr<IPathMatcher> m_matcher;
bool m_keepPlaytime;
bool m_useLinks = false;
bool m_useHardLinks = false;
bool m_copySaves = true;
};
7 changes: 4 additions & 3 deletions launcher/ui/dialogs/CopyInstanceDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)

ui->linkFilesGroup->setChecked(m_selectedOptions.isLinkFilesEnabled());
ui->hardLinksCheckbox->setChecked(m_selectedOptions.isUseHardLinksEnabled());
ui->linkWorldsCheckbox->setChecked(m_selectedOptions.isLinkWorldsEnabled());
ui->dontLinkSavesCheckbox->setChecked(m_selectedOptions.isDontLinkSavesEnabled());
}

CopyInstanceDialog::~CopyInstanceDialog()
Expand Down Expand Up @@ -179,6 +179,7 @@ void CopyInstanceDialog::on_selectAllCheckbox_stateChanged(int state)
void CopyInstanceDialog::on_copySavesCheckbox_stateChanged(int state)
{
m_selectedOptions.enableCopySaves(state == Qt::Checked);
ui->dontLinkSavesCheckbox->setChecked((state == Qt::Checked) && ui->dontLinkSavesCheckbox->isChecked());
updateSelectAllCheckbox();
}

Expand Down Expand Up @@ -235,7 +236,7 @@ void CopyInstanceDialog::on_hardLinksCheckbox_stateChanged(int state)
m_selectedOptions.enableUseHardLinks(state == Qt::Checked);
}

void CopyInstanceDialog::on_linkWorldsCheckbox_stateChanged(int state)
void CopyInstanceDialog::on_dontLinkSavesCheckbox_stateChanged(int state)
{
m_selectedOptions.enableLinkWorlds(state == Qt::Checked);
m_selectedOptions.enableDontLinkSaves(state == Qt::Checked);
}
2 changes: 1 addition & 1 deletion launcher/ui/dialogs/CopyInstanceDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private
void on_copyScreenshotsCheckbox_stateChanged(int state);
void on_linkFilesGroup_toggled(bool checked);
void on_hardLinksCheckbox_stateChanged(int state);
void on_linkWorldsCheckbox_stateChanged(int state);
void on_dontLinkSavesCheckbox_stateChanged(int state);

private:
void checkAllCheckboxes(const bool& b);
Expand Down
9 changes: 3 additions & 6 deletions launcher/ui/dialogs/CopyInstanceDialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -240,17 +240,14 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="linkWorldsCheckbox">
<widget class="QCheckBox" name="dontLinkSavesCheckbox">
<property name="toolTip">
<string>World save data will be linked and thus shared between instances.</string>
<string>If "copy saves" is selected world save data will be copied instead of linked and thus not shared between instances.</string>
</property>
<property name="text">
<string>Link worlds</string>
<string>Don't link saves</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
Expand Down

0 comments on commit 306f741

Please sign in to comment.