Add partition alignment option to align to MiB (#617409)

Make align to MiB the default setting instead of align to cylinder.

Migrate logic for alignment to cylinder into its own method
snap_to_cylinder, and place common logic in snap_to_alignment.

Add alignment checks for situations where space is needed for Master
Boot Record or Extended Boot Record.

Adjust ranges on spin buttons according to required boot record space.

Copy fix for off by one sector (#596552) from
Dialog_Partition_New::Get_New_Partition to
Dialog_Base_Partition::Get_New_Partition

Enhance resize / move logic for checking locations of nearby logical
partitions to not depend on the partition ordering.

Note: This commit does not include limiting graphic movement according
to required boot record space.
This commit is contained in:
Curtis Gedak 2010-05-20 10:00:14 -06:00
parent 2cdfb4c55a
commit e62a23b5b5
10 changed files with 347 additions and 238 deletions

View file

@ -75,7 +75,12 @@ protected:
//used to enable/disable OKbutton...
int ORIG_BEFORE, ORIG_SIZE, ORIG_AFTER ;
//used to reserve space for Master or Extended Boot Record (1 MiB)
int MIN_SPACE_BEFORE_MB ;
int MB_Needed_for_Boot_Record( const Partition & partition ) ;
//signal handlers
void on_signal_move( int, int );
void on_signal_resize( int, int, Frame_Resizer_Base::ArrowType );

View file

@ -40,6 +40,8 @@ public:
void set_devices( std::vector<Device> & devices ) ;
bool snap_to_cylinder( const Device & device, Partition & partition, Glib::ustring & error ) ;
bool snap_to_mebibyte( const Device & device, Partition & partition, Glib::ustring & error ) ;
bool snap_to_alignment( const Device & device, Partition & partition, Glib::ustring & error ) ;
bool apply_operation_to_disk( Operation * operation );
bool set_disklabel( const Glib::ustring & device_path, const Glib::ustring & disklabel ) ;

View file

@ -46,7 +46,8 @@ enum PartitionStatus {
enum PartitionAlignment {
ALIGN_CYLINDER = 0, //Align to nearest cylinder
ALIGN_STRICT = 1 //Strict alignment - no rounding
ALIGN_MEBIBYTE = 1, //Align to nearest mebibyte
ALIGN_STRICT = 2 //Strict alignment - no rounding
// Indicator if start and end sectors must remain unchanged
};
@ -124,6 +125,7 @@ public:
std::vector<Partition> logicals ;
bool strict_start ; //Indicator if start sector must stay unchanged
Sector free_space_before ; //Free space preceding partition value
Byte_Value sector_size ; //Sector size of the disk device needed for converting to/from sectors and bytes.

View file

@ -24,13 +24,12 @@ namespace GParted
Dialog_Base_Partition::Dialog_Base_Partition()
{
this ->set_has_separator( false ) ;
//FIXME: somehow the 'off by a few' MiB's warning disappeared.
//I need to display it whenever the round to cylinders isn't checked.
frame_resizer_base = NULL;
GRIP = false ;
this ->fixed_start = false ;
this ->set_resizable( false );
ORIG_BEFORE = ORIG_SIZE = ORIG_AFTER = -1 ;
MIN_SPACE_BEFORE_MB = -1 ;
//pack resizer hbox
this ->get_vbox() ->pack_start( hbox_resizer, Gtk::PACK_SHRINK );
@ -100,10 +99,13 @@ Dialog_Base_Partition::Dialog_Base_Partition()
//fill partition alignment menu
/*TO TRANSLATORS: Menu option for drop down menu "Align to:" */
menu_alignment .items() .push_back( Gtk::Menu_Helpers::MenuElem( _("Cylinder") ) ) ;
/*TO TRANSLATORS: Menu option for label "Align to:" */
menu_alignment .items() .push_back( Gtk::Menu_Helpers::MenuElem( _("MiB") ) ) ;
/*TO TRANSLATORS: Menu option for drop down menu "Align to:" */
menu_alignment .items() .push_back( Gtk::Menu_Helpers::MenuElem( _("None") ) ) ;
optionmenu_alignment .set_menu( menu_alignment );
optionmenu_alignment .set_history( ALIGN_MEBIBYTE); //Default setting
table_resize .attach( optionmenu_alignment, 1, 2, 3, 4, Gtk::FILL );
@ -143,8 +145,10 @@ Partition Dialog_Base_Partition::Get_New_Partition( Byte_Value sector_size )
selected_partition .sector_start = START + Sector(spinbutton_before .get_value_as_int()) * (MEBIBYTE / sector_size) ;
if ( ORIG_AFTER != spinbutton_after .get_value_as_int() )
selected_partition .sector_end =
selected_partition .sector_start + Sector(spinbutton_size .get_value_as_int()) * (MEBIBYTE / sector_size) ;
selected_partition .sector_end =
selected_partition .sector_start
+ Sector(spinbutton_size .get_value_as_int()) * (MEBIBYTE / sector_size)
- 1 /* one sector short of exact mebibyte multiple */;
//due to loss of precision during calcs from Sector -> MiB and back, it is possible
//the new partition thinks it's bigger then it can be. Here we solve this.
@ -167,11 +171,14 @@ Partition Dialog_Base_Partition::Get_New_Partition( Byte_Value sector_size )
switch ( optionmenu_alignment .get_history() )
{
case 0 : selected_partition .alignment = ALIGN_CYLINDER; break;
case 1 : selected_partition .alignment = ALIGN_STRICT; break;
case 1 : selected_partition .alignment = ALIGN_MEBIBYTE; break;
case 2 : selected_partition .alignment = ALIGN_STRICT; break;
default : selected_partition .alignment = ALIGN_CYLINDER ;
}
selected_partition .free_space_before = Sector(spinbutton_before .get_value_as_int()) * (MEBIBYTE / sector_size) ;
//if the original before value has not changed, then set indicator to keep start sector unchanged
if ( ORIG_BEFORE == spinbutton_before .get_value_as_int() )
selected_partition .strict_start = TRUE ;
@ -212,11 +219,29 @@ void Dialog_Base_Partition::Set_MinMax_Text( Sector min, Sector max )
label_minmax .set_text( str_temp ) ;
}
int Dialog_Base_Partition::MB_Needed_for_Boot_Record( const Partition & partition )
{
//Determine if space is needed for the Master Boot Record or
// the Extended Boot Record. Generally an an additional track or MEBIBYTE
// is required so for our purposes reserve a MEBIBYTE in front of the partition.
// NOTE: This logic also contained in Win_GParted::set_valid_operations
if ( ( partition .inside_extended
&& partition .type == TYPE_UNALLOCATED
)
|| ( partition .type == TYPE_LOGICAL )
/* Beginning of disk device */
|| ( partition .sector_start <= (MEBIBYTE / partition .sector_size) )
)
return 1 ;
else
return 0 ;
}
void Dialog_Base_Partition::on_signal_move( int x_start, int x_end )
{
GRIP = true ;
spinbutton_before .set_value( x_start == 0 ? 0 : x_start * MB_PER_PIXEL ) ;
spinbutton_before .set_value( x_start <= MIN_SPACE_BEFORE_MB * MB_PER_PIXEL ? MIN_SPACE_BEFORE_MB : x_start * MB_PER_PIXEL ) ;
if ( x_end == 500 )
{
@ -237,7 +262,7 @@ void Dialog_Base_Partition::on_signal_resize( int x_start, int x_end, Frame_Resi
spinbutton_size .set_value( ( x_end - x_start ) * MB_PER_PIXEL ) ;
before_value = fixed_start ? 0 : spinbutton_before .get_value() ;
before_value = fixed_start ? MIN_SPACE_BEFORE_MB : spinbutton_before .get_value() ;
if ( arrow == Frame_Resizer_Base::ARROW_RIGHT ) //don't touch freespace before, leave it as it is
{
@ -251,10 +276,10 @@ void Dialog_Base_Partition::on_signal_resize( int x_start, int x_end, Frame_Resi
}
else if ( arrow == Frame_Resizer_Base::ARROW_LEFT ) //don't touch freespace after, leave it as it is
{
if ( x_start == 0 )
if ( x_start <= MIN_SPACE_BEFORE_MB * MB_PER_PIXEL )
{
spinbutton_before .set_value( 0 );
spinbutton_size .set_value( TOTAL_MB - spinbutton_after.get_value() ) ;
spinbutton_before .set_value( MIN_SPACE_BEFORE_MB );
spinbutton_size .set_value( TOTAL_MB - MIN_SPACE_BEFORE_MB - spinbutton_after.get_value() ) ;
}
else
spinbutton_before .set_value(
@ -270,7 +295,7 @@ void Dialog_Base_Partition::on_spinbutton_value_changed( SPINBUTTON spinbutton )
{
if ( ! GRIP )
{
before_value = fixed_start ? 0 : spinbutton_before .get_value() ;
before_value = fixed_start ? MIN_SPACE_BEFORE_MB : spinbutton_before .get_value() ;
//Balance the spinbuttons
switch ( spinbutton )

View file

@ -39,6 +39,7 @@ void Dialog_Partition_Copy::Set_Data( const Partition & selected_partition, cons
frame_resizer_base ->set_rgb_partition_color( copied_partition .color ) ;
//set some widely used values...
MIN_SPACE_BEFORE_MB = Dialog_Base_Partition::MB_Needed_for_Boot_Record( selected_partition ) ;
START = selected_partition .sector_start ;
total_length = selected_partition .get_sector_length() ;
TOTAL_MB = Utils::round( Utils::sector_to_unit( selected_partition .get_sector_length(), selected_partition .sector_size, UNIT_MIB ) ) ;
@ -48,51 +49,7 @@ void Dialog_Partition_Copy::Set_Data( const Partition & selected_partition, cons
// handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required.
Sector copied_min_sectors = ( copied_partition .get_byte_length() + (selected_partition .sector_size - 1) ) / selected_partition .sector_size ;
long COPIED_LENGTH_MB = Utils::round( Utils::sector_to_unit( copied_min_sectors, selected_partition .sector_size, UNIT_MIB ) ) ;
// /* Copy Primary not at start of disk to within Extended partition */
// Adjust when a primary partition is copied and pasted
// into an unallocated space in an extended partition
// of an MSDOS partition table.
// Since the Extended Boot Record requires an additional track,
// this must be considered in the required space for the
// destination (selected) partition.
// NOTE: This problem does not occur for a primary partition
// at the the start of the disk because the size of the EBR and
// Master Boot Record are the same.
//
// /* Copy Primary not at start of disk to Primary at start of disk */
// Also Adjust when a primary partition that does not start at the
// beginning of the disk is copied and pasted
// into an unallocated space at the start of the disk device.
// Since the Master Boot Record requires an additional track,
// this must be considered in the required space for the
// destination (selected) partition.
//
// Because the largest unit used in the GUI is one
// cylinder size (round to cylinders), the space
// needed in the destination partition needs to be increased
// by enough to round up one cylinder size.
// Increase by half a cylinder size (or 4 MB) because this
// will round up to the next cylinder size.
// 8 MB is typical cylinder size with todays larger disks.
// 8 MB = (255 heads) * (63 sectors) * (512 bytes)
//
//FIXME: Should confirm MSDOS partition table type, track sector size, and use cylinder size from device
if ( (/* Copy Primary not at start of disk to within Extended partition */
copied_partition .type == TYPE_PRIMARY
&& copied_partition .sector_start > 63
&& selected_partition .type == TYPE_UNALLOCATED
&& selected_partition .inside_extended
)
|| ( /* Copy Primary not at start of disk to Primary at start of disk */
copied_partition .type == TYPE_PRIMARY
&& copied_partition .sector_start > 63
&& selected_partition .type == TYPE_UNALLOCATED
&& selected_partition .sector_start <=63 /* Beginning of disk device */
&& ! selected_partition .inside_extended
)
)
COPIED_LENGTH_MB += 4 ;
long COPIED_LENGTH_MB = Utils::round( Utils::sector_to_unit( copied_min_sectors, selected_partition .sector_size, UNIT_MIB ) ) ;
//now calculate proportional length of partition
frame_resizer_base ->set_x_start( 0 ) ;
@ -103,7 +60,10 @@ void Dialog_Partition_Copy::Set_Data( const Partition & selected_partition, cons
copied_partition .sectors_used, copied_partition .sector_size, UNIT_MIB ) / (TOTAL_MB/500.00) ) ) ;
if ( fs .grow )
fs .MAX = ( ! fs .MAX || fs .MAX > (TOTAL_MB * MEBIBYTE) ) ? (TOTAL_MB * MEBIBYTE) : fs .MAX - (BUF * selected_partition .sector_size) ;
if ( ! fs .MAX || fs .MAX > ((TOTAL_MB - MIN_SPACE_BEFORE_MB) * MEBIBYTE) )
fs .MAX = ((TOTAL_MB - MIN_SPACE_BEFORE_MB) * MEBIBYTE) ;
else
fs .MAX = fs .MAX - (BUF * selected_partition .sector_size) ;
else
fs .MAX = copied_partition .get_byte_length() ;
@ -115,27 +75,27 @@ void Dialog_Partition_Copy::Set_Data( const Partition & selected_partition, cons
GRIP = true ;
//set values of spinbutton_before
spinbutton_before .set_range( 0, TOTAL_MB - Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_before .set_value( 0 ) ;
spinbutton_before .set_range( MIN_SPACE_BEFORE_MB, TOTAL_MB - ceil( fs .MIN / double(MEBIBYTE) ) ) ;
spinbutton_before .set_value( MIN_SPACE_BEFORE_MB ) ;
//set values of spinbutton_size
spinbutton_size .set_range(
Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ),
Utils::round( Utils::sector_to_unit( fs .MAX, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_size .set_range( ceil( fs .MIN / double(MEBIBYTE) )
, ceil( fs .MAX / double(MEBIBYTE) )
) ;
spinbutton_size .set_value( COPIED_LENGTH_MB ) ;
//set values of spinbutton_after
spinbutton_after .set_range( 0, TOTAL_MB - Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_after .set_value( TOTAL_MB - COPIED_LENGTH_MB ) ;
spinbutton_after .set_range( 0, TOTAL_MB - MIN_SPACE_BEFORE_MB - ceil( fs .MIN / double(MEBIBYTE) ) ) ;
spinbutton_after .set_value( TOTAL_MB - MIN_SPACE_BEFORE_MB - COPIED_LENGTH_MB ) ;
GRIP = false ;
frame_resizer_base ->set_size_limits( Utils::round( fs .MIN / (MB_PER_PIXEL * MEBIBYTE) ),
Utils::round( fs .MAX / (MB_PER_PIXEL * MEBIBYTE) ) ) ;
//set contents of label_minmax
Set_MinMax_Text(
Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ),
Utils::round( Utils::sector_to_unit( fs .MAX, 1 /* Byte */, UNIT_MIB ) ) ) ;
Set_MinMax_Text( ceil( fs .MIN / double(MEBIBYTE) )
, ceil( fs .MAX / double(MEBIBYTE) )
) ;
//set global selected_partition (see Dialog_Base_Partition::Get_New_Partition )
this ->selected_partition = copied_partition ;

View file

@ -140,6 +140,7 @@ void Dialog_Partition_New::Set_Data( const Partition & partition,
table_create .attach( entry, 1, 2, 3, 4, Gtk::FILL ) ;
//set some widely used values...
MIN_SPACE_BEFORE_MB = Dialog_Base_Partition::MB_Needed_for_Boot_Record( selected_partition ) ;
START = partition.sector_start ;
total_length = partition.sector_end - partition.sector_start ;
TOTAL_MB = Utils::round( Utils::sector_to_unit( this ->selected_partition .get_sector_length(), this ->selected_partition .sector_size, UNIT_MIB ) ) ;
@ -151,8 +152,8 @@ void Dialog_Partition_New::Set_Data( const Partition & partition,
//set spinbuttons initial values
spinbutton_after .set_value( 0 ) ;
spinbutton_size .set_value( Utils::round( Utils::sector_to_unit( fs .MAX, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_before .set_value( 0 ) ;
spinbutton_size .set_value( ceil( fs .MAX / double(MEBIBYTE) ) ) ;
spinbutton_before .set_value( MIN_SPACE_BEFORE_MB ) ;
//euhrm, this wil only happen when there's a very small free space (usually the effect of a bad partitionmanager)
if ( TOTAL_MB * (MEBIBYTE / this ->selected_partition .sector_size) < this ->cylinder_size )
@ -226,11 +227,14 @@ Partition Dialog_Partition_New::Get_New_Partition( Byte_Value sector_size )
switch ( optionmenu_alignment .get_history() )
{
case 0 : part_temp .alignment = GParted::ALIGN_CYLINDER; break;
case 1 : part_temp .alignment = GParted::ALIGN_STRICT; break;
case 1 : part_temp .alignment = GParted::ALIGN_MEBIBYTE; break;
case 2 : part_temp .alignment = GParted::ALIGN_STRICT; break;
default : part_temp .alignment = GParted::ALIGN_CYLINDER ;
default : part_temp .alignment = GParted::ALIGN_MEBIBYTE ;
}
part_temp .free_space_before = Sector(spinbutton_before .get_value_as_int()) * (MEBIBYTE / sector_size) ;
return part_temp;
}
@ -268,30 +272,34 @@ void Dialog_Partition_New::optionmenu_changed( bool type )
}
else if ( fs .MIN < MEBIBYTE )
fs .MIN = MEBIBYTE ;
if ( selected_partition .get_byte_length() < fs .MIN )
fs .MIN = selected_partition .get_byte_length() ;
fs .MAX = ( fs .MAX && ( fs .MAX < (TOTAL_MB * MEBIBYTE) ) ) ? fs .MAX : (TOTAL_MB * MEBIBYTE) ;
if ( ! fs .MAX || ( fs .MAX > ((TOTAL_MB - MIN_SPACE_BEFORE_MB) * MEBIBYTE) ) )
fs .MAX = ((TOTAL_MB - MIN_SPACE_BEFORE_MB) * MEBIBYTE) ;
frame_resizer_base ->set_size_limits( Utils::round( fs .MIN / (MB_PER_PIXEL * MEBIBYTE) ),
Utils::round( fs .MAX / (MB_PER_PIXEL * MEBIBYTE) ) ) ;
//set new spinbutton ranges
spinbutton_before .set_range(
0, TOTAL_MB - Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_size .set_range(
Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ),
Utils::round( Utils::sector_to_unit( fs .MAX, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_after .set_range(
0, TOTAL_MB - Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_before .set_range( MIN_SPACE_BEFORE_MB
, TOTAL_MB - ceil( fs .MIN / double(MEBIBYTE) )
) ;
spinbutton_size .set_range( ceil( fs .MIN / double(MEBIBYTE) )
, ceil( fs .MAX / double(MEBIBYTE) )
) ;
spinbutton_after .set_range( 0
, TOTAL_MB - MIN_SPACE_BEFORE_MB
- ceil( fs .MIN / double(MEBIBYTE) )
) ;
//set contents of label_minmax
Set_MinMax_Text(
Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ),
Utils::round( Utils::sector_to_unit( fs .MAX, 1 /* Byte */, UNIT_MIB ) ) ) ;
Set_MinMax_Text( ceil( fs .MIN / double(MEBIBYTE) )
, ceil( fs .MAX / double(MEBIBYTE) )
) ;
}
//set fitting resizer colors
//backgroundcolor..
color_temp .set( optionmenu_type .get_history() == 2 ? "darkgrey" : "white" ) ;

View file

@ -102,7 +102,8 @@ void Dialog_Partition_Resize_Move::Resize_Move_Normal( const std::vector<Partiti
if ( t +1 < partitions .size() && partitions[t +1] .type == GParted::TYPE_UNALLOCATED )
next = partitions[t +1] .get_sector_length() ;
MIN_SPACE_BEFORE_MB = Dialog_Base_Partition::MB_Needed_for_Boot_Record( selected_partition ) ;
total_length = previous + selected_partition .get_sector_length() + next;
TOTAL_MB = Utils::round( Utils::sector_to_unit( total_length, selected_partition .sector_size, UNIT_MIB ) ) ;
@ -121,42 +122,34 @@ void Dialog_Partition_Resize_Move::Resize_Move_Normal( const std::vector<Partiti
if ( selected_partition .sectors_used > (fs .MIN / selected_partition .sector_size) )
fs .MIN = selected_partition .sectors_used * selected_partition .sector_size ;
//if fs. MIN is 0 here (means used == 0 as well) it's safe to have BUF / 2
fs .MIN += fs .MIN ? (BUF * selected_partition .sector_size) : (BUF/2 * selected_partition .sector_size) ;
//in certain (rare) cases fs .MIN is (now) larger than 'selected_partition'..
if ( fs .MIN > selected_partition .get_byte_length() )
fs .MIN = selected_partition .get_byte_length() ;
//ensure that minimum size is at least one mebibyte
if ( ! fs .MIN || fs .MIN < MEBIBYTE )
fs .MIN = MEBIBYTE ;
}
else
fs .MIN = selected_partition .get_byte_length() ;
//set MAX
if ( fs .grow )
{
if ( ! fs .MAX || fs .MAX > (TOTAL_MB * MEBIBYTE) )
fs .MAX = TOTAL_MB * MEBIBYTE ;
else
fs .MAX -= (BUF/2 * selected_partition .sector_size) ;
}
fs .MAX = (TOTAL_MB - MIN_SPACE_BEFORE_MB) * MEBIBYTE ;
else
fs .MAX = selected_partition .get_byte_length() ;
//set values of spinbutton_before
if ( ! fixed_start )
{
spinbutton_before .set_range(
0,
TOTAL_MB - Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_before .set_range( MIN_SPACE_BEFORE_MB
, TOTAL_MB - ceil( fs .MIN / double(MEBIBYTE) )
) ;
spinbutton_before .set_value(
Utils::round( Utils::sector_to_unit( previous, selected_partition .sector_size, UNIT_MIB ) ) ) ;
Utils::round( Utils::sector_to_unit( previous, selected_partition .sector_size, UNIT_MIB ) )
- MIN_SPACE_BEFORE_MB ) ;
}
//set values of spinbutton_size
spinbutton_size .set_range(
Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ),
Utils::round( Utils::sector_to_unit( fs .MAX, 1 /* Byte */, UNIT_MIB ) ) ) ;
spinbutton_size .set_range( ceil( fs .MIN / double(MEBIBYTE) )
, ceil( fs .MAX / double(MEBIBYTE) )
) ;
spinbutton_size .set_value(
Utils::round( Utils::sector_to_unit( selected_partition .get_sector_length(), selected_partition .sector_size, UNIT_MIB ) ) ) ;
@ -164,17 +157,17 @@ void Dialog_Partition_Resize_Move::Resize_Move_Normal( const std::vector<Partiti
Sector after_min = ( ! fs .grow && ! fs .move ) ? next : 0 ;
spinbutton_after .set_range(
Utils::round( Utils::sector_to_unit( after_min, selected_partition .sector_size, UNIT_MIB ) ),
TOTAL_MB - Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ) ) ;
TOTAL_MB - MIN_SPACE_BEFORE_MB - ceil( fs .MIN / double(MEBIBYTE) ) ) ;
spinbutton_after .set_value(
Utils::round( Utils::sector_to_unit( next, selected_partition .sector_size, UNIT_MIB ) ) ) ;
frame_resizer_base ->set_size_limits( Utils::round( fs .MIN / (MB_PER_PIXEL * MEBIBYTE) ),
Utils::round( fs .MAX / (MB_PER_PIXEL * MEBIBYTE) ) ) ;
//set contents of label_minmax
Set_MinMax_Text(
Utils::round( Utils::sector_to_unit( fs .MIN, 1 /* Byte */, UNIT_MIB ) ),
Utils::round( Utils::sector_to_unit( fs .MAX, 1 /* Byte */, UNIT_MIB ) ) ) ;
Set_MinMax_Text( ceil( fs .MIN / double(MEBIBYTE) )
, ceil( fs .MAX / double(MEBIBYTE) )
) ;
}
void Dialog_Partition_Resize_Move::Resize_Move_Extended( const std::vector<Partition> & partitions )
@ -200,6 +193,7 @@ void Dialog_Partition_Resize_Move::Resize_Move_Extended( const std::vector<Parti
next = partitions[ t +1 ] .get_sector_length() ;
//now we have enough data to calculate some important values..
MIN_SPACE_BEFORE_MB = Dialog_Base_Partition::MB_Needed_for_Boot_Record( selected_partition ) ;
total_length = previous + selected_partition .get_sector_length() + next;
TOTAL_MB = Utils::round( Utils::sector_to_unit( total_length, selected_partition .sector_size, UNIT_MIB ) ) ;
MB_PER_PIXEL = TOTAL_MB / 500.00 ;
@ -209,17 +203,40 @@ void Dialog_Partition_Resize_Move::Resize_Move_Extended( const std::vector<Parti
frame_resizer_base ->set_x_end( Utils::round( selected_partition .get_sector_length() / ( total_length / 500.00 ) ) + frame_resizer_base ->get_x_start() ) ;
//used is a bit different here... we consider start of first logical to end last logical as used space
Sector first =0, used =0 ;
for ( unsigned int i = 0 ; i < partitions[ t ] .logicals .size() ; i++ )
Sector first =0, last = 0, used =0 ;
if ( ! ( selected_partition .logicals .size() == 1
&& selected_partition .logicals .back() .type == GParted::TYPE_UNALLOCATED
)
)
{
if ( partitions[ t ] .logicals[ i ] .type == GParted::TYPE_LOGICAL )
//logical partitions other than unallocated exist
first = selected_partition .sector_end ;
last = selected_partition .sector_start ;
for ( unsigned int i = 0 ; i < partitions[ t ] .logicals .size() ; i++ )
{
if ( first == 0 )
first = partitions[ t ] .logicals[ i ] .sector_start ;
used = partitions[ t ] .logicals[ i ] .sector_end - first;
if ( partitions[ t ] .logicals[ i ] .type == GParted::TYPE_LOGICAL )
{
if ( partitions[ t ] .logicals[ i ] .sector_start < first )
first = partitions[ t ] .logicals[ i ] .sector_start - (MEBIBYTE / selected_partition .sector_size) ;
if ( first < 0 )
first = 0 ;
if ( partitions[ t ] .logicals[ i ] .sector_end > last )
last = partitions[ t ] .logicals[ i ] .sector_end ;
}
}
used = last - first;
}
//set MIN
if ( used == 0 )
{
//Reasonable minimum of 1 MiB for EBR plus 1 MiB for small partition
fs .MIN = MEBIBYTE ;
}
else
fs .MIN = used * selected_partition .sector_size ;
//set MAX
fs .MAX = (TOTAL_MB - MIN_SPACE_BEFORE_MB) * MEBIBYTE ;
dynamic_cast<Frame_Resizer_Extended *>( frame_resizer_base ) ->
set_used_start( Utils::round( (first - START) / ( total_length / 500.00 ) ) ) ;
@ -227,17 +244,14 @@ void Dialog_Partition_Resize_Move::Resize_Move_Extended( const std::vector<Parti
//set values of spinbutton_before (we assume there is no fixed start.)
if ( first == 0 ) //no logicals
spinbutton_before .set_range( 0, TOTAL_MB - Utils::round( Utils::sector_to_unit( BUF/2, selected_partition .sector_size, UNIT_MIB ) ) ) ;
spinbutton_before .set_range( MIN_SPACE_BEFORE_MB, TOTAL_MB - MIN_SPACE_BEFORE_MB - ceil( fs .MIN / double(MEBIBYTE) ) ) ;
else
spinbutton_before .set_range( 0, Utils::round( Utils::sector_to_unit( first - START, selected_partition .sector_size, UNIT_MIB ) ) ) ;
spinbutton_before .set_range( MIN_SPACE_BEFORE_MB, Utils::round( Utils::sector_to_unit( first - START, selected_partition .sector_size, UNIT_MIB ) ) ) ;
spinbutton_before .set_value( Utils::round( Utils::sector_to_unit( previous, selected_partition .sector_size, UNIT_MIB ) ) ) ;
//set values of spinbutton_size
if ( first == 0 ) //no logicals
spinbutton_size .set_range( Utils::round( Utils::sector_to_unit( BUF/2, selected_partition .sector_size, UNIT_MIB ) ), TOTAL_MB ) ;
else
spinbutton_size .set_range( Utils::round( Utils::sector_to_unit( used, selected_partition .sector_size, UNIT_MIB ) ), TOTAL_MB ) ;
spinbutton_size .set_range( ceil( fs .MIN / double(MEBIBYTE) ), TOTAL_MB - MIN_SPACE_BEFORE_MB ) ;
spinbutton_size .set_value(
Utils::round( Utils::sector_to_unit( selected_partition .get_sector_length(), selected_partition .sector_size, UNIT_MIB ) ) ) ;
@ -245,7 +259,7 @@ void Dialog_Partition_Resize_Move::Resize_Move_Extended( const std::vector<Parti
//set values of spinbutton_after
if ( first == 0 ) //no logicals
spinbutton_after .set_range(
0, TOTAL_MB - Utils::round( Utils::sector_to_unit( BUF/2, selected_partition .sector_size, UNIT_MIB ) ) ) ;
0, TOTAL_MB - ceil( fs .MIN / double(MEBIBYTE) ) - MIN_SPACE_BEFORE_MB ) ;
else
spinbutton_after .set_range(
0, Utils::round( Utils::sector_to_unit( total_length + START - first - used, selected_partition .sector_size, UNIT_MIB ) ) ) ;
@ -253,8 +267,8 @@ void Dialog_Partition_Resize_Move::Resize_Move_Extended( const std::vector<Parti
spinbutton_after .set_value( Utils::round( Utils::sector_to_unit( next, selected_partition .sector_size, UNIT_MIB ) ) ) ;
//set contents of label_minmax
Set_MinMax_Text( Utils::round( Utils::sector_to_unit( first == 0 ? BUF/2 : used, selected_partition .sector_size, UNIT_MIB ) ),
Utils::round( Utils::sector_to_unit( total_length, selected_partition .sector_size, UNIT_MIB ) ) ) ;
Set_MinMax_Text( ceil( fs .MIN / double(MEBIBYTE) )
, Utils::round( Utils::sector_to_unit( total_length - (MIN_SPACE_BEFORE_MB * (MEBIBYTE / selected_partition .sector_size)), selected_partition .sector_size, UNIT_MIB ) ) ) ;
}
} //GParted

View file

@ -372,72 +372,168 @@ Glib::ustring GParted_Core::get_thread_status_message( )
bool GParted_Core::snap_to_cylinder( const Device & device, Partition & partition, Glib::ustring & error )
{
if ( partition .alignment != ALIGN_STRICT )
Sector diff = 0;
if ( partition.type == TYPE_LOGICAL ||
partition.sector_start == device .sectors
)
{
Sector diff = 0;
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 ) )
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 ) )
partition .sector_end -= diff ;
else
partition .sector_end += (device .cylsize - diff ) ;
}
if ( partition .sector_start < 0 )
partition .sector_start = 0 ;
if ( partition .sector_end > device .length )
partition .sector_end = device .length -1 ;
//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 ) )
partition .sector_start -= diff ;
else
partition .sector_start += (device .cylsize - diff ) ;
}
//ok, do some basic checks on the partition..
if ( partition .get_sector_length() <= 0 )
{
error = String::ucompose( _("A partition cannot have a length of %1 sectors"),
partition .get_sector_length() ) ;
return false ;
}
if ( partition .get_sector_length() < partition .sectors_used )
{
error = String::ucompose(
_("A partition with used sectors (%1) greater than its length (%2) is not valid"),
partition .sectors_used,
partition .get_sector_length() ) ;
return false ;
}
//FIXME: it would be perfect if we could check for overlapping with adjacent partitions as well,
//however, finding the adjacent partitions is not as easy as it seems and at this moment all the dialogs
//already perform these checks. A perfect 'fixme-later' ;)
diff = (partition .sector_end +1) % device .cylsize ;
if ( diff )
{
if ( diff < ( device .cylsize / 2 ) )
partition .sector_end -= diff ;
else
partition .sector_end += (device .cylsize - diff ) ;
}
return true ;
}
bool GParted_Core::snap_to_mebibyte( const Device & device, Partition & partition, Glib::ustring & error )
{
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 ;
}
}
//Align start sector
diff = Sector(partition .sector_start % ( MEBIBYTE / partition .sector_size ));
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 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 )
{
//Locate the extended partition that contains the logical partitions.
int index_extended = -1 ;
for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
{
if ( device .partitions[ t ] .type == TYPE_EXTENDED )
index_extended = t ;
}
//If there is a following logical partition that starts a mebibyte or less
// from the end of this partition, then reserve a mebibyte for the EBR.
if ( index_extended != -1 )
{
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 )
< ( MEBIBYTE / device .sector_size )
)
)
partition .sector_end -= 1 ;
}
}
}
//If this is a GPT partition table then reserve a mebibyte at the end of the device
// for the backup partition table
if ( device .disktype == "gpt"
&& ( ( device .length - partition .sector_end ) <= ( MEBIBYTE / device .sector_size ) )
)
{
partition .sector_end -= 1 ;
}
//Align end sector
diff = (partition .sector_end + 1) % ( MEBIBYTE / partition .sector_size);
if ( diff )
partition .sector_end -= diff ;
return true ;
}
bool GParted_Core::snap_to_alignment( const Device & device, Partition & partition, Glib::ustring & error )
{
bool rc = true ;
if ( partition .alignment == ALIGN_CYLINDER )
rc = snap_to_cylinder( device, partition, error ) ;
else if ( partition .alignment == ALIGN_MEBIBYTE )
rc = snap_to_mebibyte( device, partition, error ) ;
//Ensure that partition start and end are not beyond the ends of the disk device
if ( partition .sector_start < 0 )
partition .sector_start = 0 ;
if ( partition .sector_end > device .length )
partition .sector_end = device .length - 1 ;
//do some basic checks on the partition
if ( partition .get_sector_length() <= 0 )
{
error = String::ucompose( _("A partition cannot have a length of %1 sectors"),
partition .get_sector_length() ) ;
return false ;
}
if ( partition .get_sector_length() < partition .sectors_used )
{
error = String::ucompose(
_("A partition with used sectors (%1) greater than its length (%2) is not valid"),
partition .sectors_used,
partition .get_sector_length() ) ;
return false ;
}
//FIXME: it would be perfect if we could check for overlapping with adjacent partitions as well,
//however, finding the adjacent partitions is not as easy as it seems and at this moment all the dialogs
//already perform these checks. A perfect 'fixme-later' ;)
return rc ;
}
bool GParted_Core::apply_operation_to_disk( Operation * operation )
{
bool succes = false ;
@ -1375,7 +1471,9 @@ bool GParted_Core::create_partition( Partition & new_partition, OperationDetail
if ( lp_partition )
{
if ( new_partition .alignment == ALIGN_STRICT )
if ( new_partition .alignment == ALIGN_STRICT
|| new_partition .alignment == ALIGN_MEBIBYTE
)
{
PedGeometry *geom = ped_geometry_new( lp_device,
new_partition .sector_start,
@ -1548,6 +1646,7 @@ bool GParted_Core::resize_move( const Device & device,
OperationDetail & operationdetail )
{
if ( (partition_new .alignment == ALIGN_STRICT)
|| (partition_new .alignment == ALIGN_MEBIBYTE)
|| partition_new .strict_start
|| calculate_exact_geom( partition_old, partition_new, operationdetail )
)
@ -1890,7 +1989,10 @@ bool GParted_Core::resize_move_partition( const Partition & partition_old,
if ( lp_partition )
{
if ( (partition_new .alignment == ALIGN_STRICT) || partition_new .strict_start ) {
if ( (partition_new .alignment == ALIGN_STRICT)
|| (partition_new .alignment == ALIGN_MEBIBYTE)
|| partition_new .strict_start
) {
PedGeometry *geom = ped_geometry_new( lp_device,
partition_new .sector_start,
partition_new .get_sector_length() ) ;

View file

@ -43,6 +43,7 @@ void Partition::Reset()
label .clear() ;
uuid .clear() ;
partition_number = sector_start = sector_end = sectors_used = sectors_unused = -1;
free_space_before = -1 ;
sector_size = 0 ;
color .set( "black" ) ;
inside_extended = busy = strict_start = false ;

View file

@ -669,10 +669,12 @@ void Win_GParted::Add_Operation( Operation * operation, int index )
{
Glib::ustring error ;
//FIXME: this is becoming a mess.. maybe it's better to check if partition_new > 0
if ( operation ->type == OPERATION_DELETE ||
operation ->type == OPERATION_FORMAT ||
if ( operation ->type == OPERATION_DELETE ||
operation ->type == OPERATION_FORMAT ||
operation ->type == OPERATION_CHECK ||
gparted_core .snap_to_cylinder( operation ->device, operation ->partition_new, error ) )
operation ->type == OPERATION_LABEL_PARTITION ||
gparted_core .snap_to_alignment( operation ->device, operation ->partition_new, error )
)
{
operation ->create_description() ;
@ -858,46 +860,34 @@ void Win_GParted::set_valid_operations()
else
required_size = copied_partition .get_byte_length() ;
// /* Copy Primary not at start of disk to within Extended partition */
// Adjust when a primary partition is copied and pasted
// into an unallocated space in an extended partition
// of an MSDOS partition table.
// Since the Extended Boot Record requires an additional track,
// this must be considered in the required space for the
// destination (selected) partition.
// NOTE: This problem does not occur for a primary partition
// at the the start of the disk because the size of the EBR and
// Master Boot Record are the same.
//
// /* Copy Primary not at start of disk to Primary at start of disk */
// Also Adjust when a primary partition that does not start at the
// beginning of the disk is copied and pasted
// into an unallocated space at the start of the disk device.
// Since the Master Boot Record requires an additional track,
// this must be considered in the required space for the
// destination (selected) partition.
//
// Because the largest unit used in the GUI is one
// cylinder size (round to cylinders), the space
// needed in the destination partition needs to be increased
// by one cylinder size.
if ( (/* Copy Primary not at start of disk to within Extended partition */
copied_partition .type == TYPE_PRIMARY
&& copied_partition .sector_start > devices[ current_device ] .sectors /* 63 for MSDOS Partition Table */
&& devices[ current_device ] .disktype == "msdos"
&& selected_partition .type == TYPE_UNALLOCATED
&& selected_partition .inside_extended
)
|| ( /* Copy Primary not at start of disk to Primary at start of disk */
copied_partition .type == TYPE_PRIMARY
&& copied_partition .sector_start > devices[ current_device ] .sectors /* 63 for MSDOS Partition Table */
&& devices[ current_device ] .disktype == "msdos"
&& selected_partition .type == TYPE_UNALLOCATED
&& selected_partition .sector_start <= devices[ current_device ] .sectors /* Beginning of disk device */
&& ! selected_partition .inside_extended
)
//Determine if space is needed for the Master Boot Record or
// the Extended Boot Record. Generally an an additional track or MEBIBYTE
// is required so for our purposes reserve a MEBIBYTE in front of the partition.
// NOTE: This logic also contained in Dialog_Base_Partition::MB_Needed_for_Boot_Record
if ( ( selected_partition .inside_extended
&& selected_partition .type == TYPE_UNALLOCATED
)
|| ( selected_partition .type == TYPE_LOGICAL )
/* Beginning of disk device */
|| ( selected_partition .sector_start <= (MEBIBYTE / selected_partition .sector_size) )
)
required_size += devices[ current_device ] .cylsize * devices[ current_device ] .sector_size ;
required_size += MEBIBYTE;
//Determine if space is needed for the Extended Boot Record for a logical partition
// after this partition. Generally an an additional track or MEBIBYTE
// is required so for our purposes reserve a MEBIBYTE in front of the partition.
if ( ( ( selected_partition .inside_extended
&& selected_partition .type == TYPE_UNALLOCATED
)
|| ( selected_partition .type == TYPE_LOGICAL )
)
&& ( selected_partition .sector_end
< ( devices[ current_device ] .length
- ( 2 * MEBIBYTE / devices[ current_device ] .sector_size )
)
)
)
required_size += MEBIBYTE;
if ( required_size <= selected_partition .get_byte_length() )
allow_paste( true ) ;