From f1ead5193d583298d8c10f6918fc4e2b8de3097a Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:25:22 +0100 Subject: [PATCH 01/11] [partition] Create PartitionLayout class In order to use a custom partition layout in the partition module, we need to write this layout in the module's config file, and store it into a dedicated object. As it doesn't look appropriate to extend an existing class with layout information, we create a new PartitionLayout class, which will be used to parse the layout from the config file and keep it in memory. Signed-off-by: Arnaud Ferraris --- src/modules/partition/CMakeLists.txt | 1 + .../partition/core/PartitionLayout.cpp | 115 ++++++++++++++++++ src/modules/partition/core/PartitionLayout.h | 70 +++++++++++ src/modules/partition/partition.conf | 27 ++++ 4 files changed, 213 insertions(+) create mode 100644 src/modules/partition/core/PartitionLayout.cpp create mode 100644 src/modules/partition/core/PartitionLayout.h diff --git a/src/modules/partition/CMakeLists.txt b/src/modules/partition/CMakeLists.txt index c166390e8..b9b2109a3 100644 --- a/src/modules/partition/CMakeLists.txt +++ b/src/modules/partition/CMakeLists.txt @@ -34,6 +34,7 @@ if ( KPMcore_FOUND ) core/PartitionCoreModule.cpp core/PartitionInfo.cpp core/PartitionIterator.cpp + core/PartitionLayout.cpp core/PartitionModel.cpp core/PartUtils.cpp gui/BootInfoWidget.cpp diff --git a/src/modules/partition/core/PartitionLayout.cpp b/src/modules/partition/core/PartitionLayout.cpp new file mode 100644 index 000000000..02ec29526 --- /dev/null +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -0,0 +1,115 @@ +/* === This file is part of Calamares - === + * + * Copyright 2018, Collabora Ltd + * + * Calamares 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. + * + * Calamares 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 Calamares. If not, see . + */ + +#include "core/PartitionLayout.h" + +#include + +PartitionLayout::PartitionLayout() +{ +} + +PartitionLayout::PartitionLayout( PartitionLayout::PartitionEntry entry ) +{ + partLayout.append( entry ); +} + +PartitionLayout::PartitionLayout( const PartitionLayout& layout ) + : partLayout( layout.partLayout ) +{ +} + +PartitionLayout::~PartitionLayout() +{ +} + +void +PartitionLayout::addEntry( PartitionLayout::PartitionEntry entry ) +{ + partLayout.append( entry ); +} + +static double +parseSizeString( QString sizeString, PartitionLayout::SizeUnit *unit ) +{ + double value; + bool ok; + + QRegExp rx( "[KkMmGg%]" ); + int pos = rx.indexIn( sizeString ); + QString valueString = sizeString.mid( 0, pos ); + QString unitString = sizeString.mid( pos ); + + value = valueString.toDouble( &ok ); + if ( !ok ) + { + /* + * In case the conversion fails, a size of 100% allows a few cases to pass + * anyway (e.g. when it is the last partition of the layout) + */ + *unit = PartitionLayout::SizeUnit::Percent; + return 100; + } + + if ( unitString.length() > 0 ) + { + if ( unitString.at(0) == '%' ) + *unit = PartitionLayout::SizeUnit::Percent; + else if ( unitString.at(0).toUpper() == 'K' ) + *unit = PartitionLayout::SizeUnit::KiB; + else if ( unitString.at(0).toUpper() == 'M' ) + *unit = PartitionLayout::SizeUnit::MiB; + else if ( unitString.at(0).toUpper() == 'G' ) + *unit = PartitionLayout::SizeUnit::GiB; + else + *unit = PartitionLayout::SizeUnit::Byte; + } + else + { + *unit = PartitionLayout::SizeUnit::Byte; + } + + return value; +} + +void +PartitionLayout::addEntry( QString mountPoint, QString size, QString min ) +{ + PartitionLayout::PartitionEntry entry; + + entry.partMountPoint = mountPoint; + entry.partFileSystem = FileSystem::Ext4; + entry.partSize = parseSizeString( size , &entry.partSizeUnit ); + entry.partMinSize = parseSizeString( min , &entry.partMinSizeUnit ); + + partLayout.append( entry ); +} + +void +PartitionLayout::addEntry( QString label, QString mountPoint, QString fs, QString size, QString min ) +{ + PartitionLayout::PartitionEntry entry; + + entry.partLabel = label; + entry.partMountPoint = mountPoint; + entry.partFileSystem = FileSystem::typeForName( fs ); + entry.partSize = parseSizeString( size , &entry.partSizeUnit ); + entry.partMinSize = parseSizeString( min , &entry.partMinSizeUnit ); + + partLayout.append( entry ); +} diff --git a/src/modules/partition/core/PartitionLayout.h b/src/modules/partition/core/PartitionLayout.h new file mode 100644 index 000000000..eadb8b012 --- /dev/null +++ b/src/modules/partition/core/PartitionLayout.h @@ -0,0 +1,70 @@ +/* === This file is part of Calamares - === + * + * Copyright 2018, Collabora Ltd + * + * Calamares 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. + * + * Calamares 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 Calamares. If not, see . + */ + +#ifndef PARTITIONLAYOUT_H +#define PARTITIONLAYOUT_H + +#include "Typedefs.h" + +// KPMcore +#include + +// Qt +#include +#include + +class Partition; + +class PartitionLayout +{ +public: + + enum SizeUnit + { + Percent = 0, + Byte, + KiB, + MiB, + GiB + }; + + struct PartitionEntry + { + QString partLabel; + QString partMountPoint; + int partFileSystem; + double partSize; + SizeUnit partSizeUnit; + double partMinSize; + SizeUnit partMinSizeUnit; + }; + + PartitionLayout(); + PartitionLayout( PartitionEntry entry ); + PartitionLayout( const PartitionLayout& layout ); + ~PartitionLayout(); + + void addEntry( PartitionEntry entry ); + void addEntry( QString mountPoint, QString size, QString min = "" ); + void addEntry( QString label, QString mountPoint, QString fs, QString size, QString min = "" ); + +private: + QList< PartitionEntry > partLayout; +}; + +#endif /* PARTITIONLAYOUT_H */ diff --git a/src/modules/partition/partition.conf b/src/modules/partition/partition.conf index 229ffc32c..1c5ece8f8 100644 --- a/src/modules/partition/partition.conf +++ b/src/modules/partition/partition.conf @@ -77,3 +77,30 @@ defaultFileSystemType: "ext4" # # If nothing is specified, LUKS is enabled in automated modes. #enableLuksAutomatedPartitioning: true + +# To apply a custom partition layout, it has to be defined this way : +# +# partitionLayout: +# - name: "rootfs" +# filesystem: "ext4" +# mountPoint: "/" +# size: 20% +# minSize: 500M +# - name: "home" +# filesystem: "ext4" +# mountPoint: "/home" +# size: 3G +# minSize: 1.5G +# - name: "data" +# filesystem: "fat32" +# mountPoint: "/data" +# size: 100% +# +# There can be any number of partitions, each entry having the following attributes: +# - name: partition label +# - filesystem: filesystem type +# - mountPoint: partition mount point +# - size: partition size in bytes (append 'K', 'M' or 'G' for KiB, MiB or GiB) +# or +# % of the available drive space if a '%' is appended to the value +# - minSize: minimum partition size (optional parameter) From b2bf873edef1f07ab30e6c9e10b1737ee87ea3ab Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:25:39 +0100 Subject: [PATCH 02/11] [partition] Initialize partition layout from config file In order to keep the partition layout during calamares' execution, we add a PartitionLayout object instance to PartitionCoreModule. This class will therefore be used to initialize the PartitionLayout object and interact with it thoughout the program's execution. When no partition layout is present in the config file, we initialize the layout with a single ext4 partition mounted on '/', as it was previously done. Signed-off-by: Arnaud Ferraris --- .../partition/core/PartitionCoreModule.cpp | 27 +++++++++++++++++++ .../partition/core/PartitionCoreModule.h | 5 ++++ .../partition/gui/PartitionViewStep.cpp | 9 +++++++ 3 files changed, 41 insertions(+) diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index f41142b6a..8abcf7035 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -43,6 +43,7 @@ #include "jobs/ResizePartitionJob.h" #include "jobs/ResizeVolumeGroupJob.h" #include "jobs/SetPartitionFlagsJob.h" +#include "utils/CalamaresUtils.h" #include "Typedefs.h" #include "utils/Logger.h" @@ -760,6 +761,32 @@ PartitionCoreModule::setBootLoaderInstallPath( const QString& path ) m_bootLoaderInstallPath = path; } +void +PartitionCoreModule::initLayout() +{ + m_partLayout = new PartitionLayout(); + + m_partLayout->addEntry( QString("/"), QString("100%") ); +} + +void +PartitionCoreModule::initLayout( const QVariantList& config ) +{ + m_partLayout = new PartitionLayout(); + + for ( const auto& r : config ) + { + QVariantMap pentry = r.toMap(); + + m_partLayout->addEntry( CalamaresUtils::getString( pentry, "name" ), + CalamaresUtils::getString( pentry, "mountPoint" ), + CalamaresUtils::getString( pentry, "filesystem" ), + CalamaresUtils::getString( pentry, "size" ), + CalamaresUtils::getString( pentry, "minSize" ) + ); + } +} + void PartitionCoreModule::revert() { diff --git a/src/modules/partition/core/PartitionCoreModule.h b/src/modules/partition/core/PartitionCoreModule.h index 15dadc7f5..55961ce58 100644 --- a/src/modules/partition/core/PartitionCoreModule.h +++ b/src/modules/partition/core/PartitionCoreModule.h @@ -20,6 +20,7 @@ #ifndef PARTITIONCOREMODULE_H #define PARTITIONCOREMODULE_H +#include "core/PartitionLayout.h" #include "core/PartitionModel.h" #include "Typedefs.h" @@ -155,6 +156,9 @@ public: void setBootLoaderInstallPath( const QString& path ); + void initLayout(); + void initLayout( const QVariantList& config ); + /** * @brief jobs creates and returns a list of jobs which can then apply the changes * requested by the user. @@ -246,6 +250,7 @@ private: bool m_hasRootMountPoint = false; bool m_isDirty = false; QString m_bootLoaderInstallPath; + PartitionLayout* m_partLayout; void doInit(); void updateHasRootMountPoint(); diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 0152f8bec..9c94e87d7 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -610,6 +610,15 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) QFuture< void > future = QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule ); watcher->setFuture( future ); + + if ( configurationMap.contains( "partitionLayout" ) ) + { + m_core->initLayout( configurationMap.values( "partitionLayout" ).at(0).toList() ); + } + else + { + m_core->initLayout(); + } } From f863912a2f8016aa7727c857dfe3a49c3c608a5b Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:26:12 +0100 Subject: [PATCH 03/11] [partition] export PartitionActions::bytesToSectors for future use As we move some of the partition creation code away from PartitionActions, we will need the bytesToSectors function. Rather than copying it, we export it in the PartitionActions namespace, so that other classes can use it. Signed-off-by: Arnaud Ferraris --- src/modules/partition/core/PartitionActions.cpp | 2 +- src/modules/partition/core/PartitionActions.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/partition/core/PartitionActions.cpp b/src/modules/partition/core/PartitionActions.cpp index a4f2baa17..c86cf015c 100644 --- a/src/modules/partition/core/PartitionActions.cpp +++ b/src/modules/partition/core/PartitionActions.cpp @@ -90,7 +90,7 @@ alignBytesToBlockSize( qint64 bytes, qint64 blocksize ) return blocks * blocksize; } -constexpr qint64 +qint64 bytesToSectors( qint64 bytes, qint64 blocksize ) { return alignBytesToBlockSize( alignBytesToBlockSize( bytes, blocksize), MiBtoBytes(1) ) / blocksize; diff --git a/src/modules/partition/core/PartitionActions.h b/src/modules/partition/core/PartitionActions.h index 5acf444fa..1c543854b 100644 --- a/src/modules/partition/core/PartitionActions.h +++ b/src/modules/partition/core/PartitionActions.h @@ -72,6 +72,8 @@ namespace Choices } // namespace Choices +qint64 bytesToSectors( qint64 bytes, qint64 blocksize ); + /** * @brief doAutopartition sets up an autopartitioning operation on the given Device. * @param core a pointer to the PartitionCoreModule instance. From 0d284759f59a2e1c282f86255d3da8d4542fce9d Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:26:37 +0100 Subject: [PATCH 04/11] [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; }; From 74a59ae68a5382a3d5bdd8c047640ef27afaa509 Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:26:53 +0100 Subject: [PATCH 05/11] [partition] Display partition labels when they exist Signed-off-by: Arnaud Ferraris --- .../partition/gui/PartitionLabelsView.cpp | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/modules/partition/gui/PartitionLabelsView.cpp b/src/modules/partition/gui/PartitionLabelsView.cpp index fbcc1de72..0a0850844 100644 --- a/src/modules/partition/gui/PartitionLabelsView.cpp +++ b/src/modules/partition/gui/PartitionLabelsView.cpp @@ -185,26 +185,35 @@ PartitionLabelsView::buildTexts( const QModelIndex& index ) const if ( index.data( PartitionModel::IsPartitionNewRole ).toBool() ) { - QString mountPoint = index.sibling( index.row(), - PartitionModel::MountPointColumn ) - .data().toString(); - if ( mountPoint == "/" ) - firstLine = m_customNewRootLabel.isEmpty() ? - tr( "Root" ) : - m_customNewRootLabel; - else if ( mountPoint == "/home" ) - firstLine = tr( "Home" ); - else if ( mountPoint == "/boot" ) - firstLine = tr( "Boot" ); - else if ( mountPoint.contains( "/efi" ) && - index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::Fat32 ) - firstLine = tr( "EFI system" ); - else if ( index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::LinuxSwap ) - firstLine = tr( "Swap" ); - else if ( !mountPoint.isEmpty() ) - firstLine = tr( "New partition for %1" ).arg( mountPoint ); + QString label = index.data( PartitionModel::FileSystemLabelRole ).toString(); + + if ( !label.isEmpty() ) + { + firstLine = label; + } else - firstLine = tr( "New partition" ); + { + QString mountPoint = index.sibling( index.row(), + PartitionModel::MountPointColumn ) + .data().toString(); + if ( mountPoint == "/" ) + firstLine = m_customNewRootLabel.isEmpty() ? + tr( "Root" ) : + m_customNewRootLabel; + else if ( mountPoint == "/home" ) + firstLine = tr( "Home" ); + else if ( mountPoint == "/boot" ) + firstLine = tr( "Boot" ); + else if ( mountPoint.contains( "/efi" ) && + index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::Fat32 ) + firstLine = tr( "EFI system" ); + else if ( index.data( PartitionModel::FileSystemTypeRole ).toInt() == FileSystem::LinuxSwap ) + firstLine = tr( "Swap" ); + else if ( !mountPoint.isEmpty() ) + firstLine = tr( "New partition for %1" ).arg( mountPoint ); + else + firstLine = tr( "New partition" ); + } } else if ( index.data( PartitionModel::OsproberNameRole ).toString().isEmpty() ) { From 2f14a2145644e098eeef54723626ab737509237d Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:27:12 +0100 Subject: [PATCH 06/11] [partition] Apply custom layout when installing "Alongside" When choosing "Install alongside another system", the custom partition layout is applied to the space freed by resizing the selected partition. Signed-off-by: Arnaud Ferraris --- .../partition/core/PartitionCoreModule.cpp | 19 ++++++++- .../partition/core/PartitionCoreModule.h | 2 + .../partition/core/PartitionLayout.cpp | 12 +++--- src/modules/partition/core/PartitionLayout.h | 2 +- src/modules/partition/gui/ChoicePage.cpp | 39 ++----------------- 5 files changed, 31 insertions(+), 43 deletions(-) diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index 9af5665a5..e79fc21e4 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -791,10 +791,14 @@ void PartitionCoreModule::layoutApply( Device *dev, qint64 firstSector, qint64 lastSector, - QString luksPassphrase ) + QString luksPassphrase, + PartitionNode* parent, + const PartitionRole& role ) { bool isEfi = PartUtils::isEfiSystem(); - QList< Partition* > partList = m_partLayout->execute( dev, firstSector, lastSector, luksPassphrase ); + QList< Partition* > partList = m_partLayout->execute( dev, firstSector, lastSector, + luksPassphrase, parent, role + ); foreach ( Partition *part, partList ) { @@ -811,6 +815,17 @@ PartitionCoreModule::layoutApply( Device *dev, } } +void +PartitionCoreModule::layoutApply( Device *dev, + qint64 firstSector, + qint64 lastSector, + QString luksPassphrase ) +{ + layoutApply( dev, firstSector, lastSector, luksPassphrase, dev->partitionTable(), + PartitionRole( PartitionRole::Primary ) + ); +} + void PartitionCoreModule::revert() { diff --git a/src/modules/partition/core/PartitionCoreModule.h b/src/modules/partition/core/PartitionCoreModule.h index 2b2c73a3f..52cb47a59 100644 --- a/src/modules/partition/core/PartitionCoreModule.h +++ b/src/modules/partition/core/PartitionCoreModule.h @@ -160,6 +160,8 @@ public: void initLayout( const QVariantList& config ); void layoutApply( Device *dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase ); + void layoutApply( Device *dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase, PartitionNode* parent, const PartitionRole& role ); + /** * @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 d0c1a7c94..bb5acdd2f 100644 --- a/src/modules/partition/core/PartitionLayout.cpp +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -151,7 +151,9 @@ sizeToSectors( double size, PartitionLayout::SizeUnit unit, qint64 totalSize, qi QList< Partition* > PartitionLayout::execute( Device *dev, qint64 firstSector, - qint64 lastSector, QString luksPassphrase ) + qint64 lastSector, QString luksPassphrase, + PartitionNode* parent, + const PartitionRole& role ) { QList< Partition* > partList; qint64 size, minSize, end; @@ -177,9 +179,9 @@ PartitionLayout::execute( Device *dev, qint64 firstSector, if ( luksPassphrase.isEmpty() ) { currentPartition = KPMHelpers::createNewPartition( - dev->partitionTable(), + parent, *dev, - PartitionRole( PartitionRole::Primary ), + role, static_cast(part.partFileSystem), firstSector, end, @@ -189,9 +191,9 @@ PartitionLayout::execute( Device *dev, qint64 firstSector, else { currentPartition = KPMHelpers::createNewEncryptedPartition( - dev->partitionTable(), + parent, *dev, - PartitionRole( PartitionRole::Primary ), + role, static_cast(part.partFileSystem), firstSector, end, diff --git a/src/modules/partition/core/PartitionLayout.h b/src/modules/partition/core/PartitionLayout.h index e3eb7296b..5ec65cf22 100644 --- a/src/modules/partition/core/PartitionLayout.h +++ b/src/modules/partition/core/PartitionLayout.h @@ -67,7 +67,7 @@ public: * @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 ); + QList< Partition* > execute( Device *dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase, PartitionNode* parent, const PartitionRole& role ); private: QList< PartitionEntry > partLayout; diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index ba49bd95d..1b2cf5a69 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -670,41 +670,10 @@ ChoicePage::doAlongsideApply() dev->logicalSize(); m_core->resizePartition( dev, candidate, firstSector, newLastSector ); - Partition* newPartition = nullptr; - QString luksPassphrase = m_encryptWidget->passphrase(); - if ( luksPassphrase.isEmpty() ) - { - newPartition = KPMHelpers::createNewPartition( - candidate->parent(), - *dev, - candidate->roles(), - FileSystem::typeForName( m_defaultFsType ), - newLastSector + 2, // * - oldLastSector, - PartitionTable::FlagNone - ); - } - else - { - newPartition = KPMHelpers::createNewEncryptedPartition( - candidate->parent(), - *dev, - candidate->roles(), - FileSystem::typeForName( m_defaultFsType ), - newLastSector + 2, // * - oldLastSector, - luksPassphrase, - PartitionTable::FlagNone - ); - } - PartitionInfo::setMountPoint( newPartition, "/" ); - PartitionInfo::setFormat( newPartition, true ); - // * for some reason ped_disk_add_partition refuses to create a new partition - // if it starts on the sector immediately after the last used sector, so we - // have to push it one sector further, therefore + 2 instead of + 1. - - m_core->createPartition( dev, newPartition ); - + m_core->layoutApply( dev, newLastSector + 2, oldLastSector, + m_encryptWidget->passphrase(), candidate->parent(), + candidate->roles() + ); m_core->dumpQueue(); break; From ba673b17eec657323e4fd57cba18efc0a22a2905 Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:27:40 +0100 Subject: [PATCH 07/11] [partition] Add configuration option to disable manual partitioning In some cases where a custom partition layout is used, use of this layout is mandatory (this can be the case when using a read-only rootfs which is updated by block-cpying an image file to it). For these cases, the user must not be able to change the partition layout, therefore we have to disable manual partitioning. In order to stay consistent with current behaviour, manual partitioning is still enabled by default. It will only be disabled if the partition module's config file contains the corresponding option set to "false". Signed-off-by: Arnaud Ferraris --- src/modules/partition/gui/ChoicePage.cpp | 10 ++++++++-- src/modules/partition/gui/ChoicePage.h | 2 ++ src/modules/partition/gui/PartitionViewStep.cpp | 1 + src/modules/partition/partition.conf | 10 ++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index 1b2cf5a69..6b703cb00 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -92,6 +92,7 @@ ChoicePage::ChoicePage( QWidget* parent ) , m_bootloaderComboBox( nullptr ) , m_lastSelectedDeviceIndex( -1 ) , m_enableEncryptionWidget( true ) + , m_allowManualPartitioning( true ) { setupUi( this ); @@ -101,6 +102,9 @@ ChoicePage::ChoicePage( QWidget* parent ) m_enableEncryptionWidget = Calamares::JobQueue::instance()-> globalStorage()-> value( "enableLuksAutomatedPartitioning" ).toBool(); + m_allowManualPartitioning = Calamares::JobQueue::instance()-> + globalStorage()-> + value( "allowManualPartitioning" ).toBool(); if ( FileSystem::typeForName( m_defaultFsType ) == FileSystem::Unknown ) m_defaultFsType = "ext4"; @@ -1214,8 +1218,10 @@ ChoicePage::setupActions() else m_deviceInfoWidget->setPartitionTableType( PartitionTable::unknownTableType ); - // Manual partitioning is always a possibility - m_somethingElseButton->show(); + if ( m_allowManualPartitioning ) + m_somethingElseButton->show(); + else + force_uncheck( m_grp, m_somethingElseButton ); bool atLeastOneCanBeResized = false; bool atLeastOneCanBeReplaced = false; diff --git a/src/modules/partition/gui/ChoicePage.h b/src/modules/partition/gui/ChoicePage.h index 07d052c2d..0def84bd4 100644 --- a/src/modules/partition/gui/ChoicePage.h +++ b/src/modules/partition/gui/ChoicePage.h @@ -165,6 +165,8 @@ private: QString m_defaultFsType; bool m_enableEncryptionWidget; + bool m_allowManualPartitioning; + QMutex m_coreMutex; }; diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 9c94e87d7..1ad76ae17 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -570,6 +570,7 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) gs->insert( "drawNestedPartitions", CalamaresUtils::getBool( configurationMap, "drawNestedPartitions", false ) ); gs->insert( "alwaysShowPartitionLabels", CalamaresUtils::getBool( configurationMap, "alwaysShowPartitionLabels", true ) ); gs->insert( "enableLuksAutomatedPartitioning", CalamaresUtils::getBool( configurationMap, "enableLuksAutomatedPartitioning", true ) ); + gs->insert( "allowManualPartitioning", CalamaresUtils::getBool( configurationMap, "allowManualPartitioning", true ) ); QString defaultFS = CalamaresUtils::getString( configurationMap, "defaultFileSystemType" ); if ( defaultFS.isEmpty() ) diff --git a/src/modules/partition/partition.conf b/src/modules/partition/partition.conf index 1c5ece8f8..a7483f36f 100644 --- a/src/modules/partition/partition.conf +++ b/src/modules/partition/partition.conf @@ -78,6 +78,16 @@ defaultFileSystemType: "ext4" # If nothing is specified, LUKS is enabled in automated modes. #enableLuksAutomatedPartitioning: true +# Allow manual partitioning. +# +# When set to false, this option hides the "Manual partitioning" button, +# limiting the user's choice to "Erase", "Replace" or "Alongside". +# This can be useful when using a custom partition layout we don't want +# the user to modify. +# +# If nothing is specified, manual partitioning is enabled. +#allowManualPartitioning: true + # To apply a custom partition layout, it has to be defined this way : # # partitionLayout: From fcd0e8d362d4d2586f24ec2ef68a5adbf8bdf57d Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 17:28:02 +0100 Subject: [PATCH 08/11] [partition] Apply partition layout when replacing free space When chosing the "Replace partition" option, free space is not handled like any partition. In order to apply the custom partition layout in that case too, we have to modify the code where "replace free space" is handled. Signed-off-by: Arnaud Ferraris --- src/modules/partition/gui/ChoicePage.cpp | 35 +++--------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index 6b703cb00..cc32ca12a 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -745,37 +745,10 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) } } - Partition* newPartition = nullptr; - if ( m_encryptWidget->state() == EncryptWidget::EncryptionConfirmed ) - { - newPartition = KPMHelpers::createNewEncryptedPartition( - newParent, - *selectedDevice(), - newRoles, - FileSystem::typeForName( m_defaultFsType ), - selectedPartition->firstSector(), - selectedPartition->lastSector(), - m_encryptWidget->passphrase(), - PartitionTable::FlagNone - ); - } - else - { - newPartition = KPMHelpers::createNewPartition( - newParent, - *selectedDevice(), - newRoles, - FileSystem::typeForName( m_defaultFsType ), - selectedPartition->firstSector(), - selectedPartition->lastSector(), - PartitionTable::FlagNone - ); - } - - PartitionInfo::setMountPoint( newPartition, "/" ); - PartitionInfo::setFormat( newPartition, true ); - - m_core->createPartition( selectedDevice(), newPartition); + m_core->layoutApply( selectedDevice(), selectedPartition->firstSector(), + selectedPartition->lastSector(), + m_encryptWidget->passphrase(), newParent, newRoles + ); } else { From cb60a3e7f1c3abed98615d76d97ed342abf005eb Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 7 Jan 2019 18:40:12 +0100 Subject: [PATCH 09/11] [partition] Keep copyright notice for copied code Some code was copied and adapted from PartitionActions.cpp. For full compliance, it is best to copy the copyright holders list from this file to PartitionLayout.cpp. Signed-off-by: Arnaud Ferraris --- src/modules/partition/core/PartitionLayout.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/partition/core/PartitionLayout.cpp b/src/modules/partition/core/PartitionLayout.cpp index bb5acdd2f..866a9d920 100644 --- a/src/modules/partition/core/PartitionLayout.cpp +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -1,5 +1,7 @@ /* === This file is part of Calamares - === * + * Copyright 2014-2017, Teo Mrnjavac + * Copyright 2017-2018, Adriaan de Groot * Copyright 2018, Collabora Ltd * * Calamares is free software: you can redistribute it and/or modify From 921f70d3bbfd32c31a2a512c4e93423255df4c75 Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Tue, 8 Jan 2019 14:05:38 +0100 Subject: [PATCH 10/11] [partition] Fix size and last sector computation Due to a computation error when calculating the total drive space and each partition's last sector, the last partition's last sector was out of boundaries, leading to an error creating this partition. This patch fixes the computation algorithm to get rid of this error. Signed-off-by: Arnaud Ferraris --- src/modules/partition/core/PartitionLayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/partition/core/PartitionLayout.cpp b/src/modules/partition/core/PartitionLayout.cpp index 866a9d920..77ef4bb81 100644 --- a/src/modules/partition/core/PartitionLayout.cpp +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -159,7 +159,7 @@ PartitionLayout::execute( Device *dev, qint64 firstSector, { QList< Partition* > partList; qint64 size, minSize, end; - qint64 totalSize = lastSector - firstSector; + qint64 totalSize = lastSector - firstSector + 1; qint64 availableSize = totalSize; // TODO: Refine partition sizes to make sure there is room for every partition @@ -176,7 +176,7 @@ PartitionLayout::execute( Device *dev, qint64 firstSector, size = minSize; if ( size > availableSize ) size = availableSize; - end = firstSector + size; + end = firstSector + size - 1; if ( luksPassphrase.isEmpty() ) { From 422d521ff7c40f706e557d77c3cbacb4d57547b1 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 23 Jan 2019 12:20:33 +0100 Subject: [PATCH 11/11] Changes: re-number releases --- CHANGES | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 0f8963ae1..f1878d9f8 100644 --- a/CHANGES +++ b/CHANGES @@ -3,7 +3,7 @@ contributors are listed. Note that Calamares does not have a historical changelog -- this log starts with version 3.2.0. The release notes on the website will have to do for older versions. -# 3.2.4 (unreleased) # +# 3.2.5 (unreleased) # This release contains contributions from (alphabetically by first name): - Alf Gaida @@ -46,6 +46,21 @@ This release contains contributions from (alphabetically by first name): these run as three separate shells, though). +# 3.2.4 (unreleased) # + +This release contains contributions from (alphabetically by first name): + - Collabora ltd. + +## Core ## + +There are no core changes in this release. + +## Modules ## + + - *partition* There is new support for partitioning layout presets. + See `partitionc.conf` for documentation and details. + + # 3.2.3 (2019-01-09) # This release contains contributions from (alphabetically by first name):