Merge branch 'master' into raid-support

This commit is contained in:
Andrius Štikonas 2019-01-06 17:17:12 +00:00
commit c2ed6634df
28 changed files with 368 additions and 86 deletions

View File

@ -28,7 +28,7 @@ set(BLKID_MIN_VERSION "2.32")
# Qca-qt5 (tested with botan and ossl backends)
# Runtime
# smartmontools 6.7
# smartmontools 7.0
# Qca plugin (botan or ossl)
set(VERSION_MAJOR "3")

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

@ -544,6 +544,12 @@ qint64 LvmDevice::freePE() const
return d_ptr->m_freePE;
}
void LvmDevice::setFreePE(qint64 freePE) const
{
d_ptr->m_freePE = freePE;
d_ptr->m_allocPE = d_ptr->m_totalPE - freePE;
}
QString LvmDevice::UUID() const
{
return d_ptr->m_UUID;

View File

@ -98,6 +98,7 @@ public:
qint64 totalPE() const;
qint64 allocatedPE() const;
qint64 freePE() const;
void setFreePE(qint64 freePE) const;
QString UUID() const;
protected:

View File

@ -80,10 +80,10 @@ public:
New, /**< from a NewOperation */
Copy, /**< from a CopyOperation */
Restore, /**< from a RestoreOperation */
StateNone __attribute__((deprecated("Use Partition::State::None"))) = None,
StateNew __attribute__((deprecated("Use Partition::State::New"))) = New,
StateCopy __attribute__((deprecated("Use Partition::State::Copy"))) = Copy,
StateRestore __attribute__((deprecated("Use Partition::State::Restore"))) = Restore
StateNone [[deprecated("Use Partition::State::None")]] = None,
StateNew [[deprecated("Use Partition::State::New")]] = New,
StateCopy [[deprecated("Use Partition::State::Copy")]] = Copy,
StateRestore [[deprecated("Use Partition::State::Restore")]] = Restore
};
Partition(PartitionNode* parent, const Device& device, const PartitionRole& role, FileSystem* fs, qint64 sectorStart, qint64 sectorEnd, QString partitionPath, PartitionTable::Flags availableFlags = PartitionTable::FlagNone, const QString& mountPoint = QString(), bool mounted = false, PartitionTable::Flags activeFlags = PartitionTable::FlagNone, State state = State::None);

View File

@ -216,8 +216,6 @@ QString PartitionTable::flagName(Flag f)
return xi18nc("@item partition flag", "msft-data");
case PartitionTable::FlagIrst:
return xi18nc("@item partition flag", "irst");
case PartitionTable::FlagEsp:
return xi18nc("@item partition flag", "esp");
default:
break;
}
@ -247,7 +245,6 @@ const QList<PartitionTable::Flag> PartitionTable::flagList()
rval.append(PartitionTable::FlagLegacyBoot);
rval.append(PartitionTable::FlagMsftData);
rval.append(PartitionTable::FlagIrst);
rval.append(PartitionTable::FlagEsp);
return rval;
}

View File

@ -88,7 +88,7 @@ public:
FlagLegacyBoot = 16384,
FlagMsftData = 32768,
FlagIrst = 65536,
FlagEsp = 131072
FlagEsp [[deprecated]] = FlagBoot
};
Q_DECLARE_FLAGS(Flags, Flag)

View File

@ -128,6 +128,7 @@ static const AttrDetails* attrDetails()
{ 175, i18nc("SMART attr name", "SSD Power Loss Protection Failure"), i18nc("SMART attr description", "Last test result, saturated at its maximum value. Bytes 0-1: last test result as microseconds to discharge cap in range [25, 5000000], lower indicates specific error code. Bytes 2-3: minutes since last test. Bytes 4-5: lifetime number of tests. Normalized value is set to 1 on test failure or 11 if the capacitor has been tested in an excessive temperature condition, otherwise 100.") },
{ 176, i18nc("SMART attr name", "SSD Erase Fail Count (chip)"), i18nc("SMART attr description", "Number of flash erase command failures.") },
{ 177, i18nc("SMART attr name", "SSD Wear Range Delta"), i18nc("SMART attr description", "Delta between most-worn and least-worn flash blocks.") },
{ 178, i18nc("SMART attr name", "SSD Used Reserved Block Count Total"), i18nc("SMART attr description", "\"Pre-Fail\" Samsung attribute.") },
{ 179, i18nc("SMART attr name", "SSD Used Reserved Block Count Total"), i18nc("SMART attr description", "\"Pre-Fail\" Samsung attribute.") },
{ 180, i18nc("SMART attr name", "SSD Unused Reserved Block Count Total"), i18nc("SMART attr description", "\"Pre-Fail\" HP attribute.") },
{ 181, i18nc("SMART attr name", "SSD Program Fail Count Total or Non-4K Aligned Access Count"), i18nc("SMART attr description", "Number of flash program operation failures since the drive was deployed.") },

View File

@ -59,7 +59,7 @@ void fat12::init()
m_Move = cmdSupportCore;
m_Copy = cmdSupportCore;
m_Backup = cmdSupportCore;
m_UpdateUUID = findExternal(QStringLiteral("dd")) ? cmdSupportFileSystem : cmdSupportNone;
m_UpdateUUID = cmdSupportCore;
m_GetUUID = cmdSupportCore;
}
@ -157,7 +157,7 @@ bool fat12::create(Report& report, const QString& deviceNode)
bool fat12::updateUUID(Report& report, const QString& deviceNode) const
{
qint64 t = time(nullptr);
long int t = time(nullptr);
char uuid[4];
for (auto &u : uuid) {
@ -165,9 +165,7 @@ bool fat12::updateUUID(Report& report, const QString& deviceNode) const
t >>= 8;
}
ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode , QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=39") });
cmd.write(QByteArray(uuid, sizeof(uuid)));
return cmd.start();
ExternalCommand cmd;
return cmd.writeData(report, QByteArray(uuid, sizeof(uuid)), deviceNode, 39);
}
}

View File

@ -50,7 +50,7 @@ void fat16::init()
m_Move = cmdSupportCore;
m_Copy = cmdSupportCore;
m_Backup = cmdSupportCore;
m_UpdateUUID = findExternal(QStringLiteral("dd")) ? cmdSupportFileSystem : cmdSupportNone;
m_UpdateUUID = cmdSupportCore;
m_Grow = findExternal(QStringLiteral("fatresize")) ? cmdSupportFileSystem : cmdSupportNone;
m_Shrink = findExternal(QStringLiteral("fatresize")) ? cmdSupportFileSystem : cmdSupportNone;
m_GetUUID = cmdSupportCore;

View File

@ -14,6 +14,7 @@
* 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 "fs/fat32.h"
#include "util/externalcommand.h"
@ -48,7 +49,8 @@ bool fat32::create(Report& report, const QString& deviceNode)
bool fat32::updateUUID(Report& report, const QString& deviceNode) const
{
qint64 t = time(nullptr);
// HACK: replace this hack with fatlabel "-i" (dosfstools 4.2)
long int t = time(nullptr);
char uuid[4];
for (auto &u : uuid) {
@ -56,10 +58,7 @@ bool fat32::updateUUID(Report& report, const QString& deviceNode) const
t >>= 8;
}
// HACK: replace this hack with fatlabel "-i" (dosfstools 4.2)
ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode, QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=67") });
cmd.write(QByteArray(uuid, sizeof(uuid)));
return cmd.start();
ExternalCommand cmd;
return cmd.writeData(report, QByteArray(uuid, sizeof(uuid)), deviceNode, 67);
}
}

View File

@ -29,7 +29,6 @@
#include <QString>
#include <QStringList>
#include <QFile>
#include <QUuid>
#include <algorithm>
#include <ctime>
@ -188,10 +187,8 @@ bool ntfs::updateBootSector(Report& report, const QString& deviceNode) const
std::swap(s[1], s[2]);
#endif
ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode , QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=28") });
cmd.write(QByteArray(s, sizeof(s)));
if (!cmd.start()) {
ExternalCommand cmd;
if (!cmd.writeData(report, QByteArray(s, sizeof(s)), deviceNode, 28)) {
Log() << xi18nc("@info:progress", "Could not write new start sector to partition <filename>%1</filename> when trying to update the NTFS boot sector.", deviceNode);
return false;
}
@ -199,10 +196,7 @@ bool ntfs::updateBootSector(Report& report, const QString& deviceNode) const
// Also update backup NTFS boot sector located at the end of the partition
// NOTE: this should fail if filesystem does not span the whole partition
qint64 pos = (lastSector() - firstSector()) * sectorSize() + 28;
ExternalCommand cmd2(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode , QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=") + QString::number(pos) });
cmd2.write(QByteArray(s, sizeof(s)));
if (!cmd2.start()) {
if (!cmd.writeData(report, QByteArray(s, sizeof(s)), deviceNode, pos)) {
Log() << xi18nc("@info:progress", "Could not write new start sector to partition <filename>%1</filename> when trying to update the NTFS boot sector.", deviceNode);
return false;
}

View File

@ -45,11 +45,7 @@ bool Job::copyBlocks(Report& report, CopyTarget& target, CopySource& source)
ExternalCommand copyCmd;
connect(&copyCmd, &ExternalCommand::progress, this, &Job::progress, Qt::QueuedConnection);
connect(&copyCmd, &ExternalCommand::reportSignal, this, &Job::updateReport, Qt::QueuedConnection);
if (copyCmd.copyBlocks(source, target)) {
return true;
}
return false;
return copyCmd.copyBlocks(source, target);
}
bool Job::rollbackCopyBlocks(Report& report, CopyTarget& origTarget, CopySource& origSource)

View File

@ -20,6 +20,7 @@
#include "core/partition.h"
#include "core/device.h"
#include "core/lvmdevice.h"
#include "jobs/job.h"
@ -50,7 +51,14 @@ void Operation::insertPreviewPartition(Device& device, Partition& p)
device.partitionTable()->removeUnallocated();
p.parent()->insert(&p);
if (p.parent()->insert(&p)) {
if (device.type() == Device::Type::LVM_Device) {
const LvmDevice& lvm = static_cast<const LvmDevice&>(device);
lvm.setFreePE(lvm.freePE() - p.length());
}
}
else
qWarning() << "failed to insert preview partition " << p.deviceNode() << " at " << &p << ".";
device.partitionTable()->updateUnallocated(device);
}
@ -59,8 +67,14 @@ void Operation::removePreviewPartition(Device& device, Partition& p)
{
Q_ASSERT(device.partitionTable());
if (p.parent()->remove(&p))
if (p.parent()->remove(&p)) {
if (device.type() == Device::Type::LVM_Device) {
const LvmDevice& lvm = static_cast<const LvmDevice&>(device);
lvm.setFreePE(lvm.freePE() + p.length());
}
device.partitionTable()->updateUnallocated(device);
}
else
qWarning() << "failed to remove partition " << p.deviceNode() << " at " << &p << " from preview.";
}

View File

@ -67,7 +67,7 @@ ResizeOperation::ResizeOperation(Device& d, Partition& p, qint64 newfirst, qint6
m_GrowSetGeomJob(nullptr),
m_CheckResizedJob(nullptr)
{
if(CheckOperation::canCheck(&partition()))
if (CheckOperation::canCheck(&partition()))
addJob(checkOriginalJob());
if (partition().roles().has(PartitionRole::Extended)) {

View File

@ -4,7 +4,29 @@
{
"Email": "vl@fidra.de",
"Name": "Volker Lanz",
"Name[x-test]": "xxVolker Lanzxx"
"Name[ast]": "Volker Lanz",
"Name[ca@valencia]": "Volker Lanz",
"Name[ca]": "Volker Lanz",
"Name[cs]": "Volker Lanz",
"Name[de]": "Volker Lanz",
"Name[el]": "Volker Lanz",
"Name[en_GB]": "Volker Lanz",
"Name[es]": "Volker Lanz",
"Name[fi]": "Volker Lanz",
"Name[fr]": "Volker Lanz",
"Name[gl]": "Volker Lanz",
"Name[it]": "Volker Lanz",
"Name[ko]": "Volker Lanz",
"Name[lt]": "Volker Lanz",
"Name[nl]": "Volker Lanz",
"Name[pl]": "Volker Lanz",
"Name[pt]": "Volker Lanz",
"Name[pt_BR]": "Volker Lanz",
"Name[sk]": "Volker Lanz",
"Name[sv]": "Volker Lanz",
"Name[uk]": "Volker Lanz",
"Name[x-test]": "xxVolker Lanzxx",
"Name[zh_CN]": "Volker Lanz"
}
],
"Category": "BackendPlugin",
@ -13,6 +35,8 @@
"Description[ca]": "Un dorsal fals del gestor de particions del KDE amb la finalitat de fer proves.",
"Description[cs]": "Falešná podpůrná vrstva pro správce diskových oddílů KDE pro testovací účely.",
"Description[de]": "Ein Dummy-Backend für die KDE-Partitionsverwaltung zu Testzwecken.",
"Description[el]": "Ένα εικονικό σύστημα υποστήριξης διαχειριστή κατατμήσεων του KDE για δοκιμές.",
"Description[en_GB]": "A KDE Partition Manager dummy backend for testing purposes.",
"Description[es]": "Un motor de simulación para el gestor de particiones de KDE para hacer pruebas.",
"Description[fi]": "KDE:n osionhallinnan valetaustaosa testaustarkoituksiin.",
"Description[fr]": "Un moteur de test pour le gestionnaire de partitions de KDE pour faire des essais.",
@ -37,6 +61,8 @@
"Name[ca]": "Dorsal fals del gestor de particions del KDE",
"Name[cs]": "Podpůrná vrstva pro správce diskových oddílů pro KDE",
"Name[de]": "KDE-Partitionsverwaltung Dummy-Backend",
"Name[el]": "KDE Εικονικό σύστημα υποστήριξης διαχειριστή κατατμήσεων",
"Name[en_GB]": "KDE Partition Manager Dummy Backend",
"Name[es]": "Motor de simulación para el gestor de particiones de KDE",
"Name[fi]": "KDE:n osionhallinnan valetaustaosa",
"Name[fr]": "Moteur de test pour le gestionnaire de partitions de KDE",

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

@ -4,7 +4,29 @@
{
"Email": "andrius@stikonas.eu",
"Name": "Andrius Štikonas",
"Name[x-test]": "xxAndrius Štikonasxx"
"Name[ast]": "Andrius Štikonas",
"Name[ca@valencia]": "Andrius Štikonas",
"Name[ca]": "Andrius Štikonas",
"Name[cs]": "Andrius Štikonas",
"Name[de]": "Andrius Štikonas",
"Name[el]": "Andrius Štikonas",
"Name[en_GB]": "Andrius Štikonas",
"Name[es]": "Andrius Štikonas",
"Name[fi]": "Andrius Štikonas",
"Name[fr]": "Andrius Štikonas",
"Name[gl]": "Andrius Štikonas",
"Name[it]": "Andrius Štikonas",
"Name[ko]": "Andrius Štikonas",
"Name[lt]": "Andrius Štikonas",
"Name[nl]": "Andrius Štikonas",
"Name[pl]": "Andrius Štikonas",
"Name[pt]": "Andrius Štikonas",
"Name[pt_BR]": "Andrius Štikonas",
"Name[sk]": "Andrius Štikonas",
"Name[sv]": "Andrius Štikonas",
"Name[uk]": "Andrius Štikonas",
"Name[x-test]": "xxAndrius Štikonasxx",
"Name[zh_CN]": "Andrius Štikonas"
}
],
"Category": "BackendPlugin",
@ -13,6 +35,8 @@
"Description[ca]": "Un dorsal «sfdisk» del gestor de particions del KDE.",
"Description[cs]": "Podpůrná vrstva sfdisk pro správce diskových oddílů pro KDE.",
"Description[de]": "Ein sfdisk-Backend für die KDE-Partitionsverwaltung.",
"Description[el]": "Σύστημα υποστήριξης sfdisk διαχειριστή κατατμήσεων του KDE.",
"Description[en_GB]": "A KDE Partition Manager sfdisk backend.",
"Description[es]": "Motor sfdisk para el gestor de particiones de KDE.",
"Description[fi]": "KDE:n osionhallinnan sfdisk-taustaosa",
"Description[fr]": "Moteur sfdisk pour le gestionnaire de partitions de KDE.",
@ -36,6 +60,8 @@
"Name[ca]": "Dorsal «sfdisk» del gestor de particions del KDE",
"Name[cs]": "Podpůrná vrstva sfdisk pro správce diskových oddílů pro KDE",
"Name[de]": "KDE-Partitionsverwaltung sfdisk-Backend",
"Name[el]": "KDE Σύστημα υποστήριξης sfdisk διαχειριστή κατατμήσεων",
"Name[en_GB]": "KDE Partition Manager sfdisk Backend",
"Name[es]": "Motor sfdisk para el gestor de particiones de KDE",
"Name[fi]": "KDE:n osionhallinnan sfdisk-taustaosa",
"Name[fr]": "Moteur sfdisk pour le gestionnaire de partitions de KDE",

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"
@ -167,12 +169,30 @@ Device* SfdiskBackend::scanDevice(const QString& deviceNode)
if ( d == nullptr && modelCommand.run(-1) && modelCommand.exitCode() == 0 )
{
QString modelName = modelCommand.output();
modelName = modelName.left(modelName.length() - 1);
QString name = modelCommand.output();
name = name.left(name.length() - 1);
Log(Log::Level::information) << xi18nc("@info:status", "Device found: %1", modelName);
if (name.trimmed().isEmpty()) {
// Get 'lsblk --output kname' in the cases where the model name is not available.
// As lsblk doesn't have an option to include a separator in its output, it is
// necessary to run it again getting only the kname as output.
ExternalCommand kname(QStringLiteral("lsblk"), {QStringLiteral("--nodeps"), QStringLiteral("--noheadings"), QStringLiteral("--output"), QStringLiteral("kname"),
deviceNode});
d = new DiskDevice(modelName, deviceNode, 255, 63, deviceSize / logicalSectorSize / 255 / 63, logicalSectorSize);
if (kname.run(-1) && kname.exitCode() == 0)
name = kname.output();
}
ExternalCommand transport(QStringLiteral("lsblk"), {QStringLiteral("--nodeps"), QStringLiteral("--noheadings"), QStringLiteral("--output"), QStringLiteral("tran"),
deviceNode});
QString icon;
if (transport.run(-1) && transport.exitCode() == 0)
if (transport.output().trimmed() == QStringLiteral("usb"))
icon = QStringLiteral("drive-removable-media-usb");
Log(Log::Level::information) << xi18nc("@info:status", "Device found: %1", name);
d = new DiskDevice(name, deviceNode, 255, 63, deviceSize / logicalSectorSize / 255 / 63, logicalSectorSize, icon);
}
if ( d )
@ -225,12 +245,12 @@ void SfdiskBackend::scanDevicePartitions(Device& d, const QJsonArray& jsonPartit
const qint64 start = partitionObject[QLatin1String("start")].toVariant().toLongLong();
const qint64 size = partitionObject[QLatin1String("size")].toVariant().toLongLong();
const QString partitionType = partitionObject[QLatin1String("type")].toString();
PartitionTable::Flag activeFlags = partitionObject[QLatin1String("bootable")].toBool() ? PartitionTable::FlagBoot : PartitionTable::FlagNone;
PartitionTable::Flags activeFlags = partitionObject[QLatin1String("bootable")].toBool() ? PartitionTable::FlagBoot : PartitionTable::FlagNone;
if (partitionType == QStringLiteral("C12A7328-F81F-11D2-BA4B-00A0C93EC93B"))
activeFlags = PartitionTable::FlagEsp;
activeFlags |= PartitionTable::FlagBoot;
else if (partitionType == QStringLiteral("21686148-6449-6E6F-744E-656564454649"))
activeFlags = PartitionTable::FlagBiosGrub;
activeFlags |= PartitionTable::FlagBiosGrub;
FileSystem::Type type = FileSystem::Type::Unknown;
type = detectFileSystem(partitionNode);
@ -332,11 +352,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);
@ -476,8 +497,8 @@ PartitionTable::Flags SfdiskBackend::availableFlags(PartitionTable::TableType ty
if (type == PartitionTable::gpt) {
// These are not really flags but for now keep them for compatibility
// We should implement changing partition type
flags = PartitionTable::FlagBiosGrub |
PartitionTable::FlagEsp;
flags = PartitionTable::Flag::FlagBiosGrub |
PartitionTable::Flag::FlagBoot;
}
else if (type == PartitionTable::msdos || type == PartitionTable::msdos_sectorbased)
flags = PartitionTable::FlagBoot;

View File

@ -198,11 +198,11 @@ static QLatin1String getPartitionType(FileSystem::Type t, PartitionTable::TableT
{
quint8 type;
switch (tableType) {
case PartitionTable::gpt:
case PartitionTable::TableType::gpt:
type = 0;
break;
case PartitionTable::msdos:
case PartitionTable::msdos_sectorbased:
case PartitionTable::TableType::msdos:
case PartitionTable::TableType::msdos_sectorbased:
type = 1;
break;
default:;
@ -227,21 +227,25 @@ bool SfdiskPartitionTable::setPartitionSystemType(Report& report, const Partitio
bool SfdiskPartitionTable::setFlag(Report& report, const Partition& partition, PartitionTable::Flag flag, bool state)
{
// We only allow setting one active partition per device
if (flag == PartitionTable::FlagBoot && state == true) {
ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--activate"), m_device->deviceNode(), QString::number(partition.number()) } );
if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0)
return true;
else
return false;
} else if (flag == PartitionTable::FlagBoot && state == false) {
ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--activate"), m_device->deviceNode(), QStringLiteral("-") } );
if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0)
return true;
// FIXME: Do not return false since we have no way of checking if partition table is MBR
if (m_device->partitionTable()->type() == PartitionTable::TableType::msdos ||
m_device->partitionTable()->type() == PartitionTable::TableType::msdos_sectorbased) {
// We only allow setting one active partition per device
if (flag == PartitionTable::Flag::FlagBoot && state == true) {
ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--activate"), m_device->deviceNode(), QString::number(partition.number()) } );
if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0)
return true;
else
return false;
} else if (flag == PartitionTable::Flag::FlagBoot && state == false) {
ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--activate"), m_device->deviceNode(), QStringLiteral("-") } );
if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0)
return true;
else
return false;
}
}
if (flag == PartitionTable::FlagEsp && state == true) {
if (flag == PartitionTable::Flag::FlagBoot && state == true) {
ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--part-type"), m_device->deviceNode(), QString::number(partition.number()),
QStringLiteral("C12A7328-F81F-11D2-BA4B-00A0C93EC93B") } );
if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0)
@ -249,10 +253,10 @@ bool SfdiskPartitionTable::setFlag(Report& report, const Partition& partition, P
else
return false;
}
if (flag == PartitionTable::FlagEsp && state == false)
if (flag == PartitionTable::Flag::FlagBoot && state == false)
setPartitionSystemType(report, partition);
if (flag == PartitionTable::FlagBiosGrub && state == true) {
if (flag == PartitionTable::Flag::FlagBiosGrub && state == true) {
ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--part-type"), m_device->deviceNode(), QString::number(partition.number()),
QStringLiteral("21686148-6449-6E6F-744E-656564454649") } );
if (sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0)
@ -260,7 +264,7 @@ bool SfdiskPartitionTable::setFlag(Report& report, const Partition& partition, P
else
return false;
}
if (flag == PartitionTable::FlagBiosGrub && state == false)
if (flag == PartitionTable::Flag::FlagBiosGrub && state == false)
setPartitionSystemType(report, partition);
return true;

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"
@ -124,9 +125,11 @@ bool ExternalCommand::start(int timeout)
if (command().isEmpty())
return false;
if (report()) {
if (report())
report()->setCommand(xi18nc("@info:status", "Command: %1 %2", command(), args().join(QStringLiteral(" "))));
}
if ( qEnvironmentVariableIsSet( "KPMCORE_DEBUG" ))
qDebug() << xi18nc("@info:status", "Command: %1 %2", command(), args().join(QStringLiteral(" ")));
QString cmd = QStandardPaths::findExecutable(command());
if (cmd.isEmpty())
@ -217,6 +220,59 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
QEventLoop loop;
auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) {
loop.exit();
if (watcher->isError())
qWarning() << watcher->error();
else {
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);
};
connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop);
loop.exec();
return rval;
}
bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte)
{
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() << "Could not connect to DBus system bus";
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
QByteArray request;
const quint64 nonce = interface->getNonce();
request.setNum(nonce);
request.append(buffer);
request.append(deviceNode.toUtf8());
request.append(QByteArray::number(firstByte));
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
QDBusPendingCall pcall = interface->writeData(privateKey->signMessage(hash, QCA::EMSA3_Raw), nonce,
buffer, deviceNode, firstByte);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
QEventLoop loop;
auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) {
loop.exit();
if (watcher->isError())

View File

@ -69,6 +69,7 @@ public:
public:
bool copyBlocks(CopySource& source, CopyTarget& target);
bool writeData(Report& report, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte); // same as copyBlocks but from QByteArray
/**< @param cmd the command to run */
void setCommand(const QString& cmd);

View File

@ -21,7 +21,6 @@
const QString allowedCommands[] = {
// TODO try to remove these later
QStringLiteral("mv"),
QStringLiteral("dd"),
// TODO no root needed
QStringLiteral("lsblk"),

View File

@ -152,12 +152,18 @@ 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)
// If targetDevice is empty then return QByteArray with data that was read from disk.
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 +178,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;
@ -207,7 +214,7 @@ bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint6
bool rval = true;
while (blocksCopied < blocksToCopy) {
while (blocksCopied < blocksToCopy && !targetDevice.isEmpty()) {
if (!(rval = readData(sourceDevice, buffer, readOffset + blockSize * blocksCopied * copyDirection, blockSize)))
break;
@ -239,8 +246,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,9 +262,37 @@ 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;
}
bool ExternalCommandHelper::writeData(const QByteArray& signature, const quint64 nonce, const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte)
{
if (m_Nonces.find(nonce) != m_Nonces.end())
m_Nonces.erase( nonce );
else
return false;
QByteArray request;
request.setNum(nonce);
request.append(buffer);
request.append(targetDevice.toUtf8());
request.append(QByteArray::number(targetFirstByte));
// Do not allow using this helper for writing to arbitrary location
if ( targetDevice.left(5) != QStringLiteral("/dev/") && !targetDevice.contains(QStringLiteral("/etc/fstab")))
return false;
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) {
qCritical() << xi18n("Invalid cryptographic signature");
return false;
}
return writeData(targetDevice, buffer, targetFirstByte);
}
QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode)
{
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

View File

@ -49,7 +49,8 @@ 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 bool writeData(const QByteArray& signature, const quint64 nonce, const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte);
Q_SCRIPTABLE void exit(const QByteArray& signature, const quint64 nonce);
private:

View File

@ -6,30 +6,42 @@ Name=Start external command daemon
Name[ca]=Inicia el dimoni d'ordres externes
Name[ca@valencia]=Inicia el dimoni d'ordres externes
Name[cs]=Spustit démona externích příkazů
Name[de]=Externen Befehlsdienst starten
Name[el]=Εκκίνηση διεργασίας με εξωτερική εντολή
Name[en_GB]=Start external command daemon
Name[es]=Iniciar el demonio de órdenes externas
Name[fi]=Käynnistä ulkoinen komentopalvelu
Name[fr]=Lancer le démon de la commande externe
Name[gl]=Iniciar o servizo de orde externa
Name[it]=Avvia demone per comando esterno
Name[ko]=외부 명령 데몬 시작
Name[lt]=Paleisti išorinių komandų tarnybą
Name[nl]=Start externe opdrachtdaemon
Name[pl]=Rozpocznij usługę zewnętrznego polecenia
Name[pt]=Iniciar o servidor de comandos externos
Name[sk]=Spustiť externé démony príkazov
Name[sv]=Starta extern kommandodemon
Name[uk]=Запуск фонової служби зовнішньої команди
Name[x-test]=xxStart external command daemonxx
Description=Administrative privileges are required to manage disks
Description[ast]=Ríquense los privilexos alministrativos pa xestionar discos
Description[ca]=Es requereixen privilegis d'administrador per gestionar discs
Description[ca@valencia]=Es requereixen privilegis d'administrador per gestionar discs
Description[cs]=Pro správu disků jsou potřeba práva administrátora
Description[de]=Systemverwalterrechte sind zur Verwaltung von Festplatten erforderlich
Description[el]=Απαιτούνται δικαιώματα διαχειριστή για τη διαχείριση δίσκων
Description[en_GB]=Administrative privileges are required to manage disks
Description[es]=Se necesitan permisos de administrador para gestionar discos
Description[fi]=Levyjen hallinta vaatii pääkäyttäjäoikeuksia
Description[fr]=Vous devez disposer des privilèges d'administrateur pour gérer les disques
Description[gl]=Requírense privilexios de administración para xestionar discos.
Description[it]=Per gestire il disco sono richiesti privilegi di amministratore
Description[ko]=디스크를 관리하려면 권한이 필요함
Description[lt]=Diskų tvarkymui reikalingos administratoriaus teisės
Description[nl]=Er zijn administratieve rechten vereist om schijven te beheren
Description[pl]=Do zarządzania dyskami wymagane są uprawnienia administratora
Description[pt]=São necessários privilégios de administrador para gerir os discos
Description[pt_BR]=São necessários privilégios administrativos para gerenciar discos
Description[sv]=Administratörsprivilegier krävs för att hantera diskar
Description[uk]=Для керування дисками потрібні права доступу адміністратора (root)
Description[x-test]=xxAdministrative privileges are required to manage disksxx