[gparted] Implement fallback if wipefs is not available or fails (#688882)



commit 7a75148a7b8f455c27a584ddc277823be0a90659
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Wed Feb 27 23:00:58 2013 +0000

    Implement fallback if wipefs is not available or fails (#688882)
    
    RHEL/CentOS 5.x uses util-linux 2.13 which predates the wipefs command.
    Also the wipefs command may fail.  Therefore implement a fallback which
    caters for both these cases by overwriting all possible file system
    super blocks with zeros at the start of the partition.
    
    The "MUST be cleared" requirement stated in the first patch is now
    satisfied.  Therefore the status of the "clear old file system
    signatures" step, as returned by erase_filesystem_signatures(), now
    reflects the success of the wipefs command or the internal write zeros.
    Failure of both will stop all operations, matching what happens with all
    other steps.
    
    Bug #688882 - Improve clearing of file system signatures

 src/GParted_Core.cc |   91 +++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 74 insertions(+), 17 deletions(-)
---
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 16c04b8..c303914 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -3130,15 +3130,16 @@ bool GParted_Core::filesystem_resize_disallowed( const Partition & partition )
 
 bool GParted_Core::erase_filesystem_signatures( const Partition & partition, OperationDetail & 
operationdetail )
 {
-       bool success = true ;
+       bool overall_success = false ;
+       operationdetail .add_child( OperationDetail(
+                       String::ucompose( _("clear old file system signatures in %1"),
+                                         partition .get_path() ) ) ) ;
+
        if ( ! Glib::find_program_in_path( "wipefs" ) .empty() )
        {
                Glib::ustring output ;
-               operationdetail .add_child( OperationDetail(
-                               String::ucompose( _("clear old file system signatures in %1"),
-                                                 partition .get_path() ) ) ) ;
                OperationDetail & od = operationdetail .get_last_child() ;
-               success &= wipe_filesystem_signatures( partition .get_path(), od, output ) ;
+               bool wipefs_success = wipe_filesystem_signatures( partition .get_path(), od, output ) ;
 
                //Before util-linux 2.21.0, released Feb 2012, wipefs only erased 1 of
                //  the 3 vfat (fat16/fat32) signatures each time it was called.  If only
@@ -3148,9 +3149,69 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
                if (    p1 != Glib::ustring::npos
                     && output .find( "(vfat)", p1+6 ) == Glib::ustring::npos )
                {
-                       success &= wipe_filesystem_signatures( partition .get_path(), od, output ) ;
-                       success &= wipe_filesystem_signatures( partition .get_path(), od, output ) ;
+                       wipefs_success &= wipe_filesystem_signatures( partition .get_path(), od, output ) ;
+                       wipefs_success &= wipe_filesystem_signatures( partition .get_path(), od, output ) ;
+               }
+               overall_success = wipefs_success ;
+       }
+
+       //Get device, disk & partition and open the device.
+       PedDevice* lp_device = NULL ;
+       PedDisk* lp_disk = NULL ;
+       PedPartition* lp_partition = NULL ;
+       bool device_is_open = false ;
+       if (    open_device_and_disk( partition .device_path, lp_device, lp_disk )
+            && ( lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ) )
+       {
+               if ( ped_device_open( lp_device ) )
+                       device_is_open = true ;
+       }
+
+       if ( ! overall_success )
+       {
+               //Wipefs either doesn't exist or reported an error clearing the file
+               //  system signatures.  Fall back to writing zeros over the first 68 KiB
+               //  of the partition to clear any super blocks and their signatures.  (May
+               //  be more if the block size is larger than 4 KiB.  File system super
+               //  blocks have a range of locations from offset 0 for vfat, ntfs and xfs
+               //  all the way up to offset 64 KiB for btrfs, reiserfs and reiser4).
+               OperationDetail & od = operationdetail .get_last_child() ;
+               od .add_child( OperationDetail( _("clear primary signatures") ) ) ;
+
+               Byte_Value bufsize = std::max( 4LL * KIBIBYTE, lp_device ->sector_size ) ;
+               Byte_Value total_size = std::min( 64LL * KIBIBYTE + bufsize, partition .get_byte_length() ) ;
+               char * buf = static_cast<char *>( malloc( bufsize ) ) ;
+               Byte_Value written = 0LL ;
+               bool zero_success = false ;
+               if ( device_is_open && buf )
+               {
+                       memset( buf, 0, bufsize ) ;
+                       while ( written < total_size )
+                       {
+                               zero_success = ped_geometry_write( & lp_partition ->geom, buf,
+                                                                  written / lp_device ->sector_size,
+                                                                  bufsize / lp_device ->sector_size ) ;
+                               if ( ! zero_success )
+                                       break ;
+                               written += bufsize ;
+                       }
+                       free( buf ) ;
+               }
+
+               if ( zero_success )
+               {
+                       od .get_last_child() .add_child( OperationDetail(
+                                       String::ucompose( _("wrote %1 of zeros at byte offset %2"),
+                                                         Utils::format_size( written, 1 ),
+                                                         0LL ),
+                                       STATUS_NONE, FONT_ITALIC ) ) ;
+                       od .get_last_child() .set_status( STATUS_SUCCES ) ;
                }
+               else
+               {
+                       od .get_last_child() .set_status( STATUS_ERROR ) ;
+               }
+               overall_success = zero_success ;
        }
 
        //Linux kernel doesn't maintain buffer cache coherency between the whole disk
@@ -3178,19 +3239,15 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
        //  Opening the device and calling ped_device_sync() took 0.15 seconds or less on
        //  a 5400 RPM laptop hard drive.  For now just always call ped_device_sync() as
        //  it doesn't add much time to the overall operation.
-       PedDevice * lp_device = ped_device_get( partition .device_path .c_str() ) ;
-       if ( lp_device != NULL )
+       if ( device_is_open )
        {
-               if ( ped_device_open( lp_device ) )
-               {
-                       ped_device_sync( lp_device ) ;
-                       ped_device_close( lp_device ) ;
-               }
-               ped_device_destroy( lp_device ) ;
+               ped_device_sync( lp_device ) ;
+               ped_device_close( lp_device ) ;
        }
+       close_device_and_disk( lp_device, lp_disk ) ;
 
-       operationdetail .get_last_child() .set_status( success ? STATUS_SUCCES : STATUS_N_A ) ;
-       return true ;
+       operationdetail .get_last_child() .set_status( overall_success ? STATUS_SUCCES : STATUS_ERROR ) ;
+       return overall_success ;
 }
 
 bool GParted_Core::wipe_filesystem_signatures( const Glib::ustring & path,


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