Support /etc/fstab using Unicode labels as mount points (#786502)

So far GParted is still loading the default non-reversible encoded
labels from blkid in the initial loading of the FS_Info module cache.
This encoded label is used to match LABEL=<label> when reading
/etc/fstab, via the get_path_by_label() call, so works for ASCII only
labels.  This prevents GParted enabling the "mount on >" partition menu
item when non-ASCII labels are used.

To fix this:
1) Stop reading the labels the wrong way.
   Via the blkid command used to initially load the FS_Info module cache
   and is subject to default non-reversible encoding of non-printable
   ASCII bytes.
2) Read all the labels the right way, but only when needed.
   Only when /etc/fstab file contains LABEL=<label> and
   get_path_by_label() is called, read all the labels from blkid without
   encoding them via run_blkid_update_cache_one_label().
3) Return label from the cache.
   get_label() returns the cached label, loading it into the cache first
   if needed with run_blkid_update_cache_one_label().

In the worst case scenario of having a LABEL=<label> in /etc/fstab blkid
will be run for every partition containing a recognised file system to
read the label.  On my desktop with 5 hard drives, 4  SWRaid arrays and
31 recognised file systems running 'blkid -o value -s LABEL ...' 31
times took 0.074 seconds of a total scan time of 9.072 seconds.  Less
that 1% of the total scanning time.  When LABEL=<label> is not used in
/etc/fstab individual blkid executions are only used to read labels for
file systems where there is no file system specific tool available
reducing the impact further.  Blkid itself caches the data in it's
blkid.tab cache file rather than reading all file systems on each
invocation.  Also the Linux file system cache will already contain the
blkid executable file, needed libraries files and the blkid.tab cache
file itself.  Hence why repeated execution of blkid is so fast.

Further to the updated comment in set_partition_label_and_uuid().
Matching LABEL=<label> from /etc/fstab uses the label obtained from
blkid run in the C locale so this kind of assumes it returns the label
correctly and it does for my limited testing on Unicode enabled
desktops.  Just not sure if it would be true for all cases in all
locales compared to the FS specific command run in the users default
locale.

Bug 786502 - Support reading Unicode labels when file system specific
             tools aren't available
This commit is contained in:
Mike Fleetwood 2017-08-28 10:52:44 +01:00 committed by Curtis Gedak
parent b022c1e3a9
commit 73fe1dbf5c
3 changed files with 29 additions and 14 deletions

View file

@ -52,6 +52,7 @@ private:
static void load_fs_info_cache();
static void load_fs_info_cache_extra_for_path( const Glib::ustring & path );
static bool run_blkid_load_cache( const Glib::ustring & path = "" );
static void update_fs_info_cache_all_labels();
static bool run_blkid_update_cache_one_label( FS_Entry & fs_entry );
static bool fs_info_cache_initialized ;

View file

@ -93,13 +93,14 @@ Glib::ustring FS_Info::get_label( const Glib::ustring & path, bool & found )
for ( unsigned int i = 0 ; i < fs_info_cache.size() ; i ++ )
if ( bs == fs_info_cache[i].path )
{
if ( fs_info_cache[i].type == "" )
if ( fs_info_cache[i].have_label || fs_info_cache[i].type == "" )
{
// This is a blank cache entry for a whole disk device
// containing a partition table, so no label (as created
// by load_fs_info_cache_extra_for_path()).
found = false;
return "";
// Already have the label or this is a blank cache entry
// for a whole disk device containing a partition table,
// so no label (as created by
// load_fs_info_cache_extra_for_path()).
found = fs_info_cache[i].have_label;
return fs_info_cache[i].label;
}
// Run blkid to get the label for this one partition, update the
@ -134,6 +135,7 @@ Glib::ustring FS_Info::get_path_by_uuid( const Glib::ustring & uuid )
Glib::ustring FS_Info::get_path_by_label( const Glib::ustring & label )
{
initialize_if_required();
update_fs_info_cache_all_labels();
for ( unsigned int i = 0 ; i < fs_info_cache.size() ; i ++ )
if ( label == fs_info_cache[i].label )
return fs_info_cache[i].path.m_name;
@ -224,7 +226,8 @@ void FS_Info::load_fs_info_cache_extra_for_path( const Glib::ustring & path )
bool FS_Info::run_blkid_load_cache( const Glib::ustring & path )
{
// Parse blkid output line by line extracting mandatory field: path and optional
// fields: type, sec_type, uuid, label.
// fields: type, sec_type, uuid. Label is not extracted here because of blkid's
// default non-reversible encoding of non printable ASCII bytes.
// Example output:
// /dev/sda1: UUID="f828ee8c-1e16-4ca9-b234-e4949dcd4bd1" TYPE="xfs"
// /dev/sda2: UUID="p31pR5-qPLm-YICz-O09i-sB4u-mAH2-GVSNWG" TYPE="LVM2_member"
@ -255,11 +258,6 @@ bool FS_Info::run_blkid_load_cache( const Glib::ustring & path )
fs_entry.type = Utils::regexp_label( lines[i], " TYPE=\"([^\"]*)\"" );
fs_entry.sec_type = Utils::regexp_label( lines[i], " SEC_TYPE=\"([^\"]*)\"" );
fs_entry.uuid = Utils::regexp_label( lines[i], " UUID=\"([^\"]*)\"" );
if ( lines[i].find( " LABEL=\"" ) != Glib::ustring::npos )
{
fs_entry.have_label = true;
fs_entry.label = Utils::regexp_label( lines[i], " LABEL=\"([^\"]*)\"" );
}
fs_info_cache.push_back( fs_entry );
loaded_entries = true;
}
@ -269,6 +267,18 @@ bool FS_Info::run_blkid_load_cache( const Glib::ustring & path )
return loaded_entries;
}
void FS_Info::update_fs_info_cache_all_labels()
{
if ( ! blkid_found )
return;
// For all cache entries which are file systems but don't yet have a label load it
// now.
for ( unsigned int i = 0 ; i < fs_info_cache.size() ; i ++ )
if ( fs_info_cache[i].type != "" && ! fs_info_cache[i].have_label )
run_blkid_update_cache_one_label( fs_info_cache[i] );
}
bool FS_Info::run_blkid_update_cache_one_label( FS_Entry & fs_entry )
{
if ( ! blkid_found )

View file

@ -1284,8 +1284,12 @@ void GParted_Core::set_partition_label_and_uuid( Partition & partition )
return;
}
// Retrieve file system label. Use file system specific method first in an effort
// to ensure multi-byte character sets are properly displayed.
// Retrieve file system label. Use file system specific method first because it
// has been that way since (#662537) to display Unicode labels correctly.
// (#786502) adds support for reading Unicode labels through the FS_Info cache.
// Either method should produce the same labels however the FS specific command is
// run in the users locale where as blkid is run in the C locale. Shouldn't
// matter but who knows for sure!
read_label( partition );
if ( ! partition.filesystem_label_known() )
{