[gparted] Handle btrfs tools rounding of figures (#499202)



commit 7fc16a1b6905f7f2d6876d317c4757ff09cdd57c
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Wed May 30 13:41:59 2012 +0100

    Handle btrfs tools rounding of figures (#499202)
    
    The btrfs programs only provide approximations of file system sizes
    because they display figures using binary prefix multipliers to two
    decimal places of precision.  E.g. 2.00GB.  For partition sizes where
    the contained file system size rounds upwards, GParted will fail to read
    the file system usage and report a warning because the file system will
    appear to be larger than the partition.
    
    For example, create a 2047 MiB partition containing a btrfs file system
    and display its size.
    
        # btrfs filesystem show
        Label: none  uuid: 92535375-5e76-4a70-896a-8d796a577993
                Total devices 1 FS bytes used 28.00KB
                devid    1 size 2.00GB used 240.62MB path /dev/sda12
    
    The file system size appears to be 2048 MiB, but that is larger than the
    partition, hence the issue GParted has.  (Actually uses the btrfs devid
    size which is the size of the btrfs file system within the partition in
    question).
    
    This issue is new with the fix for Bug #499202 because it queries the
    file system sizes for the first time.  The same issue could
    theoretically occur previously, but with the used figure (FS bytes
    used).  This would have been virtually impossible to trigger because
    btrfs file system would have to have been greater than 99% full, but
    btrfs has been notorious for early reporting of file system full.
    
    The fix is that if a btrfs file system size appears larger than the
    partition size, but the minimum possible size which could have been
    rounded to the reported figure is within the partition size use the
    smaller partition size instead.  Apply the method to the used figure
    too, in case the file system is 100% full.  Also if the btrfs file
    system size appears smaller than the partition size, but the maximum
    possible size which could have been rounded to the reported figure is
    within the partition size use the larger partition size instead to avoid
    reporting, presumably false, unallocated space.  Not applied to file
    system used figure.
    
    Bug 499202 - gparted does not see the difference if partition size
                 differs from filesystem size

 include/btrfs.h |    4 ++-
 src/btrfs.cc    |   84 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 82 insertions(+), 6 deletions(-)
---
diff --git a/include/btrfs.h b/include/btrfs.h
index 4c1ab6f..16d9dde 100644
--- a/include/btrfs.h
+++ b/include/btrfs.h
@@ -45,7 +45,9 @@ public:
 	bool check_repair( const Partition & partition, OperationDetail & operationdetail ) ;
 
 private:
-	Sector btrfs_size_to_num( Glib::ustring s ) const ;
+	Byte_Value btrfs_size_to_num( Glib::ustring str, Byte_Value ptn_bytes, bool scale_up ) const ;
+	gdouble btrfs_size_max_delta( Glib::ustring str ) const ;
+	gdouble btrfs_size_to_gdouble( Glib::ustring str ) const ;
 };
 } //GParted
 
diff --git a/src/btrfs.cc b/src/btrfs.cc
index e051314..a131586 100644
--- a/src/btrfs.cc
+++ b/src/btrfs.cc
@@ -19,6 +19,8 @@
 
 #include "../include/btrfs.h"
 
+#include <ctype.h>
+
 namespace GParted
 {
 
@@ -117,7 +119,6 @@ bool btrfs::check_repair( const Partition & partition, OperationDetail & operati
 
 void btrfs::set_used_sectors( Partition & partition )
 {
-
 	if ( btrfs_found )
 		exit_status = Utils::execute_command( "btrfs filesystem show " + partition .get_path(), output, error, true ) ;
 	else
@@ -130,15 +131,16 @@ void btrfs::set_used_sectors( Partition & partition )
 		//  file system wide used bytes (wrong for multi-device
 		//  file systems).
 
+		Byte_Value ptn_bytes = partition .get_byte_length() ;
 		Glib::ustring str ;
 		//Btrfs file system device size
 		Glib::ustring regexp = "devid .* size ([0-9\\.]+.?B) .* path " + partition .get_path() ;
 		if ( ! ( str = Utils::regexp_label( output, regexp ) ) .empty() )
-			T = btrfs_size_to_num( str ) ;
+			T = btrfs_size_to_num( str, ptn_bytes, true ) ;
 
 		//Btrfs file system wide used bytes
 		if ( ! ( str = Utils::regexp_label( output, "FS bytes used ([0-9\\.]+.?B)" ) ) .empty() )
-			N = T - btrfs_size_to_num( str ) ;
+			N = T - btrfs_size_to_num( str, ptn_bytes, false ) ;
 
 		if ( T > -1 && N > -1 )
 		{
@@ -304,7 +306,79 @@ void btrfs::read_uuid( Partition & partition )
 	}
 }
 
-Sector btrfs::btrfs_size_to_num( Glib::ustring str ) const
+//Private methods
+
+//Return the value of a btrfs tool formatted size, including reversing
+//  changes in certain cases caused by using binary prefix multipliers
+//  and rounding to two decimal places of precision.  E.g. "2.00GB".
+Byte_Value btrfs::btrfs_size_to_num( Glib::ustring str, Byte_Value ptn_bytes, bool scale_up ) const
+{
+	Byte_Value size_bytes = Utils::round( btrfs_size_to_gdouble( str ) ) ;
+	gdouble delta         = btrfs_size_max_delta( str ) ;
+	Byte_Value upper_size = size_bytes + ceil( delta ) ;
+	Byte_Value lower_size = size_bytes - floor( delta ) ;
+
+	if ( size_bytes > ptn_bytes && lower_size <= ptn_bytes )
+	{
+		//Scale value down to partition size:
+		//  The btrfs tool reported size appears larger than the partition
+		//  size, but the minimum possible size which could have been rounded
+		//  to the reported figure is within the partition size so use the
+		//  smaller partition size instead.  Applied to FS device size and FS
+		//  wide used bytes.
+		//      ............|         ptn_bytes
+		//               [    x    )  size_bytes with upper & lower size
+		//                  x         scaled down size_bytes
+		//  Do this to avoid the FS size or used bytes being larger than the
+		//  partition size and GParted failing to read the file system usage and
+		//  report a warning.
+		size_bytes = ptn_bytes ;
+	}
+	else if ( scale_up && size_bytes < ptn_bytes && upper_size > ptn_bytes )
+	{
+		//Scale value up to partition size:
+		//  The btrfs tool reported size appears smaller than the partition
+		//  size, but the maximum possible size which could have been rounded
+		//  to the reported figure is within the partition size so use the
+		//  larger partition size instead.  Applied to FS device size only.
+		//      ............|     ptn_bytes
+		//           [    x    )  size_bytes with upper & lower size
+		//                  x     scaled up size_bytes
+		//  Make an assumption that the file system actually fills the
+		//  partition, rather than is slightly smaller to avoid false reporting
+		//  of unallocated space.
+		size_bytes = ptn_bytes ;
+	}
+
+	return size_bytes ;
+}
+
+//Return maximum delta for which num +/- delta would be rounded by btrfs
+//  tools to str.  E.g. btrfs_size_max_delta("2.00GB") -> 5368709.12
+gdouble btrfs::btrfs_size_max_delta( Glib::ustring str ) const
+{
+	Glib::ustring limit_str ;
+	//Create limit_str.  E.g. str = "2.00GB" -> limit_str = "0.005GB"
+	for ( Glib::ustring::iterator p = str .begin() ; p != str .end() ; p ++ )
+	{
+		if ( isdigit( *p ) )
+			limit_str .append( "0" ) ;
+		else if ( *p == '.' )
+			limit_str .append( "." ) ;
+		else
+		{
+			limit_str .append( "5" ) ;
+			limit_str .append( p, str .end() ) ;
+			break ;
+		}
+	}
+	gdouble max_delta = btrfs_size_to_gdouble( limit_str ) ;
+	return max_delta ;
+}
+
+//Return the value of a btrfs tool formatted size.
+//  E.g. btrfs_size_to_gdouble("2.00GB") -> 2147483648.0
+gdouble btrfs::btrfs_size_to_gdouble( Glib::ustring str ) const
 {
 	gchar * suffix ;
 	gdouble rawN = g_ascii_strtod( str .c_str(), & suffix ) ;
@@ -317,7 +391,7 @@ Sector btrfs::btrfs_size_to_num( Glib::ustring str ) const
 		case 'T':	mult = TEBIBYTE ;	break ;
 		default:	mult = 1 ;		break ;
 	}
-	return Utils::round( rawN * mult ) ;
+	return rawN * mult ;
 }
 
 } //GParted



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