[gparted] Add exFAT file system usage reporting (!67)



commit 57507e21e2bd15095ce2ec50ee943689eacf8fbb
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Mon Feb 8 11:39:13 2021 +0000

    Add exFAT file system usage reporting (!67)
    
    exfatprogs 1.1.0 released 2021-02-09 [1] has gained support for
    reporting file system usage [2][3] so add that capability to GParted.
    It works like this:
    
        # dump.exfat /dev/sdb1 | egrep 'Volume Length\(sectors\):|Sector Size Bits:|Sector per Cluster 
bits:|Free Clusters:'
        Volume Length(sectors):                 524288
        Sector Size Bits:                       9
        Sector per Cluster bits:                3
        Free Clusters:                          23585
    
    Unfortunately dump.exfat returns a non-zero status on success so that
    can't be used to check for failure:
    
        # dump.exfat /dev/sdb1
        exfatprogs version : 1.1.0
        -------------- Dump Boot sector region --------------
        Volume Length(sectors):                 524288
        ...
        # echo $?
        192
    
    dump.exfat only writes errors to stderr, so use this to identify failure:
    
        # dump.exfat /dev/sdb1 1> /dev/null
        # echo $?
        192
    
        # dump.exfat /dev/zero 1> /dev/null
        invalid block device size(/dev/zero)
        bogus sector size bits : 0
        # echo $?
        234
    
    [1] exfatprogs-1.1.0 version released
        http://github.com/exfaoprogs/exfatprogs/releases/tag/1.1.0
    
    [2] [feature request] File system usage reporting
        https://github.com/exfatprogs/exfatprogs/issues/139
    
    [3] exfatprogs: add dump.exfat
        https://github.com/exfatprogs/exfatprogs/commit/7ce9b2336b06e76521f7e041d8f0712b2d98a15b
    
    Closes !67 - Add support for reading exFAT usage and updating the UUID

 include/exfat.h |  1 +
 src/exfat.cc    | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)
---
diff --git a/include/exfat.h b/include/exfat.h
index aa6f1d62..ea8b7794 100644
--- a/include/exfat.h
+++ b/include/exfat.h
@@ -31,6 +31,7 @@ class exfat : public FileSystem
 {
 public:
        FS get_filesystem_support();
+       void set_used_sectors(Partition& partition);
        bool create(const Partition& new_partition, OperationDetail& operationdetail);
        void read_label(Partition& partition);
        bool write_label(const Partition& partition, OperationDetail& operationdetail);
diff --git a/src/exfat.cc b/src/exfat.cc
index c0eab9a2..4d82ff38 100644
--- a/src/exfat.cc
+++ b/src/exfat.cc
@@ -37,6 +37,9 @@ FS exfat::get_filesystem_support()
        fs .move = FS::GPARTED ;
        fs .online_read = FS::GPARTED ;
 
+       if (! Glib::find_program_in_path("dump.exfat").empty())
+               fs.read = FS::EXTERNAL;
+
        if (! Glib::find_program_in_path("mkfs.exfat").empty())
        {
                Utils::execute_command("mkfs.exfat -V", output, error, true);
@@ -61,6 +64,70 @@ FS exfat::get_filesystem_support()
 }
 
 
+void exfat::set_used_sectors(Partition& partition)
+{
+       Utils::execute_command("dump.exfat " + Glib::shell_quote(partition.get_path()), output, error, true);
+       // dump.exfat returns non-zero status for both success and failure.  Instead use
+       // non-empty stderr to identify failure.
+       if (! error.empty())
+       {
+               if (! output.empty())
+                       partition.push_back_message(output);
+               if (! error.empty())
+                       partition.push_back_message(error);
+               return;
+       }
+
+       // Example output (lines of interest only):
+       //     $ dump.exfat /dev/sdb1
+       //     Volume Length(sectors):                  524288
+       //     Sector Size Bits:                        9
+       //     Sector per Cluster bits:                 3
+       //     Free Clusters:                           23585
+       //
+       // "exFAT file system specification"
+       // https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification
+       // Section 3.1.5 VolumeLength field
+       // Section 3.1.14 BytesPerSectorShift field
+       // Section 3.1.15 SectorsPerClusterShift field
+
+       // FS size in [FS] sectors
+       long long volume_length = -1;
+       Glib::ustring::size_type index = output.find("Volume Length(sectors):");
+       if (index < output.length())
+               sscanf(output.substr(index).c_str(), "Volume Length(sectors): %lld", &volume_length);
+
+       // FS sector size = 2^(bytes_per_sector_shift)
+       long long bytes_per_sector_shift = -1;
+       index = output.find("Sector Size Bits:");
+       if (index < output.length())
+               sscanf(output.substr(index).c_str(), "Sector Size Bits: %lld", &bytes_per_sector_shift);
+
+       // Cluster size = sector_size * 2^(sectors_per_cluster_shift)
+       long long sectors_per_cluster_shift = -1;
+       index = output.find("Sector per Cluster bits:");
+       if (index < output.length())
+               sscanf(output.substr(index).c_str(), "Sector per Cluster bits: %lld", 
&sectors_per_cluster_shift);
+
+       // Free clusters
+       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 ( volume_length             > -1 && bytes_per_sector_shift > -1 &&
+            sectors_per_cluster_shift > -1 && free_clusters          > -1   )
+       {
+               Byte_Value sector_size = 1 << bytes_per_sector_shift;
+               Byte_Value cluster_size = sector_size * (1 << sectors_per_cluster_shift);
+               Sector fs_free = free_clusters * cluster_size / partition.sector_size;
+               Sector fs_size = volume_length * sector_size / partition.sector_size;
+               partition.set_sector_usage(fs_size, fs_free);
+               partition.fs_block_size = cluster_size;
+       }
+}
+
+
 bool exfat::create(const Partition& new_partition, OperationDetail& operationdetail)
 {
        return ! execute_command("mkfs.exfat -L " + Glib::shell_quote(new_partition.get_filesystem_label()) +


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