From 8093ba2ebd53b1e4ce869d5bf7cb7798238f28d6 Mon Sep 17 00:00:00 2001 From: Mike Fleetwood Date: Tue, 10 Jan 2012 14:13:41 +0000 Subject: [PATCH] Record unallocated space within a partition (#499202) Currently GParted assumes that a file system fills its containing partition. This is not always true and can occur when resizing is performed outside of GParted or a resize operation fails. GParted doesn't display any information about unallocated space to the user and in most cases it is simply included in used space. Add partition unallocated space accounting. Make GParted record the unallocated space for mounted file system and display a warning in the Partition Information dialog when too much unallocated space is found. Partition::set_sector_usage( fs_size, fs_unused ), is the new preferred method of recording file system usage because it allows the unallocated space in a partition to be calculated. Partition::Set_Unused() and Partition::set_used() are now deprecated. NOTES: 1) Set the minimum unallocated space to be 5% before considering it significant to avoid false reporting. Worst case found was a mounted xfs file system in a 100MiB partition, which reports as ~4.7% unallocated according to file system size from statvfs(). However, it reports as having no unallocated space using xfs specific tools. 2) Unallocated space is only a graphical representation for the user. GParted must still use relevant tools to resize file systems before shrinking the data and can't assume all unallocated space exists after the file system at the end of the partition. Bug #499202 - gparted does not see the difference if partition size differs from filesystem size --- include/Partition.h | 6 +++--- src/GParted_Core.cc | 30 ++++++++++++++++++++++++++- src/Partition.cc | 50 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/include/Partition.h b/include/Partition.h index 45f64327..44661752 100644 --- a/include/Partition.h +++ b/include/Partition.h @@ -51,9 +51,6 @@ enum PartitionAlignment { // Indicator if start and end sectors must remain unchanged }; -//FIXME: we should make a difference between partition- and file system size. -//especially in the core this can make a difference when giving detailed feedback. With new cairosupport in gtkmm -//it's even possible to make stuff like this visible in the GUI in a nice and clear way class Partition { public: @@ -77,6 +74,8 @@ public: void Set_Unused( Sector sectors_unused ) ; void set_used( Sector sectors_used ) ; + void set_sector_usage( Sector sectors_fs_size, Sector sectors_fs_unused ) ; + bool significant_unallocated_space() const ; void Set_Unallocated( const Glib::ustring & device_path, Sector sector_start, @@ -117,6 +116,7 @@ public: Sector sector_end; Sector sectors_used; Sector sectors_unused; + Sector sectors_unallocated; //Difference between the size of the partition and the file system Gdk::Color color; bool inside_extended; bool busy; diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc index 9b9cdaf2..e7492b34 100644 --- a/src/GParted_Core.cc +++ b/src/GParted_Core.cc @@ -1486,7 +1486,15 @@ void GParted_Core::set_used_sectors( std::vector & partitions ) if ( partitions[ t ] .get_mountpoints() .size() > 0 ) { if ( statvfs( partitions[ t ] .get_mountpoint() .c_str(), &sfs ) == 0 ) - partitions[ t ] .Set_Unused( sfs .f_bfree * (sfs .f_bsize / partitions[ t ] .sector_size) ) ; + { + Sector fs_size = static_cast( sfs .f_blocks ) * + sfs .f_frsize / + partitions[ t ] .sector_size ; + Sector fs_free = static_cast( sfs .f_bfree ) * + sfs .f_bsize / + partitions[ t ] .sector_size ; + partitions[ t ] .set_sector_usage( fs_size, fs_free ) ; + } else partitions[ t ] .messages .push_back( "statvfs (" + @@ -1532,6 +1540,26 @@ void GParted_Core::set_used_sectors( std::vector & partitions ) } partitions[ t ] .messages .push_back( temp ) ; } + else if ( partitions[ t ] .significant_unallocated_space() ) + { + /* TO TRANSLATORS: looks like 1.28GiB of unallocated space within the partition. */ + temp = String::ucompose( _("%1 of unallocated space within the partition."), + Utils::format_size( partitions[ t ] .sectors_unallocated, partitions[ t ] .sector_size ) ) ; + FS fs = get_fs( partitions[ t ] .filesystem ) ; + if ( fs .check != GParted::FS::NONE + && fs .grow != GParted::FS::NONE ) + { + temp += "\n" ; + /* TO TRANSLATORS: To grow the file system to fill the partition, select the partition and choose the menu item: + * means that the user can perform a check of the partition which will + * also grow the file system to fill the partition. + */ + temp += _("To grow the file system to fill the partition, select the partition and choose the menu item:") ; + temp += "\n" ; + temp += _("Partition --> Check.") ; + } + partitions[ t ] .messages .push_back( temp ) ; + } } else if ( partitions[ t ] .type == GParted::TYPE_EXTENDED ) set_used_sectors( partitions[ t ] .logicals ) ; diff --git a/src/Partition.cc b/src/Partition.cc index 620fdeea..971a36e6 100644 --- a/src/Partition.cc +++ b/src/Partition.cc @@ -20,7 +20,9 @@ namespace GParted { - + +#define SIGNIFICANT_UNALLOCATED_PERCENTAGE 5.0 + Partition::Partition() { Reset() ; @@ -44,6 +46,7 @@ void Partition::Reset() label .clear() ; uuid .clear() ; partition_number = sector_start = sector_end = sectors_used = sectors_unused = -1; + sectors_unallocated = 0 ; free_space_before = -1 ; sector_size = 0 ; color .set( "black" ) ; @@ -80,24 +83,67 @@ void Partition::Set( const Glib::ustring & device_path, this ->color .set( Utils::get_color( filesystem ) ); } +//Deprecated method of setting file system free space, which assumes +// the file system fills the partition. void Partition::Set_Unused( Sector sectors_unused ) { if ( sectors_unused <= get_sector_length() ) { this ->sectors_unused = sectors_unused ; this ->sectors_used = ( sectors_unused == -1 ) ? -1 : get_sector_length() - sectors_unused ; + this ->sectors_unallocated = 0 ; } } - + +//Deprecated method of setting file system used space, which assumes +// the file system fills the partition. void Partition::set_used( Sector sectors_used ) { if ( sectors_used < get_sector_length() ) { this ->sectors_used = sectors_used ; this ->sectors_unused = ( sectors_used == -1 ) ? -1 : get_sector_length() - sectors_used ; + this ->sectors_unallocated = 0 ; } } +//Preferred method of setting file system size and free space, which also +// calculates unallocated space. Set sectors_fs_size = -1 for unknown. +void Partition::set_sector_usage( Sector sectors_fs_size, Sector sectors_fs_unused ) +{ + Sector length = get_sector_length() ; + if ( 0 <= sectors_fs_size && sectors_fs_size <= length + && 0 <= sectors_fs_unused && sectors_fs_unused <= sectors_fs_size + ) + { + sectors_used = sectors_fs_size - sectors_fs_unused ; + sectors_unused = sectors_fs_unused ; + sectors_unallocated = length - sectors_fs_size ; + } + else if ( sectors_fs_size == -1 ) + { + if ( 0 <= sectors_fs_unused && sectors_fs_unused <= length ) + { + sectors_used = length - sectors_fs_unused ; + sectors_unused = sectors_fs_unused ; + } + else + { + sectors_used = -1 ; + sectors_unused = -1 ; + } + sectors_unallocated = 0 ; + } +} + +bool Partition::significant_unallocated_space() const +{ + Sector length = get_sector_length() ; + if ( sectors_unallocated > 0 && length > 0 ) + return ( sectors_unallocated * 100.0 / length > SIGNIFICANT_UNALLOCATED_PERCENTAGE ) ; + return false ; +} + void Partition::Set_Unallocated( const Glib::ustring & device_path, Sector sector_start, Sector sector_end,