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)
{
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);
}

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"),
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<bool> reply = *watcher;
rval = reply.argumentAt<0>();
}
setExitCode(!rval);
};
connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop);
loop.exec();
return rval;
}
bool ExternalCommand::write(const QByteArray& input)
{

View File

@ -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);

View File

@ -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 <filename>%1</filename> 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 <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.
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)
{

View File

@ -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: