[gparted] Fix rollback when growing a partition by more than twice fails (#791875)



commit f54dd1070720e3db8ad90e259e7163b78b05d48e
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Sat Dec 30 12:11:44 2017 +0000

    Fix rollback when growing a partition by more than twice fails (#791875)
    
    Attempt to grow a partition to more than twice it's size.  If committing
    that change to the partition fails in such a way that the new larger
    partition boundaries are not written to the disk drive then rolling back
    will fail with libparted error:
        Can't have overlapping partitions.
    
    Example operation details:
    
        Grow /dev/sdb8 from 1.00 GiB to 2.20 GiB
        * calibrate /dev/sdb8                                      (SUCCESS)
        * check file system on /dev/sdb8 for errors and (if poss...(SUCCESS)
        * grow partition from 1.00 GiB to 2.20 GiB                 (ERROR)
        * attempt to rollback failed change to the partition       (ERROR)
            original start: 7350272
            original end:   9447423
            original size:  2097152 (1.00 GiB)
          * libparted messages                                     (ERROR)
              Can't have overlapping partitions.
    
    What happened is that resize_move_partition() passed the new Partition
    object to resize_move_partition_implement() as the source partition for
    the rollback, and than called ped_disk_partition_by_sector() with a
    sector in the middle to identify the partition to be changed.  However
    the new partition was never written to the drive so in the middle was
    outside the old smaller partition.  Therefore libparted identified empty
    space after the partition, rather than the partition itself, as the
    intended target so when ped_disk_set_partition_geom() was called it
    reported error "Can't have overlapping partitions" because it thought
    another partition was being created with the same boundaries as the old
    partition, rather than the boundaries of the old partition being
    updated.
    
    The same error also occurs when rolling back a failed partition change
    as part of a move operation when the middle of the new partition falls
    outside of the boundaries of the old partition.
    
    Fix by making a temporary Partition object from the intersection of the
    old and new partition boundaries just to be used to identify the
    partition being changed to libparted.  As this is only rolling back a
    single step adjusting the partition boundaries as part of a resize
    and/or move operation, the old and new partition boundaries must
    intersect (and in fact that intersection contains the file system data).
    
    Bug 791875 - Rollback specific failed partition change steps

 src/GParted_Core.cc |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)
---
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 008dd87..7a61724 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -2778,11 +2778,21 @@ bool GParted_Core::resize_move_partition( const Partition & partition_old,
                operationdetail.add_child(
                                OperationDetail( _("attempt to rollback failed change to the partition") ) );
 
+               // Create a temporary partition which is the intersection of the old and
+               // new partitions so that the middle sector can be used to identify the
+               // partition needing rollback, whether or not the above failed partition
+               // change made it to the drive or not.
+               Partition *partition_intersection = partition_new.clone();
+               partition_intersection->sector_start = std::max( partition_old.sector_start,
+                                                                partition_new.sector_start );
+               partition_intersection->sector_end   = std::min( partition_old.sector_end,
+                                                                partition_new.sector_end );
+
                Partition *partition_restore = partition_old.clone();
                // Ensure that old partition boundaries are not modified
                partition_restore->alignment = ALIGN_STRICT;
 
-               bool rollback_success = resize_move_partition_implement( partition_new, *partition_restore,
+               bool rollback_success = resize_move_partition_implement( *partition_intersection, 
*partition_restore,
                                                                         new_start, new_end );
 
                operationdetail.get_last_child().add_child(
@@ -2799,6 +2809,8 @@ bool GParted_Core::resize_move_partition( const Partition & partition_old,
 
                delete partition_restore;
                partition_restore = NULL;
+               delete partition_intersection;
+               partition_intersection = NULL;
 
                operationdetail.get_last_child().set_success_and_capture_errors( rollback_success );
        }


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