From 042e537ca835245083ae864a7448f86763acb2ef Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Sat, 12 Feb 2022 20:54:47 -0500 Subject: [PATCH] df: refactor is_included(), mount_info_lt() funcs Factor two helper functions, `is_included()` and `mount_info_lt()`, from the `filter_mount_list()` function. --- src/uu/df/src/df.rs | 94 ++++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/src/uu/df/src/df.rs b/src/uu/df/src/df.rs index a51966d9e..b4153f1af 100644 --- a/src/uu/df/src/df.rs +++ b/src/uu/df/src/df.rs @@ -161,6 +161,63 @@ impl Filesystem { } } +/// Whether to display the mount info given the inclusion settings. +fn is_included(mi: &MountInfo, paths: &[String], opt: &Options) -> bool { + // Don't show remote filesystems if `--local` has been given. + if mi.remote && opt.show_local_fs { + return false; + } + + // Don't show pseudo filesystems unless `--all` has been given. + if mi.dummy && !opt.show_all_fs && !opt.show_listed_fs { + return false; + } + + // Don't show filesystems if they have been explicitly excluded. + if !opt.fs_selector.should_select(&mi.fs_type) { + return false; + } + + // Don't show filesystems other than the ones specified on the + // command line, if any. + if !paths.is_empty() && !paths.contains(&mi.mount_dir) { + return false; + } + + true +} + +/// Whether the mount info in `m2` should be prioritized over `m1`. +/// +/// The "lt" in the function name is in analogy to the +/// [`std::cmp::PartialOrd::lt`]. +fn mount_info_lt(m1: &MountInfo, m2: &MountInfo) -> bool { + // let "real" devices with '/' in the name win. + if m1.dev_name.starts_with('/') && !m2.dev_name.starts_with('/') { + return false; + } + + let m1_nearer_root = m1.mount_dir.len() < m2.mount_dir.len(); + // With bind mounts, prefer items nearer the root of the source + let m2_below_root = !m1.mount_root.is_empty() + && !m2.mount_root.is_empty() + && m1.mount_root.len() > m2.mount_root.len(); + // let points towards the root of the device win. + if m1_nearer_root && !m2_below_root { + return false; + } + + // let an entry over-mounted on a new device win, but only when + // matching an existing mnt point, to avoid problematic + // replacement when given inaccurate mount lists, seen with some + // chroot environments for example. + if m1.dev_name != m2.dev_name && m1.mount_dir == m2.mount_dir { + return false; + } + + true +} + /// Keep only the specified subset of [`MountInfo`] instances. /// /// If `paths` is non-empty, this function excludes any [`MountInfo`] @@ -174,24 +231,7 @@ impl Filesystem { fn filter_mount_list(vmi: Vec, paths: &[String], opt: &Options) -> Vec { let mut mount_info_by_id = HashMap::>::new(); for mi in vmi { - // Don't show remote filesystems if `--local` has been given. - if mi.remote && opt.show_local_fs { - continue; - } - - // Don't show pseudo filesystems unless `--all` has been given. - if mi.dummy && !opt.show_all_fs && !opt.show_listed_fs { - continue; - } - - // Don't show filesystems if they have been explicitly excluded. - if !opt.fs_selector.should_select(&mi.fs_type) { - continue; - } - - // Don't show filesystems other than the ones specified on the - // command line, if any. - if !paths.is_empty() && !paths.contains(&mi.mount_dir) { + if !is_included(&mi, paths, opt) { continue; } @@ -207,23 +247,7 @@ fn filter_mount_list(vmi: Vec, paths: &[String], opt: &Options) -> Ve // then check if we need to update it or keep the previously // seen one. let seen = mount_info_by_id[&id].replace(mi.clone()); - let target_nearer_root = seen.mount_dir.len() > mi.mount_dir.len(); - // With bind mounts, prefer items nearer the root of the source - let source_below_root = !seen.mount_root.is_empty() - && !mi.mount_root.is_empty() - && seen.mount_root.len() < mi.mount_root.len(); - // let "real" devices with '/' in the name win. - if (!mi.dev_name.starts_with('/') || seen.dev_name.starts_with('/')) - // let points towards the root of the device win. - && (!target_nearer_root || source_below_root) - // let an entry over-mounted on a new device win... - && (seen.dev_name == mi.dev_name - /* ... but only when matching an existing mnt point, - to avoid problematic replacement when given - inaccurate mount lists, seen with some chroot - environments for example. */ - || seen.mount_dir != mi.mount_dir) - { + if mount_info_lt(&mi, &seen) { mount_info_by_id[&id].replace(seen); } }