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
    7ce9b2336b

Closes !67 - Add support for reading exFAT usage and updating the UUID
This commit is contained in:
Mike Fleetwood 2021-02-08 11:39:13 +00:00 committed by Curtis Gedak
parent 7c9a7cb297
commit 57507e21e2
2 changed files with 68 additions and 0 deletions

View File

@ -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);

View File

@ -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()) +