diff --git a/src/backend/corebackendpartitiontable.h b/src/backend/corebackendpartitiontable.h index 37b56f0..292523e 100644 --- a/src/backend/corebackendpartitiontable.h +++ b/src/backend/corebackendpartitiontable.h @@ -135,6 +135,15 @@ public: */ virtual bool setPartitionUUID(Report& report, const Partition& partition, const QString& uuid) = 0; + /** + * Set the attributes of a partition in the partition table (GPT only). + * @param report the report to write information to + * @param partition the partition to set the attributes for + * @param attrs the new attributes for the partition + * @return true on success + */ + virtual bool setPartitionAttributes(Report& report, const Partition& partition, quint64 attrs) = 0; + /** * Set the system type (e.g. 83 for Linux) of a partition. The type to set is taken from * the partition's file system. diff --git a/src/core/partition.h b/src/core/partition.h index 36d64b0..dd30ef3 100644 --- a/src/core/partition.h +++ b/src/core/partition.h @@ -24,7 +24,6 @@ #include "util/libpartitionmanagerexport.h" -#include #include #include @@ -131,6 +130,9 @@ public: const QString& uuid() const { return m_UUID; /**< @return the GPT Partition UUID */ } + quint64 attributes() const { + return m_Attributes; /**< @return the GPT Partition attributes */ + } qint64 firstSector() const { return m_FirstSector; /**< @return the Partition's first sector on the Device */ } @@ -219,6 +221,9 @@ public: void setUUID(const QString& s) { m_UUID = s; /**< @param s the new UUID */ } + void setAttributes(quint64 f) { + m_Attributes = f; /**< @param f the new attributes */ + } void append(Partition* p) override { m_Children.append(p); @@ -274,6 +279,7 @@ private: QString m_Label; QString m_Type; QString m_UUID; + quint64 m_Attributes; QString m_PartitionPath; QString m_MountPoint; PartitionTable::Flags m_AvailableFlags; diff --git a/src/jobs/CMakeLists.txt b/src/jobs/CMakeLists.txt index 2aa58b7..08e0776 100644 --- a/src/jobs/CMakeLists.txt +++ b/src/jobs/CMakeLists.txt @@ -8,6 +8,7 @@ set(JOBS_SRC jobs/createpartitiontablejob.cpp jobs/setpartitionlabeljob.cpp jobs/setpartitionuuidjob.cpp + jobs/setpartitionattributesjob.cpp jobs/createvolumegroupjob.cpp jobs/removevolumegroupjob.cpp jobs/deactivatevolumegroupjob.cpp diff --git a/src/jobs/setpartitionattributesjob.cpp b/src/jobs/setpartitionattributesjob.cpp new file mode 100644 index 0000000..b37c176 --- /dev/null +++ b/src/jobs/setpartitionattributesjob.cpp @@ -0,0 +1,86 @@ +/************************************************************************* + * Copyright (C) 2020 by Gaël PORTAY * + * * + * 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 "jobs/setpartitionattributesjob.h" + +#include "backend/corebackend.h" +#include "backend/corebackendmanager.h" +#include "backend/corebackenddevice.h" +#include "backend/corebackendpartitiontable.h" + +#include "core/partition.h" +#include "core/device.h" + +#include "util/report.h" + +#include +#include + +/** Creates a new SetPartitionAttributesJob (GPT only) + @param d the Device the Partition to be created will be on + @param p the Partition whose attributes is to be set is on + @param newAttrs the new attributes +*/ +SetPartitionAttributesJob::SetPartitionAttributesJob(Device& d, Partition& p, quint64 newAttrs) : + Job(), + m_Device(d), + m_Partition(p), + m_Attributes(newAttrs) +{ +} + +bool SetPartitionAttributesJob::run(Report& parent) +{ + Q_ASSERT(partition().devicePath() == device().deviceNode()); + + bool rval = true; + + Report* report = jobStarted(parent); + + // The attributes are supported by GPT only, if the partition table is not GPT, just ignore the + // request and say all is well. This helps in operations because we don't have to check for + // support to avoid having a failed job. + if (m_Device.partitionTable()->type() != PartitionTable::gpt) + report->line() << xi18nc("@info:progress", "Partition table of partition %1 does not support setting attributes. Job ignored.", partition().deviceNode()); + else { + std::unique_ptr backendDevice = CoreBackendManager::self()->backend()->openDevice(m_Device); + if (backendDevice) { + std::unique_ptr backendPartitionTable = backendDevice->openPartitionTable(); + + if (backendPartitionTable) { + if (backendPartitionTable->setPartitionAttributes(*report, partition(), m_Attributes)) { + rval = true; + partition().setAttributes(m_Attributes); + backendPartitionTable->commit(); + } else + report->line() << xi18nc("@info:progress", "Failed to set the attributes for the partition %1.", partition().deviceNode()); + } else + report->line() << xi18nc("@info:progress", "Could not open partition table on device %1 to set the attributes for the partition %2.", device().deviceNode(), partition().deviceNode()); + } else + report->line() << xi18nc("@info:progress", "Could not open device %1 to set the attributes for partition %2.", device().deviceNode(), partition().deviceNode()); + + } + + jobFinished(*report, rval); + + return rval; +} + +QString SetPartitionAttributesJob::description() const +{ + return xi18nc("@info:progress", "Set the attributes on partition %1 to \"%2\"", partition().deviceNode(), QString::number(attributes(), 0x10)); +} diff --git a/src/jobs/setpartitionattributesjob.h b/src/jobs/setpartitionattributesjob.h new file mode 100644 index 0000000..6ad7607 --- /dev/null +++ b/src/jobs/setpartitionattributesjob.h @@ -0,0 +1,68 @@ +/************************************************************************* + * Copyright (C) 2020 by Gaël PORTAY * + * * + * 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 .* + *************************************************************************/ + +#if !defined(KPMCORE_SETPARTITIONATTRIBUTESJOB_H) + +#define KPMCORE_SETPARTITIONATTRIBUTESJOB_H + +#include "jobs/job.h" + +class Partition; +class Device; +class Report; + +/** Set a Partition attributes (GPT only). + @author Gaël PORTAY +*/ +class SetPartitionAttributesJob : public Job +{ +public: + SetPartitionAttributesJob(Device& d, Partition& p, quint64 newAttrs); + +public: + bool run(Report& parent) override; + QString description() const override; + +protected: + Partition& partition() { + return m_Partition; + } + const Partition& partition() const { + return m_Partition; + } + + Device& device() { + return m_Device; + } + const Device& device() const { + return m_Device; + } + + quint64 attributes() const { + return m_Attributes; + } + void setAttributes(quint64 f) { + m_Attributes = f; + } + +private: + Device& m_Device; + Partition& m_Partition; + quint64 m_Attributes; +}; + +#endif diff --git a/src/ops/newoperation.cpp b/src/ops/newoperation.cpp index e8de081..8e4f454 100644 --- a/src/ops/newoperation.cpp +++ b/src/ops/newoperation.cpp @@ -26,6 +26,7 @@ #include "jobs/createfilesystemjob.h" #include "jobs/setpartitionlabeljob.h" #include "jobs/setpartitionuuidjob.h" +#include "jobs/setpartitionattributesjob.h" #include "jobs/setfilesystemlabeljob.h" #include "jobs/setpartflagsjob.h" #include "jobs/checkfilesystemjob.h" @@ -50,6 +51,7 @@ NewOperation::NewOperation(Device& d, Partition* p) : m_CreatePartitionJob(new CreatePartitionJob(targetDevice(), newPartition())), m_SetPartitionLabelJob(nullptr), m_SetPartitionUUIDJob(nullptr), + m_SetPartitionAttributesJob(nullptr), m_CreateFileSystemJob(nullptr), m_SetPartFlagsJob(nullptr), m_SetFileSystemLabelJob(nullptr), @@ -67,6 +69,11 @@ NewOperation::NewOperation(Device& d, Partition* p) : addJob(setPartitionUUIDJob()); } + if (p->attributes()) { + m_SetPartitionAttributesJob = new SetPartitionAttributesJob(targetDevice(), newPartition(), p->attributes()); + addJob(setPartitionAttributesJob()); + } + const FileSystem& fs = newPartition().fileSystem(); if (fs.type() != FileSystem::Type::Extended) { diff --git a/src/ops/newoperation.h b/src/ops/newoperation.h index 247999f..e596535 100644 --- a/src/ops/newoperation.h +++ b/src/ops/newoperation.h @@ -32,6 +32,7 @@ class OperationStack; class CreatePartitionJob; class SetPartitionLabelJob; class SetPartitionUUIDJob; +class SetPartitionAttributesJob; class CreateFileSystemJob; class SetFileSystemLabelJob; class SetPartFlagsJob; @@ -91,6 +92,9 @@ protected: SetPartitionUUIDJob* setPartitionUUIDJob() { return m_SetPartitionUUIDJob; } + SetPartitionAttributesJob* setPartitionAttributesJob() { + return m_SetPartitionAttributesJob; + } CreateFileSystemJob* createFileSystemJob() { return m_CreateFileSystemJob; } @@ -110,6 +114,7 @@ private: CreatePartitionJob* m_CreatePartitionJob; SetPartitionLabelJob* m_SetPartitionLabelJob; SetPartitionUUIDJob* m_SetPartitionUUIDJob; + SetPartitionAttributesJob* m_SetPartitionAttributesJob; CreateFileSystemJob* m_CreateFileSystemJob; SetPartFlagsJob* m_SetPartFlagsJob; SetFileSystemLabelJob* m_SetFileSystemLabelJob; diff --git a/src/plugins/dummy/dummypartitiontable.cpp b/src/plugins/dummy/dummypartitiontable.cpp index 136806a..046a968 100644 --- a/src/plugins/dummy/dummypartitiontable.cpp +++ b/src/plugins/dummy/dummypartitiontable.cpp @@ -134,6 +134,15 @@ bool DummyPartitionTable::setPartitionUUID(Report& report, const Partition& part return true; } +bool DummyPartitionTable::setPartitionAttributes(Report& report, const Partition& partition, quint64 attrs) +{ + Q_UNUSED(report) + Q_UNUSED(partition) + Q_UNUSED(attrs) + + return true; +} + bool DummyPartitionTable::setFlag(Report& report, const Partition& partition, PartitionTable::Flag partitionManagerFlag, bool state) { Q_UNUSED(report) diff --git a/src/plugins/dummy/dummypartitiontable.h b/src/plugins/dummy/dummypartitiontable.h index 55e9e8a..bce15b4 100644 --- a/src/plugins/dummy/dummypartitiontable.h +++ b/src/plugins/dummy/dummypartitiontable.h @@ -49,6 +49,7 @@ public: bool setPartitionLabel(Report& report, const Partition& partition, const QString& label) override; QString getPartitionUUID(Report& report, const Partition& partition) override; bool setPartitionUUID(Report& report, const Partition& partition, const QString& uuid) override; + bool setPartitionAttributes(Report& report, const Partition& partition, quint64 attrs) override; bool setPartitionSystemType(Report& report, const Partition& partition) override; bool setFlag(Report& report, const Partition& partition, PartitionTable::Flag partitionManagerFlag, bool state) override; }; diff --git a/src/plugins/sfdisk/sfdiskpartitiontable.cpp b/src/plugins/sfdisk/sfdiskpartitiontable.cpp index 809cd71..702542c 100644 --- a/src/plugins/sfdisk/sfdiskpartitiontable.cpp +++ b/src/plugins/sfdisk/sfdiskpartitiontable.cpp @@ -213,6 +213,22 @@ static QLatin1String getPartitionType(FileSystem::Type t, PartitionTable::TableT return QLatin1String(); } +static QStringList getAttributeList(quint64 attrs) +{ + QStringList list; + if (attrs & 0x01) + list += QStringLiteral("RequiredPartition"); + if (attrs & 0x02) + list += QStringLiteral("NoBlockIOProtocol"); + if (attrs & 0x04) + list += QStringLiteral("LegacyBIOSBootable"); + for (int bit = 48; bit < 64; bit++) + if (attrs & (1 << bit)) + list += QString::number(bit); + + return list; +} + bool SfdiskPartitionTable::setPartitionLabel(Report& report, const Partition& partition, const QString& label) { if (label.isEmpty()) @@ -246,6 +262,16 @@ bool SfdiskPartitionTable::setPartitionUUID(Report& report, const Partition& par return sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0; } +bool SfdiskPartitionTable::setPartitionAttributes(Report& report, const Partition& partition, quint64 attrs) +{ + QStringList attributes = getAttributeList(attrs); + if (attributes.isEmpty()) + return true; + ExternalCommand sfdiskCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--part-attrs"), m_device->deviceNode(), QString::number(partition.number()), + attributes.join(QStringLiteral(",")) } ); + return sfdiskCommand.run(-1) && sfdiskCommand.exitCode() == 0; +} + bool SfdiskPartitionTable::setPartitionSystemType(Report& report, const Partition& partition) { QString partitionType = partition.type(); diff --git a/src/plugins/sfdisk/sfdiskpartitiontable.h b/src/plugins/sfdisk/sfdiskpartitiontable.h index 08dc46c..e682760 100644 --- a/src/plugins/sfdisk/sfdiskpartitiontable.h +++ b/src/plugins/sfdisk/sfdiskpartitiontable.h @@ -49,6 +49,7 @@ public: bool setPartitionLabel(Report& report, const Partition& partition, const QString& label) override; QString getPartitionUUID(Report& report, const Partition& partition) override; bool setPartitionUUID(Report& report, const Partition& partition, const QString& uuid) override; + bool setPartitionAttributes(Report& report, const Partition& partition, quint64 attrs) override; bool setPartitionSystemType(Report& report, const Partition& partition) override; bool setFlag(Report& report, const Partition& partition, PartitionTable::Flag flag, bool state) override;