[gparted] Add partition alignment option to align to MiB (#617409)



commit e62a23b5b5f5dffff0bf83b0584bf33d0cc8e81e
Author: Curtis Gedak <gedakc gmail com>
Date:   Thu May 20 10:00:14 2010 -0600

    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.

 include/Dialog_Base_Partition.h     |    7 +-
 include/GParted_Core.h              |    2 +
 include/Partition.h                 |    4 +-
 src/Dialog_Base_Partition.cc        |   47 ++++++--
 src/Dialog_Partition_Copy.cc        |   74 +++----------
 src/Dialog_Partition_New.cc         |   50 +++++----
 src/Dialog_Partition_Resize_Move.cc |  102 ++++++++++--------
 src/GParted_Core.cc                 |  206 ++++++++++++++++++++++++++---------
 src/Partition.cc                    |    1 +
 src/Win_GParted.cc                  |   74 ++++++-------
 10 files changed, 338 insertions(+), 229 deletions(-)
---
diff --git a/include/Dialog_Base_Partition.h b/include/Dialog_Base_Partition.h
index d1b4131..58d9439 100644
--- a/include/Dialog_Base_Partition.h
+++ b/include/Dialog_Base_Partition.h
@@ -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 );
diff --git a/include/GParted_Core.h b/include/GParted_Core.h
index ddcfa5c..5202055 100644
--- a/include/GParted_Core.h
+++ b/include/GParted_Core.h
@@ -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 ) ;
diff --git a/include/Partition.h b/include/Partition.h
index a014b72..c7eaed3 100644
--- a/include/Partition.h
+++ b/include/Partition.h
@@ -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.
 
diff --git a/src/Dialog_Base_Partition.cc b/src/Dialog_Base_Partition.cc
index c6d279c..7c48557 100644
--- a/src/Dialog_Base_Partition.cc
+++ b/src/Dialog_Base_Partition.cc
@@ -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 )
diff --git a/src/Dialog_Partition_Copy.cc b/src/Dialog_Partition_Copy.cc
index be21733..88912cc 100644
--- a/src/Dialog_Partition_Copy.cc
+++ b/src/Dialog_Partition_Copy.cc
@@ -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 ;
diff --git a/src/Dialog_Partition_New.cc b/src/Dialog_Partition_New.cc
index eb38f3c..f542f25 100644
--- a/src/Dialog_Partition_New.cc
+++ b/src/Dialog_Partition_New.cc
@@ -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" ) ;
diff --git a/src/Dialog_Partition_Resize_Move.cc b/src/Dialog_Partition_Resize_Move.cc
index acd7e97..4caf886 100644
--- a/src/Dialog_Partition_Resize_Move.cc
+++ b/src/Dialog_Partition_Resize_Move.cc
@@ -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
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index cdef24b..eb076d9 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -372,70 +372,166 @@ 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
-		   ) {
-			//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  )
+	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 ) ;
+	}
+
+	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)
+		   )
 		{
-			if ( diff < ( device .cylsize / 2 ) )
-				partition .sector_start -= diff ;
-			else
-				partition .sector_start += (device .cylsize - diff ) ;
+			//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 ;
 		}
-	
-		diff = (partition .sector_end +1) % device .cylsize ;
-		if ( diff )
+	}
+
+	//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 ( diff < ( device .cylsize / 2 ) )
-				partition .sector_end -= diff ;
-			else
-				partition .sector_end += (device .cylsize - diff ) ;
+			if ( device .partitions[ t ] .type == TYPE_EXTENDED )
+				index_extended = t ;
 		}
-	
-		if ( partition .sector_start < 0 )
-			partition .sector_start = 0 ;
-		if ( partition .sector_end > device .length )
-			partition .sector_end = device .length -1 ;
 
-		//ok, do some basic checks on the partition..
-		if ( partition .get_sector_length() <= 0 )
+		//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 )
 		{
-			error = String::ucompose( _("A partition cannot have a length of %1 sectors"),
-						  partition .get_sector_length() ) ;
-			return false ;
+			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 ( partition .get_sector_length() < partition .sectors_used )
-		{
-			error = String::ucompose( 
+	//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 false ;
 	}
 
-	return true ;
+	//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 )
@@ -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() ) ;
diff --git a/src/Partition.cc b/src/Partition.cc
index 66ca19a..882da8a 100644
--- a/src/Partition.cc
+++ b/src/Partition.cc
@@ -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 ;
diff --git a/src/Win_GParted.cc b/src/Win_GParted.cc
index 1156ebf..fb4eb06 100644
--- a/src/Win_GParted.cc
+++ b/src/Win_GParted.cc
@@ -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 += 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 += devices[ current_device ] .cylsize * devices[ current_device ] .sector_size ;
+				required_size += MEBIBYTE;
 
 			if ( required_size <= selected_partition .get_byte_length() )
 				allow_paste( true ) ;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]