/* === This file is part of Calamares - === * * Copyright 2014-2017, Teo Mrnjavac * Copyright 2017-2018, Adriaan de Groot * Copyright 2018-2019, 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 "GlobalStorage.h" #include "JobQueue.h" #include "utils/Logger.h" #include "core/PartitionLayout.h" #include "core/KPMHelpers.h" #include "core/PartitionActions.h" #include "core/PartitionInfo.h" #include "core/PartUtils.h" #include #include #include static FileSystem::Type getDefaultFileSystemType() { Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); FileSystem::Type defaultFS = FileSystem::Ext4; if ( gs->contains( "defaultFileSystemType" ) ) { PartUtils::findFS( gs->value( "defaultFileSystemType" ).toString(), &defaultFS); if ( defaultFS == FileSystem::Unknown ) defaultFS = FileSystem::Ext4; } return defaultFS; } PartitionLayout::PartitionLayout() { m_defaultFsType = getDefaultFileSystemType(); } PartitionLayout::PartitionLayout( PartitionLayout::PartitionEntry entry ) { m_defaultFsType = getDefaultFileSystemType(); m_partLayout.append( entry ); } PartitionLayout::PartitionLayout( const PartitionLayout& layout ) : m_defaultFsType( layout.m_defaultFsType ) , m_partLayout( layout.m_partLayout ) { } PartitionLayout::~PartitionLayout() { } bool PartitionLayout::addEntry( PartitionLayout::PartitionEntry entry ) { if ( !entry.isValid() ) { cError() << "Partition size is invalid or has min size > max size"; return false; } m_partLayout.append( entry ); return true; } PartitionLayout::PartitionEntry::PartitionEntry( const QString& size, const QString& min, const QString& max ) : partSize( size ) , partMinSize( min ) , partMaxSize( max ) { } bool PartitionLayout::addEntry( const QString& mountPoint, const QString& size, const QString& min, const QString& max ) { PartitionLayout::PartitionEntry entry( size, min, max ); 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; } entry.partMountPoint = mountPoint; entry.partFileSystem = m_defaultFsType; m_partLayout.append( entry ); return true; } bool PartitionLayout::addEntry( const QString& label, const QString& mountPoint, const QString& fs, const QString& size, const QString& min, const QString& max ) { PartitionLayout::PartitionEntry entry( size, min, max ); 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; } entry.partLabel = label; entry.partMountPoint = mountPoint; PartUtils::findFS( fs, &entry.partFileSystem ); if ( entry.partFileSystem == FileSystem::Unknown ) entry.partFileSystem = m_defaultFsType; m_partLayout.append( entry ); return true; } QList< Partition* > PartitionLayout::execute( Device *dev, qint64 firstSector, qint64 lastSector, QString luksPassphrase, PartitionNode* parent, const PartitionRole& role ) { QList< Partition* > partList; qint64 minSize, maxSize, end; qint64 totalSize = lastSector - firstSector + 1; 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, m_partLayout ) { Partition *currentPartition = nullptr; qint64 size = -1; // Calculate partition size if ( part.partSize.isValid() ) { size = part.partSize.toSectors( totalSize, dev->logicalSize() ); } else { cWarning() << "Partition" << part.partMountPoint << "size (" << size << "sectors) is invalid, skipping..."; continue; } if ( part.partMinSize.isValid() ) minSize = part.partMinSize.toSectors( totalSize, dev->logicalSize() ); else minSize = 0; if ( part.partMaxSize.isValid() ) maxSize = part.partMaxSize.toSectors( totalSize, dev->logicalSize() ); else maxSize = availableSize; // Make sure we never go under minSize once converted to sectors if ( maxSize < minSize ) { cWarning() << "Partition" << part.partMountPoint << "max size (" << maxSize << "sectors) is < min size (" << minSize << "sectors), using min size"; maxSize = minSize; } // Adjust partition size based on user-defined boundaries and available space if ( size < minSize ) size = minSize; if ( size > maxSize ) size = maxSize; if ( size > availableSize ) size = availableSize; end = firstSector + size - 1; if ( luksPassphrase.isEmpty() ) { currentPartition = KPMHelpers::createNewPartition( parent, *dev, role, part.partFileSystem, firstSector, end, KPM_PARTITION_FLAG(None) ); } else { currentPartition = KPMHelpers::createNewEncryptedPartition( parent, *dev, role, part.partFileSystem, firstSector, end, luksPassphrase, KPM_PARTITION_FLAG(None) ); } 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; }