diff --git a/src/libcalamares/utils/Units.h b/src/libcalamares/utils/Units.h index efc100d59..34f80b17f 100644 --- a/src/libcalamares/utils/Units.h +++ b/src/libcalamares/utils/Units.h @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2017, Adriaan de Groot + * Copyright 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 @@ -24,10 +25,16 @@ namespace CalamaresUtils { +/** User defined literals, 1_KiB is 1 KibiByte (= 2^10 bytes) */ +constexpr qint64 operator ""_KiB( unsigned long long m ) +{ + return qint64(m) * 1024; +} + /** User defined literals, 1_MiB is 1 MibiByte (= 2^20 bytes) */ constexpr qint64 operator ""_MiB( unsigned long long m ) { - return qint64(m) * 1024 * 1024; + return operator ""_KiB(m) * 1024; } /** User defined literals, 1_GiB is 1 GibiByte (= 2^30 bytes) */ @@ -36,6 +43,11 @@ constexpr qint64 operator ""_GiB( unsigned long long m ) return operator ""_MiB(m) * 1024; } +constexpr qint64 KiBtoBytes( unsigned long long m ) +{ + return operator ""_KiB( m ); +} + constexpr qint64 MiBtoBytes( unsigned long long m ) { return operator ""_MiB( m ); @@ -46,7 +58,12 @@ constexpr qint64 GiBtoBytes( unsigned long long m ) return operator ""_GiB( m ); } -constexpr qint64 MiBToBytes( double m ) +constexpr qint64 KiBtoBytes( double m ) +{ + return qint64(m * 1024); +} + +constexpr qint64 MiBtoBytes( double m ) { return qint64(m * 1024 * 1024); } diff --git a/src/modules/fsresizer/ResizeFSJob.cpp b/src/modules/fsresizer/ResizeFSJob.cpp index 6394075ba..2ce9eba70 100644 --- a/src/modules/fsresizer/ResizeFSJob.cpp +++ b/src/modules/fsresizer/ResizeFSJob.cpp @@ -80,7 +80,7 @@ ResizeFSJob::RelativeSize::apply( qint64 totalSectors, qint64 sectorSize ) case unit_t::None: return -1; case unit_t::Absolute: - return CalamaresUtils::MiBtoBytes( value() ) / sectorSize; + return CalamaresUtils::MiBtoBytes( static_cast( value() ) ) / sectorSize; case unit_t::Percent: if ( value() == 100 ) return totalSectors; // Common-case, avoid futzing around diff --git a/src/modules/partition/core/PartUtils.cpp b/src/modules/partition/core/PartUtils.cpp index d09bcd149..4e8b7e8ba 100644 --- a/src/modules/partition/core/PartUtils.cpp +++ b/src/modules/partition/core/PartUtils.cpp @@ -2,6 +2,7 @@ * * Copyright 2015-2016, Teo Mrnjavac * Copyright 2018, Adriaan de Groot + * Copyright 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 @@ -117,7 +118,7 @@ canBeResized( Partition* candidate ) if ( table->numPrimaries() >= table->maxPrimaries() ) { - cDebug() << " .. partition table already has" + cDebug() << " .. partition table already has" << table->maxPrimaries() << "primary partitions."; return false; } @@ -198,7 +199,7 @@ lookForFstabEntries( const QString& partitionPath ) mountOptions.append( "noload" ); } - cDebug() << "Checking device" << partitionPath + cDebug() << "Checking device" << partitionPath << "for fstab (fs=" << r.getOutput() << ')'; FstabEntryList fstabEntries; @@ -209,9 +210,9 @@ lookForFstabEntries( const QString& partitionPath ) if ( !exit ) // if all is well { QFile fstabFile( mountsDir.path() + "/etc/fstab" ); - + cDebug() << " .. reading" << fstabFile.fileName(); - + if ( fstabFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) { const QStringList fstabLines = QString::fromLocal8Bit( fstabFile.readAll() ) @@ -458,6 +459,99 @@ findFS( QString fsName, FileSystem::Type* fsType ) return fsName; } +static qint64 +sizeToBytes( double size, SizeUnit unit, qint64 totalSize ) +{ + qint64 bytes; + + switch ( unit ) + { + case SizeUnit::Percent: + bytes = qint64( static_cast( totalSize ) * size / 100.0L ); + break; + case SizeUnit::KiB: + bytes = CalamaresUtils::KiBtoBytes(size); + break; + case SizeUnit::MiB: + bytes = CalamaresUtils::MiBtoBytes(size); + break; + case SizeUnit::GiB: + bytes = CalamaresUtils::GiBtoBytes(size); + break; + default: + bytes = size; + break; + } + + return bytes; +} + +double +parseSizeString( const QString& sizeString, SizeUnit* unit ) +{ + double value; + bool ok; + QString valueString; + QString unitString; + + QRegExp rx( "[KkMmGg%]" ); + int pos = rx.indexIn( sizeString ); + if (pos > 0) + { + valueString = sizeString.mid( 0, pos ); + unitString = sizeString.mid( pos ); + } + else + valueString = sizeString; + + 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 = SizeUnit::Percent; + return 100.0L; + } + + if ( unitString.length() > 0 ) + { + if ( unitString.at(0) == '%' ) + *unit = SizeUnit::Percent; + else if ( unitString.at(0).toUpper() == 'K' ) + *unit = SizeUnit::KiB; + else if ( unitString.at(0).toUpper() == 'M' ) + *unit = SizeUnit::MiB; + else if ( unitString.at(0).toUpper() == 'G' ) + *unit = SizeUnit::GiB; + else + *unit = SizeUnit::Byte; + } + else + { + *unit = SizeUnit::Byte; + } + + return value; +} + +qint64 +parseSizeString( const QString& sizeString, qint64 totalSize ) +{ + SizeUnit unit; + double value = parseSizeString( sizeString, &unit ); + + return sizeToBytes( value, unit, totalSize ); +} + +qint64 +sizeToSectors( double size, SizeUnit unit, qint64 totalSectors, qint64 logicalSize ) +{ + qint64 bytes = sizeToBytes( size, unit, totalSectors * logicalSize ); + return bytesToSectors( static_cast( bytes ), logicalSize ); +} + } // nmamespace PartUtils /* Implementation of methods for FstabEntry, from OsproberEntry.h */ diff --git a/src/modules/partition/core/PartUtils.h b/src/modules/partition/core/PartUtils.h index c7da86c06..0ad559a60 100644 --- a/src/modules/partition/core/PartUtils.h +++ b/src/modules/partition/core/PartUtils.h @@ -2,6 +2,7 @@ * * Copyright 2015-2016, Teo Mrnjavac * Copyright 2018, Adriaan de Groot + * Copyright 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 @@ -21,6 +22,7 @@ #define PARTUTILS_H #include "OsproberEntry.h" +#include "utils/Units.h" // KPMcore #include @@ -33,6 +35,16 @@ class Partition; namespace PartUtils { +using CalamaresUtils::MiBtoBytes; + +enum SizeUnit +{ + Percent = 0, + Byte, + KiB, + MiB, + GiB +}; /** * @brief canBeReplaced checks whether the given Partition satisfies the criteria @@ -86,6 +98,47 @@ bool isEfiBootable( const Partition* candidate ); * its value is FileSystem::Unknown if @p fsName is not recognized. */ QString findFS( QString fsName, FileSystem::Type* fsType ); + +/** + * @brief Parse a partition size string and return its value and unit used. + * @param sizeString the string to parse. + * @param unit pointer to a SizeUnit variable for storing the parsed unit. + * @return the size value, as parsed from the input string. + */ +double parseSizeString( const QString& sizeString, SizeUnit* unit ); + +/** + * @brief Parse a partition size string and return its value in bytes. + * @param sizeString the string to parse. + * @param totalSize the size of the selected drive (used when the size is expressed in %) + * @return the size value in bytes. + */ +qint64 parseSizeString( const QString& sizeString, qint64 totalSize ); + +/** + * @brief Convert a partition size to a sectors count. + * @param size the partition size. + * @param unit the partition size unit. + * @param totalSectors the total number of sectors of the selected drive. + * @param logicalSize the sector size, in bytes. + * @return the number of sectors to be used for the given partition size. + */ +qint64 sizeToSectors( double size, SizeUnit unit, qint64 totalSectors, qint64 logicalSize ); + +constexpr qint64 alignBytesToBlockSize( qint64 bytes, qint64 blocksize ) +{ + qint64 blocks = bytes / blocksize; + + if ( blocks * blocksize != bytes ) + ++blocks; + return blocks * blocksize; +} + +constexpr qint64 bytesToSectors( qint64 bytes, qint64 blocksize ) +{ + return alignBytesToBlockSize( alignBytesToBlockSize( bytes, blocksize), MiBtoBytes(1ULL) ) / blocksize; +} + } #endif // PARTUTILS_H diff --git a/src/modules/partition/core/PartitionActions.cpp b/src/modules/partition/core/PartitionActions.cpp index a135b758f..4172002fa 100644 --- a/src/modules/partition/core/PartitionActions.cpp +++ b/src/modules/partition/core/PartitionActions.cpp @@ -2,6 +2,7 @@ * * Copyright 2014-2017, Teo Mrnjavac * Copyright 2017-2018, Adriaan de Groot + * Copyright 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 @@ -28,6 +29,7 @@ #include "utils/Units.h" #include "utils/NamedEnum.h" +#include "GlobalStorage.h" #include "JobQueue.h" #include "utils/Logger.h" @@ -38,8 +40,6 @@ namespace PartitionActions { -using CalamaresUtils::GiBtoBytes; -using CalamaresUtils::MiBtoBytes; using CalamaresUtils::operator""_GiB; using CalamaresUtils::operator""_MiB; @@ -82,25 +82,10 @@ swapSuggestion( const qint64 availableSpaceB, Choices::SwapChoice swap ) return suggestedSwapSizeB; } -constexpr qint64 -alignBytesToBlockSize( qint64 bytes, qint64 blocksize ) -{ - qint64 blocks = bytes / blocksize; - - if ( blocks * blocksize != bytes ) - ++blocks; - return blocks * blocksize; -} - -qint64 -bytesToSectors( qint64 bytes, qint64 blocksize ) -{ - return alignBytesToBlockSize( alignBytesToBlockSize( bytes, blocksize), MiBtoBytes(1) ) / blocksize; -} - void doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionOptions o ) { + Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); QString defaultFsType = o.defaultFsType; if ( FileSystem::typeForName( defaultFsType ) == FileSystem::Unknown ) defaultFsType = "ext4"; @@ -109,19 +94,27 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO // Partition sizes are expressed in MiB, should be multiples of // the logical sector size (usually 512B). EFI starts with 2MiB - // empty and a 300MiB EFI boot partition, while BIOS starts at + // empty and a EFI boot partition, while BIOS starts at // the 1MiB boundary (usually sector 2048). - int uefisys_part_sizeB = isEfi ? 300_MiB : 0_MiB; int empty_space_sizeB = isEfi ? 2_MiB : 1_MiB; + int uefisys_part_sizeB = 0_MiB; + + if ( isEfi ) + { + if ( gs->contains( "efiSystemPartitionSize" ) ) + uefisys_part_sizeB = PartUtils::parseSizeString( gs->value( "efiSystemPartitionSize" ).toString(), dev->capacity() ); + else + uefisys_part_sizeB = 300_MiB; + } // Since sectors count from 0, if the space is 2048 sectors in size, // the first free sector has number 2048 (and there are 2048 sectors // before that one, numbered 0..2047). - qint64 firstFreeSector = bytesToSectors( empty_space_sizeB, dev->logicalSize() ); + qint64 firstFreeSector = PartUtils::bytesToSectors( empty_space_sizeB, dev->logicalSize() ); if ( isEfi ) { - qint64 efiSectorCount = bytesToSectors( uefisys_part_sizeB, dev->logicalSize() ); + qint64 efiSectorCount = PartUtils::bytesToSectors( uefisys_part_sizeB, dev->logicalSize() ); Q_ASSERT( efiSectorCount > 0 ); // Since sectors count from 0, and this partition is created starting diff --git a/src/modules/partition/core/PartitionActions.h b/src/modules/partition/core/PartitionActions.h index 179b835ab..d17852b63 100644 --- a/src/modules/partition/core/PartitionActions.h +++ b/src/modules/partition/core/PartitionActions.h @@ -75,8 +75,6 @@ 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. diff --git a/src/modules/partition/core/PartitionLayout.cpp b/src/modules/partition/core/PartitionLayout.cpp index 39341fddd..4f62db7d6 100644 --- a/src/modules/partition/core/PartitionLayout.cpp +++ b/src/modules/partition/core/PartitionLayout.cpp @@ -75,61 +75,11 @@ PartitionLayout::addEntry( PartitionLayout::PartitionEntry entry ) m_partLayout.append( entry ); } -static double -parseSizeString( const QString& sizeString, PartitionLayout::SizeUnit* unit ) -{ - double value; - bool ok; - QString valueString; - QString unitString; - - QRegExp rx( "[KkMmGg%]" ); - int pos = rx.indexIn( sizeString ); - if (pos > 0) - { - valueString = sizeString.mid( 0, pos ); - unitString = sizeString.mid( pos ); - } - else - valueString = sizeString; - - 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; -} - PartitionLayout::PartitionEntry::PartitionEntry(const QString& size, const QString& min) { - partSize = parseSizeString( size , &partSizeUnit ); + partSize = PartUtils::parseSizeString( size , &partSizeUnit ); if ( !min.isEmpty() ) - partMinSize = parseSizeString( min , &partMinSizeUnit ); + partMinSize = PartUtils::parseSizeString( min , &partMinSizeUnit ); } void @@ -157,35 +107,6 @@ PartitionLayout::addEntry( const QString& label, const QString& mountPoint, cons m_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, @@ -205,8 +126,8 @@ PartitionLayout::execute( Device *dev, qint64 firstSector, Partition *currentPartition = nullptr; // Calculate partition size - size = sizeToSectors( part.partSize, part.partSizeUnit, totalSize, dev->logicalSize() ); - minSize = sizeToSectors( part.partMinSize, part.partMinSizeUnit, totalSize, dev->logicalSize() ); + size = PartUtils::sizeToSectors( part.partSize, part.partSizeUnit, totalSize, dev->logicalSize() ); + minSize = PartUtils::sizeToSectors( part.partMinSize, part.partMinSizeUnit, totalSize, dev->logicalSize() ); if ( size < minSize ) size = minSize; if ( size > availableSize ) diff --git a/src/modules/partition/core/PartitionLayout.h b/src/modules/partition/core/PartitionLayout.h index 999e10425..ab597734c 100644 --- a/src/modules/partition/core/PartitionLayout.h +++ b/src/modules/partition/core/PartitionLayout.h @@ -20,6 +20,8 @@ #ifndef PARTITIONLAYOUT_H #define PARTITIONLAYOUT_H +#include "core/PartUtils.h" + #include "Typedefs.h" // KPMcore @@ -36,24 +38,15 @@ class PartitionLayout { public: - enum SizeUnit - { - Percent = 0, - Byte, - KiB, - MiB, - GiB - }; - struct PartitionEntry { QString partLabel; QString partMountPoint; FileSystem::Type partFileSystem = FileSystem::Unknown; double partSize = 0.0L; - SizeUnit partSizeUnit = Percent; + PartUtils::SizeUnit partSizeUnit = PartUtils::SizeUnit::Percent; double partMinSize = 0.0L; - SizeUnit partMinSizeUnit = Percent; + PartUtils::SizeUnit partMinSizeUnit = PartUtils::SizeUnit::Percent; /// @brief All-zeroes PartitionEntry PartitionEntry() {}; diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 6fc8b0129..ffeb8c055 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -3,7 +3,7 @@ * Copyright 2014, Aurélien Gâteau * Copyright 2014-2017, Teo Mrnjavac * Copyright 2018, Adriaan de Groot - * Copyright 2019, Collabora Ltd + * Copyright 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 @@ -489,6 +489,12 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap ) efiSP = QStringLiteral( "/boot/efi" ); gs->insert( "efiSystemPartition", efiSP ); + // Read and parse key efiSystemPartitionSize + if ( configurationMap.contains( "efiSystemPartitionSize" ) ) + { + gs->insert( "efiSystemPartitionSize", CalamaresUtils::getString( configurationMap, "efiSystemPartitionSize" ) ); + } + // SWAP SETTINGS // // This is a bit convoluted because there's legacy settings to handle as well diff --git a/src/modules/partition/partition.conf b/src/modules/partition/partition.conf index f812b67aa..66f40020c 100644 --- a/src/modules/partition/partition.conf +++ b/src/modules/partition/partition.conf @@ -3,6 +3,10 @@ # etc.) use just /boot. efiSystemPartition: "/boot/efi" +# This optional setting specifies the size of the EFI system partition. +# If nothing is specified, the default size of 300MiB will be used. +# efiSystemPartitionSize: 300M + # In autogenerated partitioning, allow the user to select a swap size? # If there is exactly one choice, no UI is presented, and the user # cannot make a choice -- this setting is used. If there is more than diff --git a/src/modules/partition/tests/PartitionJobTests.cpp b/src/modules/partition/tests/PartitionJobTests.cpp index d3fd67c12..6a7e2ab72 100644 --- a/src/modules/partition/tests/PartitionJobTests.cpp +++ b/src/modules/partition/tests/PartitionJobTests.cpp @@ -349,7 +349,8 @@ PartitionJobTests::testResizePartition() // Make the test data file smaller than the full size of the partition to // accomodate for the file system overhead - const QByteArray testData = generateTestData( CalamaresUtils::MiBtoBytes( qMin( oldSizeMB, newSizeMB ) ) * 3 / 4 ); + const unsigned long long minSizeMB = qMin( oldSizeMB, newSizeMB ); + const QByteArray testData = generateTestData( CalamaresUtils::MiBtoBytes( minSizeMB ) * 3 / 4 ); const QString testName = "test.data"; // Setup: create the test partition