Workaround older blkid not distinguishing between FAT16 and FAT32 (#743181)

Older versions of blkid don't correctly distinguish between FAT16 and
FAT32 file systems when overwriting one with the other.  This effects
GParted too with these file systems on whole disk devices where only
blkid is used to recognise the contents.  See previous fix for why only
blkid is used in this case:
    Avoid whole disk FAT being detected as MSDOS partition table
    (#743181)

Example:

    # blkid -v
    blkid from util-linux 2.20.1 (liblkid 2.20.0, 19-Oct-2011)
    # mkdosfs -F16 -I /dev/md1
    # blkid | fgrep md1
    /dev/md1: SEC_TYPE="msdos" UUID="7C23-95D9" TYPE="vfat"
    # mkdosfs -F32 -I /dev/md1
    # blkid | fgrep md1
    /dev/md1: SEC_TYPE="msdos" UUID="7F93-98F4" TYPE="vfat"

So blkid recognised the UUID changed but didn't remove the SEC_TYPE for
the FAT32 file system.  See FS_Info::get_fs_type() as it uses this to
distinguish between FAT16 and FAT32.  This is a caching update bug in
blkid, because telling blkid not to use the cache gets the right
results:

    # blkid -c /dev/null | fgrep md1
    /dev/md1: UUID="7F93-98F4" TYPE="vfat"

With testing determined that blkid from util-linux 2.23 and later are
not affected and earlier versions are affected.  Mostly recently known
affected distribution is Ubuntu 14.04 LTS with util-linux 2.20.1.

The straight forward fix would be to instruct blkid to not use its cache
with 'blkid -c /dev/null'.  But using blkid's cache is needed to prevent
blkid hanging for minutes when trying to access a non-existent floppy
drive when the BIOS is set incorrectly.  See commit:

    18f863151c
    Fix long scan problem when BIOS floppy setting incorrect

Instead, when using an older affected version of blkid and when blkid
cache reports a vfat file system, run blkid again bypassing the cache.
The device is known to exist and contain a vfat file system, just not
whether it is a FAT16 or FAT32 file system, so can't be a non-existent
floppy device and won't hang.

Bug 743181 - Add unpartitioned drive read-write support
This commit is contained in:
Mike Fleetwood 2015-03-08 11:13:20 +00:00 committed by Curtis Gedak
parent f8faee6377
commit 4087cb2e2b
2 changed files with 32 additions and 1 deletions

View file

@ -39,6 +39,7 @@ private:
Glib::ustring get_device_entry( const Glib::ustring & path ) ;
static bool fs_info_cache_initialized ;
static bool blkid_found ;
static bool need_blkid_vfat_cache_update_workaround;
static bool vol_id_found ;
static Glib::ustring fs_info_cache ;
};

View file

@ -22,6 +22,9 @@ namespace GParted
//initialize static data elements
bool FS_Info::fs_info_cache_initialized = false ;
bool FS_Info::blkid_found = false ;
// Assume workaround is needed just in case determination fails and as
// it only costs a fraction of a second to run blkid command again.
bool FS_Info::need_blkid_vfat_cache_update_workaround = true;
bool FS_Info::vol_id_found = false ;
Glib::ustring FS_Info::fs_info_cache = "";
@ -71,6 +74,24 @@ void FS_Info::set_commands_found()
{
//Set status of commands found
blkid_found = (! Glib::find_program_in_path( "blkid" ) .empty() ) ;
if ( blkid_found )
{
// Blkid from util-linux before 2.23 has a cache update bug which prevents
// correct identification between FAT16 and FAT32 when overwriting one
// with the other. Detect the need for a workaround.
Glib::ustring output, error;
Utils::execute_command( "blkid -v", output, error, true );
Glib::ustring blkid_version = Utils::regexp_label( output, "blkid.* ([0-9\\.]+) " );
int blkid_major_ver = 0;
int blkid_minor_ver = 0;
if ( sscanf( blkid_version.c_str(), "%d.%d", &blkid_major_ver, &blkid_minor_ver ) == 2 )
{
need_blkid_vfat_cache_update_workaround =
( blkid_major_ver < 2 ||
( blkid_major_ver == 2 && blkid_minor_ver < 23 ) );
}
}
vol_id_found = (! Glib::find_program_in_path( "vol_id" ) .empty() ) ;
}
@ -95,8 +116,18 @@ Glib::ustring FS_Info::get_fs_type( const Glib::ustring & path )
fs_sec_type = Utils::regexp_label( dev_path_line, "SEC_TYPE=\"([^\"]*)\"" ) ;
//If vfat, decide whether fat16 or fat32
Glib::ustring output, error;
if ( fs_type == "vfat" )
{
if ( need_blkid_vfat_cache_update_workaround )
{
// Blkid cache does not correctly add and remove SEC_TYPE when
// overwriting FAT16 and FAT32 file systems with each other, so
// prevents correct identification. Run blkid command again,
// bypassing the the cache to get the correct results.
if ( ! Utils::execute_command( "blkid -c /dev/null " + path, output, error, true ) )
fs_sec_type = Utils::regexp_label( output, "SEC_TYPE=\"([^\"]*)\"" );
}
if ( fs_sec_type == "msdos" )
fs_type = "fat16" ;
else
@ -106,7 +137,6 @@ Glib::ustring FS_Info::get_fs_type( const Glib::ustring & path )
if ( fs_type .empty() && vol_id_found )
{
//Retrieve TYPE using vol_id command
Glib::ustring output, error ;
if ( ! Utils::execute_command( "vol_id " + path, output, error, true ) )
fs_type = Utils::regexp_label( output, "ID_FS_TYPE=([^\n]*)" ) ;
}