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: