2014-01-22 21:58:53 +00:00
|
|
|
/**
|
|
|
|
* Copyright 2014 Samoilenko Yuri<kinnalru@gmail.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; either version 2 of
|
|
|
|
* the License or (at your option) version 3 or any later version
|
|
|
|
* accepted by the membership of KDE e.V. (or its successor approved
|
|
|
|
* by the membership of KDE e.V.), which shall act as a proxy
|
|
|
|
* defined in Section 14 of version 3 of the license.
|
|
|
|
*
|
|
|
|
* 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
|
2019-03-23 16:29:26 +00:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2014-01-22 21:58:53 +00:00
|
|
|
*/
|
|
|
|
|
2015-06-21 20:32:18 +01:00
|
|
|
#include "mounter.h"
|
|
|
|
|
2017-03-15 16:39:35 +00:00
|
|
|
#include <unistd.h>
|
2014-01-22 21:58:53 +00:00
|
|
|
#include <QDir>
|
2014-09-21 23:45:59 +01:00
|
|
|
#include <QDebug>
|
2014-01-22 21:58:53 +00:00
|
|
|
|
|
|
|
#include <KLocalizedString>
|
|
|
|
|
2015-06-21 20:32:18 +01:00
|
|
|
#include "mountloop.h"
|
2017-09-05 21:22:55 +01:00
|
|
|
#include "config-sftp.h"
|
2014-09-21 23:45:59 +01:00
|
|
|
#include "sftp_debug.h"
|
2016-07-05 13:27:53 +01:00
|
|
|
#include "kdeconnectconfig.h"
|
2014-01-22 21:58:53 +00:00
|
|
|
|
2015-03-09 05:12:55 +00:00
|
|
|
Mounter::Mounter(SftpPlugin* sftp)
|
2014-01-22 21:58:53 +00:00
|
|
|
: QObject(sftp)
|
|
|
|
, m_sftp(sftp)
|
2015-09-08 09:46:59 +01:00
|
|
|
, m_proc(nullptr)
|
2015-06-21 20:32:18 +01:00
|
|
|
, m_mountPoint(sftp->mountPoint())
|
2014-01-22 21:58:53 +00:00
|
|
|
, m_started(false)
|
2015-06-21 20:32:18 +01:00
|
|
|
{
|
|
|
|
|
2018-09-13 14:44:52 +01:00
|
|
|
connect(m_sftp, &SftpPlugin::packetReceived, this, &Mounter::onPackageReceived);
|
2014-01-22 21:58:53 +00:00
|
|
|
|
2016-11-26 14:12:38 +00:00
|
|
|
connect(&m_connectTimer, &QTimer::timeout, this, &Mounter::onMountTimeout);
|
2014-01-22 21:58:53 +00:00
|
|
|
|
2016-11-26 14:12:38 +00:00
|
|
|
connect(this, &Mounter::mounted, &m_connectTimer, &QTimer::stop);
|
|
|
|
connect(this, &Mounter::failed, &m_connectTimer, &QTimer::stop);
|
2014-01-22 21:58:53 +00:00
|
|
|
|
|
|
|
m_connectTimer.setInterval(10000);
|
|
|
|
m_connectTimer.setSingleShot(true);
|
2015-03-09 05:12:55 +00:00
|
|
|
|
2016-11-26 14:12:38 +00:00
|
|
|
QTimer::singleShot(0, this, &Mounter::start);
|
2015-10-18 01:31:17 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Created mounter";
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Mounter::~Mounter()
|
|
|
|
{
|
2015-10-18 01:31:17 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Destroy mounter";
|
2017-03-15 10:34:12 +00:00
|
|
|
unmount(false);
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Mounter::wait()
|
|
|
|
{
|
|
|
|
if (m_started)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2017-03-15 10:34:12 +00:00
|
|
|
|
2014-09-21 23:45:59 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Starting loop to wait for mount";
|
2017-03-15 10:34:12 +00:00
|
|
|
|
2014-01-22 21:58:53 +00:00
|
|
|
MountLoop loop;
|
2016-11-26 14:12:38 +00:00
|
|
|
connect(this, &Mounter::mounted, &loop, &MountLoop::successed);
|
|
|
|
connect(this, &Mounter::failed, &loop, &MountLoop::failed);
|
2014-01-22 21:58:53 +00:00
|
|
|
return loop.exec();
|
|
|
|
}
|
|
|
|
|
2018-09-13 14:44:52 +01:00
|
|
|
void Mounter::onPackageReceived(const NetworkPacket& np)
|
2014-01-22 21:58:53 +00:00
|
|
|
{
|
2016-11-26 14:38:08 +00:00
|
|
|
if (np.get<bool>(QStringLiteral("stop"), false))
|
2014-01-22 21:58:53 +00:00
|
|
|
{
|
2014-09-21 23:45:59 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "SFTP server stopped";
|
2017-03-15 10:34:12 +00:00
|
|
|
unmount(false);
|
2014-01-22 21:58:53 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-01-22 17:42:00 +00:00
|
|
|
|
2019-06-10 15:40:28 +01:00
|
|
|
if (np.has(QStringLiteral("errorMessage"))) {
|
|
|
|
Q_EMIT failed(np.get<QString>(QStringLiteral("errorMessage")));
|
2019-01-22 17:42:00 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-02-14 19:12:40 +00:00
|
|
|
|
|
|
|
//This is the previous code, to access sftp server using KIO. Now we are
|
|
|
|
//using the external binary sshfs, and accessing it as a local filesystem.
|
|
|
|
/*
|
2014-09-21 21:23:31 +01:00
|
|
|
* QUrl url;
|
|
|
|
* url.setScheme("sftp");
|
2014-02-14 19:12:40 +00:00
|
|
|
* url.setHost(np.get<QString>("ip"));
|
|
|
|
* url.setPort(np.get<QString>("port").toInt());
|
2014-09-21 21:23:31 +01:00
|
|
|
* url.setUserName(np.get<QString>("user"));
|
|
|
|
* url.setPassword(np.get<QString>("password"));
|
2014-02-14 19:12:40 +00:00
|
|
|
* url.setPath(np.get<QString>("path"));
|
|
|
|
* new KRun(url, 0);
|
|
|
|
* Q_EMIT mounted();
|
|
|
|
*/
|
|
|
|
|
2017-03-15 10:34:12 +00:00
|
|
|
unmount(false);
|
2015-10-18 01:31:17 +01:00
|
|
|
|
2017-03-15 10:34:12 +00:00
|
|
|
m_proc = new KProcess();
|
2014-01-22 21:58:53 +00:00
|
|
|
m_proc->setOutputChannelMode(KProcess::MergedChannels);
|
|
|
|
|
2016-11-26 14:12:38 +00:00
|
|
|
connect(m_proc, &QProcess::started, this, &Mounter::onStarted);
|
2019-04-28 15:35:44 +01:00
|
|
|
connect(m_proc, &QProcess::errorOccurred, this, &Mounter::onError);
|
|
|
|
connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &Mounter::onFinished);
|
2014-02-14 16:12:15 +00:00
|
|
|
|
2015-06-21 20:32:18 +01:00
|
|
|
QDir().mkpath(m_mountPoint);
|
2014-02-14 19:12:40 +00:00
|
|
|
|
2016-11-26 14:38:08 +00:00
|
|
|
const QString program = QStringLiteral("sshfs");
|
2014-10-10 23:01:21 +01:00
|
|
|
|
|
|
|
QString path;
|
2019-06-10 15:40:28 +01:00
|
|
|
if (np.has(QStringLiteral("multiPaths"))) path = QStringLiteral("/");
|
2016-11-26 14:38:08 +00:00
|
|
|
else path = np.get<QString>(QStringLiteral("path"));
|
2014-10-10 23:01:21 +01:00
|
|
|
|
2017-07-22 10:13:21 +01:00
|
|
|
QHostAddress addr = m_sftp->device()->getLocalIpAddress();
|
|
|
|
if (addr == QHostAddress::Null) {
|
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Device doesn't have a LanDeviceLink, unable to get IP address";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QString ip = addr.toString();
|
|
|
|
|
2014-01-22 21:58:53 +00:00
|
|
|
const QStringList arguments = QStringList()
|
2016-11-26 15:36:01 +00:00
|
|
|
<< QStringLiteral("%1@%2:%3").arg(
|
|
|
|
np.get<QString>(QStringLiteral("user")),
|
2017-07-22 10:13:21 +01:00
|
|
|
ip,
|
2016-11-26 15:36:01 +00:00
|
|
|
path)
|
2015-06-21 20:32:18 +01:00
|
|
|
<< m_mountPoint
|
2016-11-26 14:38:08 +00:00
|
|
|
<< QStringLiteral("-p") << np.get<QString>(QStringLiteral("port"))
|
2017-07-25 23:10:10 +01:00
|
|
|
<< QStringLiteral("-s") // This fixes a bug where file chunks are sent out of order and get corrupted on reception
|
2016-11-26 14:38:08 +00:00
|
|
|
<< QStringLiteral("-f")
|
|
|
|
<< QStringLiteral("-F") << QStringLiteral("/dev/null") //Do not use ~/.ssh/config
|
2019-06-10 15:40:28 +01:00
|
|
|
<< QStringLiteral("-o") << QStringLiteral("IdentityFile=") + KdeConnectConfig::instance()->privateKeyPath()
|
2016-11-26 14:38:08 +00:00
|
|
|
<< QStringLiteral("-o") << QStringLiteral("StrictHostKeyChecking=no") //Do not ask for confirmation because it is not a known host
|
|
|
|
<< QStringLiteral("-o") << QStringLiteral("UserKnownHostsFile=/dev/null") //Prevent storing as a known host
|
2018-09-04 13:40:42 +01:00
|
|
|
<< QStringLiteral("-o") << QStringLiteral("HostKeyAlgorithms=+ssh-dss") //https://bugs.kde.org/show_bug.cgi?id=351725
|
2017-03-15 16:39:35 +00:00
|
|
|
<< QStringLiteral("-o") << QStringLiteral("uid=") + QString::number(getuid())
|
|
|
|
<< QStringLiteral("-o") << QStringLiteral("gid=") + QString::number(getgid())
|
2018-04-09 17:30:14 +01:00
|
|
|
<< QStringLiteral("-o") << QStringLiteral("reconnect")
|
2017-03-15 18:48:34 +00:00
|
|
|
<< QStringLiteral("-o") << QStringLiteral("ServerAliveInterval=30")
|
2016-11-26 14:38:08 +00:00
|
|
|
<< QStringLiteral("-o") << QStringLiteral("password_stdin")
|
2016-02-17 12:51:28 +00:00
|
|
|
;
|
2015-08-25 05:27:24 +01:00
|
|
|
|
2014-01-22 21:58:53 +00:00
|
|
|
m_proc->setProgram(program, arguments);
|
|
|
|
|
2016-11-26 14:38:08 +00:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Starting process: " << m_proc->program().join(QStringLiteral(" "));
|
2014-01-22 21:58:53 +00:00
|
|
|
m_proc->start();
|
2016-02-17 12:51:28 +00:00
|
|
|
|
|
|
|
//qCDebug(KDECONNECT_PLUGIN_SFTP) << "Passing password: " << np.get<QString>("password").toLatin1();
|
2016-11-26 14:38:08 +00:00
|
|
|
m_proc->write(np.get<QString>(QStringLiteral("password")).toLatin1());
|
2016-02-17 12:51:28 +00:00
|
|
|
m_proc->write("\n");
|
|
|
|
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Mounter::onStarted()
|
|
|
|
{
|
2014-09-21 23:45:59 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Process started";
|
2014-01-22 21:58:53 +00:00
|
|
|
m_started = true;
|
|
|
|
Q_EMIT mounted();
|
2015-10-18 01:31:17 +01:00
|
|
|
|
|
|
|
//m_proc->setStandardOutputFile("/tmp/kdeconnect-sftp.out");
|
|
|
|
//m_proc->setStandardErrorFile("/tmp/kdeconnect-sftp.err");
|
2017-03-15 10:34:12 +00:00
|
|
|
|
|
|
|
auto proc = m_proc;
|
2019-02-28 13:18:47 +00:00
|
|
|
connect(m_proc, &KProcess::readyReadStandardError, this, [proc]() {
|
2017-03-15 10:34:12 +00:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "stderr: " << proc->readAll();
|
2015-06-21 20:32:18 +01:00
|
|
|
});
|
2019-02-28 13:18:47 +00:00
|
|
|
connect(m_proc, &KProcess::readyReadStandardOutput, this, [proc]() {
|
2017-03-15 10:34:12 +00:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "stdout:" << proc->readAll();
|
2015-06-21 20:32:18 +01:00
|
|
|
});
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Mounter::onError(QProcess::ProcessError error)
|
|
|
|
{
|
|
|
|
if (error == QProcess::FailedToStart)
|
|
|
|
{
|
2019-04-25 19:47:50 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "sshfs process failed to start";
|
2014-01-22 21:58:53 +00:00
|
|
|
m_started = false;
|
|
|
|
Q_EMIT failed(i18n("Failed to start sshfs"));
|
2019-04-25 19:47:50 +01:00
|
|
|
} else if(error == QProcess::ProcessError::Crashed) {
|
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "sshfs process crashed";
|
|
|
|
m_started = false;
|
|
|
|
Q_EMIT failed(i18n("sshfs process crashed"));
|
|
|
|
} else {
|
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "sshfs process error" << error;
|
|
|
|
m_started = false;
|
|
|
|
Q_EMIT failed(i18n("Unknown error in sshfs"));
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mounter::onFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
|
|
|
{
|
2019-04-25 19:47:50 +01:00
|
|
|
if (exitStatus == QProcess::NormalExit && exitCode == 0)
|
2014-01-22 21:58:53 +00:00
|
|
|
{
|
2014-09-21 23:45:59 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Process finished (exit code: " << exitCode << ")";
|
2015-03-09 05:12:55 +00:00
|
|
|
Q_EMIT unmounted();
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-06-21 20:32:18 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Process failed (exit code:" << exitCode << ")";
|
2019-04-28 20:28:06 +01:00
|
|
|
Q_EMIT failed(i18n("Error when accessing filesystem. sshfs finished with exit code %0").arg(exitCode));
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
2017-03-15 10:34:12 +00:00
|
|
|
|
|
|
|
unmount(true);
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Mounter::onMountTimeout()
|
|
|
|
{
|
2014-09-21 23:45:59 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Timeout: device not responding";
|
2014-01-22 21:58:53 +00:00
|
|
|
Q_EMIT failed(i18n("Failed to mount filesystem: device not responding"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Mounter::start()
|
|
|
|
{
|
2019-06-10 15:40:28 +01:00
|
|
|
NetworkPacket np(PACKET_TYPE_SFTP_REQUEST, {{QStringLiteral("startBrowsing"), true}});
|
2018-03-04 19:48:51 +00:00
|
|
|
m_sftp->sendPacket(np);
|
2017-03-15 10:34:12 +00:00
|
|
|
|
2014-01-22 21:58:53 +00:00
|
|
|
m_connectTimer.start();
|
|
|
|
}
|
|
|
|
|
2017-03-15 10:34:12 +00:00
|
|
|
void Mounter::unmount(bool finished)
|
2014-01-22 21:58:53 +00:00
|
|
|
{
|
2015-10-18 01:31:17 +01:00
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Unmount" << m_proc;
|
2014-01-22 21:58:53 +00:00
|
|
|
if (m_proc)
|
|
|
|
{
|
2017-03-15 10:34:12 +00:00
|
|
|
if (!finished)
|
|
|
|
{
|
|
|
|
//Process is still running, we want to stop it
|
|
|
|
//But when the finished signal come, we might have already gone.
|
|
|
|
//Disconnect everything.
|
|
|
|
m_proc->disconnect();
|
|
|
|
m_proc->kill();
|
|
|
|
|
|
|
|
auto proc = m_proc;
|
|
|
|
m_proc = nullptr;
|
|
|
|
connect(proc, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
|
|
|
[proc]() {
|
|
|
|
qCDebug(KDECONNECT_PLUGIN_SFTP) << "Free" << proc;
|
|
|
|
proc->deleteLater();
|
|
|
|
});
|
|
|
|
Q_EMIT unmounted();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_proc->deleteLater();
|
|
|
|
|
2015-10-18 01:31:17 +01:00
|
|
|
//Free mount point (won't always succeed if the path is in use)
|
2017-09-05 21:22:55 +01:00
|
|
|
#if defined(HAVE_FUSERMOUNT)
|
2016-11-26 14:38:08 +00:00
|
|
|
KProcess::execute(QStringList() << QStringLiteral("fusermount") << QStringLiteral("-u") << m_mountPoint, 10000);
|
2017-09-05 21:22:55 +01:00
|
|
|
#else
|
|
|
|
KProcess::execute(QStringList() << QStringLiteral("umount") << m_mountPoint, 10000);
|
|
|
|
#endif
|
2017-03-15 10:34:12 +00:00
|
|
|
m_proc = nullptr;
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|
2015-10-18 01:31:17 +01:00
|
|
|
m_started = false;
|
2014-01-22 21:58:53 +00:00
|
|
|
}
|