Snap partition boundaries before dialogs update FS usage (#48)

Move snap_to_*() method calls from the point when all operations are
added to the list, to earlier when Resize/Move, Paste (into new) and
Create New dialogs are composing the new partition objects.  In
particular for the Resize/Move operation, to just before updating the
file system usage.

This change finally resolves this bug.

Because of the dialog call chains into Dialog_Base_Partition,
snap_to_alignment() must be added into:
* Dialog_Base_Partition::prepare_new_partition() for the Resize/Move and
  Paste (into new) dialogs; and
* Dialog_Partition_New::Get_New_Partition() for the Create New dialog.

Closes #48 - Error when moving locked LUKS-encrypted partition
This commit is contained in:
Mike Fleetwood 2019-05-19 10:31:55 +01:00 committed by Curtis Gedak
parent 3222c8dd1a
commit 7c94b7d920
5 changed files with 224 additions and 222 deletions

View File

@ -59,6 +59,9 @@ protected:
}; };
void prepare_new_partition(); void prepare_new_partition();
static void snap_to_alignment(const Device& device, Partition& partition);
static void snap_to_cylinder(const Device& device, Partition& partition);
static void snap_to_mebibyte(const Device& device, Partition& partition);
void Set_Confirm_Button( CONFIRMBUTTON button_type ) ; void Set_Confirm_Button( CONFIRMBUTTON button_type ) ;
void Set_MinMax_Text( Sector min, Sector max ) ; void Set_MinMax_Text( Sector min, Sector max ) ;

View File

@ -51,9 +51,6 @@ public:
void set_devices_thread( std::vector<Device> * pdevices ); void set_devices_thread( std::vector<Device> * pdevices );
void guess_partition_table(const Device & device, Glib::ustring &buff); void guess_partition_table(const Device & device, Glib::ustring &buff);
void snap_to_cylinder(const Device& device, Partition& partition);
void snap_to_mebibyte(const Device& device, Partition& partition);
void snap_to_alignment(const Device& device, Partition& partition);
bool valid_partition(const Device& device, Partition& partition, Glib::ustring& error); bool valid_partition(const Device& device, Partition& partition, Glib::ustring& error);
bool apply_operation_to_disk( Operation * operation ); bool apply_operation_to_disk( Operation * operation );

View File

@ -200,8 +200,7 @@ void Dialog_Base_Partition::prepare_new_partition()
// If partition size is not an integer multiple of MiB or // If partition size is not an integer multiple of MiB or
// the start or end sectors are not MiB aligned, and space // the start or end sectors are not MiB aligned, and space
// is available, then add 1 MiB to partition so requested // is available, then add 1 MiB to partition so requested
// size is kept after GParted_Core::snap_to_mebibyte // size is kept after snap_to_mebibyte() method rounding.
// method rounding.
Sector partition_size = new_partition->sector_end - new_partition->sector_start + 1; Sector partition_size = new_partition->sector_end - new_partition->sector_start + 1;
Sector sectors_in_mib = MEBIBYTE / new_partition->sector_size; Sector sectors_in_mib = MEBIBYTE / new_partition->sector_size;
if ( ( ( partition_size % sectors_in_mib > 0 ) if ( ( ( partition_size % sectors_in_mib > 0 )
@ -228,6 +227,8 @@ void Dialog_Base_Partition::prepare_new_partition()
if ( ORIG_BEFORE == spinbutton_before .get_value_as_int() ) if ( ORIG_BEFORE == spinbutton_before .get_value_as_int() )
new_partition->strict_start = TRUE; new_partition->strict_start = TRUE;
snap_to_alignment(m_device, *new_partition);
//update partition usage //update partition usage
if ( new_partition->sector_usage_known() ) if ( new_partition->sector_usage_known() )
{ {
@ -250,6 +251,222 @@ void Dialog_Base_Partition::prepare_new_partition()
} }
} }
void Dialog_Base_Partition::snap_to_alignment(const Device& device, Partition& partition)
{
if (partition.alignment == ALIGN_CYLINDER)
snap_to_cylinder(device, partition);
else if (partition.alignment == ALIGN_MEBIBYTE)
snap_to_mebibyte(device, partition);
}
void Dialog_Base_Partition::snap_to_cylinder(const Device& device, Partition& partition)
{
Sector diff = 0;
//Determine if partition size is less than half a disk cylinder
bool less_than_half_cylinder = false;
if ( ( partition .sector_end - partition .sector_start ) < ( device .cylsize / 2 ) )
less_than_half_cylinder = true;
if ( partition.type == TYPE_LOGICAL ||
partition.sector_start == device .sectors
)
{
//Must account the relative offset between:
// (A) the Extended Boot Record sector and the next track of the
// logical partition (usually 63 sectors), and
// (B) the Master Boot Record sector and the next track of the first
// primary partition
diff = (partition .sector_start - device .sectors) % device .cylsize ;
}
else if ( partition.sector_start == 34 )
{
// (C) the GUID Partition Table (GPT) and the start of the data
// partition at sector 34
diff = (partition .sector_start - 34 ) % device .cylsize ;
}
else
{
diff = partition .sector_start % device .cylsize ;
}
if ( diff && ! partition .strict_start )
{
if ( diff < ( device .cylsize / 2 ) || less_than_half_cylinder )
partition .sector_start -= diff ;
else
partition .sector_start += (device .cylsize - diff ) ;
}
diff = (partition .sector_end +1) % device .cylsize ;
if ( diff )
{
if ( diff < ( device .cylsize / 2 ) && ! less_than_half_cylinder )
partition .sector_end -= diff ;
else
partition .sector_end += (device .cylsize - diff ) ;
}
}
void Dialog_Base_Partition::snap_to_mebibyte(const Device& device, Partition& partition)
{
Sector diff = 0;
if ( partition .sector_start < 2 || partition .type == TYPE_LOGICAL )
{
//Must account the relative offset between:
// (A) the Master Boot Record sector and the first primary/extended partition, and
// (B) the Extended Boot Record sector and the logical partition
//If strict_start is set then do not adjust sector start.
//If this partition is not simply queued for a reformat then
// add space minimum to force alignment to next mebibyte.
if ( (! partition .strict_start)
&& (partition .free_space_before == 0)
&& ( partition .status != STAT_FORMATTED)
)
{
//Unless specifically told otherwise, the Linux kernel considers extended
// boot records to be two sectors long, in order to "leave room for LILO".
partition .sector_start += 2 ;
}
}
//Calculate difference offset from Mebibyte boundary
diff = Sector(partition .sector_start % ( MEBIBYTE / partition .sector_size ));
//Align start sector only if permitted to change start sector
if ( diff && ( (! partition .strict_start)
|| ( partition .strict_start
&& ( partition .status == STAT_NEW
|| partition .status == STAT_COPY
)
)
)
)
{
partition .sector_start += ( (MEBIBYTE / partition .sector_size) - diff) ;
//If this is an extended partition then check to see if sufficient space is
// available for any following logical partition Extended Boot Record
if ( partition .type == TYPE_EXTENDED )
{
//If there is logical partition that starts less than 2 sectors
// from the start of this partition, then reserve a mebibyte for the EBR.
int index_extended = find_extended_partition( device.partitions );
if ( index_extended >= 0 )
{
for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
{
if ( ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
&& ( ( ( device .partitions[ index_extended ] .logicals[ t ] .sector_start )
- ( partition .sector_start )
)
//Unless specifically told otherwise, the Linux kernel considers extended
// boot records to be two sectors long, in order to "leave room for LILO".
< 2
)
)
{
partition .sector_start -= (MEBIBYTE / partition .sector_size) ;
}
}
}
}
}
//Align end sector
diff = (partition .sector_end + 1) % ( MEBIBYTE / partition .sector_size);
if ( diff )
partition .sector_end -= diff ;
//If this is a logical partition not at end of drive then check to see if space is
// required for a following logical partition Extended Boot Record
if ( partition .type == TYPE_LOGICAL )
{
//If there is a following logical partition that starts less than 2 sectors from
// the end of this partition, then reserve at least a mebibyte for the EBR.
int index_extended = find_extended_partition( device.partitions );
if ( index_extended >= 0 )
{
for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
{
if ( ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
&& ( device .partitions[ index_extended ] .logicals[ t ] .sector_start > partition .sector_end )
&& ( ( device .partitions[ index_extended ] .logicals[ t ] .sector_start - partition .sector_end )
//Unless specifically told otherwise, the Linux kernel considers extended
// boot records to be two sectors long, in order to "leave room for LILO".
< 2
)
)
partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
}
}
//If the logical partition end is beyond the end of the extended partition
// then reduce logical partition end by a mebibyte to address the overlap.
if ( ( index_extended != -1 )
&& ( partition .sector_end > device .partitions[ index_extended ] .sector_end )
)
partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
}
//If this is a primary or an extended partition and the partition overlaps
// the start of the next primary or extended partition then subtract a
// mebibyte from the end of the partition to address the overlap.
if ( partition .type == TYPE_PRIMARY || partition .type == TYPE_EXTENDED )
{
for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
{
if ( ( device .partitions[ t ] .type == TYPE_PRIMARY
|| device .partitions[ t ] .type == TYPE_EXTENDED
)
&& ( //For a change to an existing partition, (e.g., move or resize)
// skip comparing to original partition and
// only compare to other existing partitions
partition .status == STAT_REAL
&& partition .partition_number != device. partitions[ t ] .partition_number
)
&& ( device .partitions[ t ] .sector_start > partition .sector_start )
&& ( device .partitions[ t ] .sector_start <= partition .sector_end )
)
partition .sector_end -= ( MEBIBYTE / partition .sector_size );
}
}
//If this is an extended partition then check to see if the end of the
// extended partition encompasses the end of the last logical partition.
if ( partition .type == TYPE_EXTENDED )
{
//If there is logical partition that has an end sector beyond the
// end of the extended partition, then set the extended partition
// end sector to be the same as the end of the logical partition.
for ( unsigned int t = 0; t < partition .logicals .size(); t++ )
{
if ( ( partition .logicals[ t ] .type == TYPE_LOGICAL )
&& ( ( partition .logicals[ t ] .sector_end )
> ( partition .sector_end )
)
)
{
partition .sector_end = partition .logicals[ t ] .sector_end ;
}
}
}
//If this is a GPT partition table and the partition ends less than 34 sectors
// from the end of the device, then reserve at least a mebibyte for the
// backup partition table
if ( device .disktype == "gpt"
&& ( ( device .length - partition .sector_end ) < 34 )
)
{
partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
}
}
void Dialog_Base_Partition::Set_Confirm_Button( CONFIRMBUTTON button_type ) void Dialog_Base_Partition::Set_Confirm_Button( CONFIRMBUTTON button_type )
{ {
switch( button_type ) switch( button_type )

View File

@ -319,6 +319,8 @@ const Partition & Dialog_Partition_New::Get_New_Partition()
new_partition->logicals.push_back_adopt( unallocated ); new_partition->logicals.push_back_adopt( unallocated );
} }
Dialog_Base_Partition::snap_to_alignment(m_device, *new_partition);
return *new_partition; return *new_partition;
} }

View File

@ -329,225 +329,8 @@ Glib::ustring GParted_Core::get_thread_status_message( )
} }
void GParted_Core::snap_to_cylinder(const Device& device, Partition& partition)
{
Sector diff = 0;
//Determine if partition size is less than half a disk cylinder
bool less_than_half_cylinder = false;
if ( ( partition .sector_end - partition .sector_start ) < ( device .cylsize / 2 ) )
less_than_half_cylinder = true;
if ( partition.type == TYPE_LOGICAL ||
partition.sector_start == device .sectors
)
{
//Must account the relative offset between:
// (A) the Extended Boot Record sector and the next track of the
// logical partition (usually 63 sectors), and
// (B) the Master Boot Record sector and the next track of the first
// primary partition
diff = (partition .sector_start - device .sectors) % device .cylsize ;
}
else if ( partition.sector_start == 34 )
{
// (C) the GUID Partition Table (GPT) and the start of the data
// partition at sector 34
diff = (partition .sector_start - 34 ) % device .cylsize ;
}
else
{
diff = partition .sector_start % device .cylsize ;
}
if ( diff && ! partition .strict_start )
{
if ( diff < ( device .cylsize / 2 ) || less_than_half_cylinder )
partition .sector_start -= diff ;
else
partition .sector_start += (device .cylsize - diff ) ;
}
diff = (partition .sector_end +1) % device .cylsize ;
if ( diff )
{
if ( diff < ( device .cylsize / 2 ) && ! less_than_half_cylinder )
partition .sector_end -= diff ;
else
partition .sector_end += (device .cylsize - diff ) ;
}
}
void GParted_Core::snap_to_mebibyte(const Device& device, Partition& partition)
{
Sector diff = 0;
if ( partition .sector_start < 2 || partition .type == TYPE_LOGICAL )
{
//Must account the relative offset between:
// (A) the Master Boot Record sector and the first primary/extended partition, and
// (B) the Extended Boot Record sector and the logical partition
//If strict_start is set then do not adjust sector start.
//If this partition is not simply queued for a reformat then
// add space minimum to force alignment to next mebibyte.
if ( (! partition .strict_start)
&& (partition .free_space_before == 0)
&& ( partition .status != STAT_FORMATTED)
)
{
//Unless specifically told otherwise, the Linux kernel considers extended
// boot records to be two sectors long, in order to "leave room for LILO".
partition .sector_start += 2 ;
}
}
//Calculate difference offset from Mebibyte boundary
diff = Sector(partition .sector_start % ( MEBIBYTE / partition .sector_size ));
//Align start sector only if permitted to change start sector
if ( diff && ( (! partition .strict_start)
|| ( partition .strict_start
&& ( partition .status == STAT_NEW
|| partition .status == STAT_COPY
)
)
)
)
{
partition .sector_start += ( (MEBIBYTE / partition .sector_size) - diff) ;
//If this is an extended partition then check to see if sufficient space is
// available for any following logical partition Extended Boot Record
if ( partition .type == TYPE_EXTENDED )
{
//If there is logical partition that starts less than 2 sectors
// from the start of this partition, then reserve a mebibyte for the EBR.
int index_extended = find_extended_partition( device.partitions );
if ( index_extended >= 0 )
{
for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
{
if ( ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
&& ( ( ( device .partitions[ index_extended ] .logicals[ t ] .sector_start )
- ( partition .sector_start )
)
//Unless specifically told otherwise, the Linux kernel considers extended
// boot records to be two sectors long, in order to "leave room for LILO".
< 2
)
)
{
partition .sector_start -= (MEBIBYTE / partition .sector_size) ;
}
}
}
}
}
//Align end sector
diff = (partition .sector_end + 1) % ( MEBIBYTE / partition .sector_size);
if ( diff )
partition .sector_end -= diff ;
//If this is a logical partition not at end of drive then check to see if space is
// required for a following logical partition Extended Boot Record
if ( partition .type == TYPE_LOGICAL )
{
//If there is a following logical partition that starts less than 2 sectors from
// the end of this partition, then reserve at least a mebibyte for the EBR.
int index_extended = find_extended_partition( device.partitions );
if ( index_extended >= 0 )
{
for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
{
if ( ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
&& ( device .partitions[ index_extended ] .logicals[ t ] .sector_start > partition .sector_end )
&& ( ( device .partitions[ index_extended ] .logicals[ t ] .sector_start - partition .sector_end )
//Unless specifically told otherwise, the Linux kernel considers extended
// boot records to be two sectors long, in order to "leave room for LILO".
< 2
)
)
partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
}
}
//If the logical partition end is beyond the end of the extended partition
// then reduce logical partition end by a mebibyte to address the overlap.
if ( ( index_extended != -1 )
&& ( partition .sector_end > device .partitions[ index_extended ] .sector_end )
)
partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
}
//If this is a primary or an extended partition and the partition overlaps
// the start of the next primary or extended partition then subtract a
// mebibyte from the end of the partition to address the overlap.
if ( partition .type == TYPE_PRIMARY || partition .type == TYPE_EXTENDED )
{
for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
{
if ( ( device .partitions[ t ] .type == TYPE_PRIMARY
|| device .partitions[ t ] .type == TYPE_EXTENDED
)
&& ( //For a change to an existing partition, (e.g., move or resize)
// skip comparing to original partition and
// only compare to other existing partitions
partition .status == STAT_REAL
&& partition .partition_number != device. partitions[ t ] .partition_number
)
&& ( device .partitions[ t ] .sector_start > partition .sector_start )
&& ( device .partitions[ t ] .sector_start <= partition .sector_end )
)
partition .sector_end -= ( MEBIBYTE / partition .sector_size );
}
}
//If this is an extended partition then check to see if the end of the
// extended partition encompasses the end of the last logical partition.
if ( partition .type == TYPE_EXTENDED )
{
//If there is logical partition that has an end sector beyond the
// end of the extended partition, then set the extended partition
// end sector to be the same as the end of the logical partition.
for ( unsigned int t = 0; t < partition .logicals .size(); t++ )
{
if ( ( partition .logicals[ t ] .type == TYPE_LOGICAL )
&& ( ( partition .logicals[ t ] .sector_end )
> ( partition .sector_end )
)
)
{
partition .sector_end = partition .logicals[ t ] .sector_end ;
}
}
}
//If this is a GPT partition table and the partition ends less than 34 sectors
// from the end of the device, then reserve at least a mebibyte for the
// backup partition table
if ( device .disktype == "gpt"
&& ( ( device .length - partition .sector_end ) < 34 )
)
{
partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
}
}
void GParted_Core::snap_to_alignment(const Device& device, Partition& partition)
{
if ( partition .alignment == ALIGN_CYLINDER )
snap_to_cylinder(device, partition);
else if ( partition .alignment == ALIGN_MEBIBYTE )
snap_to_mebibyte(device, partition);
}
bool GParted_Core::valid_partition(const Device& device, Partition& partition, Glib::ustring& error) bool GParted_Core::valid_partition(const Device& device, Partition& partition, Glib::ustring& error)
{ {
snap_to_alignment(device, partition);
//Ensure that partition start and end are not beyond the ends of the disk device //Ensure that partition start and end are not beyond the ends of the disk device
if ( partition .sector_start < 0 ) if ( partition .sector_start < 0 )
partition .sector_start = 0 ; partition .sector_start = 0 ;