From 7ebedc4bb3b81e85fb4c628a2a05308ada147d68 Mon Sep 17 00:00:00 2001 From: Mike Fleetwood Date: Fri, 15 Jun 2012 13:16:30 +0100 Subject: [PATCH] Don't show intrinsic unallocated space (#499202) Most file systems report intrinsic unallocated space using the statvfs() system call when mounted, but not using their own tools. They are: ext2/3/4, fat16/32, hfs, nilfs2, reiserfs and xfs. Showing either a little or no unallocated space, depending on whether a file system is mounted or not, could be confusing to the user. When all file systems are created filling their partitions the unused figure reported by statvfs() and their own tools are the same or very close. Also the used plus unallocated figure from statvfs() agrees with the used figure from their own tools. For all file systems don't display intrinsic unallocated space (that below the threshold of 2 to 5%), instead include it as used space. As soon as the amount of unallocated space becomes significant display it everywhere and also trigger the warning. For display purposes always use the new Partition methods: get_sectors_used(), get_sectors_unused(), and get_sectors_unallocated(). When calculating new usage figures during Paste and Resize/Move operations directly access sectors_used, sectors_unused and sectors_unallocated members. Bug #499202 - gparted does not see the difference if partition size differs from filesystem size --- HACKING | 25 ++++++++--- include/Partition.h | 8 +++- src/Dialog_Partition_Info.cc | 23 +++++----- src/Dialog_Partition_Resize_Move.cc | 2 +- src/DrawingAreaVisualDisk.cc | 15 ++++--- src/GParted_Core.cc | 12 +++-- src/Partition.cc | 70 ++++++++++++++++++++++------- src/TreeView_Detail.cc | 6 ++- src/Win_GParted.cc | 2 +- 9 files changed, 115 insertions(+), 48 deletions(-) diff --git a/HACKING b/HACKING index 3f2d29fa..28d5cb47 100644 --- a/HACKING +++ b/HACKING @@ -24,10 +24,15 @@ partition usage and unallocated space ===================================== After addressing bug #499202 GParted now also displays unallocated space -as well as used and unused space for recognised file systems. The -unallocated space is shown graphically and the numeric figure is shown -in the Information Dialog if it is greater than zero. Additionally a -warning is reported if the unallocated space is considered too much. +as well as used and unused space for recognised file systems. Many file +systems which actually fill their partition report a small amount of +intrinsic unallocated space when mounted, but not when unmounted. To +avoid confusing the user and unnecessarily alarming them don't show +unallocated space below a threshold, 2 to 5% depending on partition +size. It is just included in the used figure instead. (This is +effectively how GParted behaved before bug #499202 was addressed). When +above the threshold unallocated space is shown graphically, the numeric +figure is shown in the Information Dialog and a is warning displayed. See the code and commit messages for more details. Worked example of partition and file system usage for a newly created @@ -54,8 +59,14 @@ used = fs_size - fs_free = 407128 - 406808 = 320 = 160.00 KiB unused = fs_free = 406808 = 198.64 MiB unallocated = ptn_size - fs_size = 409600 - 407128 = 2472 = 1.21 MiB + (Threshold %age for 200 MiB partition is approximately 4.675%) +threshold = ptn_size * pct = 19150 = 9.35 MiB + + (Unallocated is below threshold so is included in used figure) +disp_used = used + unallocated = 320 + 2472 = 2792 = 1.36 MiB +disp_unused = unused = 406808 = 198.64 MiB + Figures displayed in the Information dialog: Size: 200.00 MiB -Used: 160.00 KiB ( 0% ) -Unused: 198.64 MiB ( 99% ) -Unallocated: 1.21 MiB ( 1% ) +Used: 1.36 MiB ( 1% ) +Unused: 198.64 KiB ( 99% ) diff --git a/include/Partition.h b/include/Partition.h index 374e73f3..6c663ff6 100644 --- a/include/Partition.h +++ b/include/Partition.h @@ -73,8 +73,11 @@ public: bool busy ) ; void set_sector_usage( Sector sectors_fs_size, Sector sectors_fs_unused ) ; - bool significant_unallocated_space() const ; + bool sector_usage_known() const ; Sector estimated_min_size() const ; + Sector get_sectors_used() const ; + Sector get_sectors_unused() const ; + Sector get_sectors_unallocated() const ; void Set_Unallocated( const Glib::ustring & device_path, Sector sector_start, @@ -116,6 +119,7 @@ public: Sector sectors_used; Sector sectors_unused; Sector sectors_unallocated; //Difference between the size of the partition and the file system + Sector significant_threshold; //Threshold from intrinsic to significant unallocated sectors Gdk::Color color; bool inside_extended; bool busy; @@ -131,7 +135,7 @@ public: private: void sort_paths_and_remove_duplicates() ; - Sector get_significant_unallocated_sectors() const ; + Sector calc_significant_unallocated_sectors() const ; static bool compare_paths( const Glib::ustring & A, const Glib::ustring & B ) ; diff --git a/src/Dialog_Partition_Info.cc b/src/Dialog_Partition_Info.cc index fdd9a74f..5d4b8a87 100644 --- a/src/Dialog_Partition_Info.cc +++ b/src/Dialog_Partition_Info.cc @@ -136,10 +136,10 @@ void Dialog_Partition_Info::init_drawingarea() unused = 0 ; unallocated = 400 - BORDER *2 ; } - else if ( partition .sectors_used >= 0 && partition .sectors_unused >= 0 ) + else if ( partition .sector_usage_known() ) { - used = Utils::round( ( 400 - BORDER *2 ) / ( dlength / partition .sectors_used ) ) ; - unused = Utils::round( ( 400 - BORDER *2 ) / ( dlength / partition .sectors_unused ) ) ; + used = Utils::round( ( 400 - BORDER *2 ) / ( dlength / partition .get_sectors_used() ) ) ; + unused = Utils::round( ( 400 - BORDER *2 ) / ( dlength / partition .get_sectors_unused() ) ) ; unallocated = 400 - BORDER *2 - used - unused ; } else @@ -202,11 +202,14 @@ void Dialog_Partition_Info::Display_Info() top++, bottom++, Gtk::FILL ) ; - if ( partition.sectors_used != -1 ) + if ( partition .sector_usage_known() ) { + Sector used = partition .get_sectors_used() ; + Sector unused = partition .get_sectors_unused() ; + Sector unallocated = partition .get_sectors_unallocated() ; //calculate relative diskusage - int percent_unused = Utils::round( partition .sectors_unused * 100.0 / ptn_sectors ) ; - int percent_unallocated = Utils::round( partition .sectors_unallocated * 100.0 / ptn_sectors ) ; + int percent_unused = Utils::round( unused * 100.0 / ptn_sectors ) ; + int percent_unallocated = Utils::round( unallocated * 100.0 / ptn_sectors ) ; int percent_used = 100 - percent_unallocated - percent_unused ; //Used @@ -214,7 +217,7 @@ void Dialog_Partition_Info::Display_Info() 0, 1, top, bottom, Gtk::FILL ) ; - table ->attach( * Utils::mk_label( Utils::format_size( partition .sectors_used, partition .sector_size ), true, Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false, true ), + table ->attach( * Utils::mk_label( Utils::format_size( used, partition .sector_size ), true, Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false, true ), 1, 2, top, bottom, Gtk::FILL ) ; @@ -228,7 +231,7 @@ void Dialog_Partition_Info::Display_Info() 0, 1, top, bottom, Gtk::FILL ) ; - table ->attach( * Utils::mk_label( Utils::format_size( partition .sectors_unused, partition .sector_size ), true, Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false, true ), + table ->attach( * Utils::mk_label( Utils::format_size( unused, partition .sector_size ), true, Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false, true ), 1, 2, top, bottom, Gtk::FILL ) ; @@ -238,13 +241,13 @@ void Dialog_Partition_Info::Display_Info() Gtk::FILL ) ; //unallocated - if ( partition .sectors_unallocated > 0 ) + if ( unallocated > 0 ) { table ->attach( * Utils::mk_label( "" + Glib::ustring( _("Unallocated:") ) + "" ), 0, 1, top, bottom, Gtk::FILL ) ; - table ->attach( * Utils::mk_label( Utils::format_size( partition .sectors_unallocated, partition .sector_size ), true, Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false, true ), + table ->attach( * Utils::mk_label( Utils::format_size( unallocated, partition .sector_size ), true, Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false, true ), 1, 2, top, bottom, Gtk::FILL ) ; diff --git a/src/Dialog_Partition_Resize_Move.cc b/src/Dialog_Partition_Resize_Move.cc index 85596a64..b88c53ee 100644 --- a/src/Dialog_Partition_Resize_Move.cc +++ b/src/Dialog_Partition_Resize_Move.cc @@ -63,7 +63,7 @@ void Dialog_Partition_Resize_Move::Set_Data( const Partition & selected_partitio void Dialog_Partition_Resize_Move::Resize_Move_Normal( const std::vector & partitions ) { //little bit of paranoia ;) - if ( selected_partition .sectors_used == -1 && + if ( ! selected_partition .sector_usage_known() && selected_partition .status != STAT_NEW && selected_partition .filesystem != FS_LINUX_SWAP ) fs .shrink = GParted::FS::NONE ; diff --git a/src/DrawingAreaVisualDisk.cc b/src/DrawingAreaVisualDisk.cc index 9d45fb66..6f58b057 100644 --- a/src/DrawingAreaVisualDisk.cc +++ b/src/DrawingAreaVisualDisk.cc @@ -108,20 +108,21 @@ void DrawingAreaVisualDisk::set_static_data( const std::vector & part { //Use sum_sectors as the denominator to calculate fraction_used and // fraction_unallocated in case it doesn't equal partition_length. - Sector sum_sectors = partitions[ t ] .sectors_used - + partitions[ t ] .sectors_unused - + partitions[ t ] .sectors_unallocated ; - if ( partitions[ t ] .sectors_unallocated > 0 ) + Sector used = partitions[ t ] .get_sectors_used() ; + Sector unused = partitions[ t ] .get_sectors_unused() ; + Sector unallocated = partitions[ t ] .get_sectors_unallocated() ; + Sector sum_sectors = used + unused + unallocated ; + if ( unallocated > 0 ) visual_partitions .back() .fraction_unallocated = - partitions[ t ] .sectors_unallocated / static_cast( sum_sectors ) ; + unallocated / static_cast( sum_sectors ) ; else visual_partitions .back() .fraction_unallocated = 0.0 ; //Calculate fraction used from free space so any hidden overhead is counted as used - if ( partitions[ t ] .sectors_unused >= 0 ) + if ( unused >= 0 ) visual_partitions .back() .fraction_used = 1.0 - visual_partitions .back() .fraction_unallocated - - partitions[ t ] .sectors_unused / static_cast( sum_sectors ) ; + - unused / static_cast( sum_sectors ) ; } visual_partitions .back() .color = partitions[ t ] .color; diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc index a6bc845d..b5b74234 100644 --- a/src/GParted_Core.cc +++ b/src/GParted_Core.cc @@ -604,6 +604,11 @@ bool GParted_Core::snap_to_alignment( const Device & device, Partition & partiti return false ; } + //FIXME: I think that this if condition should be impossible because Partition::set_sector_usage(), + // and ::set_used() and ::Set_Unused() before that, don't allow setting file usage figures to be + // larger than the partition size. A btrfs file system spanning muiltiple partitions will have + // usage figures larger than any single partition but the figures will won't be set because of + // the above reasoning. Confirm condition is impossible and consider removing this code. if ( partition .get_sector_length() < partition .sectors_used ) { error = String::ucompose( @@ -1522,7 +1527,8 @@ void GParted_Core::set_used_sectors( std::vector & partitions ) } } - if ( partitions[ t ] .sectors_used == -1 ) + Sector unallocated ; + if ( ! partitions[ t ] .sector_usage_known() ) { temp = _("Unable to read the contents of this file system!") ; temp += "\n" ; @@ -1540,11 +1546,11 @@ void GParted_Core::set_used_sectors( std::vector & partitions ) } partitions[ t ] .messages .push_back( temp ) ; } - else if ( partitions[ t ] .significant_unallocated_space() ) + else if ( ( unallocated = partitions[ t ] .get_sectors_unallocated() ) > 0 ) { /* 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 ) ) ; + Utils::format_size( unallocated, partitions[ t ] .sector_size ) ) ; FS fs = get_fs( partitions[ t ] .filesystem ) ; if ( fs .check != GParted::FS::NONE && fs .grow != GParted::FS::NONE ) diff --git a/src/Partition.cc b/src/Partition.cc index d37d6f58..faf648ca 100644 --- a/src/Partition.cc +++ b/src/Partition.cc @@ -45,6 +45,7 @@ void Partition::Reset() uuid .clear() ; partition_number = sector_start = sector_end = sectors_used = sectors_unused = -1; sectors_unallocated = 0 ; + significant_threshold = 1 ; free_space_before = -1 ; sector_size = 0 ; color .set( "black" ) ; @@ -90,9 +91,10 @@ void Partition::set_sector_usage( Sector sectors_fs_size, Sector sectors_fs_unus && 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 ; + sectors_used = sectors_fs_size - sectors_fs_unused ; + sectors_unused = sectors_fs_unused ; + sectors_unallocated = length - sectors_fs_size ; + significant_threshold = calc_significant_unallocated_sectors() ; } else if ( sectors_fs_size == -1 ) { @@ -106,15 +108,14 @@ void Partition::set_sector_usage( Sector sectors_fs_size, Sector sectors_fs_unus sectors_used = -1 ; sectors_unused = -1 ; } - sectors_unallocated = 0 ; + sectors_unallocated = 0 ; + significant_threshold = 1 ; } } -bool Partition::significant_unallocated_space() const +bool Partition::sector_usage_known() const { - if ( get_sector_length() >= 0 && sectors_unallocated > 0 ) - return sectors_unallocated >= get_significant_unallocated_sectors() ; - return false ; + return sectors_used >= 0 && sectors_unused >= 0 ; } Sector Partition::estimated_min_size() const @@ -122,11 +123,45 @@ Sector Partition::estimated_min_size() const //Add unallocated sectors up to the significant threshold, to // account for any intrinsic unallocated sectors in the // file systems minimum partition size. - if ( sectors_used > 0 ) - return sectors_used + std::min( sectors_unallocated, get_significant_unallocated_sectors() ) ; + if ( sectors_used >= 0 ) + return sectors_used + std::min( sectors_unallocated, significant_threshold ) ; return -1 ; } +//Return user displayable used sectors. +// Only add unallocated sectors up to the significant threshold to +// account for any intrinsic unallocated sectors in the file system. +// Above the threshold just return the used sectors figure. +Sector Partition::get_sectors_used() const +{ + if ( sectors_used >= 0 ) + { + if ( sectors_unallocated < significant_threshold ) + return sectors_used + sectors_unallocated ; + else + return sectors_used ; + } + return -1 ; +} + +//Return user displayable unused sectors. +Sector Partition::get_sectors_unused() const +{ + return sectors_unused ; +} + +//Return user displayable unallocated sectors. +// Return zero below the significant unallocated sectors threshold, as +// the figure has been added to the displayable used sectors. Above the +// threshold just return the unallocated sectors figure. +Sector Partition::get_sectors_unallocated() const +{ + if ( sectors_unallocated < significant_threshold ) + return 0 ; + else + return sectors_unallocated ; +} + void Partition::Set_Unallocated( const Glib::ustring & device_path, Sector sector_start, Sector sector_end, @@ -297,19 +332,21 @@ bool Partition::compare_paths( const Glib::ustring & A, const Glib::ustring & B // 5% , ptn size <= 100 MiB // linear scaling from 5% down to 2%, 100 MiB < ptn size <= 1 GiB // 2% , 1 GiB < ptn size -Sector Partition::get_significant_unallocated_sectors() const +Sector Partition::calc_significant_unallocated_sectors() const { const double HIGHER_UNALLOCATED_FRACTION = 0.05 ; const double LOWER_UNALLOCATED_FRACTION = 0.02 ; Sector length = get_sector_length() ; Byte_Value byte_len = length * sector_size ; + Sector significant ; + if ( byte_len <= 0 ) { - return 0 ; + significant = 1; } else if ( byte_len <= 100 * MEBIBYTE ) { - return Utils::round( length * HIGHER_UNALLOCATED_FRACTION ) ; + significant = Utils::round( length * HIGHER_UNALLOCATED_FRACTION ) ; } else if ( byte_len <= 1 * GIBIBYTE ) { @@ -317,12 +354,15 @@ Sector Partition::get_significant_unallocated_sectors() const ( byte_len - 100 * MEBIBYTE ) * ( HIGHER_UNALLOCATED_FRACTION - LOWER_UNALLOCATED_FRACTION ) / ( 1 * GIBIBYTE - 100 * MEBIBYTE ) + LOWER_UNALLOCATED_FRACTION ; - return Utils::round( length * fraction ) ; + significant = Utils::round( length * fraction ) ; } else { - return Utils::round( length * LOWER_UNALLOCATED_FRACTION ) ; + significant = Utils::round( length * LOWER_UNALLOCATED_FRACTION ) ; } + if ( significant <= 1 ) + significant = 1; + return significant ; } Partition::~Partition() diff --git a/src/TreeView_Detail.cc b/src/TreeView_Detail.cc index 8ca97359..a47bc7bf 100644 --- a/src/TreeView_Detail.cc +++ b/src/TreeView_Detail.cc @@ -190,12 +190,14 @@ void TreeView_Detail::create_row( const Gtk::TreeRow & treerow, const Partition treerow[ treeview_detail_columns .size ] = Utils::format_size( partition .get_sector_length(), partition .sector_size ) ; //used + Sector used = partition .get_sectors_used() ; treerow[ treeview_detail_columns .used ] = - partition .sectors_used == -1 ? "---" : Utils::format_size( partition .sectors_used, partition .sector_size ) ; + used == -1 ? "---" : Utils::format_size( used, partition .sector_size ) ; //unused + Sector unused = partition .get_sectors_unused() ; treerow[ treeview_detail_columns .unused ] = - partition .sectors_unused == -1 ? "---" : Utils::format_size( partition .sectors_unused, partition .sector_size ) ; + unused == -1 ? "---" : Utils::format_size( unused, partition .sector_size ) ; //flags treerow[ treeview_detail_columns .flags ] = diff --git a/src/Win_GParted.cc b/src/Win_GParted.cc index 8c3be42a..d339e96c 100644 --- a/src/Win_GParted.cc +++ b/src/Win_GParted.cc @@ -969,7 +969,7 @@ void Win_GParted::set_valid_operations() { Byte_Value required_size ; if ( copied_partition .filesystem == GParted::FS_XFS ) - required_size = copied_partition .sectors_used * copied_partition .sector_size; + required_size = copied_partition .estimated_min_size() * copied_partition .sector_size; else required_size = copied_partition .get_byte_length() ;