From 5b80c6045c5306e5e61f963d30c0a9b8773e5407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrius=20=C5=A0tikonas?= Date: Thu, 10 Sep 2020 23:54:23 +0100 Subject: [PATCH] Fix fstab editing functionality. In the old code QByteArray fstabContents was actually empty. Also, writeData function was opening file in append mode, thus nothing was actually written. Split writeData function into two: * one for block devices * another for writing fstab file BUG: 417205 --- src/core/fstab.cpp | 4 +-- src/util/externalcommand.cpp | 41 +++++++++++++++++++++++++++++- src/util/externalcommand.h | 1 + src/util/externalcommandhelper.cpp | 38 ++++++++++++++++++++++++--- src/util/externalcommandhelper.h | 2 ++ 5 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/core/fstab.cpp b/src/core/fstab.cpp index a91686f..630cd0c 100644 --- a/src/core/fstab.cpp +++ b/src/core/fstab.cpp @@ -260,12 +260,12 @@ static void writeEntry(QTextStream& s, const FstabEntry& entry) bool writeMountpoints(const FstabEntryList& fstabEntries, const QString& filename) { Report report(nullptr); - QByteArray fstabContents; + QString fstabContents; QTextStream out(&fstabContents); for (const auto &e : fstabEntries) writeEntry(out, e); ExternalCommand cmd; - return cmd.writeData(report, fstabContents, filename, 0); + return cmd.createFile(report, fstabContents.toLocal8Bit(), filename); } diff --git a/src/util/externalcommand.cpp b/src/util/externalcommand.cpp index 9ba2fac..49f78e1 100644 --- a/src/util/externalcommand.cpp +++ b/src/util/externalcommand.cpp @@ -232,7 +232,7 @@ bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer, auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), QStringLiteral("/Helper"), QDBusConnection::systemBus(), this); interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days - + QDBusPendingCall pcall = interface->writeData(buffer, deviceNode, firstByte); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); @@ -255,6 +255,45 @@ bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer, return rval; } +bool ExternalCommand::createFile(Report& commandReport, const QByteArray& buffer, const QString& deviceNode) +{ + d->m_Report = commandReport.newChild(); + if (report()) + report()->setCommand(xi18nc("@info:status", "Command: %1 %2", command(), args().join(QStringLiteral(" ")))); + + bool rval = true; + + if (!QDBusConnection::systemBus().isConnected()) { + qWarning() << QDBusConnection::systemBus().lastError().message(); + return false; + } + + auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), + QStringLiteral("/Helper"), QDBusConnection::systemBus(), this); + interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days + + QDBusPendingCall pcall = interface->createFile(buffer, deviceNode); + + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); + QEventLoop loop; + + auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) { + loop.exit(); + if (watcher->isError()) + qWarning() << watcher->error(); + else { + QDBusPendingReply reply = *watcher; + rval = reply.argumentAt<0>(); + } + setExitCode(!rval); + }; + + connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop); + loop.exec(); + + return rval; +} + bool ExternalCommand::write(const QByteArray& input) { diff --git a/src/util/externalcommand.h b/src/util/externalcommand.h index be56818..b2152a6 100644 --- a/src/util/externalcommand.h +++ b/src/util/externalcommand.h @@ -71,6 +71,7 @@ public: public: bool copyBlocks(const CopySource& source, CopyTarget& target); bool writeData(Report& commandReport, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte); // same as copyBlocks but from QByteArray + bool createFile(Report& commandReport, const QByteArray& buffer, const QString& deviceNode); // same as writeData but creates a new file /**< @param cmd the command to run */ void setCommand(const QString& cmd); diff --git a/src/util/externalcommandhelper.cpp b/src/util/externalcommandhelper.cpp index 9e96966..6ccdda0 100644 --- a/src/util/externalcommandhelper.cpp +++ b/src/util/externalcommandhelper.cpp @@ -118,7 +118,7 @@ bool ExternalCommandHelper::readData(const QString& sourceDevice, QByteArray& bu return true; } -/** Writes the data from buffer to a given device or file. +/** Writes the data from buffer to a given device. @param targetDevice device or file to write to @param buffer the data that we write @param offset offset where to begin writing @@ -128,7 +128,8 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr { QFile device(targetDevice); - if (!device.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered)) { + auto flags = QIODevice::WriteOnly | QIODevice::Unbuffered | QIODevice::Append; + if (!device.open(flags)) { qCritical() << xi18n("Could not open device %1 for writing.", targetDevice); return false; } @@ -146,6 +147,29 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr return true; } +/** Creates a new file with given contents. + @param filePath file to write to + @param fileContents the data that we write + @return true on success +*/ +bool ExternalCommandHelper::createFile(const QString &filePath, const QByteArray& fileContents) +{ + QFile device(filePath); + + auto flags = QIODevice::WriteOnly | QIODevice::Unbuffered; + if (!device.open(flags)) { + qCritical() << xi18n("Could not open file %1 for writing.", filePath); + return false; + } + + if (device.write(fileContents) != fileContents.size()) { + qCritical() << xi18n("Could not write to file %1.", filePath); + return false; + } + + return true; +} + // If targetDevice is empty then return QByteArray with data that was read from disk. QVariantMap ExternalCommandHelper::copyblocks(const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize) { @@ -239,12 +263,20 @@ QVariantMap ExternalCommandHelper::copyblocks(const QString& sourceDevice, const bool ExternalCommandHelper::writeData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte) { // Do not allow using this helper for writing to arbitrary location - if ( targetDevice.left(5) != QStringLiteral("/dev/") && !targetDevice.contains(QStringLiteral("/etc/fstab"))) + if ( targetDevice.left(5) != QStringLiteral("/dev/") ) return false; return writeData(targetDevice, buffer, targetFirstByte); } +bool ExternalCommandHelper::createFile(const QByteArray& fileContents, const QString& filePath) +{ + // Do not allow using this helper for writing to arbitrary location + if ( !filePath.contains(QStringLiteral("/etc/fstab")) ) + return false; + + return createFile(filePath, fileContents); +} QVariantMap ExternalCommandHelper::start(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode) { diff --git a/src/util/externalcommandhelper.h b/src/util/externalcommandhelper.h index 6d7029b..8c1e6e0 100644 --- a/src/util/externalcommandhelper.h +++ b/src/util/externalcommandhelper.h @@ -41,12 +41,14 @@ Q_SIGNALS: public: bool readData(const QString& sourceDevice, QByteArray& buffer, const qint64 offset, const qint64 size); bool writeData(const QString& targetDevice, const QByteArray& buffer, const qint64 offset); + bool createFile(const QString& filePath, const QByteArray& fileContents); public Q_SLOTS: ActionReply init(const QVariantMap& args); Q_SCRIPTABLE QVariantMap start(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode); Q_SCRIPTABLE QVariantMap copyblocks(const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize); Q_SCRIPTABLE bool writeData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte); + Q_SCRIPTABLE bool createFile(const QByteArray& fileContents, const QString& filePath); Q_SCRIPTABLE void exit(); private: