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
This commit is contained in:
Andrius Štikonas 2020-09-10 23:54:23 +01:00
parent 45bd205e79
commit 5b80c6045c
5 changed files with 80 additions and 6 deletions

View File

@ -260,12 +260,12 @@ static void writeEntry(QTextStream& s, const FstabEntry& entry)
bool writeMountpoints(const FstabEntryList& fstabEntries, const QString& filename) bool writeMountpoints(const FstabEntryList& fstabEntries, const QString& filename)
{ {
Report report(nullptr); Report report(nullptr);
QByteArray fstabContents; QString fstabContents;
QTextStream out(&fstabContents); QTextStream out(&fstabContents);
for (const auto &e : fstabEntries) for (const auto &e : fstabEntries)
writeEntry(out, e); writeEntry(out, e);
ExternalCommand cmd; ExternalCommand cmd;
return cmd.writeData(report, fstabContents, filename, 0); return cmd.createFile(report, fstabContents.toLocal8Bit(), filename);
} }

View File

@ -232,7 +232,7 @@ bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer,
auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"),
QStringLiteral("/Helper"), QDBusConnection::systemBus(), this); QStringLiteral("/Helper"), QDBusConnection::systemBus(), this);
interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days
QDBusPendingCall pcall = interface->writeData(buffer, deviceNode, firstByte); QDBusPendingCall pcall = interface->writeData(buffer, deviceNode, firstByte);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
@ -255,6 +255,45 @@ bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer,
return rval; 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<bool> reply = *watcher;
rval = reply.argumentAt<0>();
}
setExitCode(!rval);
};
connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop);
loop.exec();
return rval;
}
bool ExternalCommand::write(const QByteArray& input) bool ExternalCommand::write(const QByteArray& input)
{ {

View File

@ -71,6 +71,7 @@ public:
public: public:
bool copyBlocks(const CopySource& source, CopyTarget& target); 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 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 */ /**< @param cmd the command to run */
void setCommand(const QString& cmd); void setCommand(const QString& cmd);

View File

@ -118,7 +118,7 @@ bool ExternalCommandHelper::readData(const QString& sourceDevice, QByteArray& bu
return true; 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 targetDevice device or file to write to
@param buffer the data that we write @param buffer the data that we write
@param offset offset where to begin writing @param offset offset where to begin writing
@ -128,7 +128,8 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
{ {
QFile device(targetDevice); 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 <filename>%1</filename> for writing.", targetDevice); qCritical() << xi18n("Could not open device <filename>%1</filename> for writing.", targetDevice);
return false; return false;
} }
@ -146,6 +147,29 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
return true; 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 <filename>%1</filename> for writing.", filePath);
return false;
}
if (device.write(fileContents) != fileContents.size()) {
qCritical() << xi18n("Could not write to file <filename>%1</filename>.", filePath);
return false;
}
return true;
}
// If targetDevice is empty then return QByteArray with data that was read from disk. // 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) 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) bool ExternalCommandHelper::writeData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte)
{ {
// Do not allow using this helper for writing to arbitrary location // 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 false;
return writeData(targetDevice, buffer, targetFirstByte); 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) QVariantMap ExternalCommandHelper::start(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode)
{ {

View File

@ -41,12 +41,14 @@ Q_SIGNALS:
public: public:
bool readData(const QString& sourceDevice, QByteArray& buffer, const qint64 offset, const qint64 size); 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 writeData(const QString& targetDevice, const QByteArray& buffer, const qint64 offset);
bool createFile(const QString& filePath, const QByteArray& fileContents);
public Q_SLOTS: public Q_SLOTS:
ActionReply init(const QVariantMap& args); ActionReply init(const QVariantMap& args);
Q_SCRIPTABLE QVariantMap start(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode); 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 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 writeData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte);
Q_SCRIPTABLE bool createFile(const QByteArray& fileContents, const QString& filePath);
Q_SCRIPTABLE void exit(); Q_SCRIPTABLE void exit();
private: private: