2020-08-25 16:05:56 +02:00
|
|
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
2019-01-07 17:25:22 +01:00
|
|
|
*
|
2020-08-22 01:19:58 +02:00
|
|
|
* SPDX-FileCopyrightText: 2014-2017 Teo Mrnjavac <teo@kde.org>
|
|
|
|
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
|
|
|
|
* SPDX-FileCopyrightText: 2018-2019 Collabora Ltd <arnaud.ferraris@collabora.com>
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
2019-01-07 17:25:22 +01:00
|
|
|
*
|
2020-08-25 16:05:56 +02:00
|
|
|
* Calamares is Free Software: see the License-Identifier above.
|
2019-01-07 17:25:22 +01:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-02-22 12:58:55 +01:00
|
|
|
#include "GlobalStorage.h"
|
|
|
|
#include "JobQueue.h"
|
|
|
|
|
2019-04-17 19:16:48 +02:00
|
|
|
#include "utils/Logger.h"
|
|
|
|
|
2019-01-07 17:25:22 +01:00
|
|
|
#include "core/PartitionLayout.h"
|
|
|
|
|
2019-01-07 17:26:37 +01:00
|
|
|
#include "core/KPMHelpers.h"
|
2020-02-14 11:15:57 +01:00
|
|
|
#include "core/PartUtils.h"
|
2019-01-07 17:26:37 +01:00
|
|
|
#include "core/PartitionActions.h"
|
|
|
|
#include "core/PartitionInfo.h"
|
|
|
|
|
|
|
|
#include <kpmcore/core/device.h>
|
|
|
|
#include <kpmcore/core/partition.h>
|
2019-01-07 17:25:22 +01:00
|
|
|
#include <kpmcore/fs/filesystem.h>
|
|
|
|
|
2019-02-22 18:42:16 +01:00
|
|
|
static FileSystem::Type
|
2019-02-22 12:58:55 +01:00
|
|
|
getDefaultFileSystemType()
|
|
|
|
{
|
|
|
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
2019-02-22 18:42:16 +01:00
|
|
|
FileSystem::Type defaultFS = FileSystem::Ext4;
|
2019-02-22 12:58:55 +01:00
|
|
|
|
2019-02-22 18:42:16 +01:00
|
|
|
if ( gs->contains( "defaultFileSystemType" ) )
|
|
|
|
{
|
2020-02-14 11:15:57 +01:00
|
|
|
PartUtils::findFS( gs->value( "defaultFileSystemType" ).toString(), &defaultFS );
|
2019-02-22 18:42:16 +01:00
|
|
|
if ( defaultFS == FileSystem::Unknown )
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-02-22 18:42:16 +01:00
|
|
|
defaultFS = FileSystem::Ext4;
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2019-02-22 18:42:16 +01:00
|
|
|
}
|
2019-02-22 12:58:55 +01:00
|
|
|
|
2019-02-22 18:42:16 +01:00
|
|
|
return defaultFS;
|
2019-02-22 12:58:55 +01:00
|
|
|
}
|
|
|
|
|
2019-01-07 17:25:22 +01:00
|
|
|
PartitionLayout::PartitionLayout()
|
|
|
|
{
|
2019-02-22 13:08:59 +01:00
|
|
|
m_defaultFsType = getDefaultFileSystemType();
|
2019-01-07 17:25:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PartitionLayout::PartitionLayout( PartitionLayout::PartitionEntry entry )
|
|
|
|
{
|
2019-02-22 13:08:59 +01:00
|
|
|
m_defaultFsType = getDefaultFileSystemType();
|
|
|
|
m_partLayout.append( entry );
|
2019-01-07 17:25:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PartitionLayout::PartitionLayout( const PartitionLayout& layout )
|
2019-04-15 16:06:21 +02:00
|
|
|
: m_defaultFsType( layout.m_defaultFsType )
|
|
|
|
, m_partLayout( layout.m_partLayout )
|
2019-01-07 17:25:22 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-02-14 11:15:57 +01:00
|
|
|
PartitionLayout::~PartitionLayout() {}
|
2019-01-07 17:25:22 +01:00
|
|
|
|
2019-04-17 19:16:48 +02:00
|
|
|
bool
|
2019-01-07 17:25:22 +01:00
|
|
|
PartitionLayout::addEntry( PartitionLayout::PartitionEntry entry )
|
|
|
|
{
|
2019-04-17 19:16:48 +02:00
|
|
|
if ( !entry.isValid() )
|
|
|
|
{
|
|
|
|
cError() << "Partition size is invalid or has min size > max size";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-22 13:08:59 +01:00
|
|
|
m_partLayout.append( entry );
|
2019-04-17 19:16:48 +02:00
|
|
|
|
|
|
|
return true;
|
2019-01-07 17:25:22 +01:00
|
|
|
}
|
|
|
|
|
2020-06-21 02:30:22 +02:00
|
|
|
PartitionLayout::PartitionEntry::PartitionEntry()
|
|
|
|
: partAttributes( 0 )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-04-08 12:19:35 +02:00
|
|
|
PartitionLayout::PartitionEntry::PartitionEntry( const QString& size, const QString& min, const QString& max )
|
2019-05-14 11:52:58 +02:00
|
|
|
: partSize( size )
|
|
|
|
, partMinSize( min )
|
|
|
|
, partMaxSize( max )
|
2020-06-21 02:30:22 +02:00
|
|
|
, partAttributes( 0 )
|
2019-02-11 23:37:14 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-04-17 19:16:48 +02:00
|
|
|
bool
|
2019-04-08 12:19:35 +02:00
|
|
|
PartitionLayout::addEntry( const QString& mountPoint, const QString& size, const QString& min, const QString& max )
|
2019-01-07 17:25:22 +01:00
|
|
|
{
|
2019-04-08 12:19:35 +02:00
|
|
|
PartitionLayout::PartitionEntry entry( size, min, max );
|
2019-01-07 17:25:22 +01:00
|
|
|
|
2019-04-17 19:16:48 +02:00
|
|
|
if ( !entry.isValid() )
|
|
|
|
{
|
|
|
|
cError() << "Partition size" << size << "is invalid or" << min << ">" << max;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( mountPoint.isEmpty() || !mountPoint.startsWith( QString( "/" ) ) )
|
|
|
|
{
|
|
|
|
cError() << "Partition mount point" << mountPoint << "is invalid";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-07 17:25:22 +01:00
|
|
|
entry.partMountPoint = mountPoint;
|
2019-02-22 13:08:59 +01:00
|
|
|
entry.partFileSystem = m_defaultFsType;
|
2019-01-07 17:25:22 +01:00
|
|
|
|
2019-02-22 13:08:59 +01:00
|
|
|
m_partLayout.append( entry );
|
2019-04-17 19:16:48 +02:00
|
|
|
|
|
|
|
return true;
|
2019-01-07 17:25:22 +01:00
|
|
|
}
|
|
|
|
|
2019-04-17 19:16:48 +02:00
|
|
|
bool
|
2020-02-14 11:15:57 +01:00
|
|
|
PartitionLayout::addEntry( const QString& label,
|
2020-05-14 18:30:58 +02:00
|
|
|
const QString& uuid,
|
2020-03-19 13:37:21 +01:00
|
|
|
const QString& type,
|
2020-03-21 19:21:16 +01:00
|
|
|
quint64 attributes,
|
2020-02-14 11:15:57 +01:00
|
|
|
const QString& mountPoint,
|
|
|
|
const QString& fs,
|
2020-03-16 22:25:55 +01:00
|
|
|
const QVariantMap& features,
|
2020-02-14 11:15:57 +01:00
|
|
|
const QString& size,
|
|
|
|
const QString& min,
|
|
|
|
const QString& max )
|
2019-01-07 17:25:22 +01:00
|
|
|
{
|
2019-04-08 12:19:35 +02:00
|
|
|
PartitionLayout::PartitionEntry entry( size, min, max );
|
2019-01-07 17:25:22 +01:00
|
|
|
|
2019-04-17 19:16:48 +02:00
|
|
|
if ( !entry.isValid() )
|
|
|
|
{
|
|
|
|
cError() << "Partition size" << size << "is invalid or" << min << ">" << max;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( mountPoint.isEmpty() || !mountPoint.startsWith( QString( "/" ) ) )
|
|
|
|
{
|
|
|
|
cError() << "Partition mount point" << mountPoint << "is invalid";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-07 17:25:22 +01:00
|
|
|
entry.partLabel = label;
|
2020-05-14 18:30:58 +02:00
|
|
|
entry.partUUID = uuid;
|
2020-03-19 13:37:21 +01:00
|
|
|
entry.partType = type;
|
2020-03-21 19:21:16 +01:00
|
|
|
entry.partAttributes = attributes;
|
2019-01-07 17:25:22 +01:00
|
|
|
entry.partMountPoint = mountPoint;
|
2019-02-22 18:42:16 +01:00
|
|
|
PartUtils::findFS( fs, &entry.partFileSystem );
|
2019-02-22 12:58:55 +01:00
|
|
|
if ( entry.partFileSystem == FileSystem::Unknown )
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-02-22 13:08:59 +01:00
|
|
|
entry.partFileSystem = m_defaultFsType;
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2020-03-16 22:25:55 +01:00
|
|
|
entry.partFeatures = features;
|
2019-01-07 17:25:22 +01:00
|
|
|
|
2019-02-22 13:08:59 +01:00
|
|
|
m_partLayout.append( entry );
|
2019-04-17 19:16:48 +02:00
|
|
|
|
|
|
|
return true;
|
2019-01-07 17:25:22 +01:00
|
|
|
}
|
2019-01-07 17:26:37 +01:00
|
|
|
|
|
|
|
QList< Partition* >
|
2020-02-14 11:15:57 +01:00
|
|
|
PartitionLayout::execute( Device* dev,
|
|
|
|
qint64 firstSector,
|
|
|
|
qint64 lastSector,
|
|
|
|
QString luksPassphrase,
|
2019-01-07 17:27:12 +01:00
|
|
|
PartitionNode* parent,
|
|
|
|
const PartitionRole& role )
|
2019-01-07 17:26:37 +01:00
|
|
|
{
|
|
|
|
QList< Partition* > partList;
|
2019-05-14 10:46:21 +02:00
|
|
|
qint64 minSize, maxSize, end;
|
2019-01-08 14:05:38 +01:00
|
|
|
qint64 totalSize = lastSector - firstSector + 1;
|
2019-01-07 17:26:37 +01:00
|
|
|
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
|
|
|
|
|
2020-02-14 11:15:57 +01:00
|
|
|
foreach ( const PartitionLayout::PartitionEntry& part, m_partLayout )
|
2019-01-07 17:26:37 +01:00
|
|
|
{
|
2020-02-14 11:15:57 +01:00
|
|
|
Partition* currentPartition = nullptr;
|
2019-01-07 17:26:37 +01:00
|
|
|
|
2019-05-14 10:46:21 +02:00
|
|
|
qint64 size = -1;
|
2019-01-07 17:26:37 +01:00
|
|
|
// Calculate partition size
|
2019-04-17 19:16:48 +02:00
|
|
|
if ( part.partSize.isValid() )
|
|
|
|
{
|
|
|
|
size = part.partSize.toSectors( totalSize, dev->logicalSize() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-02-14 11:15:57 +01:00
|
|
|
cWarning() << "Partition" << part.partMountPoint << "size (" << size << "sectors) is invalid, skipping...";
|
2019-04-17 19:16:48 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( part.partMinSize.isValid() )
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-04-17 19:16:48 +02:00
|
|
|
minSize = part.partMinSize.toSectors( totalSize, dev->logicalSize() );
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2019-04-17 19:16:48 +02:00
|
|
|
else
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-04-17 19:16:48 +02:00
|
|
|
minSize = 0;
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2019-04-17 19:16:48 +02:00
|
|
|
|
|
|
|
if ( part.partMaxSize.isValid() )
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-04-17 19:16:48 +02:00
|
|
|
maxSize = part.partMaxSize.toSectors( totalSize, dev->logicalSize() );
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2019-04-17 19:16:48 +02:00
|
|
|
else
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-04-17 19:16:48 +02:00
|
|
|
maxSize = availableSize;
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2019-04-17 19:16:48 +02:00
|
|
|
|
|
|
|
// Make sure we never go under minSize once converted to sectors
|
|
|
|
if ( maxSize < minSize )
|
|
|
|
{
|
2020-02-14 11:15:57 +01:00
|
|
|
cWarning() << "Partition" << part.partMountPoint << "max size (" << maxSize << "sectors) is < min size ("
|
|
|
|
<< minSize << "sectors), using min size";
|
2019-04-17 19:16:48 +02:00
|
|
|
maxSize = minSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust partition size based on user-defined boundaries and available space
|
2019-01-07 17:26:37 +01:00
|
|
|
if ( size < minSize )
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-01-07 17:26:37 +01:00
|
|
|
size = minSize;
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2019-04-08 12:19:35 +02:00
|
|
|
if ( size > maxSize )
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-04-08 12:19:35 +02:00
|
|
|
size = maxSize;
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2019-01-07 17:26:37 +01:00
|
|
|
if ( size > availableSize )
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2019-01-07 17:26:37 +01:00
|
|
|
size = availableSize;
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2019-01-08 14:05:38 +01:00
|
|
|
end = firstSector + size - 1;
|
2019-01-07 17:26:37 +01:00
|
|
|
|
|
|
|
if ( luksPassphrase.isEmpty() )
|
|
|
|
{
|
|
|
|
currentPartition = KPMHelpers::createNewPartition(
|
2020-02-14 11:15:57 +01:00
|
|
|
parent, *dev, role, part.partFileSystem, firstSector, end, KPM_PARTITION_FLAG( None ) );
|
2019-01-07 17:26:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
currentPartition = KPMHelpers::createNewEncryptedPartition(
|
2020-02-14 11:15:57 +01:00
|
|
|
parent, *dev, role, part.partFileSystem, firstSector, end, luksPassphrase, KPM_PARTITION_FLAG( None ) );
|
2019-01-07 17:26:37 +01:00
|
|
|
}
|
|
|
|
PartitionInfo::setFormat( currentPartition, true );
|
|
|
|
PartitionInfo::setMountPoint( currentPartition, part.partMountPoint );
|
|
|
|
if ( !part.partLabel.isEmpty() )
|
2020-02-14 11:15:57 +01:00
|
|
|
{
|
2020-03-18 22:11:05 +01:00
|
|
|
currentPartition->setLabel( part.partLabel );
|
2019-01-07 17:26:37 +01:00
|
|
|
currentPartition->fileSystem().setLabel( part.partLabel );
|
2020-02-14 11:15:57 +01:00
|
|
|
}
|
2020-05-14 18:30:58 +02:00
|
|
|
if ( !part.partUUID.isEmpty() )
|
|
|
|
{
|
|
|
|
currentPartition->setUUID( part.partUUID );
|
|
|
|
}
|
2020-03-19 13:37:21 +01:00
|
|
|
if ( !part.partType.isEmpty() )
|
|
|
|
{
|
|
|
|
#if defined( WITH_KPMCORE42API )
|
|
|
|
currentPartition->setType( part.partType );
|
|
|
|
#else
|
|
|
|
cWarning() << "Ignoring type; requires KPMcore >= 4.2.0.";
|
2020-03-21 19:21:16 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if ( part.partAttributes )
|
|
|
|
{
|
|
|
|
#if defined( WITH_KPMCORE42API )
|
|
|
|
currentPartition->setAttributes( part.partAttributes );
|
|
|
|
#else
|
|
|
|
cWarning() << "Ignoring attributes; requires KPMcore >= 4.2.0.";
|
2020-03-23 17:09:44 +01:00
|
|
|
#endif
|
|
|
|
}
|
2020-03-16 22:25:55 +01:00
|
|
|
if ( !part.partFeatures.isEmpty() )
|
|
|
|
{
|
|
|
|
#if defined( WITH_KPMCORE42API )
|
|
|
|
for ( const auto& k : part.partFeatures.keys() )
|
2020-03-23 17:09:44 +01:00
|
|
|
{
|
2020-04-07 21:38:15 +02:00
|
|
|
currentPartition->fileSystem().addFeature( k, part.partFeatures.value( k ) );
|
2020-03-23 17:09:44 +01:00
|
|
|
}
|
2020-03-16 22:25:55 +01:00
|
|
|
#else
|
|
|
|
cWarning() << "Ignoring features; requires KPMcore >= 4.2.0.";
|
2020-03-19 13:37:21 +01:00
|
|
|
#endif
|
|
|
|
}
|
2019-01-07 17:26:37 +01:00
|
|
|
// 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;
|
|
|
|
}
|