diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index c4b9fa40c..bc3ce0511 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -22,6 +22,9 @@ set( libSources ProcessJob.cpp Settings.cpp ) +set( partSources + partition/PartitionSize.cpp +) set( utilsSources utils/CalamaresUtilsSystem.cpp utils/CommandList.cpp @@ -72,7 +75,7 @@ if( WITH_PYTHON ) ) endif() -add_library( calamares SHARED ${libSources} ${kdsagSources} ${utilsSources} ) +add_library( calamares SHARED ${libSources} ${kdsagSources} ${partSources} ${utilsSources} ) set_target_properties( calamares PROPERTIES VERSION ${CALAMARES_VERSION_SHORT} diff --git a/src/libcalamares/partition/PartitionSize.cpp b/src/libcalamares/partition/PartitionSize.cpp new file mode 100644 index 000000000..edff0fe1e --- /dev/null +++ b/src/libcalamares/partition/PartitionSize.cpp @@ -0,0 +1,238 @@ +/* === This file is part of Calamares - === + * + * 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 + * 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 "partition/PartitionSize.h" +#include "utils/Logger.h" +#include "utils/Units.h" + +namespace Calamares +{ + +static const NamedEnumTable& +unitSuffixes() +{ + static const NamedEnumTable names{ + { QStringLiteral( "%" ), SizeUnit::Percent }, + { QStringLiteral( "K" ), SizeUnit::KiB }, + { QStringLiteral( "KiB" ), SizeUnit::KiB }, + { QStringLiteral( "M" ), SizeUnit::MiB }, + { QStringLiteral( "MiB" ), SizeUnit::MiB }, + { QStringLiteral( "G" ), SizeUnit::GiB }, + { QStringLiteral( "GiB" ), SizeUnit::GiB } + }; + + return names; +} + +PartitionSize::PartitionSize( const QString& s ) + : NamedSuffix( unitSuffixes(), s ) +{ + if ( ( unit() == unit_t::Percent ) && ( value() > 100 || value() < 0 ) ) + { + cDebug() << "Percent value" << value() << "is not valid."; + m_value = 0; + } + + if ( m_unit == unit_t::None ) + { + m_value = s.toInt(); + if ( m_value > 0 ) + m_unit = unit_t::Byte; + } + + if ( m_value <= 0 ) + { + m_value = 0; + m_unit = unit_t::None; + } +} + +qint64 +PartitionSize::toSectors( qint64 totalSectors, qint64 sectorSize ) const +{ + if ( !isValid() ) + return -1; + if ( totalSectors < 1 || sectorSize < 1 ) + return -1; + + switch ( m_unit ) + { + case unit_t::None: + return -1; + case unit_t::Percent: + if ( value() == 100 ) + return totalSectors; // Common-case, avoid futzing around + else + return totalSectors * value() / 100; + case unit_t::Byte: + case unit_t::KiB: + case unit_t::MiB: + case unit_t::GiB: + return CalamaresUtils::bytesToSectors ( toBytes(), sectorSize ); + } + + return -1; +} + +qint64 +PartitionSize::toBytes( qint64 totalSectors, qint64 sectorSize ) const +{ + if ( !isValid() ) + return -1; + + switch ( m_unit ) + { + case unit_t::None: + return -1; + case unit_t::Percent: + if ( totalSectors < 1 || sectorSize < 1 ) + return -1; + if ( value() == 100 ) + return totalSectors * sectorSize; // Common-case, avoid futzing around + else + return totalSectors * value() / 100; + case unit_t::Byte: + case unit_t::KiB: + case unit_t::MiB: + case unit_t::GiB: + return toBytes(); + } + + // notreached + return -1; +} + +qint64 +PartitionSize::toBytes( qint64 totalBytes ) const +{ + if ( !isValid() ) + return -1; + + switch ( m_unit ) + { + case unit_t::None: + return -1; + case unit_t::Percent: + if ( totalBytes < 1 ) + return -1; + if ( value() == 100 ) + return totalBytes; // Common-case, avoid futzing around + else + return totalBytes * value() / 100; + case unit_t::Byte: + case unit_t::KiB: + case unit_t::MiB: + case unit_t::GiB: + return toBytes(); + } + + // notreached + return -1; +} + +qint64 +PartitionSize::toBytes() const +{ + if ( !isValid() ) + return -1; + + switch ( m_unit ) + { + case unit_t::Byte: + return value(); + case unit_t::KiB: + return CalamaresUtils::KiBtoBytes( static_cast( value() ) ); + case unit_t::MiB: + return CalamaresUtils::MiBtoBytes( static_cast( value() ) ); + case unit_t::GiB: + return CalamaresUtils::GiBtoBytes( static_cast( value() ) ); + default: + break; + } + + // Reached only when unit is Percent or None + return -1; +} + +bool +PartitionSize::operator< ( const PartitionSize& other ) const +{ + if ( ( m_unit == unit_t::None || other.m_unit == unit_t::None ) || + ( m_unit == unit_t::Percent && other.m_unit != unit_t::Percent ) || + ( m_unit != unit_t::Percent && other.m_unit == unit_t::Percent ) ) + return false; + + switch ( m_unit ) + { + case unit_t::Percent: + return ( m_value < other.m_value ); + case unit_t::Byte: + case unit_t::KiB: + case unit_t::MiB: + case unit_t::GiB: + return ( toBytes() < other.toBytes () ); + } + + return false; +} + +bool +PartitionSize::operator> ( const PartitionSize& other ) const +{ + if ( ( m_unit == unit_t::None || other.m_unit == unit_t::None ) || + ( m_unit == unit_t::Percent && other.m_unit != unit_t::Percent ) || + ( m_unit != unit_t::Percent && other.m_unit == unit_t::Percent ) ) + return false; + + switch ( m_unit ) + { + case unit_t::Percent: + return ( m_value > other.m_value ); + case unit_t::Byte: + case unit_t::KiB: + case unit_t::MiB: + case unit_t::GiB: + return ( toBytes() > other.toBytes () ); + } + + return false; +} + +bool +PartitionSize::operator== ( const PartitionSize& other ) const +{ + if ( ( m_unit == unit_t::None || other.m_unit == unit_t::None ) || + ( m_unit == unit_t::Percent && other.m_unit != unit_t::Percent ) || + ( m_unit != unit_t::Percent && other.m_unit == unit_t::Percent ) ) + return false; + + switch ( m_unit ) + { + case unit_t::Percent: + return ( m_value == other.m_value ); + case unit_t::Byte: + case unit_t::KiB: + case unit_t::MiB: + case unit_t::GiB: + return ( toBytes() == other.toBytes () ); + } + + return false; +} + +} // namespace Calamares diff --git a/src/libcalamares/partition/PartitionSize.h b/src/libcalamares/partition/PartitionSize.h new file mode 100644 index 000000000..13ffa5c70 --- /dev/null +++ b/src/libcalamares/partition/PartitionSize.h @@ -0,0 +1,103 @@ +/* === This file is part of Calamares - === + * + * 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 + * 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 PARTITION_PARTITIONSIZE_H +#define PARTITION_PARTITIONSIZE_H + +#include "utils/Units.h" +#include "utils/NamedSuffix.h" + +// Qt +#include + +namespace Calamares +{ + +enum class SizeUnit +{ + None, + Percent, + Byte, + KiB, + MiB, + GiB +}; + +/** @brief Partition size expressions + * + * Sizes can be specified in bytes, KiB, MiB, GiB or percent (of + * the available drive space are on). This class handles parsing + * of such strings from the config file. + */ +class PartitionSize : public NamedSuffix +{ +public: + PartitionSize() : NamedSuffix() { } + PartitionSize( int v, unit_t u ) : NamedSuffix( v, u ) { } + PartitionSize( const QString& ); + + bool isValid() const + { + return ( unit() != SizeUnit::None ) && ( value() > 0 ); + } + + bool operator< ( const PartitionSize& other ) const; + bool operator> ( const PartitionSize& other ) const; + bool operator== ( const PartitionSize& other ) const; + + /** @brief Convert the size to the number of sectors @p totalSectors . + * + * Each sector has size @p sectorSize, for converting sizes in Bytes, + * KiB, MiB or GiB to sector counts. + * + * @return the number of sectors needed, or -1 for invalid sizes. + */ + qint64 toSectors( qint64 totalSectors, qint64 sectorSize ) const; + + /** @brief Convert the size to bytes. + * + * The device's sectors count @p totalSectors and sector size + * @p sectoreSize are used to calculated the total size, which + * is then used to calculate the size when using Percent. + * + * @return the size in bytes, or -1 for invalid sizes. + */ + qint64 toBytes( qint64 totalSectors, qint64 sectorSize ) const; + + /** @brief Convert the size to bytes. + * + * Total size @p totalBytes is needed for sizes in Percent. This + * parameter is unused in any other case. + * + * @return the size in bytes, or -1 for invalid sizes. + */ + qint64 toBytes( qint64 totalBytes ) const; + + /** @brief Convert the size to bytes. + * + * This method is only valid for sizes in Bytes, KiB, MiB or GiB. + * It will return -1 in any other case. + * + * @return the size in bytes, or -1 if it cannot be calculated. + */ + qint64 toBytes() const; +}; + +} // namespace Calamares + +#endif // PARTITION_PARTITIONSIZE_H