From 2007f2b8ea9054b92e08247e68b5b4a6df87d881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrius=20=C5=A0tikonas?= Date: Sun, 28 Oct 2018 17:22:12 +0000 Subject: [PATCH] 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 --- src/core/CMakeLists.txt | 1 + src/core/copytargetbytearray.cpp | 29 ++++++++++++++ src/core/copytargetbytearray.h | 58 ++++++++++++++++++++++++++++ src/plugins/sfdisk/CMakeLists.txt | 3 ++ src/plugins/sfdisk/sfdiskbackend.cpp | 13 ++++--- src/util/externalcommand.cpp | 9 ++++- src/util/externalcommandhelper.cpp | 25 ++++++++---- src/util/externalcommandhelper.h | 2 +- 8 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 src/core/copytargetbytearray.cpp create mode 100644 src/core/copytargetbytearray.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 719ec3a..578f37c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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 diff --git a/src/core/copytargetbytearray.cpp b/src/core/copytargetbytearray.cpp new file mode 100644 index 0000000..8728049 --- /dev/null +++ b/src/core/copytargetbytearray.cpp @@ -0,0 +1,29 @@ +/************************************************************************* + * Copyright (C) 2018 by Andrius Štikonas * + * * + * 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 .* + *************************************************************************/ + +#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) +{ +} diff --git a/src/core/copytargetbytearray.h b/src/core/copytargetbytearray.h new file mode 100644 index 0000000..709fa9a --- /dev/null +++ b/src/core/copytargetbytearray.h @@ -0,0 +1,58 @@ +/************************************************************************* + * Copyright (C) 2018 by Andrius Štikonas * + * * + * 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 .* + *************************************************************************/ + +#ifndef KPMCORE_COPYTARGETBYTEARRAY_H +#define KPMCORE_COPYTARGETBYTEARRAY_H + +#include "core/copytarget.h" + +#include +#include +#include + +/** 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 +*/ +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 diff --git a/src/plugins/sfdisk/CMakeLists.txt b/src/plugins/sfdisk/CMakeLists.txt index d910c3f..c7b137d 100644 --- a/src/plugins/sfdisk/CMakeLists.txt +++ b/src/plugins/sfdisk/CMakeLists.txt @@ -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}) diff --git a/src/plugins/sfdisk/sfdiskbackend.cpp b/src/plugins/sfdisk/sfdiskbackend.cpp index a563250..6b54384 100644 --- a/src/plugins/sfdisk/sfdiskbackend.cpp +++ b/src/plugins/sfdisk/sfdiskbackend.cpp @@ -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); diff --git a/src/util/externalcommand.cpp b/src/util/externalcommand.cpp index 14194d5..21bb2bb 100644 --- a/src/util/externalcommand.cpp +++ b/src/util/externalcommand.cpp @@ -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 reply = *watcher; - rval = reply.argumentAt<0>(); + QDBusPendingReply reply = *watcher; + rval = reply.value()[QStringLiteral("success")].toBool(); + + CopyTargetByteArray *byteArrayTarget = dynamic_cast(&target); + if (byteArrayTarget) + byteArrayTarget->m_Array = reply.value()[QStringLiteral("targetByteArray")].toByteArray(); } setExitCode(!rval); }; diff --git a/src/util/externalcommandhelper.cpp b/src/util/externalcommandhelper.cpp index 0c701e2..87edade 100644 --- a/src/util/externalcommandhelper.cpp +++ b/src/util/externalcommandhelper.cpp @@ -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) diff --git a/src/util/externalcommandhelper.h b/src/util/externalcommandhelper.h index 0ab9ef9..3f7959c 100644 --- a/src/util/externalcommandhelper.h +++ b/src/util/externalcommandhelper.h @@ -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: