1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge pull request #3091 from jfinkels/df-flatten-filter-mount-list

df: refactor filter_mount_list() to be more flat
This commit is contained in:
Sylvestre Ledru 2022-02-07 10:59:23 +01:00 committed by GitHub
commit b14e396983
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -161,64 +161,79 @@ impl Filesystem {
} }
} }
/// Keep only the specified subset of [`MountInfo`] instances.
///
/// If `paths` is non-empty, this function excludes any [`MountInfo`]
/// that is not mounted at the specified path.
///
/// The `opt` argument specifies a variety of ways of excluding
/// [`MountInfo`] instances; see [`Options`] for more information.
///
/// Finally, if there are duplicate entries, the one with the shorter
/// path is kept.
fn filter_mount_list(vmi: Vec<MountInfo>, paths: &[String], opt: &Options) -> Vec<MountInfo> { fn filter_mount_list(vmi: Vec<MountInfo>, paths: &[String], opt: &Options) -> Vec<MountInfo> {
vmi.into_iter() let mut mount_info_by_id = HashMap::<String, Cell<MountInfo>>::new();
.filter_map(|mi| { for mi in vmi {
if (mi.remote && opt.show_local_fs) // Don't show remote filesystems if `--local` has been given.
|| (mi.dummy && !opt.show_all_fs && !opt.show_listed_fs) if mi.remote && opt.show_local_fs {
|| !opt.fs_selector.should_select(&mi.fs_type) continue;
{ }
None
} else { // Don't show pseudo filesystems unless `--all` has been given.
if paths.is_empty() { if mi.dummy && !opt.show_all_fs && !opt.show_listed_fs {
// No path specified continue;
return Some((mi.dev_id.clone(), mi)); }
}
if paths.contains(&mi.mount_dir) { // Don't show filesystems if they have been explicitly excluded.
// One or more paths have been provided if !opt.fs_selector.should_select(&mi.fs_type) {
Some((mi.dev_id.clone(), mi)) continue;
} else { }
// Not a path we want to see
None // Don't show filesystems other than the ones specified on the
} // command line, if any.
} if !paths.is_empty() && !paths.contains(&mi.mount_dir) {
}) continue;
.fold( }
HashMap::<String, Cell<MountInfo>>::new(),
|mut acc, (id, mi)| { // If the device ID has not been encountered yet, just store it.
#[allow(clippy::map_entry)] let id = mi.dev_id.clone();
{ #[allow(clippy::map_entry)]
if acc.contains_key(&id) { if !mount_info_by_id.contains_key(&id) {
let seen = acc[&id].replace(mi.clone()); mount_info_by_id.insert(id, Cell::new(mi));
let target_nearer_root = seen.mount_dir.len() > mi.mount_dir.len(); continue;
// 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() // Otherwise, if we have seen the current device ID before,
&& seen.mount_root.len() < mi.mount_root.len(); // then check if we need to update it or keep the previously
// let "real" devices with '/' in the name win. // seen one.
if (!mi.dev_name.starts_with('/') || seen.dev_name.starts_with('/')) let seen = mount_info_by_id[&id].replace(mi.clone());
// let points towards the root of the device win. let target_nearer_root = seen.mount_dir.len() > mi.mount_dir.len();
&& (!target_nearer_root || source_below_root) // With bind mounts, prefer items nearer the root of the source
// let an entry over-mounted on a new device win... let source_below_root = !seen.mount_root.is_empty()
&& (seen.dev_name == mi.dev_name && !mi.mount_root.is_empty()
/* ... but only when matching an existing mnt point, && seen.mount_root.len() < mi.mount_root.len();
to avoid problematic replacement when given // let "real" devices with '/' in the name win.
inaccurate mount lists, seen with some chroot if (!mi.dev_name.starts_with('/') || seen.dev_name.starts_with('/'))
environments for example. */ // let points towards the root of the device win.
|| seen.mount_dir != mi.mount_dir) && (!target_nearer_root || source_below_root)
{ // let an entry over-mounted on a new device win...
acc[&id].replace(seen); && (seen.dev_name == mi.dev_name
} /* ... but only when matching an existing mnt point,
} else { to avoid problematic replacement when given
acc.insert(id, Cell::new(mi)); inaccurate mount lists, seen with some chroot
} environments for example. */
acc || seen.mount_dir != mi.mount_dir)
} {
}, mount_info_by_id[&id].replace(seen);
) }
.into_iter() }
.map(|ent| ent.1.into_inner())
.collect::<Vec<_>>() // Take ownership of the `MountInfo` instances and collect them
// into a `Vec`.
mount_info_by_id
.into_values()
.map(|m| m.into_inner())
.collect()
} }
/// Convert `value` to a human readable string based on `base`. /// Convert `value` to a human readable string based on `base`.