diff options
| author | Trial97 <alexandru.tripon97@gmail.com> | 2023-05-04 20:29:33 +0300 | 
|---|---|---|
| committer | Trial97 <alexandru.tripon97@gmail.com> | 2023-05-04 20:29:33 +0300 | 
| commit | 9fbec3793f02f6bb3e692f98f2d86cad12c52190 (patch) | |
| tree | 9f375cbb5e46020f172fd01acd92988fe17655bc /launcher/filelink | |
| parent | b2ecb9ac09573d13c6edf8f6ea0924c1f7006b4b (diff) | |
| parent | 64ba5e4ed1456bed159cfe7b41ed9175b8baf5c4 (diff) | |
| download | PrismLauncher-9fbec3793f02f6bb3e692f98f2d86cad12c52190.tar.gz PrismLauncher-9fbec3793f02f6bb3e692f98f2d86cad12c52190.tar.bz2 PrismLauncher-9fbec3793f02f6bb3e692f98f2d86cad12c52190.zip | |
Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into develop
Diffstat (limited to 'launcher/filelink')
| -rw-r--r-- | launcher/filelink/FileLink.cpp | 277 | ||||
| -rw-r--r-- | launcher/filelink/FileLink.h | 67 | ||||
| -rw-r--r-- | launcher/filelink/filelink.exe.manifest | 28 | ||||
| -rw-r--r-- | launcher/filelink/main.cpp | 30 | 
4 files changed, 402 insertions, 0 deletions
| diff --git a/launcher/filelink/FileLink.cpp b/launcher/filelink/FileLink.cpp new file mode 100644 index 00000000..c9599b82 --- /dev/null +++ b/launcher/filelink/FileLink.cpp @@ -0,0 +1,277 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + *  Prism Launcher - Minecraft Launcher + *  Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.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/>. + * + */ + +#include "FileLink.h" +#include "BuildConfig.h" + +#include "StringUtils.h" + +#include <iostream> + +#include <QAccessible> +#include <QCommandLineParser> + +#include <QDebug> + +#include <DesktopServices.h> + +#include <sys.h> + +#if defined Q_OS_WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <stdio.h> +#include <windows.h> +#endif + +// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header + +#ifdef __APPLE__ +#include <Availability.h>  // for deployment target to support pre-catalina targets without std::fs +#endif                     // __APPLE__ + +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) +#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +#define GHC_USE_STD_FS +#include <filesystem> +namespace fs = std::filesystem; +#endif  // MacOS min version check +#endif  // Other OSes version check + +#ifndef GHC_USE_STD_FS +#include <ghc/filesystem.hpp> +namespace fs = ghc::filesystem; +#endif + +FileLinkApp::FileLinkApp(int& argc, char** argv) : QCoreApplication(argc, argv), socket(new QLocalSocket(this)) +{ +#if defined Q_OS_WIN32 +    // attach the parent console +    if (AttachConsole(ATTACH_PARENT_PROCESS)) { +        // if attach succeeds, reopen and sync all the i/o +        if (freopen("CON", "w", stdout)) { +            std::cout.sync_with_stdio(); +        } +        if (freopen("CON", "w", stderr)) { +            std::cerr.sync_with_stdio(); +        } +        if (freopen("CON", "r", stdin)) { +            std::cin.sync_with_stdio(); +        } +        auto out = GetStdHandle(STD_OUTPUT_HANDLE); +        DWORD written; +        const char* endline = "\n"; +        WriteConsole(out, endline, strlen(endline), &written, NULL); +        consoleAttached = true; +    } +#endif +    setOrganizationName(BuildConfig.LAUNCHER_NAME); +    setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN); +    setApplicationName(BuildConfig.LAUNCHER_NAME + "FileLink"); +    setApplicationVersion(BuildConfig.printableVersionString() + "\n" + BuildConfig.GIT_COMMIT); + +    // Commandline parsing +    QCommandLineParser parser; +    parser.setApplicationDescription(QObject::tr("a batch MKLINK program for windows to be used with prismlauncher")); + +    parser.addOptions({ { { "s", "server" }, "Join the specified server on launch", "pipe name" }, +                        { { "H", "hard" }, "use hard links instead of symbolic", "true/false" } }); +    parser.addHelpOption(); +    parser.addVersionOption(); + +    parser.process(arguments()); + +    QString serverToJoin = parser.value("server"); +    m_useHardLinks = QVariant(parser.value("hard")).toBool(); + +    qDebug() << "link program launched"; + +    if (!serverToJoin.isEmpty()) { +        qDebug() << "joining server" << serverToJoin; +        joinServer(serverToJoin); +    } else { +        qDebug() << "no server to join"; +        exit(); +    } +} + +void FileLinkApp::joinServer(QString server) +{ +    blockSize = 0; + +    in.setDevice(&socket); + +    connect(&socket, &QLocalSocket::connected, this, [&]() { qDebug() << "connected to server"; }); + +    connect(&socket, &QLocalSocket::readyRead, this, &FileLinkApp::readPathPairs); + +    connect(&socket, &QLocalSocket::errorOccurred, this, [&](QLocalSocket::LocalSocketError socketError) { +        switch (socketError) { +            case QLocalSocket::ServerNotFoundError: +                qDebug() +                    << ("The host was not found. Please make sure " +                        "that the server is running and that the " +                        "server name is correct."); +                break; +            case QLocalSocket::ConnectionRefusedError: +                qDebug() +                    << ("The connection was refused by the peer. " +                        "Make sure the server is running, " +                        "and check that the server name " +                        "is correct."); +                break; +            case QLocalSocket::PeerClosedError: +                qDebug() << ("The connection was closed by the peer. "); +                break; +            default: +                qDebug() << "The following error occurred: " << socket.errorString(); +        } +    }); + +    connect(&socket, &QLocalSocket::disconnected, this, [&]() { +        qDebug() << "disconnected from server, should exit"; +        exit(); +    }); + +    socket.connectToServer(server); +} + +void FileLinkApp::runLink() +{ +    std::error_code os_err; + +    qDebug() << "creating links"; + +    for (auto link : m_links_to_make) { +        QString src_path = link.src; +        QString dst_path = link.dst; + +        FS::ensureFilePathExists(dst_path); +        if (m_useHardLinks) { +            qDebug() << "making hard link:" << src_path << "to" << dst_path; +            fs::create_hard_link(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), os_err); +        } else if (fs::is_directory(StringUtils::toStdString(src_path))) { +            qDebug() << "making directory_symlink:" << src_path << "to" << dst_path; +            fs::create_directory_symlink(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), os_err); +        } else { +            qDebug() << "making symlink:" << src_path << "to" << dst_path; +            fs::create_symlink(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), os_err); +        } + +        if (os_err) { +            qWarning() << "Failed to link files:" << QString::fromStdString(os_err.message()); +            qDebug() << "Source file:" << src_path; +            qDebug() << "Destination file:" << dst_path; +            qDebug() << "Error category:" << os_err.category().name(); +            qDebug() << "Error code:" << os_err.value(); + +            FS::LinkResult result = { src_path, dst_path, QString::fromStdString(os_err.message()), os_err.value() }; +            m_path_results.append(result); +        } else { +            FS::LinkResult result = { src_path, dst_path }; +            m_path_results.append(result); +        } +    } + +    sendResults(); +    qDebug() << "done, should exit soon"; +} + +void FileLinkApp::sendResults() +{ +    // construct block of data to send +    QByteArray block; +    QDataStream out(&block, QIODevice::WriteOnly); + +    qint32 blocksize = quint32(sizeof(quint32)); +    for (auto result : m_path_results) { +        blocksize += quint32(result.src.size()); +        blocksize += quint32(result.dst.size()); +        blocksize += quint32(result.err_msg.size()); +        blocksize += quint32(sizeof(quint32)); +    } +    qDebug() << "About to write block of size:" << blocksize; +    out << blocksize; + +    out << quint32(m_path_results.length()); +    for (auto result : m_path_results) { +        out << result.src; +        out << result.dst; +        out << result.err_msg; +        out << quint32(result.err_value); +    } + +    qint64 byteswritten = socket.write(block); +    bool bytesflushed = socket.flush(); +    qDebug() << "block flushed" << byteswritten << bytesflushed; +} + +void FileLinkApp::readPathPairs() +{ +    m_links_to_make.clear(); +    qDebug() << "Reading path pairs from server"; +    qDebug() << "bytes available" << socket.bytesAvailable(); +    if (blockSize == 0) { +        // Relies on the fact that QDataStream serializes a quint32 into +        // sizeof(quint32) bytes +        if (socket.bytesAvailable() < (int)sizeof(quint32)) +            return; +        qDebug() << "reading block size"; +        in >> blockSize; +    } +    qDebug() << "blocksize is" << blockSize; +    qDebug() << "bytes available" << socket.bytesAvailable(); +    if (socket.bytesAvailable() < blockSize || in.atEnd()) +        return; + +    quint32 numLinks; +    in >> numLinks; +    qDebug() << "numLinks" << numLinks; + +    for (int i = 0; i < numLinks; i++) { +        FS::LinkPair pair; +        in >> pair.src; +        in >> pair.dst; +        qDebug() << "link" << pair.src << "to" << pair.dst; +        m_links_to_make.append(pair); +    } + +    runLink(); +} + +FileLinkApp::~FileLinkApp() +{ +    qDebug() << "link program shutting down"; +    // Shut down logger by setting the logger function to nothing +    qInstallMessageHandler(nullptr); + +#if defined Q_OS_WIN32 +    // Detach from Windows console +    if (consoleAttached) { +        fclose(stdout); +        fclose(stdin); +        fclose(stderr); +        FreeConsole(); +    } +#endif +} diff --git a/launcher/filelink/FileLink.h b/launcher/filelink/FileLink.h new file mode 100644 index 00000000..4c47d9bb --- /dev/null +++ b/launcher/filelink/FileLink.h @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + *  Prism Launcher - Minecraft Launcher + *  Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.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 <QtCore> + +#include <QApplication> +#include <QDataStream> +#include <QDateTime> +#include <QDebug> +#include <QFlag> +#include <QIcon> +#include <QLocalSocket> +#include <QUrl> +#include <memory> + +#define PRISM_EXTERNAL_EXE +#include "FileSystem.h" + +class FileLinkApp : public QCoreApplication { +    // friends for the purpose of limiting access to deprecated stuff +    Q_OBJECT +   public: +    FileLinkApp(int& argc, char** argv); +    virtual ~FileLinkApp(); + +   private: +    void joinServer(QString server); +    void readPathPairs(); +    void runLink(); +    void sendResults(); + +    bool m_useHardLinks = false; + +    QDateTime m_startTime; +    QLocalSocket socket; +    QDataStream in; +    quint32 blockSize; + +    QList<FS::LinkPair> m_links_to_make; +    QList<FS::LinkResult> m_path_results; + +#if defined Q_OS_WIN32 +    // used on Windows to attach the standard IO streams +    bool consoleAttached = false; +#endif +}; diff --git a/launcher/filelink/filelink.exe.manifest b/launcher/filelink/filelink.exe.manifest new file mode 100644 index 00000000..239aa978 --- /dev/null +++ b/launcher/filelink/filelink.exe.manifest @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +  <application xmlns="urn:schemas-microsoft-com:asm.v3"> +    <windowsSettings> +    </windowsSettings> +  </application> +  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> +    <application> +      <!-- Windows 10, Windows 11 --> +      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> +      <!-- Windows 8.1 --> +      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> +      <!-- Windows 8 --> +      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> +      <!-- Windows 7 --> +      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> +    </application> +  </compatibility> +  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> +    <security> +      <requestedPrivileges> +        <requestedExecutionLevel +          level="requireAdministrator" +          uiAccess="false"/> +       </requestedPrivileges> +    </security> +  </trustInfo> +</assembly> diff --git a/launcher/filelink/main.cpp b/launcher/filelink/main.cpp new file mode 100644 index 00000000..83566a3c --- /dev/null +++ b/launcher/filelink/main.cpp @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> +// +// SPDX-License-Identifier: GPL-3.0-only + +/* + *  Prism Launcher - Minecraft Launcher + *  Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.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/>. + * + */ + +#include "FileLink.h" + +int main(int argc, char* argv[]) +{ +    FileLinkApp ldh(argc, argv); + +    return ldh.exec(); +} | 
