diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index cad7e7a6e..302c69155 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -44,7 +44,9 @@ set( libSources network/Manager.cpp # Partition service + partition/Mount.cpp partition/PartitionSize.cpp + partition/Sync.cpp # Utility service utils/CalamaresUtilsSystem.cpp @@ -111,6 +113,38 @@ if( Qt5Xml_FOUND ) list( APPEND OPTIONAL_PUBLIC_LIBRARIES Qt5::Network Qt5::Xml ) endif() +### OPTIONAL KPMcore support +# +# +find_package( KPMcore 3.3 ) +set_package_properties( + KPMcore PROPERTIES + URL "https://invent.kde.org/kde/kpmcore" + DESCRIPTION "KDE Partitioning library" + TYPE RECOMMENDED + PURPOSE "For partitioning service" +) + +if ( KPMcore_FOUND ) + find_package( Qt5 REQUIRED DBus ) # Needed for KPMCore + find_package( KF5 REQUIRED I18n WidgetsAddons ) # Needed for KPMCore + + if( KPMcore_VERSION VERSION_GREATER_EQUAL "4.0" ) + add_definitions( -DWITH_KPMCORE4API ) # kpmcore 4 with new API + elseif( KPMcore_VERSION VERSION_GREATER "3.3.70" ) + message( FATAL_ERROR "KPMCore beta versions ${KPMcore_VERSION} not supported" ) + endif() + + include_directories( ${KPMCORE_INCLUDE_DIR} ) + list( APPEND libSources + partition/FileSystem.cpp + partition/KPMManager.cpp + partition/PartitionIterator.cpp + partition/PartitionQuery.cpp + ) + list( APPEND OPTIONAL_PRIVATE_LIBRARIES kpmcore ) +endif() + ### LIBRARY # # diff --git a/src/libcalamares/JobQueue.cpp b/src/libcalamares/JobQueue.cpp index 2690769db..44382fb91 100644 --- a/src/libcalamares/JobQueue.cpp +++ b/src/libcalamares/JobQueue.cpp @@ -36,12 +36,13 @@ public: : QThread( queue ) , m_queue( queue ) , m_jobIndex( 0 ) + , m_jobCount( 0 ) { } virtual ~JobThread() override; - void setJobs( const JobList& jobs ) + void setJobs( JobList&& jobs ) { m_jobs = jobs; @@ -73,7 +74,7 @@ public: } emitProgress(); - cDebug() << "Starting" << ( anyFailed ? "EMERGENCY JOB" : "job" ) << job->prettyName(); + cDebug() << "Starting" << ( anyFailed ? "EMERGENCY JOB" : "job" ) << job->prettyName() << " (there are" << m_jobs.count() << " left)"; connect( job.data(), &Job::progress, this, &JobThread::emitProgress ); JobResult result = job->exec(); if ( !anyFailed && !result ) @@ -103,6 +104,7 @@ private: QList< qreal > m_jobWeights; JobQueue* m_queue; int m_jobIndex; + int m_jobCount; void emitProgress( qreal jobPercent = 0 ) { @@ -193,7 +195,7 @@ void JobQueue::start() { Q_ASSERT( !m_thread->isRunning() ); - m_thread->setJobs( m_jobs ); + m_thread->setJobs( std::move( m_jobs ) ); m_jobs.clear(); m_thread->start(); } diff --git a/src/libcalamares/PythonJobApi.cpp b/src/libcalamares/PythonJobApi.cpp index 132a9dcf5..393958664 100644 --- a/src/libcalamares/PythonJobApi.cpp +++ b/src/libcalamares/PythonJobApi.cpp @@ -22,6 +22,7 @@ #include "GlobalStorage.h" #include "JobQueue.h" #include "PythonHelper.h" +#include "partition/Mount.h" #include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" #include "utils/String.h" @@ -63,10 +64,10 @@ mount( const std::string& device_path, const std::string& filesystem_name, const std::string& options ) { - return CalamaresUtils::System::instance()->mount( QString::fromStdString( device_path ), - QString::fromStdString( mount_point ), - QString::fromStdString( filesystem_name ), - QString::fromStdString( options ) ); + return CalamaresUtils::Partition::mount( QString::fromStdString( device_path ), + QString::fromStdString( mount_point ), + QString::fromStdString( filesystem_name ), + QString::fromStdString( options ) ); } diff --git a/src/libcalamares/partition/FileSystem.cpp b/src/libcalamares/partition/FileSystem.cpp new file mode 100644 index 000000000..fbbe48581 --- /dev/null +++ b/src/libcalamares/partition/FileSystem.cpp @@ -0,0 +1,74 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Aurélien Gâteau + * Copyright 2015-2016, Teo Mrnjavac + * Copyright 2018-2019 Adriaan de Groot + * + * 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 "FileSystem.h" + +#include + +namespace CalamaresUtils +{ +namespace Partition +{ + +QString +prettyNameForFileSystemType( FileSystem::Type t ) +{ + switch ( t ) + { + case FileSystem::Unknown: + return QObject::tr( "unknown" ); + case FileSystem::Extended: + return QObject::tr( "extended" ); + case FileSystem::Unformatted: + return QObject::tr( "unformatted" ); + case FileSystem::LinuxSwap: + return QObject::tr( "swap" ); + case FileSystem::Fat16: + case FileSystem::Fat32: + case FileSystem::Ntfs: + case FileSystem::Xfs: + case FileSystem::Jfs: + case FileSystem::Hfs: + case FileSystem::Ufs: + case FileSystem::Hpfs: + case FileSystem::Luks: + case FileSystem::Ocfs2: + case FileSystem::Zfs: + case FileSystem::Nilfs2: + return FileSystem::nameForType( t ).toUpper(); + case FileSystem::ReiserFS: + return "ReiserFS"; + case FileSystem::Reiser4: + return "Reiser4"; + case FileSystem::HfsPlus: + return "HFS+"; + case FileSystem::Btrfs: + return "Btrfs"; + case FileSystem::Exfat: + return "exFAT"; + case FileSystem::Lvm2_PV: + return "LVM PV"; + default: + return FileSystem::nameForType( t ); + } +} + +} // namespace Partition +} // namespace CalamaresUtils diff --git a/src/libcalamares/partition/FileSystem.h b/src/libcalamares/partition/FileSystem.h new file mode 100644 index 000000000..9923f5dfd --- /dev/null +++ b/src/libcalamares/partition/FileSystem.h @@ -0,0 +1,39 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Aurélien Gâteau + * Copyright 2015-2016, Teo Mrnjavac + * Copyright 2019, Adriaan de Groot + * + * 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 . + */ + +/* + * NOTE: this functionality is only available when Calamares is compiled + * with KPMcore support. + */ + +#ifndef PARTITION_FILESYSTEM_H +#define PARTITION_FILESYSTEM_H + +#include + +namespace CalamaresUtils +{ +namespace Partition +{ +QString prettyNameForFileSystemType( FileSystem::Type t ); +} // namespace Partition +} // namespace CalamaresUtils + +#endif // PARTITION_PARTITIONQUERY_H diff --git a/src/libcalamares/partition/KPMManager.cpp b/src/libcalamares/partition/KPMManager.cpp new file mode 100644 index 000000000..efc5f0003 --- /dev/null +++ b/src/libcalamares/partition/KPMManager.cpp @@ -0,0 +1,128 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * 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 "KPMManager.h" + +#include "utils/Logger.h" + +#include +#include +#if defined( WITH_KPMCORE4API ) +#include +#endif + + +#include + + +namespace CalamaresUtils +{ +namespace Partition +{ +class InternalManager +{ +public: + InternalManager(); + ~InternalManager(); +}; + +static bool s_kpm_loaded = false; + +/* + * We have one living InternalManager object at a time. + * It is managed by shared_ptr<>s help by KPMManager + * objects, but since we can create KPMManager objects + * independent of each other, all of which share ownership + * of the same InternalManager, hang on to one extra reference + * to the InternalManager so we can hand it out in getInternal(). + */ +static std::weak_ptr< InternalManager > s_backend; + +InternalManager::InternalManager() +{ + cDebug() << "KPMCore backend starting .."; + + Q_ASSERT( s_backend.expired() ); + + if ( !s_kpm_loaded ) + { + QByteArray backendName = qgetenv( "KPMCORE_BACKEND" ); + if ( !CoreBackendManager::self()->load( backendName.isEmpty() ? CoreBackendManager::defaultBackendName() + : backendName ) ) + { + cWarning() << "Failed to load backend plugin" << backendName; + } + else + { + auto* backend_p = CoreBackendManager::self()->backend(); + cDebug() << Logger::SubEntry << "Backend @" << (void*)backend_p << backend_p->id() << backend_p->version(); + s_kpm_loaded = true; + } + } +} + +InternalManager::~InternalManager() +{ + cDebug() << "Cleaning up KPMCore backend .."; + +#if defined( WITH_KPMCORE4API ) + auto backend_p = CoreBackendManager::self()->backend(); + if ( backend_p ) + { + ExternalCommand::stopHelper(); + } +#endif +} + +std::shared_ptr< InternalManager > +getInternal() +{ + if ( s_backend.expired() ) + { + auto p = std::make_shared< InternalManager >(); + s_backend = p; + return p; + } + return s_backend.lock(); +} + +KPMManager::KPMManager() + : m_d( getInternal() ) +{ + cDebug() << "KPMManager" << s_backend.use_count() << "created."; +} + +KPMManager::~KPMManager() +{ + cDebug() << "KPMManager" << s_backend.use_count() << "being destroyed."; +} + +KPMManager::operator bool() const +{ + return s_kpm_loaded; +} + +CoreBackend* +KPMManager::backend() const +{ + return s_kpm_loaded ? CoreBackendManager::self()->backend() : nullptr; +} + + +} // namespace Partition +} // namespace CalamaresUtils diff --git a/src/libcalamares/partition/KPMManager.h b/src/libcalamares/partition/KPMManager.h new file mode 100644 index 000000000..5f7039221 --- /dev/null +++ b/src/libcalamares/partition/KPMManager.h @@ -0,0 +1,69 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * 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 . + */ + +/* + * NOTE: this functionality is only available when Calamares is compiled + * with KPMcore support. + */ + +#ifndef PARTITION_KPMMANAGER_H +#define PARTITION_KPMMANAGER_H + +#include + +class CoreBackend; + +namespace CalamaresUtils +{ +namespace Partition +{ +/// @brief Handle to KPMCore +class InternalManager; + +/** @brief KPMCore loader and cleanup + * + * A Calamares plugin that uses KPMCore should hold an object of + * this class; its only responsibility is to load KPMCore + * and to cleanly unload it on destruction (with KPMCore 4, + * also to shutdown the privileged helper application). + * + * It loads the default plugin ("parted" with KPMCore 3, "sfdisk" + * with KPMCore 4), but this can be overridden by setting the + * environment variable KPMCORE_BACKEND. Setting it to + * "dummy" will load the dummy plugin instead. + */ +class KPMManager +{ +public: + KPMManager(); + ~KPMManager(); + + /// @brief Is KPMCore loaded correctly? + operator bool() const; + + /// @brief Gets the KPMCore backend (e.g. CoreBackendManager::self()->backend() ) + CoreBackend* backend() const; + +private: + std::shared_ptr< InternalManager > m_d; +}; + +} // namespace Partition +} // namespace CalamaresUtils + +#endif // PARTITION_KPMMANAGER_H diff --git a/src/libcalamares/partition/Mount.cpp b/src/libcalamares/partition/Mount.cpp new file mode 100644 index 000000000..91fcefff5 --- /dev/null +++ b/src/libcalamares/partition/Mount.cpp @@ -0,0 +1,132 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Teo Mrnjavac + * Copyright 2017-2019, Adriaan de Groot + * + * 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 "Mount.h" + +#include "partition/Sync.h" +#include "utils/CalamaresUtilsSystem.h" +#include "utils/Logger.h" + +#include +#include + +namespace CalamaresUtils +{ +namespace Partition +{ + +int +mount( const QString& devicePath, const QString& mountPoint, const QString& filesystemName, const QString& options ) +{ + if ( devicePath.isEmpty() || mountPoint.isEmpty() ) + { + if ( devicePath.isEmpty() ) + { + cWarning() << "Can't mount an empty device."; + } + if ( mountPoint.isEmpty() ) + { + cWarning() << "Can't mount on an empty mountpoint."; + } + + return static_cast< int >( ProcessResult::Code::NoWorkingDirectory ); + } + + QDir mountPointDir( mountPoint ); + if ( !mountPointDir.exists() ) + { + bool ok = mountPointDir.mkpath( mountPoint ); + if ( !ok ) + { + cWarning() << "Could not create mountpoint" << mountPoint; + return static_cast< int >( ProcessResult::Code::NoWorkingDirectory ); + } + } + + QStringList args = { "mount" }; + + if ( !filesystemName.isEmpty() ) + { + args << "-t" << filesystemName; + } + if ( !options.isEmpty() ) + { + if ( options.startsWith( '-' ) ) + { + args << options; + } + else + { + args << "-o" << options; + } + } + args << devicePath << mountPoint; + + auto r = CalamaresUtils::System::runCommand( args, std::chrono::seconds( 10 ) ); + sync(); + return r.getExitCode(); +} + +int +unmount( const QString& path, const QStringList& options ) +{ + auto r + = CalamaresUtils::System::runCommand( QStringList { "umount" } << options << path, std::chrono::seconds( 10 ) ); + sync(); + return r.getExitCode(); +} + +struct TemporaryMount::Private +{ + QString m_devicePath; + QTemporaryDir m_mountDir; +}; + + +TemporaryMount::TemporaryMount( const QString& devicePath, const QString& filesystemName, const QString& options ) + : m_d( new Private ) +{ + m_d->m_devicePath = devicePath; + m_d->m_mountDir.setAutoRemove( false ); + int r = mount( devicePath, m_d->m_mountDir.path(), filesystemName, options ); + if ( !r ) + { + delete m_d; + m_d = nullptr; + } +} + +TemporaryMount::~TemporaryMount() +{ + if ( m_d ) + { + unmount( m_d->m_devicePath, { "-R" } ); + delete m_d; + m_d = nullptr; + } +} + +QString +TemporaryMount::path() const +{ + return m_d ? m_d->m_mountDir.path() : QString(); +} + +} // namespace Partition +} // namespace CalamaresUtils diff --git a/src/libcalamares/partition/Mount.h b/src/libcalamares/partition/Mount.h new file mode 100644 index 000000000..041e7e757 --- /dev/null +++ b/src/libcalamares/partition/Mount.h @@ -0,0 +1,80 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Teo Mrnjavac + * Copyright 2017-2019, Adriaan de Groot + * + * 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_MOUNT_H +#define PARTITION_MOUNT_H + +#include "DllMacro.h" + +#include +#include + +namespace CalamaresUtils +{ +namespace Partition +{ + +/** + * Runs the mount utility with the specified parameters. + * @param devicePath the path of the partition to mount. + * @param mountPoint the full path of the target mount point. + * @param filesystemName the name of the filesystem (optional). + * @param options any additional options as passed to mount -o (optional). + * If @p options starts with a dash (-) then it is passed unchanged + * and no -o option is added; this is used in handling --bind mounts. + * @returns the program's exit code, or: + * Crashed = QProcess crash + * FailedToStart = QProcess cannot start + * NoWorkingDirectory = bad arguments + */ +DLLEXPORT int mount( const QString& devicePath, + const QString& mountPoint, + const QString& filesystemName = QString(), + const QString& options = QString() ); + +/** @brief Unmount the given @p path (device or mount point). + * + * Runs umount(8) in the host system. + * + * @returns the program's exit code, or special codes like mount(). + */ +DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() ); + +class DLLEXPORT TemporaryMount +{ +public: + TemporaryMount( const QString& devicePath, + const QString& filesystemName = QString(), + const QString& options = QString() ); + TemporaryMount( const TemporaryMount& ) = delete; + TemporaryMount& operator=( const TemporaryMount& ) = delete; + ~TemporaryMount(); + + bool isValid() const { return m_d; } + QString path() const; + +private: + struct Private; + Private* m_d = nullptr; +}; + +} // namespace Partition +} // namespace CalamaresUtils + +#endif diff --git a/src/modules/partition/core/PartitionIterator.cpp b/src/libcalamares/partition/PartitionIterator.cpp similarity index 90% rename from src/modules/partition/core/PartitionIterator.cpp rename to src/libcalamares/partition/PartitionIterator.cpp index 34471f6f2..642752163 100644 --- a/src/modules/partition/core/PartitionIterator.cpp +++ b/src/libcalamares/partition/PartitionIterator.cpp @@ -2,7 +2,7 @@ * * Copyright 2014, Aurélien Gâteau * Copyright 2015, Teo Mrnjavac - * Copyright 2017, Adriaan de Groot + * Copyright 2017, 2019 Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,12 +25,19 @@ #include #include +namespace CalamaresUtils +{ +namespace Partition +{ + +using Partition = ::Partition; + PartitionIterator::PartitionIterator( PartitionTable* table ) : m_table( table ) -{} +{ +} -Partition* -PartitionIterator::operator*() const +Partition* PartitionIterator::operator*() const { return m_current; } @@ -39,7 +46,9 @@ void PartitionIterator::operator++() { if ( !m_current ) + { return; + } if ( m_current->hasChildren() ) { // Go to the first child @@ -78,18 +87,21 @@ PartitionIterator::operator==( const PartitionIterator& other ) const bool PartitionIterator::operator!=( const PartitionIterator& other ) const { - return ! ( *this == other ); + return !( *this == other ); } PartitionIterator PartitionIterator::begin( Device* device ) { if ( !device ) + { return PartitionIterator( nullptr ); - Q_ASSERT(device); + } PartitionTable* table = device->partitionTable(); if ( !table ) + { return PartitionIterator( nullptr ); + } return PartitionIterator::begin( table ); } @@ -101,7 +113,9 @@ PartitionIterator::begin( PartitionTable* table ) // Does not usually happen, but it did happen on a tiny (10MiB) disk with an MBR // partition table. if ( children.isEmpty() ) + { return it; + } it.m_current = children.first(); return it; } @@ -110,10 +124,14 @@ PartitionIterator PartitionIterator::end( Device* device ) { if ( !device ) + { return PartitionIterator( nullptr ); + } PartitionTable* table = device->partitionTable(); if ( !table ) + { return PartitionIterator( nullptr ); + } return PartitionIterator::end( table ); } @@ -123,3 +141,6 @@ PartitionIterator::end( PartitionTable* table ) { return PartitionIterator( table ); } + +} // namespace Partition +} // namespace CalamaresUtils diff --git a/src/modules/partition/core/PartitionIterator.h b/src/libcalamares/partition/PartitionIterator.h similarity index 53% rename from src/modules/partition/core/PartitionIterator.h rename to src/libcalamares/partition/PartitionIterator.h index b72c2de8a..78d930cf4 100644 --- a/src/modules/partition/core/PartitionIterator.h +++ b/src/libcalamares/partition/PartitionIterator.h @@ -2,6 +2,7 @@ * * Copyright 2014, Aurélien Gâteau * Copyright 2015, Teo Mrnjavac + * Copyright 2019, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,37 +18,57 @@ * along with Calamares. If not, see . */ -#ifndef PARTITIONITERATOR_H -#define PARTITIONITERATOR_H +/* + * NOTE: this functionality is only available when Calamares is compiled + * with KPMcore support. + */ + +#ifndef PARTITION_PARTITIONITERATOR_H +#define PARTITION_PARTITIONITERATOR_H class Device; class Partition; class PartitionTable; -/** +namespace CalamaresUtils +{ +namespace Partition +{ + +/** @brief Iterator over KPMCore partitions + * * A forward-only iterator to go through the partitions of a device, * independently of whether they are primary, logical or extended. + * + * An iterator can be created from a device (then it refers to the + * partition table of that device) or a partition table. The + * partition table must remain valid throughout iteration. + * + * A nullptr is valid, for an empty iterator. */ class PartitionIterator { public: - Partition* operator*() const; + ::Partition* operator*() const; void operator++(); bool operator==( const PartitionIterator& other ) const; bool operator!=( const PartitionIterator& other ) const; - static PartitionIterator begin( Device* device ); - static PartitionIterator begin( PartitionTable* table ); - static PartitionIterator end( Device* device ); - static PartitionIterator end( PartitionTable* table ); + static PartitionIterator begin( ::Device* device ); + static PartitionIterator begin( ::PartitionTable* table ); + static PartitionIterator end( ::Device* device ); + static PartitionIterator end( ::PartitionTable* table ); private: - PartitionIterator( PartitionTable* table ); + PartitionIterator( ::PartitionTable* table ); - PartitionTable* m_table; - Partition* m_current = nullptr; + ::PartitionTable* m_table; + ::Partition* m_current = nullptr; }; -#endif /* PARTITIONITERATOR_H */ +} // namespace Partition +} // namespace CalamaresUtils + +#endif // PARTITION_PARTITIONITERATOR_H diff --git a/src/libcalamares/partition/PartitionQuery.cpp b/src/libcalamares/partition/PartitionQuery.cpp new file mode 100644 index 000000000..6693f7e6c --- /dev/null +++ b/src/libcalamares/partition/PartitionQuery.cpp @@ -0,0 +1,102 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Aurélien Gâteau + * Copyright 2015-2016, Teo Mrnjavac + * Copyright 2018-2019 Adriaan de Groot + * + * 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 "PartitionQuery.h" + +#include "PartitionIterator.h" + +#include +#include + +namespace CalamaresUtils +{ +namespace Partition +{ + +// Types from KPMCore +using ::Device; +using ::Partition; + +bool +isPartitionFreeSpace( Partition* partition ) +{ + return partition->roles().has( PartitionRole::Unallocated ); +} + + +bool +isPartitionNew( Partition* partition ) +{ +#if defined( WITH_KPMCORE4API ) + constexpr auto NewState = Partition::State::New; +#else + constexpr auto NewState = Partition::StateNew; +#endif + return partition->state() == NewState; +} + + +Partition* +findPartitionByCurrentMountPoint( const QList< Device* >& devices, const QString& mountPoint ) +{ + for ( auto device : devices ) + for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it ) + if ( ( *it )->mountPoint() == mountPoint ) + { + return *it; + } + return nullptr; +} + + +Partition* +findPartitionByPath( const QList< Device* >& devices, const QString& path ) +{ + if ( path.simplified().isEmpty() ) + { + return nullptr; + } + + for ( auto device : devices ) + for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it ) + if ( ( *it )->partitionPath() == path.simplified() ) + { + return *it; + } + return nullptr; +} + + +QList< Partition* > +findPartitions( const QList< Device* >& devices, std::function< bool( Partition* ) > criterionFunction ) +{ + QList< Partition* > results; + for ( auto device : devices ) + for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it ) + if ( criterionFunction( *it ) ) + { + results.append( *it ); + } + return results; +} + + +} // namespace Partition +} // namespace CalamaresUtils diff --git a/src/libcalamares/partition/PartitionQuery.h b/src/libcalamares/partition/PartitionQuery.h new file mode 100644 index 000000000..18eb7edd2 --- /dev/null +++ b/src/libcalamares/partition/PartitionQuery.h @@ -0,0 +1,78 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Aurélien Gâteau + * Copyright 2015-2016, Teo Mrnjavac + * Copyright 2019, Adriaan de Groot + * + * 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 . + */ + +/* + * NOTE: this functionality is only available when Calamares is compiled + * with KPMcore support. + */ + +#ifndef PARTITION_PARTITIONQUERY_H +#define PARTITION_PARTITIONQUERY_H + +#include + +#include + +class Device; +class Partition; + +namespace CalamaresUtils +{ +namespace Partition +{ + +using ::Device; +using ::Partition; + +/** @brief Is this a free-space area? */ +bool isPartitionFreeSpace( Partition* ); + +/** @brief Is this partition newly-to-be-created? + * + * Returns true if the partition is planned to be created by the installer as + * opposed to already existing on the disk. + */ +bool isPartitionNew( Partition* ); + +/** + * Iterates on all devices and return the first partition which is (already) + * mounted on @p mountPoint. + */ +Partition* findPartitionByCurrentMountPoint( const QList< Device* >& devices, const QString& mountPoint ); + +// TODO: add this distinction +// Partition* findPartitionByIntendedMountPoint( const QList< Device* >& devices, const QString& mountPoint ); + +/** + * Iterates on all devices and partitions and returns a pointer to the Partition object + * for the given path, or nullptr if a Partition for the given path cannot be found. + */ +Partition* findPartitionByPath( const QList< Device* >& devices, const QString& path ); + +/** + * Iterates on all devices and partitions and returns a list of pointers to the Partition + * objects that satisfy the conditions defined in the criterion function. + */ +QList< Partition* > findPartitions( const QList< Device* >& devices, + std::function< bool( Partition* ) > criterionFunction ); +} // namespace Partition +} // namespace CalamaresUtils + +#endif // PARTITION_PARTITIONQUERY_H diff --git a/src/libcalamares/partition/Sync.cpp b/src/libcalamares/partition/Sync.cpp new file mode 100644 index 000000000..c5e131cfa --- /dev/null +++ b/src/libcalamares/partition/Sync.cpp @@ -0,0 +1,36 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * 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 "Sync.h" + +#include "utils/CalamaresUtilsSystem.h" +#include "utils/Logger.h" + +void +CalamaresUtils::Partition::sync() +{ + auto r = CalamaresUtils::System::runCommand( { "/sbin/udevadm", "settle" }, std::chrono::seconds( 10 ) ); + + if ( r.getExitCode() != 0 ) + { + cWarning() << "Could not settle disks."; + r.explainProcess( "udevadm", std::chrono::seconds( 10 ) ); + } + + CalamaresUtils::System::runCommand( { "/bin/sync" }, std::chrono::seconds( 10 ) ); +} diff --git a/src/libcalamares/partition/Sync.h b/src/libcalamares/partition/Sync.h new file mode 100644 index 000000000..510858500 --- /dev/null +++ b/src/libcalamares/partition/Sync.h @@ -0,0 +1,46 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * 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_SYNC_H +#define PARTITION_SYNC_H + +namespace CalamaresUtils +{ +namespace Partition +{ + +/** @brief Run "udevadm settle" or other disk-sync mechanism. + * + * Call this after mounting, unmount, toggling swap, or other functions + * that might cause the disk to be "busy" for other disk-modifying + * actions (in particular, KPMcore actions with the sfdisk backend + * are sensitive, and systemd tends to keep disks busy after a change + * for a while). + */ +void sync(); + +/** @brief RAII class for calling sync() */ +struct Syncer +{ + ~Syncer() { sync(); } +}; + +} // namespace Partition +} // namespace CalamaresUtils + +#endif diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.cpp b/src/libcalamares/utils/CalamaresUtilsSystem.cpp index 61e05976a..f16dc18c5 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.cpp +++ b/src/libcalamares/utils/CalamaresUtilsSystem.cpp @@ -117,53 +117,6 @@ System::instance() } -int -System::mount( const QString& devicePath, - const QString& mountPoint, - const QString& filesystemName, - const QString& options ) -{ - if ( devicePath.isEmpty() || mountPoint.isEmpty() ) - { - if ( devicePath.isEmpty() ) - { - cWarning() << "Can't mount an empty device."; - } - if ( mountPoint.isEmpty() ) - { - cWarning() << "Can't mount on an empty mountpoint."; - } - - return static_cast< int >( ProcessResult::Code::NoWorkingDirectory ); - } - - QDir mountPointDir( mountPoint ); - if ( !mountPointDir.exists() ) - { - bool ok = mountPointDir.mkpath( mountPoint ); - if ( !ok ) - { - cWarning() << "Could not create mountpoint" << mountPoint; - return static_cast< int >( ProcessResult::Code::NoWorkingDirectory ); - } - } - - QString program( "mount" ); - QStringList args = { devicePath, mountPoint }; - - if ( !filesystemName.isEmpty() ) - { - args << "-t" << filesystemName; - } - - if ( !options.isEmpty() ) - { - args << "-o" << options; - } - - return QProcess::execute( program, args ); -} - ProcessResult System::runCommand( System::RunLocation location, const QStringList& args, diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.h b/src/libcalamares/utils/CalamaresUtilsSystem.h index ca8e0d797..cf6df35f4 100644 --- a/src/libcalamares/utils/CalamaresUtilsSystem.h +++ b/src/libcalamares/utils/CalamaresUtilsSystem.h @@ -103,23 +103,6 @@ public: static System* instance(); - /** - * Runs the mount utility with the specified parameters. - * @param devicePath the path of the partition to mount. - * @param mountPoint the full path of the target mount point. - * @param filesystemName the name of the filesystem (optional). - * @param options any additional options as passed to mount -o (optional). - * @returns the program's exit code, or: - * Crashed = QProcess crash - * FailedToStart = QProcess cannot start - * NoWorkingDirectory = bad arguments - */ - DLLEXPORT int mount( const QString& devicePath, - const QString& mountPoint, - const QString& filesystemName = QString(), - const QString& options = QString() ); - - /** (Typed) Boolean describing where a particular command should be run, * whether in the host (live) system or in the (chroot) target system. */ @@ -152,6 +135,16 @@ public: const QString& stdInput = QString(), std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) ); + /** @brief Convenience wrapper for runCommand() + * + * Runs the given command-line @p args in the host in the current direcory + * with no input, and the given @p timeoutSec for completion. + */ + static inline ProcessResult runCommand( const QStringList& args, std::chrono::seconds timeoutSec ) + { + return runCommand( RunLocation::RunInHost, args, QString(), QString(), timeoutSec ); + } + /** @brief Convenience wrapper for runCommand(). * Runs the command in the location specified through the boolean * doChroot(), which is what you usually want for running commands diff --git a/src/libcalamaresui/viewpages/PythonQtUtilsWrapper.cpp b/src/libcalamaresui/viewpages/PythonQtUtilsWrapper.cpp index c13e063bd..d16bd56f8 100644 --- a/src/libcalamaresui/viewpages/PythonQtUtilsWrapper.cpp +++ b/src/libcalamaresui/viewpages/PythonQtUtilsWrapper.cpp @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2016, Teo Mrnjavac + * Copyright 2019, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +19,7 @@ #include "PythonQtUtilsWrapper.h" +#include "partition/Mount.h" #include "utils/CalamaresUtilsSystem.h" #include "utils/Logger.h" #include "utils/String.h" @@ -46,7 +48,7 @@ Utils::mount( const QString& device_path, const QString& filesystem_name, const QString& options ) const { - return CalamaresUtils::System::instance()->mount( device_path, mount_point, filesystem_name, options ); + return CalamaresUtils::Partition::mount( device_path, mount_point, filesystem_name, options ); } diff --git a/src/modules/fsresizer/CMakeLists.txt b/src/modules/fsresizer/CMakeLists.txt index 3d82489b7..2448e516d 100644 --- a/src/modules/fsresizer/CMakeLists.txt +++ b/src/modules/fsresizer/CMakeLists.txt @@ -8,11 +8,10 @@ set( _partition_defs "" ) if ( KPMcore_FOUND AND Qt5DBus_FOUND AND KF5CoreAddons_FOUND AND KF5Config_FOUND ) include_directories( ${KPMCORE_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/src/modules/partition ) - if ( KPMcore_VERSION VERSION_GREATER "3.3.0") - list( APPEND _partition_defs WITH_KPMCORE331API) # kpmcore > 3.3.0 with deprecations - endif() - if ( KPMcore_VERSION VERSION_GREATER "3.90") - list( APPEND _partition_defs WITH_KPMCORE4API) # kpmcore 4 with new API + if( KPMcore_VERSION VERSION_GREATER_EQUAL "4.0" ) + list( APPEND _partition_defs WITH_KPMCORE4API ) # kpmcore 4 with new API + elseif( KPMcore_VERSION VERSION_GREATER "3.3.70" ) + message( FATAL_ERROR "KPMCore beta versions ${KPMcore_VERSION} are not supported" ) endif() # The PartitionIterator is a small class, and it's easiest -- but also a @@ -22,7 +21,6 @@ if ( KPMcore_FOUND AND Qt5DBus_FOUND AND KF5CoreAddons_FOUND AND KF5Config_FOUND EXPORT_MACRO PLUGINDLLEXPORT_PRO SOURCES ResizeFSJob.cpp - ${PROJECT_SOURCE_DIR}/src/modules/partition/core/PartitionIterator.cpp LINK_PRIVATE_LIBRARIES kpmcore calamares diff --git a/src/modules/fsresizer/ResizeFSJob.cpp b/src/modules/fsresizer/ResizeFSJob.cpp index 6b9ef9d3e..217f1315e 100644 --- a/src/modules/fsresizer/ResizeFSJob.cpp +++ b/src/modules/fsresizer/ResizeFSJob.cpp @@ -18,6 +18,14 @@ #include "ResizeFSJob.h" +#include "CalamaresVersion.h" +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "partition/PartitionIterator.h" +#include "utils/Logger.h" +#include "utils/Units.h" +#include "utils/Variant.h" + #include #include #include @@ -29,17 +37,7 @@ #include #include -#include "CalamaresVersion.h" -#include "JobQueue.h" -#include "GlobalStorage.h" - -#include "utils/Logger.h" -#include "utils/Units.h" -#include "utils/Variant.h" - -// From partition module -#include "core/PartitionIterator.h" - +using CalamaresUtils::Partition::PartitionIterator; ResizeFSJob::ResizeFSJob( QObject* parent ) : Calamares::CppJob( parent ) @@ -60,13 +58,13 @@ ResizeFSJob::prettyName() const } ResizeFSJob::PartitionMatch -ResizeFSJob::findPartition( CoreBackend* backend ) +ResizeFSJob::findPartition() { using DeviceList = QList< Device* >; -#ifdef WITH_KPMCORE331API - DeviceList devices = backend->scanDevices( /* not includeReadOnly, not includeLoopback */ ScanFlag(0) ); +#if defined( WITH_KPMCORE4API ) + DeviceList devices = m_kpmcore.backend()->scanDevices( /* not includeReadOnly, not includeLoopback */ ScanFlag(0) ); #else - DeviceList devices = backend->scanDevices( /* excludeReadOnly */ true ); + DeviceList devices = m_kpmcore.backend()->scanDevices( /* excludeReadOnly */ true ); #endif cDebug() << "ResizeFSJob found" << devices.count() << "devices."; @@ -172,35 +170,17 @@ ResizeFSJob::exec() tr( "Invalid configuration" ), tr( "The file-system resize job has an invalid configuration and will not run." ) ); - // Get KPMCore - auto backend_p = CoreBackendManager::self()->backend(); - if ( backend_p ) - cDebug() << "KPMCore backend @" << ( void* )backend_p << backend_p->id() << backend_p->version(); - else - { - cDebug() << "No KPMCore backend loaded yet"; - QByteArray backendName = qgetenv( "KPMCORE_BACKEND" ); - if ( !CoreBackendManager::self()->load( backendName.isEmpty() ? CoreBackendManager::defaultBackendName() : backendName ) ) - { - cWarning() << "Could not load KPMCore backend."; - return Calamares::JobResult::error( - tr( "KPMCore not Available" ), - tr( "Calamares cannot start KPMCore for the file-system resize job." ) ); - } - - backend_p = CoreBackendManager::self()->backend(); - } - if ( !backend_p ) + if ( !m_kpmcore) { cWarning() << "Could not load KPMCore backend (2)."; return Calamares::JobResult::error( tr( "KPMCore not Available" ), tr( "Calamares cannot start KPMCore for the file-system resize job." ) ); } - backend_p->initFSSupport(); // Might not be enough, see below + m_kpmcore.backend()->initFSSupport(); // Might not be enough, see below // Now get the partition and FS we want to work on - PartitionMatch m = findPartition( backend_p ); + PartitionMatch m = findPartition(); if ( !m.first || !m.second ) return Calamares::JobResult::error( tr( "Resize Failed" ), diff --git a/src/modules/fsresizer/ResizeFSJob.h b/src/modules/fsresizer/ResizeFSJob.h index 76ca6c219..0c24ee759 100644 --- a/src/modules/fsresizer/ResizeFSJob.h +++ b/src/modules/fsresizer/ResizeFSJob.h @@ -24,6 +24,7 @@ #include +#include "partition/KPMManager.h" #include "partition/PartitionSize.h" #include "utils/PluginFactory.h" @@ -72,6 +73,7 @@ public: } private: + CalamaresUtils::Partition::KPMManager m_kpmcore; PartitionSize m_size; PartitionSize m_atleast; QString m_fsname; // Either this, or devicename, is set, not both @@ -79,8 +81,8 @@ private: bool m_required; using PartitionMatch = QPair; - /** @brief Find the configured FS using KPMCore @p backend */ - PartitionMatch findPartition( CoreBackend* backend ); + /** @brief Find the configured FS */ + PartitionMatch findPartition(); /** @brief Return a new end-sector for the given dev-part pair. */ qint64 findGrownEnd( PartitionMatch ); diff --git a/src/modules/partition/CMakeLists.txt b/src/modules/partition/CMakeLists.txt index f9c32b39e..2ac926346 100644 --- a/src/modules/partition/CMakeLists.txt +++ b/src/modules/partition/CMakeLists.txt @@ -20,7 +20,7 @@ find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE) find_package( KPMcore 3.3 ) set_package_properties( KPMcore PROPERTIES - PURPOSE "For partitioning module" + PURPOSE "For partition module" ) find_package( KF5Config CONFIG ) find_package( KF5I18n CONFIG ) @@ -51,7 +51,6 @@ if ( KPMcore_FOUND AND Qt5DBus_FOUND AND KF5CoreAddons_FOUND AND KF5Config_FOUND core/PartitionActions.cpp core/PartitionCoreModule.cpp core/PartitionInfo.cpp - core/PartitionIterator.cpp core/PartitionLayout.cpp core/PartitionModel.cpp core/PartUtils.cpp diff --git a/src/modules/partition/core/ColorUtils.cpp b/src/modules/partition/core/ColorUtils.cpp index ffe45d443..63f51cddf 100644 --- a/src/modules/partition/core/ColorUtils.cpp +++ b/src/modules/partition/core/ColorUtils.cpp @@ -20,8 +20,9 @@ #include "core/ColorUtils.h" #include "core/KPMHelpers.h" -#include "core/PartitionIterator.h" +#include "partition/PartitionIterator.h" +#include "partition/PartitionQuery.h" #include "utils/Logger.h" // KPMcore @@ -32,6 +33,10 @@ #include #include +using CalamaresUtils::Partition::PartitionIterator; +using CalamaresUtils::Partition::isPartitionFreeSpace; +using CalamaresUtils::Partition::isPartitionNew; + static const int NUM_PARTITION_COLORS = 5; static const int NUM_NEW_PARTITION_COLORS = 4; //Let's try to use the Breeze palette @@ -89,7 +94,7 @@ colorForPartition( Partition* partition ) return FREE_SPACE_COLOR; } - if ( KPMHelpers::isPartitionFreeSpace( partition ) ) + if ( isPartitionFreeSpace( partition ) ) return FREE_SPACE_COLOR; if ( partition->roles().has( PartitionRole::Extended ) ) return EXTENDED_COLOR; @@ -124,16 +129,16 @@ colorForPartition( Partition* partition ) Partition* child = *it; if ( child == partition ) break; - if ( !KPMHelpers::isPartitionFreeSpace( child ) && + if ( !isPartitionFreeSpace( child ) && !child->hasChildren() ) { - if ( KPMHelpers::isPartitionNew( child ) ) + if ( isPartitionNew( child ) ) ++newColorIdx; ++colorIdx; } } - if ( KPMHelpers::isPartitionNew( partition ) ) + if ( isPartitionNew( partition ) ) return NEW_PARTITION_COLORS[ newColorIdx % NUM_NEW_PARTITION_COLORS ]; if ( partition->fileSystem().supportGetUUID() != FileSystem::cmdSupportNone && @@ -170,9 +175,9 @@ colorForPartitionInFreeSpace( Partition* partition ) Partition* child = *it; if ( child == partition ) break; - if ( !KPMHelpers::isPartitionFreeSpace( child ) && + if ( !isPartitionFreeSpace( child ) && !child->hasChildren() && - KPMHelpers::isPartitionNew( child ) ) + isPartitionNew( child ) ) ++newColorIdx; } return NEW_PARTITION_COLORS[ newColorIdx % NUM_NEW_PARTITION_COLORS ]; diff --git a/src/modules/partition/core/DeviceList.cpp b/src/modules/partition/core/DeviceList.cpp index 680d30dd6..f11293533 100644 --- a/src/modules/partition/core/DeviceList.cpp +++ b/src/modules/partition/core/DeviceList.cpp @@ -20,23 +20,24 @@ #include "DeviceList.h" #include "PartitionCoreModule.h" - #include "core/DeviceModel.h" #include "core/KPMHelpers.h" -#include "core/PartitionIterator.h" + +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "partition/PartitionIterator.h" +#include "utils/Logger.h" #include #include #include #include -#include -#include -#include - #include #include +using CalamaresUtils::Partition::PartitionIterator; + namespace PartUtils { @@ -108,7 +109,7 @@ QList< Device* > getDevices( DeviceType which, qint64 minimumSize ) bool writableOnly = (which == DeviceType::WritableOnly); CoreBackend* backend = CoreBackendManager::self()->backend(); -#ifdef WITH_KPMCORE331API +#if defined( WITH_KPMCORE4API ) DeviceList devices = backend->scanDevices( /* not includeReadOnly, not includeLoopback */ ScanFlag(0) ); #else DeviceList devices = backend->scanDevices( /* excludeReadOnly */ true ); diff --git a/src/modules/partition/core/KPMHelpers.cpp b/src/modules/partition/core/KPMHelpers.cpp index 0265a17e5..c3d4c07cc 100644 --- a/src/modules/partition/core/KPMHelpers.cpp +++ b/src/modules/partition/core/KPMHelpers.cpp @@ -21,7 +21,9 @@ #include "core/KPMHelpers.h" #include "core/PartitionInfo.h" -#include "core/PartitionIterator.h" + +#include "partition/PartitionIterator.h" +#include "utils/Logger.h" // KPMcore #include @@ -30,47 +32,11 @@ #include #include -#include "utils/Logger.h" - -#include - +using CalamaresUtils::Partition::PartitionIterator; namespace KPMHelpers { -static bool s_KPMcoreInited = false; - -bool -initKPMcore() -{ - if ( s_KPMcoreInited ) - return true; - - QByteArray backendName = qgetenv( "KPMCORE_BACKEND" ); - if ( !CoreBackendManager::self()->load( backendName.isEmpty() ? CoreBackendManager::defaultBackendName() : backendName ) ) - { - cWarning() << "Failed to load backend plugin" << backendName; - return false; - } - s_KPMcoreInited = true; - return true; -} - - -bool -isPartitionFreeSpace( Partition* partition ) -{ - return partition->roles().has( PartitionRole::Unallocated ); -} - - -bool -isPartitionNew( Partition* partition ) -{ - return partition->state() == KPM_PARTITION_STATE(New); -} - - Partition* findPartitionByMountPoint( const QList< Device* >& devices, const QString& mountPoint ) { @@ -82,33 +48,6 @@ findPartitionByMountPoint( const QList< Device* >& devices, const QString& mount } -Partition* -findPartitionByPath( const QList< Device* >& devices, const QString& path ) -{ - if ( path.simplified().isEmpty() ) - return nullptr; - - for ( auto device : devices ) - for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it ) - if ( ( *it )->partitionPath() == path.simplified() ) - return *it; - return nullptr; -} - - -QList< Partition* > -findPartitions( const QList< Device* >& devices, - std::function< bool ( Partition* ) > criterionFunction ) -{ - QList< Partition* > results; - for ( auto device : devices ) - for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it ) - if ( criterionFunction( *it ) ) - results.append( *it ); - return results; -} - - Partition* createNewPartition( PartitionNode* parent, const Device& device, @@ -197,48 +136,4 @@ clonePartition( Device* device, Partition* partition ) partition->activeFlags() ); } - -QString -prettyNameForFileSystemType( FileSystem::Type t ) -{ - switch ( t ) - { - case FileSystem::Unknown: - return QObject::tr( "unknown" ); - case FileSystem::Extended: - return QObject::tr( "extended" ); - case FileSystem::Unformatted: - return QObject::tr( "unformatted" ); - case FileSystem::LinuxSwap: - return QObject::tr( "swap" ); - case FileSystem::Fat16: - case FileSystem::Fat32: - case FileSystem::Ntfs: - case FileSystem::Xfs: - case FileSystem::Jfs: - case FileSystem::Hfs: - case FileSystem::Ufs: - case FileSystem::Hpfs: - case FileSystem::Luks: - case FileSystem::Ocfs2: - case FileSystem::Zfs: - case FileSystem::Nilfs2: - return FileSystem::nameForType( t ).toUpper(); - case FileSystem::ReiserFS: - return "ReiserFS"; - case FileSystem::Reiser4: - return "Reiser4"; - case FileSystem::HfsPlus: - return "HFS+"; - case FileSystem::Btrfs: - return "Btrfs"; - case FileSystem::Exfat: - return "exFAT"; - case FileSystem::Lvm2_PV: - return "LVM PV"; - default: - return FileSystem::nameForType( t ); - } -} - } // namespace diff --git a/src/modules/partition/core/KPMHelpers.h b/src/modules/partition/core/KPMHelpers.h index bb510cafb..f2934c4eb 100644 --- a/src/modules/partition/core/KPMHelpers.h +++ b/src/modules/partition/core/KPMHelpers.h @@ -34,7 +34,7 @@ class Partition; class PartitionNode; class PartitionRole; -#ifdef WITH_KPMCORE331API +#if defined( WITH_KPMCORE4API ) #define KPM_PARTITION_FLAG(x) PartitionTable::Flag::x #define KPM_PARTITION_STATE(x) Partition::State::x #define KPM_PARTITION_FLAG_ESP PartitionTable::Flag::Boot @@ -50,46 +50,12 @@ class PartitionRole; namespace KPMHelpers { -/** - * Thin wrapper on top of CoreBackendManager. Hides things like initializing the - * Config instance or instantiating the backend. - * - * Initialize PartitionManager Config object and load a PartitionManager - * backend. It loads the "libparted" plugin by default, but this can be - * overloaded by settings the environment variable KPMCORE_BACKEND. Setting it to - * "dummy" will load the dummy plugin instead. - * - * @return true if initialization was successful. - */ -bool initKPMcore(); - -bool isPartitionFreeSpace( Partition* ); - -/** - * Returns true if the partition is planned to be created by the installer as - * opposed to already existing on the disk. - */ -bool isPartitionNew( Partition* ); - /** * Iterates on all devices and return the first partition which is associated * with mountPoint. This uses PartitionInfo::mountPoint(), not Partition::mountPoint() */ Partition* findPartitionByMountPoint( const QList< Device* >& devices, const QString& mountPoint ); -/** - * Iterates on all devices and partitions and returns a pointer to the Partition object - * for the given path, or nullptr if a Partition for the given path cannot be found. - */ -Partition* findPartitionByPath( const QList< Device* >& devices, const QString& path ); - -/** - * Iterates on all devices and partitions and returns a list of pointers to the Partition - * objects that satisfy the conditions defined in the criterion function. - */ -QList< Partition* > findPartitions( const QList< Device* >& devices, - std::function< bool ( Partition* ) > criterionFunction ); - /** * Helper function to create a new Partition object (does not create anything * on the disk) associated with a FileSystem. @@ -113,8 +79,6 @@ Partition* createNewEncryptedPartition( PartitionNode* parent, Partition* clonePartition( Device* device, Partition* partition ); -QString prettyNameForFileSystemType( FileSystem::Type t ); - static inline QString untranslatedFS( FileSystem& fs ) { diff --git a/src/modules/partition/core/PartUtils.cpp b/src/modules/partition/core/PartUtils.cpp index 94630b472..b1eee4cef 100644 --- a/src/modules/partition/core/PartUtils.cpp +++ b/src/modules/partition/core/PartUtils.cpp @@ -25,21 +25,26 @@ #include "core/DeviceModel.h" #include "core/KPMHelpers.h" #include "core/PartitionInfo.h" -#include "core/PartitionIterator.h" + +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "partition/Mount.h" +#include "partition/PartitionIterator.h" +#include "partition/PartitionQuery.h" +#include "utils/CalamaresUtilsSystem.h" +#include "utils/Logger.h" #include #include #include #include -#include -#include -#include -#include - #include #include +using CalamaresUtils::Partition::isPartitionFreeSpace; +using CalamaresUtils::Partition::isPartitionNew; + namespace PartUtils { @@ -132,7 +137,7 @@ canBeResized( Partition* candidate ) return false; } - if ( KPMHelpers::isPartitionFreeSpace( candidate ) ) + if ( isPartitionFreeSpace( candidate ) ) { cDebug() << Logger::SubEntry << "NO, partition is free space"; return false; @@ -205,7 +210,7 @@ canBeResized( PartitionCoreModule* core, const QString& partitionPath ) for ( int i = 0; i < dm->rowCount(); ++i ) { Device* dev = dm->deviceForIndex( dm->index( i ) ); - Partition* candidate = KPMHelpers::findPartitionByPath( { dev }, partitionWithOs ); + Partition* candidate = CalamaresUtils::Partition::findPartitionByPath( { dev }, partitionWithOs ); if ( candidate ) { return canBeResized( candidate ); @@ -241,13 +246,11 @@ lookForFstabEntries( const QString& partitionPath ) << "for fstab (fs=" << r.getOutput() << ')'; FstabEntryList fstabEntries; - QTemporaryDir mountsDir; - mountsDir.setAutoRemove( false ); - int exit = QProcess::execute( "mount", { "-o", mountOptions.join(','), partitionPath, mountsDir.path() } ); - if ( !exit ) // if all is well + CalamaresUtils::Partition::TemporaryMount mount( partitionPath, QString(), mountOptions.join(',') ); + if ( mount.isValid() ) { - QFile fstabFile( mountsDir.path() + "/etc/fstab" ); + QFile fstabFile( mount.path() + "/etc/fstab" ); cDebug() << Logger::SubEntry << "reading" << fstabFile.fileName(); @@ -265,9 +268,6 @@ lookForFstabEntries( const QString& partitionPath ) } else cWarning() << "Could not read fstab from mounted fs"; - - if ( QProcess::execute( "umount", { "-R", mountsDir.path() } ) ) - cWarning() << "Could not unmount" << mountsDir.path(); } else cWarning() << "Could not mount existing fs"; diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp index 4b23c86e4..cd5d009f0 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -27,7 +27,6 @@ #include "core/DeviceList.h" #include "core/DeviceModel.h" #include "core/PartitionInfo.h" -#include "core/PartitionIterator.h" #include "core/PartitionModel.h" #include "core/KPMHelpers.h" #include "core/PartUtils.h" @@ -45,12 +44,13 @@ #include "jobs/ResizeVolumeGroupJob.h" #include "jobs/SetPartitionFlagsJob.h" -#include "utils/Variant.h" - #ifdef DEBUG_PARTITION_LAME #include "JobExample.h" #endif +#include "partition/PartitionIterator.h" +#include "partition/PartitionQuery.h" #include "utils/Logger.h" +#include "utils/Variant.h" // KPMcore #include @@ -70,6 +70,9 @@ #include #include +using CalamaresUtils::Partition::PartitionIterator; +using CalamaresUtils::Partition::isPartitionFreeSpace; +using CalamaresUtils::Partition::isPartitionNew; PartitionCoreModule::RefreshHelper::RefreshHelper(PartitionCoreModule* module) : m_module( module ) @@ -144,7 +147,7 @@ PartitionCoreModule::PartitionCoreModule( QObject* parent ) , m_deviceModel( new DeviceModel( this ) ) , m_bootLoaderModel( new BootLoaderModel( this ) ) { - if ( !KPMHelpers::initKPMcore() ) + if ( !m_kpmcore ) qFatal( "Failed to initialize KPMcore backend" ); } @@ -395,7 +398,7 @@ PartitionCoreModule::deletePartition( Device* device, Partition* partition ) // deleting them, so let's play it safe and keep our own list. QList< Partition* > lst; for ( auto childPartition : partition->children() ) - if ( !KPMHelpers::isPartitionFreeSpace( childPartition ) ) + if ( !isPartitionFreeSpace( childPartition ) ) lst << childPartition; for ( auto childPartition : lst ) @@ -653,7 +656,7 @@ PartitionCoreModule::scanForEfiSystemPartitions() } QList< Partition* > efiSystemPartitions = - KPMHelpers::findPartitions( devices, PartUtils::isEfiBootable ); + CalamaresUtils::Partition::findPartitions( devices, PartUtils::isEfiBootable ); if ( efiSystemPartitions.isEmpty() ) cWarning() << "system is EFI but no EFI system partitions found."; @@ -687,14 +690,9 @@ PartitionCoreModule::scanForLVMPVs() #if defined( WITH_KPMCORE4API ) VolumeManagerDevice::scanDevices( physicalDevices ); for ( auto p : LVM::pvList::list() ) -#else -#if defined( WITH_KPMCORE331API ) - LvmDevice::scanSystemLVM( physicalDevices ); - for ( auto p : LVM::pvList::list() ) #else LvmDevice::scanSystemLVM( physicalDevices ); for ( auto p : LVM::pvList ) -#endif #endif { m_lvmPVs << p.partition().data(); @@ -728,7 +726,7 @@ PartitionCoreModule::scanForLVMPVs() if ( innerFS && innerFS->type() == FileSystem::Type::Lvm2_PV ) m_lvmPVs << p; } -#ifdef WITH_KPMCORE4API +#if defined( WITH_KPMCORE4API ) else if ( p->fileSystem().type() == FileSystem::Type::Luks2 ) { // Encrypted LVM PVs diff --git a/src/modules/partition/core/PartitionCoreModule.h b/src/modules/partition/core/PartitionCoreModule.h index 7faf67863..aaae67bab 100644 --- a/src/modules/partition/core/PartitionCoreModule.h +++ b/src/modules/partition/core/PartitionCoreModule.h @@ -26,6 +26,7 @@ #include "core/PartitionModel.h" #include "Job.h" +#include "partition/KPMManager.h" // KPMcore #include @@ -235,6 +236,8 @@ Q_SIGNALS: void deviceReverted( Device* device ); private: + CalamaresUtils::Partition::KPMManager m_kpmcore; + void refreshAfterModelChange(); /** diff --git a/src/modules/partition/core/PartitionModel.cpp b/src/modules/partition/core/PartitionModel.cpp index 8b13ab0a0..db3be50a6 100644 --- a/src/modules/partition/core/PartitionModel.cpp +++ b/src/modules/partition/core/PartitionModel.cpp @@ -22,6 +22,9 @@ #include "core/ColorUtils.h" #include "core/PartitionInfo.h" #include "core/KPMHelpers.h" + +#include "partition/FileSystem.h" +#include "partition/PartitionQuery.h" #include "utils/Logger.h" // CalaPM @@ -36,6 +39,9 @@ // Qt #include +using CalamaresUtils::Partition::isPartitionFreeSpace; +using CalamaresUtils::Partition::isPartitionNew; + //- ResetHelper -------------------------------------------- PartitionModel::ResetHelper::ResetHelper( PartitionModel* model ) : m_model( model ) @@ -140,17 +146,17 @@ PartitionModel::data( const QModelIndex& index, int role ) const int col = index.column(); if ( col == NameColumn ) { - if ( KPMHelpers::isPartitionFreeSpace( partition ) ) + if ( isPartitionFreeSpace( partition ) ) return tr( "Free Space" ); else { - return KPMHelpers::isPartitionNew( partition ) + return isPartitionNew( partition ) ? tr( "New partition" ) : partition->partitionPath(); } } if ( col == FileSystemColumn ) - return KPMHelpers::prettyNameForFileSystemType( partition->fileSystem().type() ); + return CalamaresUtils::Partition::prettyNameForFileSystemType( partition->fileSystem().type() ); if ( col == MountPointColumn ) return PartitionInfo::mountPoint( partition ); if ( col == SizeColumn ) @@ -172,16 +178,16 @@ PartitionModel::data( const QModelIndex& index, int role ) const QString name; if ( col == NameColumn ) { - if ( KPMHelpers::isPartitionFreeSpace( partition ) ) + if ( isPartitionFreeSpace( partition ) ) name = tr( "Free Space" ); else { - name = KPMHelpers::isPartitionNew( partition ) + name = isPartitionNew( partition ) ? tr( "New partition" ) : partition->partitionPath(); } } - QString prettyFileSystem = KPMHelpers::prettyNameForFileSystemType( partition->fileSystem().type() ); + QString prettyFileSystem = CalamaresUtils::Partition::prettyNameForFileSystemType( partition->fileSystem().type() ); qint64 size = ( partition->lastSector() - partition->firstSector() + 1 ) * m_device->logicalSize(); QString prettySize = KFormat().formatByteSize( size ); return QVariant(name + " " + prettyFileSystem + " " + prettySize); @@ -189,10 +195,10 @@ PartitionModel::data( const QModelIndex& index, int role ) const case SizeRole: return ( partition->lastSector() - partition->firstSector() + 1 ) * m_device->logicalSize(); case IsFreeSpaceRole: - return KPMHelpers::isPartitionFreeSpace( partition ); + return isPartitionFreeSpace( partition ); case IsPartitionNewRole: - return KPMHelpers::isPartitionNew( partition ); + return isPartitionNew( partition ); case FileSystemLabelRole: if ( partition->fileSystem().supportGetLabel() != FileSystem::cmdSupportNone && diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index 5e8260dec..aebf9a7f6 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -28,7 +28,6 @@ #include "core/PartitionActions.h" #include "core/PartitionCoreModule.h" #include "core/PartitionInfo.h" -#include "core/PartitionIterator.h" #include "core/PartitionModel.h" #include "BootInfoWidget.h" @@ -40,14 +39,16 @@ #include "ReplaceWidget.h" #include "ScanningDialog.h" -#include "utils/CalamaresUtilsGui.h" +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "partition/PartitionIterator.h" +#include "partition/PartitionQuery.h" #include "utils/Logger.h" #include "utils/Retranslator.h" #include "utils/Units.h" #include "Branding.h" -#include "GlobalStorage.h" -#include "JobQueue.h" +#include "utils/CalamaresUtilsGui.h" #include #include @@ -65,6 +66,9 @@ #include using PartitionActions::Choices::SwapChoice; +using CalamaresUtils::Partition::PartitionIterator; +using CalamaresUtils::Partition::isPartitionFreeSpace; +using CalamaresUtils::Partition::findPartitionByPath; /** @brief Given a set of swap choices, return a sensible value from it. * @@ -691,7 +695,7 @@ ChoicePage::doAlongsideApply() for ( int i = 0; i < dm->rowCount(); ++i ) { Device* dev = dm->deviceForIndex( dm->index( i ) ); - Partition* candidate = KPMHelpers::findPartitionByPath( { dev }, path ); + Partition* candidate = findPartitionByPath( { dev }, path ); if ( candidate ) { qint64 firstSector = candidate->firstSector(); @@ -754,7 +758,7 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) Partition* selectedPartition = static_cast< Partition* >( current.data( PartitionModel::PartitionPtrRole ) .value< void* >() ); - if ( KPMHelpers::isPartitionFreeSpace( selectedPartition ) ) + if ( isPartitionFreeSpace( selectedPartition ) ) { //NOTE: if the selected partition is free space, we don't deal with // a separate /home partition at all because there's no existing @@ -768,7 +772,7 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) if ( parent && parent->roles().has( PartitionRole::Extended ) ) { newRoles = PartitionRole( PartitionRole::Logical ); - newParent = KPMHelpers::findPartitionByPath( { selectedDevice() }, parent->partitionPath() ); + newParent = findPartitionByPath( { selectedDevice() }, parent->partitionPath() ); } } @@ -782,7 +786,7 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) // We can't use the PartitionPtrRole because we need to make changes to the // main DeviceModel, not the immutable copy. QString partPath = current.data( PartitionModel::PartitionPathRole ).toString(); - selectedPartition = KPMHelpers::findPartitionByPath( { selectedDevice() }, + selectedPartition = findPartitionByPath( { selectedDevice() }, partPath ); if ( selectedPartition ) { @@ -805,7 +809,7 @@ ChoicePage::doReplaceSelectedPartition( const QModelIndex& current ) gs->value( "defaultFileSystemType" ).toString(), m_encryptWidget->passphrase() } ); - Partition* homePartition = KPMHelpers::findPartitionByPath( { selectedDevice() }, + Partition* homePartition = findPartitionByPath( { selectedDevice() }, *homePartitionPath ); if ( homePartition && doReuseHomePartition ) diff --git a/src/modules/partition/gui/CreatePartitionDialog.cpp b/src/modules/partition/gui/CreatePartitionDialog.cpp index 926df03a3..f6ef2737b 100644 --- a/src/modules/partition/gui/CreatePartitionDialog.cpp +++ b/src/modules/partition/gui/CreatePartitionDialog.cpp @@ -31,9 +31,10 @@ #include "ui_CreatePartitionDialog.h" -#include "utils/Logger.h" #include "GlobalStorage.h" #include "JobQueue.h" +#include "partition/PartitionQuery.h" +#include "utils/Logger.h" // KPMcore #include @@ -279,7 +280,7 @@ CreatePartitionDialog::checkMountPointSelection() void CreatePartitionDialog::initPartResizerWidget( Partition* partition ) { - QColor color = KPMHelpers::isPartitionFreeSpace( partition ) + QColor color = CalamaresUtils::Partition::isPartitionFreeSpace( partition ) ? ColorUtils::colorForPartitionInFreeSpace( partition ) : ColorUtils::colorForPartition( partition ); m_partitionSizeController->init( m_device, partition, color ); diff --git a/src/modules/partition/gui/PartitionPage.cpp b/src/modules/partition/gui/PartitionPage.cpp index 915f899b2..d2ad49c23 100644 --- a/src/modules/partition/gui/PartitionPage.cpp +++ b/src/modules/partition/gui/PartitionPage.cpp @@ -40,11 +40,13 @@ #include "ui_PartitionPage.h" #include "ui_CreatePartitionTableDialog.h" +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "partition/PartitionQuery.h" #include "utils/Logger.h" #include "utils/Retranslator.h" + #include "Branding.h" -#include "JobQueue.h" -#include "GlobalStorage.h" // KPMcore #include @@ -132,7 +134,7 @@ PartitionPage::updateButtons() Q_ASSERT( model ); Partition* partition = model->partitionForIndex( index ); Q_ASSERT( partition ); - bool isFree = KPMHelpers::isPartitionFreeSpace( partition ); + bool isFree = CalamaresUtils::Partition::isPartitionFreeSpace( partition ); bool isExtended = partition->roles().has( PartitionRole::Extended ); bool isInVG = m_core->isInVG( partition ); @@ -392,7 +394,7 @@ PartitionPage::onEditClicked() Partition* partition = model->partitionForIndex( index ); Q_ASSERT( partition ); - if ( KPMHelpers::isPartitionNew( partition ) ) + if ( CalamaresUtils::Partition::isPartitionNew( partition ) ) updatePartitionToCreate( model->device(), partition ); else editExistingPartition( model->device(), partition ); @@ -452,7 +454,7 @@ PartitionPage::onPartitionViewActivated() // but I don't expect there will be other occurences of triggering the same // action from multiple UI elements in this page, so it does not feel worth // the price. - if ( KPMHelpers::isPartitionFreeSpace( partition ) ) + if ( CalamaresUtils::Partition::isPartitionFreeSpace( partition ) ) m_ui->createButton->click(); else m_ui->editButton->click(); diff --git a/src/modules/partition/gui/PartitionSplitterWidget.cpp b/src/modules/partition/gui/PartitionSplitterWidget.cpp index 0281ab32c..bcc80b65a 100644 --- a/src/modules/partition/gui/PartitionSplitterWidget.cpp +++ b/src/modules/partition/gui/PartitionSplitterWidget.cpp @@ -19,10 +19,12 @@ #include "PartitionSplitterWidget.h" #include "core/ColorUtils.h" -#include "core/PartitionIterator.h" #include "core/KPMHelpers.h" +#include "partition/PartitionIterator.h" +#include "partition/PartitionQuery.h" #include "utils/Logger.h" + #include "utils/CalamaresUtilsGui.h" #include @@ -33,6 +35,8 @@ #include #include +using CalamaresUtils::Partition::PartitionIterator; + static const int VIEW_HEIGHT = qMax( CalamaresUtils::defaultFontHeight() + 8, // wins out with big fonts int( CalamaresUtils::defaultFontHeight() * 0.6 ) + 22 ); // wins out with small fonts static const int CORNER_RADIUS = 3; @@ -66,7 +70,7 @@ PartitionSplitterWidget::init( Device* dev, bool drawNestedPartitions ) PartitionSplitterItem newItem = { ( *it )->partitionPath(), ColorUtils::colorForPartition( *it ), - KPMHelpers::isPartitionFreeSpace( *it ), + CalamaresUtils::Partition::isPartitionFreeSpace( *it ), ( *it )->capacity(), PartitionSplitterItem::Normal, {} diff --git a/src/modules/partition/gui/PartitionViewStep.cpp b/src/modules/partition/gui/PartitionViewStep.cpp index 1bb7f64fd..fc7f689b5 100644 --- a/src/modules/partition/gui/PartitionViewStep.cpp +++ b/src/modules/partition/gui/PartitionViewStep.cpp @@ -75,7 +75,7 @@ PartitionViewStep::PartitionViewStep( QObject* parent ) m_waitingWidget = new WaitingWidget( QString() ); m_widget->addWidget( m_waitingWidget ); - CALAMARES_RETRANSLATE( qobject_cast< WaitingWidget* >( m_waitingWidget )->setText( tr( "Gathering system information..." ) ); ) + CALAMARES_RETRANSLATE( m_waitingWidget->setText( tr( "Gathering system information..." ) ); ) m_core = new PartitionCoreModule( this ); // Unusable before init is complete! // We're not done loading, but we need the configuration map first. diff --git a/src/modules/partition/gui/PartitionViewStep.h b/src/modules/partition/gui/PartitionViewStep.h index 0a62b3aa3..4a378402c 100644 --- a/src/modules/partition/gui/PartitionViewStep.h +++ b/src/modules/partition/gui/PartitionViewStep.h @@ -35,6 +35,7 @@ class ChoicePage; class PartitionPage; class PartitionCoreModule; class QStackedWidget; +class WaitingWidget; template class QFutureWatcher; @@ -82,7 +83,7 @@ private: ChoicePage* m_choicePage; PartitionPage* m_manualPartitionPage; - QWidget* m_waitingWidget; + WaitingWidget* m_waitingWidget; QFutureWatcher* m_future; QSet< PartitionActions::Choices::SwapChoice > m_swapChoices; diff --git a/src/modules/partition/jobs/ClearMountsJob.cpp b/src/modules/partition/jobs/ClearMountsJob.cpp index 605087147..2678a70a3 100644 --- a/src/modules/partition/jobs/ClearMountsJob.cpp +++ b/src/modules/partition/jobs/ClearMountsJob.cpp @@ -21,7 +21,9 @@ #include "ClearMountsJob.h" #include "core/PartitionInfo.h" -#include "core/PartitionIterator.h" + +#include "partition/Sync.h" +#include "partition/PartitionIterator.h" #include "utils/Logger.h" // KPMcore @@ -33,6 +35,7 @@ #include #include +using CalamaresUtils::Partition::PartitionIterator; ClearMountsJob::ClearMountsJob( Device* device ) : Calamares::Job() @@ -57,25 +60,47 @@ ClearMountsJob::prettyStatusMessage() const } +QStringList +getPartitionsForDevice( const QString& deviceName ) +{ + QStringList partitions; + + QFile dev_partitions( "/proc/partitions" ); + if ( dev_partitions.open( QFile::ReadOnly ) ) + { + cDebug() << "Reading from" << dev_partitions.fileName(); + QTextStream in( &dev_partitions ); + (void) in.readLine(); // That's the header line, skip it + while ( !in.atEnd() ) + { + // The fourth column (index from 0, so index 3) is the name of the device; + // keep it if it is followed by something. + QStringList columns = in.readLine().split( ' ', QString::SkipEmptyParts ); + if ( ( columns.count() >= 4 ) && ( columns[3].startsWith( deviceName ) ) && ( columns[3] != deviceName ) ) + { + partitions.append( columns[3] ); + } + } + } + else + { + cDebug() << "Could not open" << dev_partitions.fileName(); + } + + return partitions; +} + Calamares::JobResult ClearMountsJob::exec() { - QStringList goodNews; + CalamaresUtils::Partition::Syncer s; QString deviceName = m_device->deviceNode().split( '/' ).last(); + QStringList goodNews; QProcess process; - process.setProgram( "sh" ); - process.setArguments( { - "-c", - QString( "echo $(awk '{print $4}' /proc/partitions | sed -e '/name/d' -e '/^$/d' -e '/[1-9]/!d' | grep %1)" ) - .arg( deviceName ) - } ); - process.start(); - process.waitForFinished(); - const QString partitions = process.readAllStandardOutput(); - const QStringList partitionsList = partitions.simplified().split( ' ' ); + QStringList partitionsList = getPartitionsForDevice( deviceName ); // Build a list of partitions of type 82 (Linux swap / Solaris). // We then need to clear them just in case they contain something resumable from a diff --git a/src/modules/partition/jobs/ClearMountsJob.h b/src/modules/partition/jobs/ClearMountsJob.h index 26514913e..6b98aac08 100644 --- a/src/modules/partition/jobs/ClearMountsJob.h +++ b/src/modules/partition/jobs/ClearMountsJob.h @@ -19,7 +19,7 @@ #ifndef CLEARMOUNTSJOB_H #define CLEARMOUNTSJOB_H -#include +#include "Job.h" class Device; diff --git a/src/modules/partition/jobs/ClearTempMountsJob.h b/src/modules/partition/jobs/ClearTempMountsJob.h index 36adca91b..d7b2c55f4 100644 --- a/src/modules/partition/jobs/ClearTempMountsJob.h +++ b/src/modules/partition/jobs/ClearTempMountsJob.h @@ -19,7 +19,7 @@ #ifndef CLEARTEMPMOUNTSJOB_H #define CLEARTEMPMOUNTSJOB_H -#include +#include "Job.h" class Device; diff --git a/src/modules/partition/jobs/CreatePartitionJob.h b/src/modules/partition/jobs/CreatePartitionJob.h index e25c74241..fe4ab2203 100644 --- a/src/modules/partition/jobs/CreatePartitionJob.h +++ b/src/modules/partition/jobs/CreatePartitionJob.h @@ -20,7 +20,7 @@ #ifndef CREATEPARTITIONJOB_H #define CREATEPARTITIONJOB_H -#include +#include "PartitionJob.h" class Device; class Partition; diff --git a/src/modules/partition/jobs/CreatePartitionTableJob.cpp b/src/modules/partition/jobs/CreatePartitionTableJob.cpp index 3465a0e2d..b18f56a04 100644 --- a/src/modules/partition/jobs/CreatePartitionTableJob.cpp +++ b/src/modules/partition/jobs/CreatePartitionTableJob.cpp @@ -20,21 +20,22 @@ #include "jobs/CreatePartitionTableJob.h" -#include "core/PartitionIterator.h" - +#include "partition/PartitionIterator.h" #include "utils/Logger.h" // KPMcore -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include // Qt #include +using CalamaresUtils::Partition::PartitionIterator; + CreatePartitionTableJob::CreatePartitionTableJob( Device* device, PartitionTable::TableType type ) : m_device( device ) , m_type( type ) @@ -99,7 +100,7 @@ CreatePartitionTableJob::exec() cDebug() << "lsblk:\n" << lsblk.readAllStandardOutput(); QProcess mount; - mount.setProgram( "mount" ); + mount.setProgram( "mount" ); // Debug output only, not mounting something mount.setProcessChannelMode( QProcess::MergedChannels ); mount.start(); mount.waitForFinished(); diff --git a/src/modules/partition/jobs/CreatePartitionTableJob.h b/src/modules/partition/jobs/CreatePartitionTableJob.h index 38ef5365c..d4f65ba51 100644 --- a/src/modules/partition/jobs/CreatePartitionTableJob.h +++ b/src/modules/partition/jobs/CreatePartitionTableJob.h @@ -20,7 +20,8 @@ #ifndef CREATEPARTITIONTABLEJOB_H #define CREATEPARTITIONTABLEJOB_H -#include +#include "Job.h" +#include "partition/KPMManager.h" // KPMcore #include @@ -50,6 +51,7 @@ public: } private: + CalamaresUtils::Partition::KPMManager m_kpmcore; Device* m_device; PartitionTable::TableType m_type; PartitionTable* createTable(); diff --git a/src/modules/partition/jobs/CreateVolumeGroupJob.h b/src/modules/partition/jobs/CreateVolumeGroupJob.h index 6f85eaab8..dfdf0319f 100644 --- a/src/modules/partition/jobs/CreateVolumeGroupJob.h +++ b/src/modules/partition/jobs/CreateVolumeGroupJob.h @@ -19,12 +19,13 @@ #ifndef CREATEVOLUMEGROUPJOB_H #define CREATEVOLUMEGROUPJOB_H -#include - -#include +#include "Job.h" +#include "partition/KPMManager.h" #include +class Partition; + class CreateVolumeGroupJob : public Calamares::Job { Q_OBJECT @@ -40,6 +41,7 @@ public: void undoPreview(); private: + CalamaresUtils::Partition::KPMManager m_kpmcore; QString m_vgName; QVector< const Partition* > m_pvList; qint32 m_peSize; diff --git a/src/modules/partition/jobs/DeactivateVolumeGroupJob.h b/src/modules/partition/jobs/DeactivateVolumeGroupJob.h index 17be7cdef..ff6569b10 100644 --- a/src/modules/partition/jobs/DeactivateVolumeGroupJob.h +++ b/src/modules/partition/jobs/DeactivateVolumeGroupJob.h @@ -20,6 +20,7 @@ #define DEACTIVATEVOLUMEGROUPJOB_H #include "Job.h" +#include "partition/KPMManager.h" class LvmDevice; @@ -35,6 +36,7 @@ public: Calamares::JobResult exec() override; private: + CalamaresUtils::Partition::KPMManager m_kpmcore; LvmDevice* m_device; }; diff --git a/src/modules/partition/jobs/DeletePartitionJob.cpp b/src/modules/partition/jobs/DeletePartitionJob.cpp index 5cd4a08ea..07880ce65 100644 --- a/src/modules/partition/jobs/DeletePartitionJob.cpp +++ b/src/modules/partition/jobs/DeletePartitionJob.cpp @@ -21,12 +21,12 @@ #include "jobs/DeletePartitionJob.h" // KPMcore -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include DeletePartitionJob::DeletePartitionJob( Device* device, Partition* partition ) : PartitionJob( partition ) diff --git a/src/modules/partition/jobs/DeletePartitionJob.h b/src/modules/partition/jobs/DeletePartitionJob.h index 805689cc0..cdc0b7f63 100644 --- a/src/modules/partition/jobs/DeletePartitionJob.h +++ b/src/modules/partition/jobs/DeletePartitionJob.h @@ -20,7 +20,7 @@ #ifndef DELETEPARTITIONJOB_H #define DELETEPARTITIONJOB_H -#include +#include "PartitionJob.h" class Device; class Partition; diff --git a/src/modules/partition/jobs/FillGlobalStorageJob.cpp b/src/modules/partition/jobs/FillGlobalStorageJob.cpp index 12faaf969..940c712d1 100644 --- a/src/modules/partition/jobs/FillGlobalStorageJob.cpp +++ b/src/modules/partition/jobs/FillGlobalStorageJob.cpp @@ -18,22 +18,25 @@ * along with Calamares. If not, see . */ -#include "jobs/FillGlobalStorageJob.h" +#include "FillGlobalStorageJob.h" #include "core/KPMHelpers.h" #include "core/PartitionInfo.h" -#include "core/PartitionIterator.h" #include "Branding.h" #include "GlobalStorage.h" #include "JobQueue.h" + +#include "partition/PartitionIterator.h" #include "utils/Logger.h" +#include "Branding.h" + // KPMcore -#include -#include -#include -#include +#include +#include +#include +#include // Qt #include @@ -43,6 +46,7 @@ using KPMHelpers::untranslatedFS; using KPMHelpers::userVisibleFS; +using CalamaresUtils::Partition::PartitionIterator; typedef QHash< QString, QString > UuidForPartitionHash; diff --git a/src/modules/partition/jobs/FillGlobalStorageJob.h b/src/modules/partition/jobs/FillGlobalStorageJob.h index 357d939a2..c2bf80a06 100644 --- a/src/modules/partition/jobs/FillGlobalStorageJob.h +++ b/src/modules/partition/jobs/FillGlobalStorageJob.h @@ -20,7 +20,7 @@ #ifndef FILLGLOBALSTORAGEJOB_H #define FILLGLOBALSTORAGEJOB_H -#include +#include "Job.h" // Qt #include diff --git a/src/modules/partition/jobs/FormatPartitionJob.cpp b/src/modules/partition/jobs/FormatPartitionJob.cpp index c877343c3..5798a0ad3 100644 --- a/src/modules/partition/jobs/FormatPartitionJob.cpp +++ b/src/modules/partition/jobs/FormatPartitionJob.cpp @@ -24,12 +24,12 @@ #include "utils/Logger.h" // KPMcore -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include using KPMHelpers::untranslatedFS; using KPMHelpers::userVisibleFS; diff --git a/src/modules/partition/jobs/FormatPartitionJob.h b/src/modules/partition/jobs/FormatPartitionJob.h index 683deb66e..9ce4a0677 100644 --- a/src/modules/partition/jobs/FormatPartitionJob.h +++ b/src/modules/partition/jobs/FormatPartitionJob.h @@ -20,7 +20,7 @@ #ifndef FORMATPARTITIONJOB_H #define FORMATPARTITIONJOB_H -#include +#include "PartitionJob.h" class Device; class Partition; diff --git a/src/modules/partition/jobs/PartitionJob.cpp b/src/modules/partition/jobs/PartitionJob.cpp index 1da8b0ba0..6adf99122 100644 --- a/src/modules/partition/jobs/PartitionJob.cpp +++ b/src/modules/partition/jobs/PartitionJob.cpp @@ -16,7 +16,7 @@ * along with Calamares. If not, see . */ -#include +#include "PartitionJob.h" PartitionJob::PartitionJob( Partition* partition ) : m_partition( partition ) diff --git a/src/modules/partition/jobs/PartitionJob.h b/src/modules/partition/jobs/PartitionJob.h index 61245203c..4cb5e5db6 100644 --- a/src/modules/partition/jobs/PartitionJob.h +++ b/src/modules/partition/jobs/PartitionJob.h @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2014, Aurélien Gâteau + * Copyright 2019, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,12 +20,13 @@ #ifndef PARTITIONJOB_H #define PARTITIONJOB_H -#include +#include "Job.h" +#include "partition/KPMManager.h" class Partition; /** - * Base class for jobs which affect a partition. + * Base class for jobs which affect a partition and which use KPMCore. */ class PartitionJob : public Calamares::Job { @@ -46,6 +48,7 @@ public slots: void iprogress( int percent ); protected: + CalamaresUtils::Partition::KPMManager m_kpmcore; Partition* m_partition; }; diff --git a/src/modules/partition/jobs/RemoveVolumeGroupJob.h b/src/modules/partition/jobs/RemoveVolumeGroupJob.h index 009e6f44d..8687eb544 100644 --- a/src/modules/partition/jobs/RemoveVolumeGroupJob.h +++ b/src/modules/partition/jobs/RemoveVolumeGroupJob.h @@ -19,7 +19,8 @@ #ifndef REMOVEVOLUMEGROUPJOB_H #define REMOVEVOLUMEGROUPJOB_H -#include +#include "Job.h" +#include "partition/KPMManager.h" class LvmDevice; @@ -35,6 +36,7 @@ public: Calamares::JobResult exec() override; private: + CalamaresUtils::Partition::KPMManager m_kpmcore; LvmDevice* m_device; }; diff --git a/src/modules/partition/jobs/ResizePartitionJob.cpp b/src/modules/partition/jobs/ResizePartitionJob.cpp index bac4c7a6c..ebc47d286 100644 --- a/src/modules/partition/jobs/ResizePartitionJob.cpp +++ b/src/modules/partition/jobs/ResizePartitionJob.cpp @@ -23,9 +23,9 @@ #include "utils/Units.h" // KPMcore -#include -#include -#include +#include +#include +#include using CalamaresUtils::BytesToMiB; diff --git a/src/modules/partition/jobs/ResizePartitionJob.h b/src/modules/partition/jobs/ResizePartitionJob.h index 9e6d39943..f8413f214 100644 --- a/src/modules/partition/jobs/ResizePartitionJob.h +++ b/src/modules/partition/jobs/ResizePartitionJob.h @@ -20,7 +20,7 @@ #ifndef RESIZEPARTITIONJOB_H #define RESIZEPARTITIONJOB_H -#include +#include "PartitionJob.h" class Device; class Partition; diff --git a/src/modules/partition/jobs/ResizeVolumeGroupJob.h b/src/modules/partition/jobs/ResizeVolumeGroupJob.h index fb0ff715b..1519dfa9d 100644 --- a/src/modules/partition/jobs/ResizeVolumeGroupJob.h +++ b/src/modules/partition/jobs/ResizeVolumeGroupJob.h @@ -19,7 +19,8 @@ #ifndef RESIZEVOLUMEGROUPJOB_H #define RESIZEVOLUMEGROUPJOB_H -#include +#include "Job.h" +#include "partition/KPMManager.h" #include @@ -42,6 +43,7 @@ private: QString targetPartitions() const; private: + CalamaresUtils::Partition::KPMManager m_kpmcore; LvmDevice* m_device; QVector< const Partition* > m_partitionList; }; diff --git a/src/modules/partition/jobs/SetPartitionFlagsJob.cpp b/src/modules/partition/jobs/SetPartitionFlagsJob.cpp index 09380a24c..4e7636e2d 100644 --- a/src/modules/partition/jobs/SetPartitionFlagsJob.cpp +++ b/src/modules/partition/jobs/SetPartitionFlagsJob.cpp @@ -27,11 +27,11 @@ #include "utils/Units.h" // KPMcore -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include using CalamaresUtils::BytesToMiB; using KPMHelpers::untranslatedFS; diff --git a/src/modules/partition/jobs/SetPartitionFlagsJob.h b/src/modules/partition/jobs/SetPartitionFlagsJob.h index 464ad0c6b..30cad9a21 100644 --- a/src/modules/partition/jobs/SetPartitionFlagsJob.h +++ b/src/modules/partition/jobs/SetPartitionFlagsJob.h @@ -22,7 +22,7 @@ #ifndef SETPARTITIONFLAGSJOB_H #define SETPARTITIONFLAGSJOB_H -#include +#include "PartitionJob.h" #include diff --git a/src/modules/partition/tests/CMakeLists.txt b/src/modules/partition/tests/CMakeLists.txt index ac3968df9..804dd9277 100644 --- a/src/modules/partition/tests/CMakeLists.txt +++ b/src/modules/partition/tests/CMakeLists.txt @@ -1,18 +1,9 @@ find_package( Qt5 COMPONENTS Gui REQUIRED ) +# Roundabout way of saying .. set( PartitionModule_SOURCE_DIR .. ) - -set( partitionjobtests_SRCS - ${PartitionModule_SOURCE_DIR}/core/KPMHelpers.cpp - ${PartitionModule_SOURCE_DIR}/core/PartitionInfo.cpp - ${PartitionModule_SOURCE_DIR}/core/PartitionIterator.cpp - ${PartitionModule_SOURCE_DIR}/jobs/CreatePartitionJob.cpp - ${PartitionModule_SOURCE_DIR}/jobs/CreatePartitionTableJob.cpp - ${PartitionModule_SOURCE_DIR}/jobs/DeletePartitionJob.cpp - ${PartitionModule_SOURCE_DIR}/jobs/PartitionJob.cpp - ${PartitionModule_SOURCE_DIR}/jobs/ResizePartitionJob.cpp - PartitionJobTests.cpp -) +# This is set by parent CMakeLists.txt +# set( _partition_defs ) include_directories( ${Qt5Gui_INCLUDE_DIRS} @@ -22,7 +13,16 @@ include_directories( ) if( ECM_FOUND AND BUILD_TESTING ) - ecm_add_test( ${partitionjobtests_SRCS} + ecm_add_test( + ${PartitionModule_SOURCE_DIR}/core/KPMHelpers.cpp + ${PartitionModule_SOURCE_DIR}/core/PartitionInfo.cpp + ${PartitionModule_SOURCE_DIR}/jobs/CreatePartitionJob.cpp + ${PartitionModule_SOURCE_DIR}/jobs/CreatePartitionTableJob.cpp + ${PartitionModule_SOURCE_DIR}/jobs/DeletePartitionJob.cpp + ${PartitionModule_SOURCE_DIR}/jobs/PartitionJob.cpp + ${PartitionModule_SOURCE_DIR}/jobs/ResizePartitionJob.cpp + PartitionJobTests.cpp + TEST_NAME partitionjobtests LINK_LIBRARIES ${CALAMARES_LIBRARIES} @@ -33,4 +33,20 @@ if( ECM_FOUND AND BUILD_TESTING ) set_target_properties( partitionjobtests PROPERTIES AUTOMOC TRUE ) target_compile_definitions( partitionjobtests PRIVATE ${_partition_defs} ) + + ecm_add_test( + ${PartitionModule_SOURCE_DIR}/jobs/ClearMountsJob.cpp + ClearMountsJobTests.cpp + + TEST_NAME clearmountsjobtests + LINK_LIBRARIES + ${CALAMARES_LIBRARIES} + kpmcore + Qt5::Core + Qt5::Test + ) + + set_target_properties( clearmountsjobtests PROPERTIES AUTOMOC TRUE ) + target_compile_definitions( clearmountsjobtests PRIVATE ${_partition_defs} ) + endif() diff --git a/src/modules/partition/tests/ClearMountsJobTests.cpp b/src/modules/partition/tests/ClearMountsJobTests.cpp new file mode 100644 index 000000000..1f01c4638 --- /dev/null +++ b/src/modules/partition/tests/ClearMountsJobTests.cpp @@ -0,0 +1,66 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * 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 "ClearMountsJobTests.h" + +#include "utils/Logger.h" + +#include + +QTEST_GUILESS_MAIN( ClearMountsJobTests ) + + +/* Not exactly public API */ +QStringList +getPartitionsForDevice( const QString& deviceName ); + +QStringList +getPartitionsForDevice_other(const QString& deviceName) +{ + QProcess process; + process.setProgram( "sh" ); + process.setArguments( { + "-c", + QString( "echo $(awk '{print $4}' /proc/partitions | sed -e '/name/d' -e '/^$/d' -e '/[1-9]/!d' | grep %1)" ) + .arg( deviceName ) + } ); + process.start(); + process.waitForFinished(); + + const QString partitions = process.readAllStandardOutput(); + const QStringList partitionsList = partitions.simplified().split( ' ' ); + + return partitionsList; +} + + +ClearMountsJobTests::ClearMountsJobTests() +{ + Logger::setupLogLevel(6); +} + +void ClearMountsJobTests::testFindPartitions() +{ + QStringList partitions = getPartitionsForDevice( "sda" ); + QStringList other_part = getPartitionsForDevice_other( "sda" ); + + cDebug() << "Initial implementation:" << Logger::DebugList( partitions ); + cDebug() << "Other implementation:" << Logger::DebugList( other_part ); + + QCOMPARE( partitions, other_part ); +} diff --git a/src/modules/partition/tests/ClearMountsJobTests.h b/src/modules/partition/tests/ClearMountsJobTests.h new file mode 100644 index 000000000..0cc2b5c78 --- /dev/null +++ b/src/modules/partition/tests/ClearMountsJobTests.h @@ -0,0 +1,34 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * 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 CLEARMOUNTSJOBTESTS_H +#define CLEARMOUNTSJOBTESTS_H + +#include + +class ClearMountsJobTests : public QObject +{ + Q_OBJECT +public: + ClearMountsJobTests(); + +private Q_SLOTS: + void testFindPartitions(); +}; + +#endif diff --git a/src/modules/partition/tests/PartitionJobTests.cpp b/src/modules/partition/tests/PartitionJobTests.cpp index f3bd8dd13..7684ad7a8 100644 --- a/src/modules/partition/tests/PartitionJobTests.cpp +++ b/src/modules/partition/tests/PartitionJobTests.cpp @@ -19,16 +19,18 @@ #include +#include "partition/KPMManager.h" +#include "partition/PartitionQuery.h" +#include "utils/Logger.h" #include "utils/Units.h" +#include #include #include #include -#include // CalaPM #include -#include #include // Qt @@ -40,6 +42,7 @@ QTEST_GUILESS_MAIN( PartitionJobTests ) using namespace Calamares; using CalamaresUtils::operator""_MiB; +using CalamaresUtils::Partition::isPartitionFreeSpace; class PartitionMounter { @@ -56,15 +59,14 @@ public: ~PartitionMounter() { if ( !m_mounted ) + { return; + } int ret = QProcess::execute( "umount", QStringList() << m_mountPointDir.path() ); QCOMPARE( ret, 0 ); } - QString mountPoint() const - { - return m_mounted ? m_mountPointDir.path() : QString(); - } + QString mountPoint() const { return m_mounted ? m_mountPointDir.path() : QString(); } private: QString m_devicePath; @@ -77,9 +79,9 @@ static QByteArray generateTestData( qint64 size ) { QByteArray ba; - ba.resize( static_cast( size ) ); + ba.resize( static_cast< int >( size ) ); // Fill the array explicitly to keep Valgrind happy - for ( auto it = ba.data() ; it < ba.data() + size ; ++it ) + for ( auto it = ba.data(); it < ba.data() + size; ++it ) { *it = char( rand() & 0xff ); } @@ -102,9 +104,9 @@ writeFile( const QString& path, const QByteArray data ) if ( count < 0 ) { QString msg = QString( "Writing file failed. Only %1 bytes written out of %2. Error: '%3'." ) - .arg( ptr - data.constData() ) - .arg( data.size() ) - .arg( file.errorString() ); + .arg( ptr - data.constData() ) + .arg( data.size() ) + .arg( file.errorString() ); QFAIL( qPrintable( msg ) ); } ptr += count; @@ -114,9 +116,11 @@ writeFile( const QString& path, const QByteArray data ) static Partition* firstFreePartition( PartitionNode* parent ) { - for( auto child : parent->children() ) - if ( KPMHelpers::isPartitionFreeSpace( child ) ) + for ( auto child : parent->children() ) + if ( isPartitionFreeSpace( child ) ) + { return child; + } return nullptr; } @@ -143,7 +147,9 @@ QueueRunner::run() m_queue->start(); QEventLoop loop; while ( !m_finished ) + { loop.processEvents(); + } return m_success; } @@ -161,10 +167,13 @@ QueueRunner::onFailed( const QString& message, const QString& details ) QFAIL( qPrintable( msg ) ); } +CalamaresUtils::Partition::KPMManager* kpmcore = nullptr; + //- PartitionJobTests ------------------------------------------------------------------ PartitionJobTests::PartitionJobTests() : m_runner( &m_queue ) -{} +{ +} void PartitionJobTests::initTestCase() @@ -173,21 +182,27 @@ PartitionJobTests::initTestCase() if ( devicePath.isEmpty() ) { // The 0 is to keep the macro parameters happy - QSKIP( "Skipping test, CALAMARES_TEST_DISK is not set. It should point to a disk which can be safely formatted", 0 ); + QSKIP( "Skipping test, CALAMARES_TEST_DISK is not set. It should point to a disk which can be safely formatted", + 0 ); } - QVERIFY( KPMHelpers::initKPMcore() ); + kpmcore = new CalamaresUtils::Partition::KPMManager(); FileSystemFactory::init(); refreshDevice(); } +void +PartitionJobTests::cleanupTestCase() +{ + delete kpmcore; +} + void PartitionJobTests::refreshDevice() { QString devicePath = qgetenv( "CALAMARES_TEST_DISK" ); - CoreBackend* backend = CoreBackendManager::self()->backend(); - m_device.reset( backend->scanDevice( devicePath ) ); + m_device.reset( kpmcore->backend()->scanDevice( devicePath ) ); QVERIFY( !m_device.isNull() ); } @@ -206,7 +221,7 @@ PartitionJobTests::testPartitionTable() } void -PartitionJobTests::queuePartitionTableCreation( PartitionTable::TableType type) +PartitionJobTests::queuePartitionTableCreation( PartitionTable::TableType type ) { auto job = new CreatePartitionTableJob( m_device.data(), type ); job->updatePreview(); @@ -214,7 +229,10 @@ PartitionJobTests::queuePartitionTableCreation( PartitionTable::TableType type) } CreatePartitionJob* -PartitionJobTests::newCreatePartitionJob( Partition* freeSpacePartition, PartitionRole role, FileSystem::Type type, qint64 size ) +PartitionJobTests::newCreatePartitionJob( Partition* freeSpacePartition, + PartitionRole role, + FileSystem::Type type, + qint64 size ) { Q_ASSERT( freeSpacePartition ); @@ -222,25 +240,27 @@ PartitionJobTests::newCreatePartitionJob( Partition* freeSpacePartition, Partiti qint64 lastSector; if ( size > 0 ) + { lastSector = firstSector + size / m_device->logicalSize(); + } else + { lastSector = freeSpacePartition->lastSector(); - FileSystem* fs = FileSystemFactory::create( type, firstSector, lastSector - ,m_device->logicalSize() - ); + } + FileSystem* fs = FileSystemFactory::create( type, firstSector, lastSector, m_device->logicalSize() ); - Partition* partition = new Partition( - freeSpacePartition->parent(), - *m_device, - role, - fs, firstSector, lastSector, - QString() /* path */, - KPM_PARTITION_FLAG(None) /* availableFlags */, - QString() /* mountPoint */, - false /* mounted */, - KPM_PARTITION_FLAG(None) /* activeFlags */, - KPM_PARTITION_STATE(New) - ); + Partition* partition = new Partition( freeSpacePartition->parent(), + *m_device, + role, + fs, + firstSector, + lastSector, + QString() /* path */, + KPM_PARTITION_FLAG( None ) /* availableFlags */, + QString() /* mountPoint */, + false /* mounted */, + KPM_PARTITION_FLAG( None ) /* activeFlags */, + KPM_PARTITION_STATE( New ) ); return new CreatePartitionJob( m_device.data(), partition ); } @@ -253,7 +273,7 @@ PartitionJobTests::testCreatePartition() freePartition = firstFreePartition( m_device->partitionTable() ); QVERIFY( freePartition ); - job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Primary ), FileSystem::Ext4, 1_MiB); + job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Primary ), FileSystem::Ext4, 1_MiB ); Partition* partition1 = job->partition(); QVERIFY( partition1 ); job->updatePreview(); @@ -261,7 +281,7 @@ PartitionJobTests::testCreatePartition() freePartition = firstFreePartition( m_device->partitionTable() ); QVERIFY( freePartition ); - job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Primary ), FileSystem::LinuxSwap, 1_MiB); + job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Primary ), FileSystem::LinuxSwap, 1_MiB ); Partition* partition2 = job->partition(); QVERIFY( partition2 ); job->updatePreview(); @@ -269,7 +289,7 @@ PartitionJobTests::testCreatePartition() freePartition = firstFreePartition( m_device->partitionTable() ); QVERIFY( freePartition ); - job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Primary ), FileSystem::Fat32, 1_MiB); + job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Primary ), FileSystem::Fat32, 1_MiB ); Partition* partition3 = job->partition(); QVERIFY( partition3 ); job->updatePreview(); @@ -294,7 +314,7 @@ PartitionJobTests::testCreatePartitionExtended() freePartition = firstFreePartition( m_device->partitionTable() ); QVERIFY( freePartition ); - job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Primary ), FileSystem::Ext4, 10_MiB); + job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Primary ), FileSystem::Ext4, 10_MiB ); Partition* partition1 = job->partition(); QVERIFY( partition1 ); job->updatePreview(); @@ -302,14 +322,15 @@ PartitionJobTests::testCreatePartitionExtended() freePartition = firstFreePartition( m_device->partitionTable() ); QVERIFY( freePartition ); - job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Extended ), FileSystem::Extended, 10_MiB); + job = newCreatePartitionJob( + freePartition, PartitionRole( PartitionRole::Extended ), FileSystem::Extended, 10_MiB ); job->updatePreview(); m_queue.enqueue( job_ptr( job ) ); Partition* extendedPartition = job->partition(); freePartition = firstFreePartition( extendedPartition ); QVERIFY( freePartition ); - job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Logical ), FileSystem::Ext4, 0); + job = newCreatePartitionJob( freePartition, PartitionRole( PartitionRole::Logical ), FileSystem::Ext4, 0 ); Partition* partition2 = job->partition(); QVERIFY( partition2 ); job->updatePreview(); @@ -333,10 +354,10 @@ PartitionJobTests::testResizePartition_data() QTest::addColumn< unsigned int >( "newStartMiB" ); QTest::addColumn< unsigned int >( "newSizeMiB" ); - QTest::newRow("grow") << 10 << 50 << 10 << 70; - QTest::newRow("shrink") << 10 << 70 << 10 << 50; - QTest::newRow("moveLeft") << 10 << 50 << 8 << 50; - QTest::newRow("moveRight") << 10 << 50 << 12 << 50; + QTest::newRow( "grow" ) << 10 << 50 << 10 << 70; + QTest::newRow( "shrink" ) << 10 << 70 << 10 << 50; + QTest::newRow( "moveLeft" ) << 10 << 50 << 8 << 50; + QTest::newRow( "moveRight" ) << 10 << 50 << 12 << 50; } void @@ -350,9 +371,9 @@ PartitionJobTests::testResizePartition() const qint64 sectorsPerMiB = 1_MiB / m_device->logicalSize(); qint64 oldFirst = sectorsPerMiB * oldStartMiB; - qint64 oldLast = oldFirst + sectorsPerMiB * oldSizeMiB - 1; + qint64 oldLast = oldFirst + sectorsPerMiB * oldSizeMiB - 1; qint64 newFirst = sectorsPerMiB * newStartMiB; - qint64 newLast = newFirst + sectorsPerMiB * newSizeMiB - 1; + qint64 newLast = newFirst + sectorsPerMiB * newSizeMiB - 1; // Make the test data file smaller than the full size of the partition to // accomodate for the file system overhead @@ -366,15 +387,13 @@ PartitionJobTests::testResizePartition() Partition* freePartition = firstFreePartition( m_device->partitionTable() ); QVERIFY( freePartition ); - Partition* partition = KPMHelpers::createNewPartition( - freePartition->parent(), - *m_device, - PartitionRole( PartitionRole::Primary ), - FileSystem::Ext4, - oldFirst, - oldLast, - KPM_PARTITION_FLAG(None) - ); + Partition* partition = KPMHelpers::createNewPartition( freePartition->parent(), + *m_device, + PartitionRole( PartitionRole::Primary ), + FileSystem::Ext4, + oldFirst, + oldLast, + KPM_PARTITION_FLAG( None ) ); CreatePartitionJob* job = new CreatePartitionJob( m_device.data(), partition ); job->updatePreview(); m_queue.enqueue( job_ptr( job ) ); @@ -386,7 +405,8 @@ PartitionJobTests::testResizePartition() // Write a test file in the partition refreshDevice(); QVERIFY( m_device->partitionTable() ); - Partition* partition = m_device->partitionTable()->findPartitionBySector( oldFirst, PartitionRole( PartitionRole::Primary ) ); + Partition* partition + = m_device->partitionTable()->findPartitionBySector( oldFirst, PartitionRole( PartitionRole::Primary ) ); QVERIFY( partition ); QCOMPARE( partition->firstSector(), oldFirst ); QCOMPARE( partition->lastSector(), oldLast ); @@ -411,7 +431,8 @@ PartitionJobTests::testResizePartition() { refreshDevice(); QVERIFY( m_device->partitionTable() ); - Partition* partition = m_device->partitionTable()->findPartitionBySector( newFirst, PartitionRole( PartitionRole::Primary ) ); + Partition* partition + = m_device->partitionTable()->findPartitionBySector( newFirst, PartitionRole( PartitionRole::Primary ) ); QVERIFY( partition ); QCOMPARE( partition->firstSector(), newFirst ); QCOMPARE( partition->lastSector(), newLast ); diff --git a/src/modules/partition/tests/PartitionJobTests.h b/src/modules/partition/tests/PartitionJobTests.h index 62d5924ea..1aad945e5 100644 --- a/src/modules/partition/tests/PartitionJobTests.h +++ b/src/modules/partition/tests/PartitionJobTests.h @@ -59,6 +59,7 @@ public: private Q_SLOTS: void initTestCase(); + void cleanupTestCase(); void testPartitionTable(); void testCreatePartition(); void testCreatePartitionExtended(); @@ -71,7 +72,8 @@ private: QueueRunner m_runner; void queuePartitionTableCreation( PartitionTable::TableType type ); - CreatePartitionJob* newCreatePartitionJob( Partition* freeSpacePartition, PartitionRole, FileSystem::Type type, qint64 size ); + CreatePartitionJob* + newCreatePartitionJob( Partition* freeSpacePartition, PartitionRole, FileSystem::Type type, qint64 size ); void refreshDevice(); }; diff --git a/src/modules/unpackfs/main.py b/src/modules/unpackfs/main.py index a6ee3455d..66eb563f3 100644 --- a/src/modules/unpackfs/main.py +++ b/src/modules/unpackfs/main.py @@ -274,34 +274,29 @@ class UnpackOperation: def mount_image(self, entry, imgmountdir): """ - Mount given image as loop device. + Mount given @p entry as loop device on @p imgmountdir. A *file* entry (e.g. one with *sourcefs* set to *file*) is not mounted and just ignored. - :param entry: - :param imgmountdir: + :param entry: the entry to mount (source is the important property) + :param imgmountdir: where to mount it + + :returns: None, but throws if the mount failed """ if entry.is_file(): return if os.path.isdir(entry.source): - subprocess.check_call(["mount", - "--bind", entry.source, - imgmountdir]) + r = libcalamares.utils.mount(entry.source, imgmountdir, "", "--bind") elif os.path.isfile(entry.source): - subprocess.check_call(["mount", - entry.source, - imgmountdir, - "-t", entry.sourcefs, - "-o", "loop" - ]) + r = libcalamares.utils.mount(entry.source, imgmountdir, entry.sourcefs, "loop") else: # entry.source is a device - subprocess.check_call(["mount", - entry.source, - imgmountdir, - "-t", entry.sourcefs - ]) + r = libcalamares.utils.mount(entry.source, imgmountdir, entry.sourcefs, "") + + if r != 0: + raise subprocess.CalledProcessError(r, "mount") + def unpack_image(self, entry, imgmountdir): """