2015-06-04 01:29:22 +01:00
/*************************************************************************
* Copyright ( C ) 2010 , 2011 , 2012 by Volker Lanz < vl @ fidra . de > *
2016-03-02 19:00:31 +00:00
* Copyright ( C ) 2016 by Andrius Š tikonas < andrius @ stikonas . eu > *
2015-06-04 01:29:22 +01:00
* *
* This program 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 . *
* *
* This program 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 this program . If not , see < http : //www.gnu.org/licenses/>.*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "plugins/libparted/libpartedpartitiontable.h"
# include "plugins/libparted/libpartedpartition.h"
# include "plugins/libparted/libpartedbackend.h"
# include "backend/corebackend.h"
# include "backend/corebackendmanager.h"
# include "core/partition.h"
# include "core/device.h"
# include "fs/filesystem.h"
# include "util/report.h"
# include "util/externalcommand.h"
# include <KLocalizedString>
# include <unistd.h>
2015-07-13 15:16:36 +01:00
LibPartedPartitionTable : : LibPartedPartitionTable ( PedDevice * device ) :
CoreBackendPartitionTable ( ) ,
m_PedDevice ( device ) ,
2015-07-22 14:48:03 +01:00
m_PedDisk ( nullptr )
2015-06-04 01:29:22 +01:00
{
}
LibPartedPartitionTable : : ~ LibPartedPartitionTable ( )
{
2016-06-02 13:46:16 +01:00
ped_disk_destroy ( m_PedDisk ) ;
2015-06-04 01:29:22 +01:00
}
bool LibPartedPartitionTable : : open ( )
{
2015-07-13 15:16:36 +01:00
m_PedDisk = ped_disk_new ( pedDevice ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
return m_PedDisk ! = nullptr ;
2015-06-04 01:29:22 +01:00
}
bool LibPartedPartitionTable : : commit ( quint32 timeout )
{
2015-07-13 15:16:36 +01:00
return commit ( pedDisk ( ) , timeout ) ;
2015-06-04 01:29:22 +01:00
}
bool LibPartedPartitionTable : : commit ( PedDisk * pd , quint32 timeout )
{
2015-07-22 14:48:03 +01:00
if ( pd = = nullptr )
2015-07-13 15:16:36 +01:00
return false ;
bool rval = ped_disk_commit_to_dev ( pd ) ;
2016-05-01 14:32:00 +01:00
if ( rval )
2015-07-13 15:16:36 +01:00
rval = ped_disk_commit_to_os ( pd ) ;
if ( ! ExternalCommand ( QStringLiteral ( " udevadm " ) , QStringList ( ) < < QStringLiteral ( " settle " ) < < QStringLiteral ( " --timeout= " ) + QString : : number ( timeout ) ) . run ( ) & &
! ExternalCommand ( QStringLiteral ( " udevsettle " ) , QStringList ( ) < < QStringLiteral ( " --timeout= " ) + QString : : number ( timeout ) ) . run ( ) )
sleep ( timeout ) ;
return rval ;
2015-06-04 01:29:22 +01:00
}
CoreBackendPartition * LibPartedPartitionTable : : getExtendedPartition ( )
{
2015-07-13 15:16:36 +01:00
PedPartition * pedPartition = ped_disk_extended_partition ( pedDisk ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( pedPartition = = nullptr )
return nullptr ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return new LibPartedPartition ( pedPartition ) ;
2015-06-04 01:29:22 +01:00
}
CoreBackendPartition * LibPartedPartitionTable : : getPartitionBySector ( qint64 sector )
{
2015-07-13 15:16:36 +01:00
PedPartition * pedPartition = ped_disk_get_partition_by_sector ( pedDisk ( ) , sector ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( pedPartition = = nullptr )
return nullptr ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return new LibPartedPartition ( pedPartition ) ;
2015-06-04 01:29:22 +01:00
}
2015-07-13 15:16:36 +01:00
static const struct {
FileSystem : : Type type ;
QString name ;
} mapFileSystemTypeToLibPartedName [ ] = {
{ FileSystem : : Btrfs , QStringLiteral ( " btrfs " ) } ,
{ FileSystem : : Ext2 , QStringLiteral ( " ext2 " ) } ,
{ FileSystem : : Ext3 , QStringLiteral ( " ext3 " ) } ,
{ FileSystem : : Ext4 , QStringLiteral ( " ext4 " ) } ,
{ FileSystem : : LinuxSwap , QStringLiteral ( " linux-swap " ) } ,
{ FileSystem : : Fat16 , QStringLiteral ( " fat16 " ) } ,
{ FileSystem : : Fat32 , QStringLiteral ( " fat32 " ) } ,
{ FileSystem : : Nilfs2 , QStringLiteral ( " nilfs2 " ) } ,
{ FileSystem : : Ntfs , QStringLiteral ( " ntfs " ) } ,
{ FileSystem : : Exfat , QStringLiteral ( " ntfs " ) } ,
{ FileSystem : : ReiserFS , QStringLiteral ( " reiserfs " ) } ,
2016-04-20 16:03:10 +01:00
{ FileSystem : : Reiser4 , QStringLiteral ( " reiserfs " ) } ,
2015-07-13 15:16:36 +01:00
{ FileSystem : : Xfs , QStringLiteral ( " xfs " ) } ,
{ FileSystem : : Jfs , QStringLiteral ( " jfs " ) } ,
{ FileSystem : : Hfs , QStringLiteral ( " hfs " ) } ,
{ FileSystem : : HfsPlus , QStringLiteral ( " hfs+ " ) } ,
2017-09-03 21:24:15 +01:00
{ FileSystem : : Ufs , QStringLiteral ( " ufs " ) } ,
{ FileSystem : : Udf , QStringLiteral ( " ntfs " ) }
2015-06-04 01:29:22 +01:00
} ;
static PedFileSystemType * getPedFileSystemType ( FileSystem : : Type t )
{
2015-07-13 15:16:36 +01:00
for ( quint32 i = 0 ; i < sizeof ( mapFileSystemTypeToLibPartedName ) / sizeof ( mapFileSystemTypeToLibPartedName [ 0 ] ) ; i + + )
if ( mapFileSystemTypeToLibPartedName [ i ] . type = = t )
return ped_file_system_type_get ( mapFileSystemTypeToLibPartedName [ i ] . name . toLatin1 ( ) . constData ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// if we didn't find anything, go with ext2 as a safe fallback
return ped_file_system_type_get ( " ext2 " ) ;
2015-06-04 01:29:22 +01:00
}
QString LibPartedPartitionTable : : createPartition ( Report & report , const Partition & partition )
{
2015-07-13 15:16:36 +01:00
Q_ASSERT ( partition . devicePath ( ) = = QString : : fromUtf8 ( pedDevice ( ) - > path ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
QString rval = QString ( ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
// According to libParted docs, PedPartitionType can be "nullptr if unknown". That's obviously wrong,
2015-07-13 15:16:36 +01:00
// it's a typedef for an enum. So let's use something the libparted devs will hopefully never
// use...
PedPartitionType pedType = static_cast < PedPartitionType > ( 0xffffffff ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( partition . roles ( ) . has ( PartitionRole : : Extended ) )
pedType = PED_PARTITION_EXTENDED ;
else if ( partition . roles ( ) . has ( PartitionRole : : Logical ) )
pedType = PED_PARTITION_LOGICAL ;
else if ( partition . roles ( ) . has ( PartitionRole : : Primary ) )
pedType = PED_PARTITION_NORMAL ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( pedType = = static_cast < int > ( 0xffffffff ) ) {
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Unknown partition role for new partition <filename>%1</filename> (roles: %2) " , partition . deviceNode ( ) , partition . roles ( ) . toString ( ) ) ;
2015-07-13 15:16:36 +01:00
return QString ( ) ;
}
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
PedFileSystemType * pedFsType = ( partition . roles ( ) . has ( PartitionRole : : Extended ) | | partition . fileSystem ( ) . type ( ) = = FileSystem : : Unformatted ) ? nullptr : getPedFileSystemType ( partition . fileSystem ( ) . type ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
PedPartition * pedPartition = ped_partition_new ( pedDisk ( ) , pedType , pedFsType , partition . firstSector ( ) , partition . lastSector ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( pedPartition = = nullptr ) {
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Failed to create new partition <filename>%1</filename>. " , partition . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
return QString ( ) ;
}
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
PedConstraint * pedConstraint = nullptr ;
2015-07-13 15:16:36 +01:00
PedGeometry * pedGeometry = ped_geometry_new ( pedDevice ( ) , partition . firstSector ( ) , partition . length ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( pedGeometry )
pedConstraint = ped_constraint_exact ( pedGeometry ) ;
2016-06-02 13:46:16 +01:00
ped_geometry_destroy ( pedGeometry ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( pedConstraint = = nullptr ) {
2016-07-17 23:41:00 +01:00
report . line ( ) < < i18nc ( " @info:progress " , " Failed to create a new partition: could not get geometry for constraint. " ) ;
2015-07-13 15:16:36 +01:00
return QString ( ) ;
}
2015-06-04 01:29:22 +01:00
2016-06-02 13:46:16 +01:00
if ( ped_disk_add_partition ( pedDisk ( ) , pedPartition , pedConstraint ) ) {
char * pedPath = ped_partition_get_path ( pedPartition ) ;
rval = QString : : fromUtf8 ( pedPath ) ;
free ( pedPath ) ;
}
2015-07-13 15:16:36 +01:00
else {
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Failed to add partition <filename>%1</filename> to device <filename>%2</filename>. " , partition . deviceNode ( ) , QString : : fromUtf8 ( pedDisk ( ) - > dev - > path ) ) ;
2015-07-13 15:16:36 +01:00
report . line ( ) < < LibPartedBackend : : lastPartedExceptionMessage ( ) ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
ped_constraint_destroy ( pedConstraint ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return rval ;
2015-06-04 01:29:22 +01:00
}
bool LibPartedPartitionTable : : deletePartition ( Report & report , const Partition & partition )
{
2015-07-13 15:16:36 +01:00
Q_ASSERT ( partition . devicePath ( ) = = QString : : fromUtf8 ( pedDevice ( ) - > path ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
bool rval = false ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
PedPartition * pedPartition = partition . roles ( ) . has ( PartitionRole : : Extended )
? ped_disk_extended_partition ( pedDisk ( ) )
: ped_disk_get_partition_by_sector ( pedDisk ( ) , partition . firstSector ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( pedPartition ) {
rval = ped_disk_delete_partition ( pedDisk ( ) , pedPartition ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( ! rval )
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not delete partition <filename>%1</filename>. " , partition . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
} else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Deleting partition failed: Partition to delete (<filename>%1</filename>) not found on disk. " , partition . deviceNode ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return rval ;
2015-06-04 01:29:22 +01:00
}
bool LibPartedPartitionTable : : updateGeometry ( Report & report , const Partition & partition , qint64 sector_start , qint64 sector_end )
{
2015-07-13 15:16:36 +01:00
Q_ASSERT ( partition . devicePath ( ) = = QString : : fromUtf8 ( pedDevice ( ) - > path ) ) ;
bool rval = false ;
PedPartition * pedPartition = ( partition . roles ( ) . has ( PartitionRole : : Extended ) )
? ped_disk_extended_partition ( pedDisk ( ) )
: ped_disk_get_partition_by_sector ( pedDisk ( ) , partition . firstSector ( ) ) ;
if ( pedPartition ) {
if ( PedGeometry * pedGeometry = ped_geometry_new ( pedDevice ( ) , sector_start , sector_end - sector_start + 1 ) ) {
if ( PedConstraint * pedConstraint = ped_constraint_exact ( pedGeometry ) ) {
if ( ped_disk_set_partition_geom ( pedDisk ( ) , pedPartition , pedConstraint , sector_start , sector_end ) )
rval = true ;
else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not set geometry for partition <filename>%1</filename> while trying to resize/move it. " , partition . deviceNode ( ) ) ;
2016-06-02 13:46:16 +01:00
ped_constraint_destroy ( pedConstraint ) ;
2015-07-13 15:16:36 +01:00
} else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not get constraint for partition <filename>%1</filename> while trying to resize/move it. " , partition . deviceNode ( ) ) ;
2016-06-02 13:46:16 +01:00
ped_geometry_destroy ( pedGeometry ) ;
2015-07-13 15:16:36 +01:00
} else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not get geometry for partition <filename>%1</filename> while trying to resize/move it. " , partition . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
} else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not open partition <filename>%1</filename> while trying to resize/move it. " , partition . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
return rval ;
2015-06-04 01:29:22 +01:00
}
bool LibPartedPartitionTable : : clobberFileSystem ( Report & report , const Partition & partition )
{
2015-07-13 15:16:36 +01:00
bool rval = false ;
if ( PedPartition * pedPartition = ped_disk_get_partition_by_sector ( pedDisk ( ) , partition . firstSector ( ) ) ) {
if ( pedPartition - > type = = PED_PARTITION_NORMAL | | pedPartition - > type = = PED_PARTITION_LOGICAL ) {
if ( ped_device_open ( pedDevice ( ) ) ) {
//reiser4 stores "ReIsEr4" at sector 128 with a sector size of 512 bytes
2016-05-16 14:54:22 +01:00
// We need to use memset instead of = {0} because clang sucks.
2016-05-16 14:57:27 +01:00
const long long zeroes_length = pedDevice ( ) - > sector_size * 129 ;
2017-06-01 01:36:38 +01:00
char * zeroes = new char [ zeroes_length ] ;
2016-05-16 14:57:27 +01:00
memset ( zeroes , 0 , zeroes_length * sizeof ( char ) ) ;
2016-05-16 14:54:22 +01:00
2016-04-20 15:07:21 +01:00
rval = ped_geometry_write ( & pedPartition - > geom , zeroes , 0 , 129 ) ;
2017-06-01 01:36:38 +01:00
delete [ ] zeroes ;
2015-07-13 15:16:36 +01:00
if ( ! rval )
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Failed to erase filesystem signature on partition <filename>%1</filename>. " , partition . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
ped_device_close ( pedDevice ( ) ) ;
}
} else
rval = true ;
} else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not delete file system on partition <filename>%1</filename>: Failed to get partition. " , partition . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
return rval ;
2015-06-04 01:29:22 +01:00
}
# if defined LIBPARTED_FS_RESIZE_LIBRARY_SUPPORT
static void pedTimerHandler ( PedTimer * pedTimer , void * )
{
2015-07-13 15:16:36 +01:00
CoreBackendManager : : self ( ) - > backend ( ) - > emitProgress ( pedTimer - > frac * 100 ) ;
2015-06-04 01:29:22 +01:00
}
# endif
bool LibPartedPartitionTable : : resizeFileSystem ( Report & report , const Partition & partition , qint64 newLength )
{
2015-07-13 15:16:36 +01:00
bool rval = false ;
2015-06-04 01:29:22 +01:00
# if defined LIBPARTED_FS_RESIZE_LIBRARY_SUPPORT
2015-07-13 15:16:36 +01:00
if ( PedGeometry * originalGeometry = ped_geometry_new ( pedDevice ( ) , partition . fileSystem ( ) . firstSector ( ) , partition . fileSystem ( ) . length ( ) ) ) {
if ( PedFileSystem * pedFileSystem = ped_file_system_open ( originalGeometry ) ) {
if ( PedGeometry * resizedGeometry = ped_geometry_new ( pedDevice ( ) , partition . fileSystem ( ) . firstSector ( ) , newLength ) ) {
2015-07-22 14:48:03 +01:00
PedTimer * pedTimer = ped_timer_new ( pedTimerHandler , nullptr ) ;
2015-07-13 15:16:36 +01:00
rval = ped_file_system_resize ( pedFileSystem , resizedGeometry , pedTimer ) ;
ped_timer_destroy ( pedTimer ) ;
if ( ! rval )
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not resize file system on partition <filename>%1</filename>. " , partition . deviceNode ( ) ) ;
2016-06-02 13:46:16 +01:00
ped_geometry_destroy ( resizedGeometry ) ;
2015-07-13 15:16:36 +01:00
} else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not get geometry for resized partition <filename>%1</filename> while trying to resize the file system. " , partition . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
ped_file_system_close ( pedFileSystem ) ;
} else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not open partition <filename>%1</filename> while trying to resize the file system. " , partition . deviceNode ( ) ) ;
2016-06-02 13:46:16 +01:00
ped_geometry_destroy ( originalGeometry ) ;
2015-07-13 15:16:36 +01:00
} else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not read geometry for partition <filename>%1</filename> while trying to resize the file system. " , partition . deviceNode ( ) ) ;
2015-06-04 01:29:22 +01:00
# else
2015-07-13 15:16:36 +01:00
Q_UNUSED ( report ) ;
Q_UNUSED ( partition ) ;
Q_UNUSED ( newLength ) ;
2015-06-04 01:29:22 +01:00
# endif
2015-07-13 15:16:36 +01:00
return rval ;
2015-06-04 01:29:22 +01:00
}
FileSystem : : Type LibPartedPartitionTable : : detectFileSystemBySector ( Report & report , const Device & device , qint64 sector )
{
2015-07-13 15:16:36 +01:00
PedPartition * pedPartition = ped_disk_get_partition_by_sector ( pedDisk ( ) , sector ) ;
2015-06-04 01:29:22 +01:00
2016-05-06 19:14:01 +01:00
char * pedPath = ped_partition_get_path ( pedPartition ) ;
FileSystem : : Type type = FileSystem : : Unknown ;
if ( pedPartition & & pedPath )
type = CoreBackendManager : : self ( ) - > backend ( ) - > detectFileSystem ( QString : : fromUtf8 ( pedPath ) ) ;
2015-07-13 15:16:36 +01:00
else
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not determine file system of partition at sector %1 on device <filename>%2</filename>. " , sector , device . deviceNode ( ) ) ;
2016-05-06 19:14:01 +01:00
free ( pedPath ) ;
2015-06-04 01:29:22 +01:00
2016-05-06 19:14:01 +01:00
return type ;
2015-06-04 01:29:22 +01:00
}
bool LibPartedPartitionTable : : setPartitionSystemType ( Report & report , const Partition & partition )
{
2015-07-22 14:48:03 +01:00
PedFileSystemType * pedFsType = ( partition . roles ( ) . has ( PartitionRole : : Extended ) | | partition . fileSystem ( ) . type ( ) = = FileSystem : : Unformatted ) ? nullptr : getPedFileSystemType ( partition . fileSystem ( ) . type ( ) ) ;
if ( pedFsType = = nullptr ) {
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not update the system type for partition <filename>%1</filename>. " , partition . deviceNode ( ) ) ;
report . line ( ) < < xi18nc ( " @info:progress " , " No file system defined. " ) ;
2015-07-13 15:16:36 +01:00
return false ;
}
PedPartition * pedPartition = ped_disk_get_partition_by_sector ( pedDisk ( ) , partition . firstSector ( ) ) ;
2015-07-22 14:48:03 +01:00
if ( pedPartition = = nullptr ) {
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Could not update the system type for partition <filename>%1</filename>. " , partition . deviceNode ( ) ) ;
report . line ( ) < < xi18nc ( " @info:progress " , " No partition found at sector %1. " , partition . firstSector ( ) ) ;
2015-07-13 15:16:36 +01:00
return false ;
}
return ped_partition_set_system ( pedPartition , pedFsType ) ! = 0 ;
2015-06-04 01:29:22 +01:00
}