Allow copyblocks to be used together with small QByteArrays.

Add CopyTargetByteArray. CopySourceByteArray is not implemented yet.

This is only suitable for reading small amount of data such as GPT header
or FAT boot sector location. Not meant for copying whole partition because
data has to be transfered over DBus.

Differential Revision: https://phabricator.kde.org/D16487
This commit is contained in:
Andrius Štikonas 2018-10-28 17:22:12 +00:00
parent 9ca63ab501
commit 2007f2b8ea
8 changed files with 125 additions and 15 deletions

View File

@ -6,6 +6,7 @@ set(CORE_SRC
core/copysourcefile.cpp
core/copysourceshred.cpp
core/copytarget.cpp
core/copytargetbytearray.cpp
core/copytargetdevice.cpp
core/copytargetfile.cpp
core/device.cpp

View File

@ -0,0 +1,29 @@
/*************************************************************************
* Copyright (C) 2018 by Andrius Štikonas <andrius@stikonas.eu> *
* *
* 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 3 of *
* the License, or (at your option) any later version. *
* *
* 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 *
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "core/copytargetbytearray.h"
/** This class is for reading disk data into QByteArray
It is only suitable for reading small amount of data such as GPT header or
FAT boot sector. DBus is too slow for copying data of the whole partition.
@param QByteArray to write to
*/
CopyTargetByteArray::CopyTargetByteArray(QByteArray& array) :
CopyTarget(),
m_Array(array)
{
}

View File

@ -0,0 +1,58 @@
/*************************************************************************
* Copyright (C) 2018 by Andrius Štikonas <andrius@stikonas.eu> *
* *
* 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 3 of *
* the License, or (at your option) any later version. *
* *
* 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 *
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
*************************************************************************/
#ifndef KPMCORE_COPYTARGETBYTEARRAY_H
#define KPMCORE_COPYTARGETBYTEARRAY_H
#include "core/copytarget.h"
#include <QtGlobal>
#include <QByteArray>
#include <QString>
/** A file to copy to.
Represents a target file to copy to. Used to back up a FileSystem to a file.
@see CopySourceFile, CopyTargetDevice
@author Volker Lanz <vl@fidra.de>
*/
class CopyTargetByteArray : public CopyTarget
{
public:
CopyTargetByteArray(QByteArray& array);
public:
bool open() override {
return true;
}
QString path() const override {
return QString();
}
qint64 firstByte() const override {
return 0; /**< @return always 0 for QByteArray */
}
qint64 lastByte() const override {
return bytesWritten(); /**< @return the number of bytes written so far */
}
QByteArray& m_Array;
};
#endif

View File

@ -18,6 +18,9 @@ set (pmsfdiskbackendplugin_SRCS
sfdiskdevice.cpp
sfdiskpartitiontable.cpp
${CMAKE_SOURCE_DIR}/src/backend/corebackenddevice.cpp
${CMAKE_SOURCE_DIR}/src/core/copysourcedevice.cpp
${CMAKE_SOURCE_DIR}/src/core/copytargetdevice.cpp
${CMAKE_SOURCE_DIR}/src/core/copytargetbytearray.cpp
)
add_library(pmsfdiskbackendplugin SHARED ${pmsfdiskbackendplugin_SRCS})

View File

@ -21,6 +21,8 @@
#include "plugins/sfdisk/sfdiskbackend.h"
#include "plugins/sfdisk/sfdiskdevice.h"
#include "core/copysourcedevice.h"
#include "core/copytargetbytearray.h"
#include "core/diskdevice.h"
#include "core/lvmdevice.h"
#include "core/partitiontable.h"
@ -332,11 +334,12 @@ bool SfdiskBackend::updateDevicePartitionTable(Device &d, const QJsonObject &jso
{
// Read the maximum number of GPT partitions
qint32 maxEntries;
ExternalCommand ddCommand(QStringLiteral("dd"),
{ QStringLiteral("skip=1"), QStringLiteral("count=1"), (QStringLiteral("if=") + d.deviceNode()) },
QProcess::SeparateChannels);
if (ddCommand.run(-1) && ddCommand.exitCode() == 0 ) {
QByteArray gptHeader = ddCommand.rawOutput();
QByteArray gptHeader;
CopySourceDevice source(d, 512, 1023);
CopyTargetByteArray target(gptHeader);
ExternalCommand copyCmd;
if (copyCmd.copyBlocks(source, target)) {
QByteArray gptMaxEntries = gptHeader.mid(80, 4);
QDataStream stream(&gptMaxEntries, QIODevice::ReadOnly);
stream.setByteOrder(QDataStream::LittleEndian);

View File

@ -20,6 +20,7 @@
#include "core/device.h"
#include "core/copysource.h"
#include "core/copytarget.h"
#include "core/copytargetbytearray.h"
#include "core/copysourcedevice.h"
#include "core/copytargetdevice.h"
#include "util/globallog.h"
@ -222,8 +223,12 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
if (watcher->isError())
qWarning() << watcher->error();
else {
QDBusPendingReply<bool> reply = *watcher;
rval = reply.argumentAt<0>();
QDBusPendingReply<QVariantMap> reply = *watcher;
rval = reply.value()[QStringLiteral("success")].toBool();
CopyTargetByteArray *byteArrayTarget = dynamic_cast<CopyTargetByteArray*>(&target);
if (byteArrayTarget)
byteArrayTarget->m_Array = reply.value()[QStringLiteral("targetByteArray")].toByteArray();
}
setExitCode(!rval);
};

View File

@ -152,12 +152,17 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
return true;
}
bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize)
QVariantMap ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize)
{
QVariantMap reply;
reply[QStringLiteral("success")] = true;
if (m_Nonces.find(nonce) != m_Nonces.end())
m_Nonces.erase( nonce );
else
return false;
else {
reply[QStringLiteral("success")] = false;
return reply;
}
QByteArray request;
@ -172,7 +177,8 @@ bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint6
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) {
qCritical() << xi18n("Invalid cryptographic signature");
return false;
reply[QStringLiteral("success")] = false;
return reply;
}
const qint64 blocksToCopy = sourceLength / blockSize;
@ -239,8 +245,12 @@ bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint6
HelperSupport::progressStep(report);
rval = readData(sourceDevice, buffer, lastBlockReadOffset, lastBlock);
if (rval)
rval = writeData(targetDevice, buffer, lastBlockWriteOffset);
if (rval) {
if (targetDevice.isEmpty())
reply[QStringLiteral("targetByteArray")] = buffer;
else
rval = writeData(targetDevice, buffer, lastBlockWriteOffset);
}
if (rval) {
HelperSupport::progressStep(100);
@ -251,7 +261,8 @@ bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint6
report[QStringLiteral("report")] = xi18ncp("@info:progress argument 2 is a string such as 7 bytes (localized accordingly)", "Copying 1 block (%2) finished.", "Copying %1 blocks (%2) finished.", blocksCopied, i18np("1 byte", "%1 bytes", bytesWritten));
HelperSupport::progressStep(report);
return rval;
reply[QStringLiteral("success")] = rval;
return reply;
}
QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode)

View File

@ -49,7 +49,7 @@ public Q_SLOTS:
ActionReply init(const QVariantMap& args);
Q_SCRIPTABLE quint64 getNonce();
Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode);
Q_SCRIPTABLE bool copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize);
Q_SCRIPTABLE QVariantMap copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize);
Q_SCRIPTABLE void exit(const QByteArray& signature, const quint64 nonce);
private: