[gparted] Switch to faster ntfsinfo to read NTFS usage (#47)



commit ef4d4cb100156a13b6b64641010e88b8899c8b12
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Sun Apr 14 10:20:04 2019 +0100

    Switch to faster ntfsinfo to read NTFS usage (#47)
    
    A user reported GParted was slow to refresh and timing ntfsresize to
    query his file systems found that it was taking 4.7 seconds and 9.2
    seconds for sizes 31.7 GiB and 49 GiB NTFS file systems respectively.
    Almost 14 seconds just to read the usage.
    
    Created a 4 GiB NTFS and filled it with as many 4 KiB files as possible,
    just over 800,000 files.
    
        # df -k /mnt/2
        Filesystem     1K-blocks    Used Available Use% Mounted on
        /dev/sdb2        4194300 4193860       440 100% /mnt/2
        # df -i /mnt/2
        Filesystem     Inodes  IUsed IFree IUse% Mounted on
        /dev/sdb2      819640 808591 11049   99% /mnt/2
    
    Testing perform of ntfsresize:
    
        # time ntfsresize --info --force --no-progress-bar /dev/sdb2 | \
        > egrep 'Current volume size|resize at|Cluster size'
        Cluster size       : 4096 bytes
        Current volume size: 4294963712 bytes (4295 MB)
        You might resize at 4294516736 bytes (freeing 450560 bytes).
    
        real    0m5.231s
        user    0m2.072s
        sys     0m3.014s
    
    Computation of figures:
        Clusters per volume = 4294963712 / 4096 = 1048575.125
        Free clusters = (4294963712 - 4294516736) / 4096 = 109.125
    
    Testing performance of ntfscluster, as used before this commit [1] from
    GParted 0.3 in 2006:
    
        # time ntfscluster --force /dev/sdb2 | \
        > egrep 'bytes per cluster|bytes per volume|clusters per volume|clusters of free space'
        ...
        bytes per cluster       : 4096
        bytes per volume        : 4294963200
        clusters per volume     : 131071
        clusters of free space  : 110
    
        real    0m4.243s
        user    0m1.629s
        sys     0m2.587s
    
    Note that the clusters per volume figure reported by ntfscluster is
    wrong.  4294963200 / 4096 = 1048575, not 131071.
    
    Testing performance using ntfsinfo:
    
        # time ntfsinfo --mft /dev/sdb2 | \
        egrep 'Cluster Size|Volume Size in Clusters|Free Clusters'
                Cluster Size: 4096
                Volume Size in Clusters: 1048575
                Free Clusters: 110 (0.0%)
    
        real    0m0.022s
        user    0m0.012s
        sys     0m0.018s
    
    Repeating the above tests while also using 'btrace /dev/sdb2' and Ctrl-C
    around each test via a separate terminal, reports these numbers of I/Os
    being performed:
      Command      Read requests   Read bytes
    - ntfsresize           2,695     1116 MiB
    - ntfscluster          2,685     1116 MiB
    - ntfsinfo                13     2208 KiB
    No wonder that ntfsresize and ntfscluster take a long time, they read
    just over 1 GiB of data from the 4 GiB file system, where as ntfsinfo
    only reads just over 2 MiB.
    
    Switch to using ntfsinfo to report file system usage.
    
    [1] 9d956594d6acf0d983ae9105df2f3772194a5404
        replaced ntfscluster with ntfsresize (see #350789)
    
    Closes #47 - GParted is slow refreshing NTFS file systems

 src/ntfs.cc | 76 +++++++++++++++++++++++++++----------------------------------
 1 file changed, 33 insertions(+), 43 deletions(-)
---
diff --git a/src/ntfs.cc b/src/ntfs.cc
index ed54b98c..f93172c3 100644
--- a/src/ntfs.cc
+++ b/src/ntfs.cc
@@ -62,11 +62,11 @@ FS ntfs::get_filesystem_support()
 
        fs .busy = FS::GPARTED ;
 
-       if ( ! Glib::find_program_in_path( "ntfsresize" ) .empty() )
-       {
+       if (! Glib::find_program_in_path("ntfsinfo").empty())
                fs.read = FS::EXTERNAL;
+
+       if (! Glib::find_program_in_path("ntfsresize").empty())
                fs.check = FS::EXTERNAL;
-       }
 
        if ( ! Glib::find_program_in_path( "ntfslabel" ) .empty() ) {
                Glib::ustring version ;
@@ -93,7 +93,7 @@ FS ntfs::get_filesystem_support()
        }
 
        //resizing is a delicate process ...
-       if ( fs .read && fs .check )
+       if (fs.check)
        {
                fs.grow = FS::EXTERNAL;
 
@@ -101,7 +101,6 @@ FS ntfs::get_filesystem_support()
                        fs.shrink = FS::EXTERNAL;
        }
 
-       //we need ntfsresize to set correct used/unused after cloning
        if ( ! Glib::find_program_in_path( "ntfsclone" ) .empty() )
                fs.copy = FS::EXTERNAL;
 
@@ -120,47 +119,38 @@ FS ntfs::get_filesystem_support()
 
 void ntfs::set_used_sectors( Partition & partition ) 
 {
-       exit_status = Utils::execute_command( "ntfsresize --info --force --no-progress-bar " +
-                                             Glib::shell_quote( partition.get_path() ),
-                                             output, error, true );
-       if ( exit_status == 0 || exit_status == 1 )
+       exit_status = Utils::execute_command("ntfsinfo --mft " + Glib::shell_quote(partition.get_path()),
+                                            output, error, true);
+       if (exit_status != 0)
        {
-               Glib::ustring::size_type index = output.find( "Current volume size:" );
-               if ( index >= output .length() ||
-                    sscanf( output.substr( index ).c_str(), "Current volume size: %lld", &T ) != 1 )
-                       T = -1 ;
-
-               index = output .find( "resize at" ) ;
-               if ( index >= output .length() ||
-                    sscanf( output.substr( index ).c_str(), "resize at %lld", &N ) != 1 )
-                       N = -1 ;
-               //For an absolutely full NTFS, "ntfsresize --info" exits
-               //  with status 1 and reports this message instead
-               index = output .find( "ERROR: Volume is full" ) ;
-               if ( index < output .length() )
-                       N = T ;
-
-               index = output.find( "Cluster size" );
-               if ( index >= output.length() ||
-                    sscanf( output.substr( index ).c_str(), "Cluster size       : %lld", &S ) != 1 )
-                       S = -1;
-
-               if ( T > -1 && N > -1 )
-               {
-                       T = Utils::round( T / double(partition .sector_size) ) ;
-                       N = Utils::round( N / double(partition .sector_size) ) ;
-                       partition .set_sector_usage( T, T - N );
-               }
-               if ( S > -1 )
-                       partition.fs_block_size = S;
+               if (! output.empty())
+                       partition.push_back_message(output);
+               if (! error.empty())
+                       partition.push_back_message(output);
+               return;
        }
-       else
+
+       long long cluster_size = -1;
+       Glib::ustring::size_type index = output.find("Cluster Size:");
+       if (index < output.length())
+               sscanf(output.substr(index).c_str(), "Cluster Size: %lld", &cluster_size);
+
+       long long volume_size = -1;
+       index = output.find("Volume Size in Clusters:");
+       if (index < output.length())
+               sscanf(output.substr(index).c_str(), "Volume Size in Clusters: %lld", &volume_size);
+
+       long long free_clusters = -1;
+       index = output.find("Free Clusters:");
+       if (index < output.length())
+               sscanf(output.substr(index).c_str(), "Free Clusters: %lld", &free_clusters);
+
+       if (cluster_size > -1 && volume_size > -1 && free_clusters > -1)
        {
-               if ( ! output .empty() )
-                       partition.push_back_message( output );
-               
-               if ( ! error .empty() )
-                       partition.push_back_message( error );
+               Sector fs_size = volume_size * cluster_size / partition.sector_size;
+               Sector fs_free = free_clusters * cluster_size / partition.sector_size;
+               partition.set_sector_usage(fs_size, fs_free);
+               partition.fs_block_size = cluster_size;
        }
 }
 


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