Skip to content

Commit

Permalink
Fix symlinking for Windows.
Browse files Browse the repository at this point in the history
  • Loading branch information
DeathByDenim committed Mar 13, 2015
1 parent 947626f commit d652237
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 69 deletions.
59 changes: 2 additions & 57 deletions bundle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@
#include <QCryptographicHash>
#include <QNetworkReply>
#include <zlib.h>
#if !defined(_WIN32)
# include <unistd.h>
# include <cstring>
# include <cerrno>
#endif

Bundle::Bundle(QString install_path, Patcher *patcher)
: QObject(), mInstallPath(install_path), mPatcher(patcher), mNeedsDownloading(false), mBufferSize(10*1024)
Expand Down Expand Up @@ -160,16 +155,7 @@ void Bundle::verifyFinished()
if(mNeedsDownloading)
emit downloadMe();
else
{
#ifdef _WIN32
for(QMap<QString,QString>::const_iterator symlink = mCopyLater.constBegin(); symlink != mCopyLater.constEnd(); ++symlink)
{
QFile from_file(symlink.key());
from_file.copy(symlink.value());
}
#endif
emit finished();
}
}
}

Expand Down Expand Up @@ -314,14 +300,6 @@ void Bundle::downloadFinished()

reply->deleteLater();

#ifdef _WIN32
for(QMap<QString,QString>::const_iterator symlink = mCopyLater.constBegin(); symlink != mCopyLater.constEnd(); ++symlink)
{
QFile from_file(symlink.key());
from_file.copy(symlink.value());
}
#endif

emit finished();
}
}
Expand Down Expand Up @@ -402,41 +380,8 @@ void Bundle::nextFile()

bool Bundle::createSymbolicLink(const QString& from, const QString& to)
{
// This is the same file, so make a symbolic link, but first
// find the relative path.
QStringList path1 = from.split(QRegExp("[\\\\/]"));
QStringList path2 = to.split(QRegExp("[\\\\/]"));
int i;
for(i = 0; i < path2.count() - 1; i++)
{
if(path1[i] == path2[i])
{
path1[i] = "";
path2[i] = "";
}
else
break;
}
for(; i < path2.count() - 1; i++)
{
path1.push_front("..");
}

for(int i = path1.count() - 1; i >= 0; i--)
{
if(path1[i].isEmpty())
path1.removeAt(i);
}

#if defined(_WIN32)
mCopyLater[mInstallPath + "/" + to] = path1.join("/");
#else
int res = symlink(path1.join("/").toStdString().c_str(), (mInstallPath + "/" + to).toStdString().c_str());
if(res != 0)
{
return false;
}
#endif
// Add to the list, which is retrieved by Patcher later to make the actual links.
mSymLinkLater[mInstallPath + "/" + to] = mInstallPath + "/" + from;

return true;
}
Expand Down
5 changes: 2 additions & 3 deletions bundle.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Bundle : public QObject
QString checksum() {return mChecksum;}
qint64 totalSize() {return mTotalSize;}
void downloadAndExtract(QNetworkAccessManager* network_access_manager, QString download_url);
const QMap<QString,QString> & symLinks() {return mSymLinkLater;}

private:
struct File
Expand Down Expand Up @@ -58,9 +59,7 @@ class Bundle : public QObject
QFile *mCurrentFile;
bool mCurrentFileIsGzipped;
int mFilesCurrentIndex;
#if defined(_WIN32)
QMap<QString,QString> mCopyLater;
#endif
QMap<QString,QString> mSymLinkLater;

static bool verifySHA1(Bundle::File file_entry, bool* downloading, Patcher* patcher, QString install_path);
void prepareZLib();
Expand Down
136 changes: 133 additions & 3 deletions patcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
#include <QNetworkReply>
#include <QMessageBox>
#include <QApplication>
#if !defined(_WIN32)
# include <unistd.h>
# include <cstring>
# include <cerrno>
#endif

bool error_occurred = false;

Expand Down Expand Up @@ -124,20 +129,145 @@ void Patcher::bundleVerifyDone()
}
}

void Patcher::bundleError(QString error_string)
{
emit stateChange("Error occurred");
emit error(error_string);
}

void Patcher::bundleFinished()
{/*
for(QMap<QString,QString>::const_iterator symlink = mCopyLater.constBegin(); symlink != mCopyLater.constEnd(); ++symlink)
{
QFile from_file(symlink.key());
from_file.copy(symlink.value());
}
int res = symlink(path1.join("/").toStdString().c_str(), (mInstallPath + "/" + to).toStdString().c_str());
if(res != 0)
{
return false;
}
*/

Bundle *bundle = dynamic_cast<Bundle *>(sender());
if(bundle)
{
for(QMap<QString,QString>::const_iterator link = bundle->symLinks().constBegin(); link != bundle->symLinks().constEnd(); ++link)
{
mSymLinkLater.insert(link.key(), link.value());
}
}

mBundlesFinished++;
if(mBundlesFinished == mNumBundles)
{
processSymLinks();

emit stateChange("Done");
emit done();
}
}

void Patcher::bundleError(QString error_string)
void Patcher::processSymLinks()
{
emit stateChange("Error occurred");
emit error(error_string);
bool something_changed;

while(mSymLinkLater.size() > 0)
{
something_changed = false;
for(QMap<QString,QString>::const_iterator slink = mSymLinkLater.constBegin(); slink != mSymLinkLater.constEnd(); ++slink)
{
QFile source_file(slink.value());
if(source_file.exists())
{
QFile target_file(slink.key());
if(target_file.exists())
target_file.remove();

#ifdef _WIN32
if(!from_file.copy(symlink.key()))
{
emit error(tr("Error copying duplicate file \"%1\" to \"%2\".\n%3").arg(symlink.value()).arg(symlink.value()).arg(from_file.errorString()));
return;
}
#else
// For proper symlinks, we need to find the relative path.
QStringList target_path = slink.key().split(QRegExp("[\\\\/]"));
QStringList source_path = slink.value().split(QRegExp("[\\\\/]"));
int i;
for(i = 0; i < target_path.count() - 1; i++)
{
if(source_path[i] == target_path[i])
{
source_path[i] = "";
target_path[i] = "";
}
else
break;
}
for(; i < target_path.count() - 1; i++)
{
source_path.push_front("..");
}

for(int i = source_path.count() - 1; i >= 0; i--)
{
if(source_path[i].isEmpty())
source_path.removeAt(i);
}

int res = symlink(source_path.join("/").toStdString().c_str(), slink.key().toStdString().c_str());
if(res != 0)
{
int error_code = errno;
emit error(tr("Error creating symlink from \"%1\" to \"%2\".\n%3").arg(source_file.fileName()).arg(source_path.join('/')).arg(strerror(error_code)));
return;
}
#endif

mSymLinkLater.remove(slink.key());
something_changed = true;
break;
}
}

if(!something_changed)
{
emit error(tr("Error copying duplicate file. Source does not exist."));
return;
}
}

/*
// This is the same file, so make a symbolic link, but first
// find the relative path.
QStringList path1 = from.split(QRegExp("[\\\\/]"));
QStringList path2 = to.split(QRegExp("[\\\\/]"));
int i;
for(i = 0; i < path2.count() - 1; i++)
{
if(path1[i] == path2[i])
{
path1[i] = "";
path2[i] = "";
}
else
break;
}
for(; i < path2.count() - 1; i++)
{
path1.push_front("..");
}
for(int i = path1.count() - 1; i >= 0; i--)
{
if(path1[i].isEmpty())
path1.removeAt(i);
}
int res = symlink(path1.join("/").toStdString().c_str(), (mInstallPath + "/" + to).toStdString().c_str());
*/
}


Expand Down
15 changes: 9 additions & 6 deletions patcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <QObject>
#include <QJsonDocument>
#include <QMutex>
#include <QMap>

class QNetworkAccessManager;

Expand All @@ -16,7 +17,7 @@ class Patcher : public QObject
~Patcher();

void setInstallPath(QString install_path) {mInstallPath = install_path;}
void setDownloadUrl(QString url) {mDownloadUrl = url;}
void setDownloadUrl(QString url) {mDownloadUrl = url;}
void giveJsonData(QByteArray data);
QByteArray getFile(QString filename);

Expand All @@ -33,8 +34,10 @@ class Patcher : public QObject
int mNumBundles;
int mBundlesVerified;
int mBundlesFinished;
QMap<QString,QString> mSymLinkLater;

void startVerifying();
void processSymLinks();

signals:
void error(QString);
Expand All @@ -43,11 +46,11 @@ class Patcher : public QObject
void stateChange(QString state);

private slots:
void bundleDownloadMe();
void bundleDownloadProgress(qint64);
void bundleVerifyDone();
void bundleFinished();
void bundleError(QString error);
void bundleDownloadMe();
void bundleDownloadProgress(qint64);
void bundleVerifyDone();
void bundleFinished();
void bundleError(QString error);

public slots:
void parseManifest();
Expand Down

0 comments on commit d652237

Please sign in to comment.