From 0d284759f59a2e1c282f86255d3da8d4542fce9d Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:26:37 +0100 Subject: [PATCH] [partition] Apply custom partition layout for Erase and Replace choices This patches add new methods to both PartitionLayout and PartitionCoreModule classes which apply the partition layout to the available drive space. In addition, the partition creation code from PartitioinActions is removed to call the newly created methods instead, thus applying the custom partition layout when the "Erase whole disk" and "Replace partition" choices are selected. Signed-off-by: Arnaud Ferraris --- .../partition/core/PartitionActions.cpp | 71 ++----------- .../partition/core/PartitionCoreModule.cpp | 24 +++++ .../partition/core/PartitionCoreModule.h | 1 + .../partition/core/PartitionLayout.cpp | 99 +++++++++++++++++++ src/modules/partition/core/PartitionLayout.h | 6 ++ 5 files changed, 138 insertions(+), 63 deletions(-) diff --git a/src/modules/partition/core/PartitionActions.cpp b/src/modules/partition/core/PartitionActions.cpp index c86cf015c..08278a3b6 100644 --- a/src/modules/partition/core/PartitionActions.cpp +++ b/src/modules/partition/core/PartitionActions.cpp @@ -169,39 +169,7 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO lastSectorForRoot -= suggestedSwapSizeB / dev->logicalSize() + 1; } - Partition* rootPartition = nullptr; - if ( o.luksPassphrase.isEmpty() ) - { - rootPartition = KPMHelpers::createNewPartition( - dev->partitionTable(), - *dev, - PartitionRole( PartitionRole::Primary ), - FileSystem::typeForName( defaultFsType ), - firstFreeSector, - lastSectorForRoot, - PartitionTable::FlagNone - ); - } - else - { - rootPartition = KPMHelpers::createNewEncryptedPartition( - dev->partitionTable(), - *dev, - PartitionRole( PartitionRole::Primary ), - FileSystem::typeForName( defaultFsType ), - firstFreeSector, - lastSectorForRoot, - o.luksPassphrase, - PartitionTable::FlagNone - ); - } - PartitionInfo::setFormat( rootPartition, true ); - PartitionInfo::setMountPoint( rootPartition, "/" ); - // Some buggy (legacy) BIOSes test if the bootflag of at least one partition is set. - // Otherwise they ignore the device in boot-order, so add it here. - core->createPartition( dev, rootPartition, - rootPartition->activeFlags() | ( isEfi ? PartitionTable::FlagNone : PartitionTable::FlagBoot ) - ); + core->layoutApply( dev, firstFreeSector, lastSectorForRoot, o.luksPassphrase ); if ( shouldCreateSwap ) { @@ -245,6 +213,8 @@ doReplacePartition( PartitionCoreModule* core, Partition* partition, Choices::ReplacePartitionOptions o ) { + qint64 firstSector, lastSector; + cDebug() << "doReplacePartition for device" << partition->partitionPath(); QString defaultFsType = o.defaultFsType; @@ -267,38 +237,13 @@ doReplacePartition( PartitionCoreModule* core, } } - Partition* newPartition = nullptr; - if ( o.luksPassphrase.isEmpty() ) - { - newPartition = KPMHelpers::createNewPartition( - partition->parent(), - *dev, - newRoles, - FileSystem::typeForName( defaultFsType ), - partition->firstSector(), - partition->lastSector(), - PartitionTable::FlagNone - ); - } - else - { - newPartition = KPMHelpers::createNewEncryptedPartition( - partition->parent(), - *dev, - newRoles, - FileSystem::typeForName( defaultFsType ), - partition->firstSector(), - partition->lastSector(), - o.luksPassphrase, - PartitionTable::FlagNone - ); - } - PartitionInfo::setMountPoint( newPartition, "/" ); - PartitionInfo::setFormat( newPartition, true ); - + // Save the first and last sector values as the partition will be deleted + firstSector = partition->firstSector(); + lastSector = partition->lastSector(); if ( !partition->roles().has( PartitionRole::Unallocated ) ) core->deletePartition( dev, partition ); - core->createPartition( dev, newPartition ); + + core->layoutApply( dev, firstSector, lastSector, o.luksPassphrase ); core->dumpQueue(); } diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index 8abcf7035..9af5665a5 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -787,6 +787,30 @@ PartitionCoreModule::initLayout( const QVariantList& config ) } } +void +PartitionCoreModule::layoutApply( Device *dev, + qint64 firstSector, + qint64 lastSector, + QString luksPassphrase ) +{ + bool isEfi = PartUtils::isEfiSystem(); + QList< Partition* > partList = m_partLayout->execute( dev, firstSector, lastSector, luksPassphrase ); + + foreach ( Partition *part, partList ) + { + if ( part->mountPoint() == "/" ) + { + createPartition( dev, part, + part->activeFlags() | ( isEfi ? PartitionTable::FlagNone : PartitionTable::FlagBoot ) + ); + } + else + { + createPartition( dev, part ); + } + } +} + void PartitionCoreModule::revert() { diff --git a/src/modules/partition/core/PartitionCoreModule.h b/src/modules/partition/core/PartitionCoreModule.h index 55961ce58..2b2c73a3f 100644 --- a/src/modules/partition/core/PartitionCoreModule.h +++ b/src/modules/partition/core/PartitionCoreModule.h @@ -159,6 +159,7 @@ public: void initLayout(); void initLayout( const QVariantList& config ); + void layoutApply( Device *dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase ); /** * @brief jobs creates and returns a list of jobs which can then apply the changes * requested by the user. diff --git a/src/modules/partition/core/PartitionLayout.cpp b/src/modules/partition/core/PartitionLayout.cpp index 02ec29526..d0c1a7c94 100644 --- a/src/modules/partition/core/PartitionLayout.cpp +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -18,6 +18,12 @@ #include "core/PartitionLayout.h" +#include "core/KPMHelpers.h" +#include "core/PartitionActions.h" +#include "core/PartitionInfo.h" + +#include +#include #include PartitionLayout::PartitionLayout() @@ -113,3 +119,96 @@ PartitionLayout::addEntry( QString label, QString mountPoint, QString fs, QStrin partLayout.append( entry ); } + +static qint64 +sizeToSectors( double size, PartitionLayout::SizeUnit unit, qint64 totalSize, qint64 logicalSize ) +{ + qint64 sectors; + double tmp; + + if ( unit == PartitionLayout::SizeUnit::Percent ) + { + tmp = static_cast( totalSize ) * size / 100; + sectors = static_cast( tmp ); + } + else + { + tmp = size; + if ( unit >= PartitionLayout::SizeUnit::KiB ) + tmp *= 1024; + if ( unit >= PartitionLayout::SizeUnit::MiB ) + tmp *= 1024; + if ( unit >= PartitionLayout::SizeUnit::GiB ) + tmp *= 1024; + + sectors = PartitionActions::bytesToSectors( static_cast( tmp ), + logicalSize + ); + } + + return sectors; +} + +QList< Partition* > +PartitionLayout::execute( Device *dev, qint64 firstSector, + qint64 lastSector, QString luksPassphrase ) +{ + QList< Partition* > partList; + qint64 size, minSize, end; + qint64 totalSize = lastSector - firstSector; + qint64 availableSize = totalSize; + + // TODO: Refine partition sizes to make sure there is room for every partition + // Use a default (200-500M ?) minimum size for partition without minSize + + foreach( const PartitionLayout::PartitionEntry& part, partLayout ) + { + Partition *currentPartition = nullptr; + + // Calculate partition size + size = sizeToSectors( part.partSize, part.partSizeUnit, totalSize, dev->logicalSize() ); + minSize = sizeToSectors( part.partMinSize, part.partMinSizeUnit, totalSize, dev->logicalSize() ); + if ( size < minSize ) + size = minSize; + if ( size > availableSize ) + size = availableSize; + end = firstSector + size; + + if ( luksPassphrase.isEmpty() ) + { + currentPartition = KPMHelpers::createNewPartition( + dev->partitionTable(), + *dev, + PartitionRole( PartitionRole::Primary ), + static_cast(part.partFileSystem), + firstSector, + end, + PartitionTable::FlagNone + ); + } + else + { + currentPartition = KPMHelpers::createNewEncryptedPartition( + dev->partitionTable(), + *dev, + PartitionRole( PartitionRole::Primary ), + static_cast(part.partFileSystem), + firstSector, + end, + luksPassphrase, + PartitionTable::FlagNone + ); + } + PartitionInfo::setFormat( currentPartition, true ); + PartitionInfo::setMountPoint( currentPartition, part.partMountPoint ); + if ( !part.partLabel.isEmpty() ) + currentPartition->fileSystem().setLabel( part.partLabel ); + // Some buggy (legacy) BIOSes test if the bootflag of at least one partition is set. + // Otherwise they ignore the device in boot-order, so add it here. + partList.append( currentPartition ); + firstSector = end + 1; + availableSize -= size; + } + + return partList; +} diff --git a/src/modules/partition/core/PartitionLayout.h b/src/modules/partition/core/PartitionLayout.h index eadb8b012..e3eb7296b 100644 --- a/src/modules/partition/core/PartitionLayout.h +++ b/src/modules/partition/core/PartitionLayout.h @@ -63,6 +63,12 @@ public: void addEntry( QString mountPoint, QString size, QString min = "" ); void addEntry( QString label, QString mountPoint, QString fs, QString size, QString min = "" ); + /** + * @brief Apply the current partition layout to the selected drive space. + * @return A list of Partition objects. + */ + QList< Partition* > execute( Device *dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase ); + private: QList< PartitionEntry > partLayout; };