refactor: make complete list of links to make and send that.
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
parent
6d160a7b7e
commit
8ba51c7900
@ -66,7 +66,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
//for ShellExecute
|
//for ShellExecute
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
//#include <shlwapi.h>
|
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <Shellapi.h>
|
#include <Shellapi.h>
|
||||||
#else
|
#else
|
||||||
@ -228,94 +227,120 @@ bool copy::operator()(const QString& offset, bool dryRun)
|
|||||||
|
|
||||||
bool create_link::operator()(const QString& offset, bool dryRun)
|
bool create_link::operator()(const QString& offset, bool dryRun)
|
||||||
{
|
{
|
||||||
|
m_linked = 0; // reset counter
|
||||||
|
m_path_results.clear();
|
||||||
|
m_links_to_make.clear();
|
||||||
|
|
||||||
|
m_path_results.clear();
|
||||||
|
|
||||||
|
make_link_list(offset);
|
||||||
|
|
||||||
|
if (!dryRun)
|
||||||
|
return make_links();
|
||||||
|
|
||||||
for (auto pair : m_path_pairs) {
|
|
||||||
if (!make_link(pair.src, pair.dst, offset, dryRun)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief links a directory and it's contents from src to dest
|
* @brief make a list off all the links ot make
|
||||||
* @param offset subdirectory form src to link to dest
|
* @param offset subdirectory form src to link to dest
|
||||||
* @return if there was an error during the attempt to link
|
* @return if there was an error during the attempt to link
|
||||||
*/
|
*/
|
||||||
bool create_link::make_link(const QString& srcPath, const QString& dstPath, const QString& offset, bool dryRun)
|
void create_link::make_link_list( const QString& offset)
|
||||||
{
|
{
|
||||||
m_linked = 0; // reset counter
|
for (auto pair : m_path_pairs) {
|
||||||
|
const QString& srcPath = pair.src;
|
||||||
|
const QString& dstPath = pair.dst;
|
||||||
|
|
||||||
auto src = PathCombine(QDir(srcPath).absolutePath(), offset);
|
auto src = PathCombine(QDir(srcPath).absolutePath(), offset);
|
||||||
auto dst = PathCombine(QDir(dstPath).absolutePath(), offset);
|
auto dst = PathCombine(QDir(dstPath).absolutePath(), offset);
|
||||||
|
|
||||||
// you can't hard link a directory so make sure if we deal with a directory we do so recursively
|
// you can't hard link a directory so make sure if we deal with a directory we do so recursively
|
||||||
if (m_useHardLinks)
|
if (m_useHardLinks)
|
||||||
m_recursive = true;
|
m_recursive = true;
|
||||||
|
|
||||||
// Function that'll do the actual linking
|
// Function that'll do the actual linking
|
||||||
auto link_file = [&](QString src_path, QString relative_dst_path) {
|
auto link_file = [&](QString src_path, QString relative_dst_path) {
|
||||||
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
|
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist)) {
|
||||||
return;
|
qDebug() << "path" << relative_dst_path << "in black list or not in whitelist";
|
||||||
|
return;
|
||||||
auto dst_path = PathCombine(dst, relative_dst_path);
|
|
||||||
if (!dryRun) {
|
|
||||||
|
|
||||||
ensureFilePathExists(dst_path);
|
|
||||||
if (m_useHardLinks) {
|
|
||||||
if (m_debug)
|
|
||||||
qDebug() << "making hard link:" << src_path << "to" << dst_path;
|
|
||||||
fs::create_hard_link(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), m_os_err);
|
|
||||||
} else if (fs::is_directory(StringUtils::toStdString(src_path))) {
|
|
||||||
if (m_debug)
|
|
||||||
qDebug() << "making directory_symlink:" << src_path << "to" << dst_path;
|
|
||||||
fs::create_directory_symlink(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), m_os_err);
|
|
||||||
} else {
|
|
||||||
if (m_debug)
|
|
||||||
qDebug() << "making symlink:" << src_path << "to" << dst_path;
|
|
||||||
fs::create_symlink(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), m_os_err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto dst_path = PathCombine(dst, relative_dst_path);
|
||||||
|
LinkPair link = {src_path, dst_path};
|
||||||
|
m_links_to_make.append(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((!m_recursive) || !fs::is_directory(StringUtils::toStdString(src))) {
|
||||||
|
if (m_debug)
|
||||||
|
qDebug() << "linking single file or dir:" << src << "to" << dst;
|
||||||
|
link_file(src, "");
|
||||||
|
} else {
|
||||||
|
if (m_debug)
|
||||||
|
qDebug() << "linking recursivly:" << src << "to" << dst;
|
||||||
|
QDir src_dir(src);
|
||||||
|
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
||||||
|
|
||||||
|
while (source_it.hasNext()) {
|
||||||
|
auto src_path = source_it.next();
|
||||||
|
auto relative_path = src_dir.relativeFilePath(src_path);
|
||||||
|
|
||||||
|
link_file(src_path, relative_path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create_link::make_links()
|
||||||
|
{
|
||||||
|
for (auto link : m_links_to_make) {
|
||||||
|
|
||||||
|
QString src_path = link.src;
|
||||||
|
QString dst_path = link.dst;
|
||||||
|
|
||||||
|
ensureFilePathExists(dst_path);
|
||||||
|
if (m_useHardLinks) {
|
||||||
|
if (m_debug)
|
||||||
|
qDebug() << "making hard link:" << src_path << "to" << dst_path;
|
||||||
|
fs::create_hard_link(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), m_os_err);
|
||||||
|
} else if (fs::is_directory(StringUtils::toStdString(src_path))) {
|
||||||
|
if (m_debug)
|
||||||
|
qDebug() << "making directory_symlink:" << src_path << "to" << dst_path;
|
||||||
|
fs::create_directory_symlink(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), m_os_err);
|
||||||
|
} else {
|
||||||
|
if (m_debug)
|
||||||
|
qDebug() << "making symlink:" << src_path << "to" << dst_path;
|
||||||
|
fs::create_symlink(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), m_os_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (m_os_err) {
|
if (m_os_err) {
|
||||||
qWarning() << "Failed to link files:" << QString::fromStdString(m_os_err.message());
|
qWarning() << "Failed to link files:" << QString::fromStdString(m_os_err.message());
|
||||||
qDebug() << "Source file:" << src_path;
|
qDebug() << "Source file:" << src_path;
|
||||||
qDebug() << "Destination file:" << dst_path;
|
qDebug() << "Destination file:" << dst_path;
|
||||||
qDebug() << "Error catagory:" << m_os_err.category().name();
|
qDebug() << "Error catagory:" << m_os_err.category().name();
|
||||||
qDebug() << "Error code:" << m_os_err.value();
|
qDebug() << "Error code:" << m_os_err.value();
|
||||||
emit linkFailed(src_path, dst_path, m_os_err);
|
emit linkFailed(src_path, dst_path, QString::fromStdString(m_os_err.message()), m_os_err.value());
|
||||||
} else {
|
} else {
|
||||||
m_linked++;
|
m_linked++;
|
||||||
emit fileLinked(relative_dst_path);
|
emit fileLinked(src_path, dst_path);
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
if ((!m_recursive) || !fs::is_directory(StringUtils::toStdString(src))) {
|
|
||||||
if (m_debug)
|
|
||||||
qDebug() << "linking single file or dir:" << src << "to" << dst;
|
|
||||||
link_file(src, "");
|
|
||||||
} else {
|
|
||||||
if (m_debug)
|
|
||||||
qDebug() << "linking recursivly:" << src << "to" << dst;
|
|
||||||
QDir src_dir(src);
|
|
||||||
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
|
||||||
|
|
||||||
while (source_it.hasNext()) {
|
|
||||||
auto src_path = source_it.next();
|
|
||||||
auto relative_path = src_dir.relativeFilePath(src_path);
|
|
||||||
|
|
||||||
link_file(src_path, relative_path);
|
|
||||||
if (m_os_err) return false;
|
|
||||||
}
|
}
|
||||||
|
if (m_os_err) return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
return m_os_err.value() == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_link::runPrivlaged(const QString& offset)
|
void create_link::runPrivlaged(const QString& offset)
|
||||||
{
|
{
|
||||||
|
m_linked = 0; // reset counter
|
||||||
|
m_path_results.clear();
|
||||||
|
m_links_to_make.clear();
|
||||||
|
|
||||||
|
bool gotResults = false;
|
||||||
|
|
||||||
|
make_link_list(offset);
|
||||||
|
|
||||||
QString serverName = BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink_server" + StringUtils::getRandomAlphaNumeric(8);
|
QString serverName = BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink_server" + StringUtils::getRandomAlphaNumeric(8);
|
||||||
|
|
||||||
@ -325,26 +350,73 @@ bool create_link::runPrivlaged(const QString& offset)
|
|||||||
// construct block of data to send
|
// construct block of data to send
|
||||||
QByteArray block;
|
QByteArray block;
|
||||||
QDataStream out(&block, QIODevice::WriteOnly);
|
QDataStream out(&block, QIODevice::WriteOnly);
|
||||||
out.setVersion(QDataStream::Qt_5_15); // choose correct version better?
|
out.setVersion(QDataStream::Qt_5_0); // choose correct version better?
|
||||||
|
|
||||||
qint32 blocksize = quint32(sizeof(quint32));
|
qint32 blocksize = quint32(sizeof(quint32));
|
||||||
for (auto pair : m_path_pairs) {
|
for (auto link : m_links_to_make) {
|
||||||
blocksize += quint32(pair.src.size());
|
blocksize += quint32(link.src.size());
|
||||||
blocksize += quint32(pair.dst.size());
|
blocksize += quint32(link.dst.size());
|
||||||
}
|
}
|
||||||
qDebug() << "About to write block of size:" << blocksize;
|
qDebug() << "About to write block of size:" << blocksize;
|
||||||
out << blocksize;
|
out << blocksize;
|
||||||
|
|
||||||
out << quint32(m_path_pairs.length());
|
out << quint32(m_links_to_make.length());
|
||||||
for (auto pair : m_path_pairs) {
|
for (auto link : m_links_to_make) {
|
||||||
out << pair.src;
|
out << link.src;
|
||||||
out << pair.dst;
|
out << link.dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLocalSocket *clientConnection = m_linkServer.nextPendingConnection();
|
QLocalSocket *clientConnection = m_linkServer.nextPendingConnection();
|
||||||
connect(clientConnection, &QLocalSocket::disconnected,
|
connect(clientConnection, &QLocalSocket::disconnected,
|
||||||
clientConnection, &QLocalSocket::deleteLater);
|
clientConnection, &QLocalSocket::deleteLater);
|
||||||
|
|
||||||
|
connect(clientConnection, &QLocalSocket::readyRead, this, [&, clientConnection](){
|
||||||
|
QDataStream in;
|
||||||
|
quint32 blockSize = 0;
|
||||||
|
in.setDevice(clientConnection);
|
||||||
|
in.setVersion(QDataStream::Qt_5_0);
|
||||||
|
qDebug() << "Reading path results from client";
|
||||||
|
qDebug() << "bytes avalible" << clientConnection->bytesAvailable();
|
||||||
|
|
||||||
|
// Relies on the fact that QDataStream serializes a quint32 into
|
||||||
|
// sizeof(quint32) bytes
|
||||||
|
if (clientConnection->bytesAvailable() < (int)sizeof(quint32))
|
||||||
|
return;
|
||||||
|
qDebug() << "reading block size";
|
||||||
|
in >> blockSize;
|
||||||
|
|
||||||
|
qDebug() << "blocksize is" << blockSize;
|
||||||
|
qDebug() << "bytes avalible" << clientConnection->bytesAvailable();
|
||||||
|
if (clientConnection->bytesAvailable() < blockSize || in.atEnd())
|
||||||
|
return;
|
||||||
|
|
||||||
|
quint32 numResults;
|
||||||
|
in >> numResults;
|
||||||
|
qDebug() << "numResults" << numResults;
|
||||||
|
|
||||||
|
for(int i = 0; i < numResults; i++) {
|
||||||
|
FS::LinkResult result;
|
||||||
|
in >> result.src;
|
||||||
|
in >> result.dst;
|
||||||
|
in >> result.err_msg;
|
||||||
|
qint32 err_value;
|
||||||
|
in >> err_value;
|
||||||
|
result.err_value = err_value;
|
||||||
|
if (result.err_value) {
|
||||||
|
qDebug() << "privlaged link fail" << result.src << "to" << result.dst << "code" << result.err_value << result.err_msg;
|
||||||
|
emit linkFailed(result.src, result.dst, result.err_msg, result.err_value);
|
||||||
|
} else {
|
||||||
|
qDebug() << "privlaged link success" << result.src << "to" << result.dst;
|
||||||
|
m_linked++;
|
||||||
|
emit fileLinked(result.src, result.dst);
|
||||||
|
}
|
||||||
|
m_path_results.append(result);
|
||||||
|
}
|
||||||
|
gotResults = true;
|
||||||
|
qDebug() << "results recieved, closing connection";
|
||||||
|
clientConnection->close();
|
||||||
|
});
|
||||||
|
|
||||||
qint64 byteswritten = clientConnection->write(block);
|
qint64 byteswritten = clientConnection->write(block);
|
||||||
bool bytesflushed = clientConnection->flush();
|
bool bytesflushed = clientConnection->flush();
|
||||||
qDebug() << "block flushed" << byteswritten << bytesflushed;
|
qDebug() << "block flushed" << byteswritten << bytesflushed;
|
||||||
@ -354,20 +426,15 @@ bool create_link::runPrivlaged(const QString& offset)
|
|||||||
qDebug() << "Listening on pipe" << serverName;
|
qDebug() << "Listening on pipe" << serverName;
|
||||||
if (!m_linkServer.listen(serverName)) {
|
if (!m_linkServer.listen(serverName)) {
|
||||||
qDebug() << "Unable to start local pipe server on" << serverName << ":" << m_linkServer.errorString();
|
qDebug() << "Unable to start local pipe server on" << serverName << ":" << m_linkServer.errorString();
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalLinkFileProcess *linkFileProcess = new ExternalLinkFileProcess(serverName, this);
|
ExternalLinkFileProcess* linkFileProcess = new ExternalLinkFileProcess(serverName, m_useHardLinks, this);
|
||||||
connect(linkFileProcess, &ExternalLinkFileProcess::processExited, this, [&](){
|
connect(linkFileProcess, &ExternalLinkFileProcess::processExited, this, [&]() { emit finishedPrivlaged(gotResults); });
|
||||||
emit finishedPrivlaged();
|
|
||||||
});
|
|
||||||
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
|
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
|
||||||
|
|
||||||
linkFileProcess->start();
|
linkFileProcess->start();
|
||||||
|
|
||||||
// linkFileProcess->wait();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -375,6 +442,8 @@ void ExternalLinkFileProcess::runLinkFile() {
|
|||||||
QString fileLinkExe = PathCombine(QCoreApplication::instance()->applicationDirPath(), BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink");
|
QString fileLinkExe = PathCombine(QCoreApplication::instance()->applicationDirPath(), BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink");
|
||||||
QString params = "-s " + m_server;
|
QString params = "-s " + m_server;
|
||||||
|
|
||||||
|
params += " -H " + QVariant(m_useHardLinks).toString();
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
SHELLEXECUTEINFO ShExecInfo;
|
SHELLEXECUTEINFO ShExecInfo;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -133,13 +133,22 @@ struct LinkPair {
|
|||||||
QString dst;
|
QString dst;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExternalLinkFileProcess : public QThread
|
struct LinkResult {
|
||||||
{
|
QString src;
|
||||||
|
QString dst;
|
||||||
|
QString err_msg;
|
||||||
|
int err_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExternalLinkFileProcess : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ExternalLinkFileProcess(QString server, QObject* parent = nullptr) : QThread(parent), m_server(server) {}
|
ExternalLinkFileProcess(QString server, bool useHardLinks, QObject* parent = nullptr)
|
||||||
|
: QThread(parent), m_server(server), m_useHardLinks(useHardLinks)
|
||||||
|
{}
|
||||||
|
|
||||||
void run() override {
|
void run() override
|
||||||
|
{
|
||||||
runLinkFile();
|
runLinkFile();
|
||||||
emit processExited();
|
emit processExited();
|
||||||
}
|
}
|
||||||
@ -150,6 +159,8 @@ class ExternalLinkFileProcess : public QThread
|
|||||||
private:
|
private:
|
||||||
void runLinkFile();
|
void runLinkFile();
|
||||||
|
|
||||||
|
bool m_useHardLinks = false;
|
||||||
|
|
||||||
QString m_server;
|
QString m_server;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -200,19 +211,21 @@ class create_link : public QObject {
|
|||||||
|
|
||||||
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
||||||
|
|
||||||
bool runPrivlaged() { return runPrivlaged(QString()); }
|
void runPrivlaged() { runPrivlaged(QString()); }
|
||||||
bool runPrivlaged(const QString& offset);
|
void runPrivlaged(const QString& offset);
|
||||||
|
|
||||||
int totalLinked() { return m_linked; }
|
int totalLinked() { return m_linked; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void fileLinked(const QString& relativeName);
|
void fileLinked(const QString& srcName, const QString& dstName);
|
||||||
void linkFailed(const QString& srcName, const QString& dstName, std::error_code err);
|
void linkFailed(const QString& srcName, const QString& dstName, const QString& err_msg, int err_value);
|
||||||
void finishedPrivlaged();
|
void finishedPrivlaged(bool gotResults);
|
||||||
|
void finished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool operator()(const QString& offset, bool dryRun = false);
|
bool operator()(const QString& offset, bool dryRun = false);
|
||||||
bool make_link(const QString& src_path, const QString& dst_path, const QString& offset, bool dryRun);
|
void make_link_list(const QString& offset);
|
||||||
|
bool make_links();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_useHardLinks = false;
|
bool m_useHardLinks = false;
|
||||||
@ -221,6 +234,8 @@ class create_link : public QObject {
|
|||||||
bool m_recursive = true;
|
bool m_recursive = true;
|
||||||
|
|
||||||
QList<LinkPair> m_path_pairs;
|
QList<LinkPair> m_path_pairs;
|
||||||
|
QList<LinkResult> m_path_results;
|
||||||
|
QList<LinkPair> m_links_to_make;
|
||||||
|
|
||||||
int m_linked;
|
int m_linked;
|
||||||
bool m_debug = false;
|
bool m_debug = false;
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include "FileLink.h"
|
#include "FileLink.h"
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@ -43,6 +45,24 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -82,7 +102,8 @@ FileLinkApp::FileLinkApp(int &argc, char **argv) : QCoreApplication(argc, argv),
|
|||||||
parser.setApplicationDescription(QObject::tr("a batch MKLINK program for windows to be used with prismlauncher"));
|
parser.setApplicationDescription(QObject::tr("a batch MKLINK program for windows to be used with prismlauncher"));
|
||||||
|
|
||||||
parser.addOptions({
|
parser.addOptions({
|
||||||
{{"s", "server"}, "Join the specified server on launch", "pipe name"}
|
{{"s", "server"}, "Join the specified server on launch", "pipe name"},
|
||||||
|
{{"H", "hard"}, "use hard links insted of symbolic", "true/false"}
|
||||||
});
|
});
|
||||||
parser.addHelpOption();
|
parser.addHelpOption();
|
||||||
parser.addVersionOption();
|
parser.addVersionOption();
|
||||||
@ -90,6 +111,7 @@ FileLinkApp::FileLinkApp(int &argc, char **argv) : QCoreApplication(argc, argv),
|
|||||||
parser.process(arguments());
|
parser.process(arguments());
|
||||||
|
|
||||||
QString serverToJoin = parser.value("server");
|
QString serverToJoin = parser.value("server");
|
||||||
|
m_useHardLinks = QVariant(parser.value("hard")).toBool();
|
||||||
|
|
||||||
qDebug() << "link program launched";
|
qDebug() << "link program launched";
|
||||||
|
|
||||||
@ -109,7 +131,7 @@ void FileLinkApp::joinServer(QString server)
|
|||||||
blockSize = 0;
|
blockSize = 0;
|
||||||
|
|
||||||
in.setDevice(&socket);
|
in.setDevice(&socket);
|
||||||
in.setVersion(QDataStream::Qt_5_15);
|
in.setVersion(QDataStream::Qt_5_0);
|
||||||
|
|
||||||
connect(&socket, &QLocalSocket::connected, this, [&](){
|
connect(&socket, &QLocalSocket::connected, this, [&](){
|
||||||
qDebug() << "connected to server";
|
qDebug() << "connected to server";
|
||||||
@ -120,25 +142,27 @@ void FileLinkApp::joinServer(QString server)
|
|||||||
connect(&socket, &QLocalSocket::errorOccurred, this, [&](QLocalSocket::LocalSocketError socketError){
|
connect(&socket, &QLocalSocket::errorOccurred, this, [&](QLocalSocket::LocalSocketError socketError){
|
||||||
switch (socketError) {
|
switch (socketError) {
|
||||||
case QLocalSocket::ServerNotFoundError:
|
case QLocalSocket::ServerNotFoundError:
|
||||||
qDebug() << tr("The host was not found. Please make sure "
|
qDebug() << ("The host was not found. Please make sure "
|
||||||
"that the server is running and that the "
|
"that the server is running and that the "
|
||||||
"server name is correct.");
|
"server name is correct.");
|
||||||
break;
|
break;
|
||||||
case QLocalSocket::ConnectionRefusedError:
|
case QLocalSocket::ConnectionRefusedError:
|
||||||
qDebug() << tr("The connection was refused by the peer. "
|
qDebug() << ("The connection was refused by the peer. "
|
||||||
"Make sure the server is running, "
|
"Make sure the server is running, "
|
||||||
"and check that the server name "
|
"and check that the server name "
|
||||||
"is correct.");
|
"is correct.");
|
||||||
break;
|
break;
|
||||||
case QLocalSocket::PeerClosedError:
|
case QLocalSocket::PeerClosedError:
|
||||||
|
qDebug() << ("The connection was closed by the peer. ");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qDebug() << tr("The following error occurred: %1.").arg(socket.errorString());
|
qDebug() << "The following error occurred: " << socket.errorString();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(&socket, &QLocalSocket::disconnected, this, [&](){
|
connect(&socket, &QLocalSocket::disconnected, this, [&](){
|
||||||
qDebug() << "dissconnected from server";
|
qDebug() << "dissconnected from server, should exit";
|
||||||
|
exit();
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.connectToServer(server);
|
socket.connectToServer(server);
|
||||||
@ -148,19 +172,81 @@ void FileLinkApp::joinServer(QString server)
|
|||||||
|
|
||||||
void FileLinkApp::runLink()
|
void FileLinkApp::runLink()
|
||||||
{
|
{
|
||||||
qDebug() << "creating link";
|
|
||||||
FS::create_link lnk(m_path_pairs);
|
std::error_code os_err;
|
||||||
lnk.debug(true);
|
|
||||||
if (!lnk()) {
|
qDebug() << "creating links";
|
||||||
qDebug() << "Link Failed!" << lnk.getOSError().value() << lnk.getOSError().message().c_str();
|
|
||||||
|
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 catagory:" << 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//exit();
|
|
||||||
qDebug() << "done, should exit";
|
sendResults();
|
||||||
|
qDebug() << "done, should exit soon";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileLinkApp::sendResults()
|
||||||
|
{
|
||||||
|
// construct block of data to send
|
||||||
|
QByteArray block;
|
||||||
|
QDataStream out(&block, QIODevice::WriteOnly);
|
||||||
|
out.setVersion(QDataStream::Qt_5_0);
|
||||||
|
|
||||||
|
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()
|
void FileLinkApp::readPathPairs()
|
||||||
{
|
{
|
||||||
m_path_pairs.clear();
|
m_links_to_make.clear();
|
||||||
qDebug() << "Reading path pairs from server";
|
qDebug() << "Reading path pairs from server";
|
||||||
qDebug() << "bytes avalible" << socket.bytesAvailable();
|
qDebug() << "bytes avalible" << socket.bytesAvailable();
|
||||||
if (blockSize == 0) {
|
if (blockSize == 0) {
|
||||||
@ -176,16 +262,16 @@ void FileLinkApp::readPathPairs()
|
|||||||
if (socket.bytesAvailable() < blockSize || in.atEnd())
|
if (socket.bytesAvailable() < blockSize || in.atEnd())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
quint32 numPairs;
|
quint32 numLinks;
|
||||||
in >> numPairs;
|
in >> numLinks;
|
||||||
qDebug() << "numPairs" << numPairs;
|
qDebug() << "numLinks" << numLinks;
|
||||||
|
|
||||||
for(int i = 0; i < numPairs; i++) {
|
for(int i = 0; i < numLinks; i++) {
|
||||||
FS::LinkPair pair;
|
FS::LinkPair pair;
|
||||||
in >> pair.src;
|
in >> pair.src;
|
||||||
in >> pair.dst;
|
in >> pair.dst;
|
||||||
qDebug() << "link" << pair.src << "to" << pair.dst;
|
qDebug() << "link" << pair.src << "to" << pair.dst;
|
||||||
m_path_pairs.append(pair);
|
m_links_to_make.append(pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
runLink();
|
runLink();
|
||||||
|
@ -52,13 +52,17 @@ private:
|
|||||||
void joinServer(QString server);
|
void joinServer(QString server);
|
||||||
void readPathPairs();
|
void readPathPairs();
|
||||||
void runLink();
|
void runLink();
|
||||||
|
void sendResults();
|
||||||
|
|
||||||
|
bool m_useHardLinks = false;
|
||||||
|
|
||||||
QDateTime m_startTime;
|
QDateTime m_startTime;
|
||||||
QLocalSocket socket;
|
QLocalSocket socket;
|
||||||
QDataStream in;
|
QDataStream in;
|
||||||
quint32 blockSize;
|
quint32 blockSize;
|
||||||
|
|
||||||
QList<FS::LinkPair> m_path_pairs;
|
QList<FS::LinkPair> m_links_to_make;
|
||||||
|
QList<FS::LinkResult> m_path_results;
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
// used on Windows to attach the standard IO streams
|
// used on Windows to attach the standard IO streams
|
||||||
|
@ -66,12 +66,17 @@ class LinkTask : public Task {
|
|||||||
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
|
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
|
||||||
|
|
||||||
qDebug() << "atempting to run with privelage";
|
qDebug() << "atempting to run with privelage";
|
||||||
connect(m_lnk, &FS::create_link::finishedPrivlaged, this, [&](){
|
connect(m_lnk, &FS::create_link::finishedPrivlaged, this, [&](bool gotResults){
|
||||||
emitSucceeded();
|
if (gotResults) {
|
||||||
|
emitSucceeded();
|
||||||
|
} else {
|
||||||
|
qDebug() << "Privlaged run exited without results!";
|
||||||
|
emitFailed();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
m_lnk->runPrivlaged();
|
m_lnk->runPrivlaged();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Link Failed!" << m_lnk->getOSError().value() << m_lnk->getOSError().message().c_str();
|
qDebug() << "Link Failed!" << m_lnk->getOSError().value() << m_lnk->getOSError().message().c_str();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
qDebug() << "Link Failed!" << m_lnk->getOSError().value() << m_lnk->getOSError().message().c_str();
|
qDebug() << "Link Failed!" << m_lnk->getOSError().value() << m_lnk->getOSError().message().c_str();
|
||||||
|
Loading…
Reference in New Issue
Block a user