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



commit 4087cb2e2ba3e5b43e0118f6364f3b00f44961d9
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Sun Mar 8 11:13:20 2015 +0000

    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:
    
        18f863151c82934fe0a980853cc3deb1e439bec2
        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

 include/FS_Info.h |    1 +
 src/FS_Info.cc    |   32 +++++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletions(-)
---
diff --git a/include/FS_Info.h b/include/FS_Info.h
index 21dc054..88343e6 100644
--- a/include/FS_Info.h
+++ b/include/FS_Info.h
@@ -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 ;
 };
diff --git a/src/FS_Info.cc b/src/FS_Info.cc
index 89eb991..cb7d833 100644
--- a/src/FS_Info.cc
+++ b/src/FS_Info.cc
@@ -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]*)" ) ;
        }


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