Skip to content

Commit b14e396

Browse files
authored
Merge pull request #3091 from jfinkels/df-flatten-filter-mount-list
df: refactor filter_mount_list() to be more flat
2 parents 4d07083 + 572b2e0 commit b14e396

File tree

1 file changed

+72
-57
lines changed

1 file changed

+72
-57
lines changed

src/uu/df/src/df.rs

Lines changed: 72 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -161,64 +161,79 @@ impl Filesystem {
161161
}
162162
}
163163

164+
/// Keep only the specified subset of [`MountInfo`] instances.
165+
///
166+
/// If `paths` is non-empty, this function excludes any [`MountInfo`]
167+
/// that is not mounted at the specified path.
168+
///
169+
/// The `opt` argument specifies a variety of ways of excluding
170+
/// [`MountInfo`] instances; see [`Options`] for more information.
171+
///
172+
/// Finally, if there are duplicate entries, the one with the shorter
173+
/// path is kept.
164174
fn filter_mount_list(vmi: Vec<MountInfo>, paths: &[String], opt: &Options) -> Vec<MountInfo> {
165-
vmi.into_iter()
166-
.filter_map(|mi| {
167-
if (mi.remote && opt.show_local_fs)
168-
|| (mi.dummy && !opt.show_all_fs && !opt.show_listed_fs)
169-
|| !opt.fs_selector.should_select(&mi.fs_type)
170-
{
171-
None
172-
} else {
173-
if paths.is_empty() {
174-
// No path specified
175-
return Some((mi.dev_id.clone(), mi));
176-
}
177-
if paths.contains(&mi.mount_dir) {
178-
// One or more paths have been provided
179-
Some((mi.dev_id.clone(), mi))
180-
} else {
181-
// Not a path we want to see
182-
None
183-
}
184-
}
185-
})
186-
.fold(
187-
HashMap::<String, Cell<MountInfo>>::new(),
188-
|mut acc, (id, mi)| {
189-
#[allow(clippy::map_entry)]
190-
{
191-
if acc.contains_key(&id) {
192-
let seen = acc[&id].replace(mi.clone());
193-
let target_nearer_root = seen.mount_dir.len() > mi.mount_dir.len();
194-
// With bind mounts, prefer items nearer the root of the source
195-
let source_below_root = !seen.mount_root.is_empty()
196-
&& !mi.mount_root.is_empty()
197-
&& seen.mount_root.len() < mi.mount_root.len();
198-
// let "real" devices with '/' in the name win.
199-
if (!mi.dev_name.starts_with('/') || seen.dev_name.starts_with('/'))
200-
// let points towards the root of the device win.
201-
&& (!target_nearer_root || source_below_root)
202-
// let an entry over-mounted on a new device win...
203-
&& (seen.dev_name == mi.dev_name
204-
/* ... but only when matching an existing mnt point,
205-
to avoid problematic replacement when given
206-
inaccurate mount lists, seen with some chroot
207-
environments for example. */
208-
|| seen.mount_dir != mi.mount_dir)
209-
{
210-
acc[&id].replace(seen);
211-
}
212-
} else {
213-
acc.insert(id, Cell::new(mi));
214-
}
215-
acc
216-
}
217-
},
218-
)
219-
.into_iter()
220-
.map(|ent| ent.1.into_inner())
221-
.collect::<Vec<_>>()
175+
let mut mount_info_by_id = HashMap::<String, Cell<MountInfo>>::new();
176+
for mi in vmi {
177+
// Don't show remote filesystems if `--local` has been given.
178+
if mi.remote && opt.show_local_fs {
179+
continue;
180+
}
181+
182+
// Don't show pseudo filesystems unless `--all` has been given.
183+
if mi.dummy && !opt.show_all_fs && !opt.show_listed_fs {
184+
continue;
185+
}
186+
187+
// Don't show filesystems if they have been explicitly excluded.
188+
if !opt.fs_selector.should_select(&mi.fs_type) {
189+
continue;
190+
}
191+
192+
// Don't show filesystems other than the ones specified on the
193+
// command line, if any.
194+
if !paths.is_empty() && !paths.contains(&mi.mount_dir) {
195+
continue;
196+
}
197+
198+
// If the device ID has not been encountered yet, just store it.
199+
let id = mi.dev_id.clone();
200+
#[allow(clippy::map_entry)]
201+
if !mount_info_by_id.contains_key(&id) {
202+
mount_info_by_id.insert(id, Cell::new(mi));
203+
continue;
204+
}
205+
206+
// Otherwise, if we have seen the current device ID before,
207+
// then check if we need to update it or keep the previously
208+
// seen one.
209+
let seen = mount_info_by_id[&id].replace(mi.clone());
210+
let target_nearer_root = seen.mount_dir.len() > mi.mount_dir.len();
211+
// With bind mounts, prefer items nearer the root of the source
212+
let source_below_root = !seen.mount_root.is_empty()
213+
&& !mi.mount_root.is_empty()
214+
&& seen.mount_root.len() < mi.mount_root.len();
215+
// let "real" devices with '/' in the name win.
216+
if (!mi.dev_name.starts_with('/') || seen.dev_name.starts_with('/'))
217+
// let points towards the root of the device win.
218+
&& (!target_nearer_root || source_below_root)
219+
// let an entry over-mounted on a new device win...
220+
&& (seen.dev_name == mi.dev_name
221+
/* ... but only when matching an existing mnt point,
222+
to avoid problematic replacement when given
223+
inaccurate mount lists, seen with some chroot
224+
environments for example. */
225+
|| seen.mount_dir != mi.mount_dir)
226+
{
227+
mount_info_by_id[&id].replace(seen);
228+
}
229+
}
230+
231+
// Take ownership of the `MountInfo` instances and collect them
232+
// into a `Vec`.
233+
mount_info_by_id
234+
.into_values()
235+
.map(|m| m.into_inner())
236+
.collect()
222237
}
223238

224239
/// Convert `value` to a human readable string based on `base`.

0 commit comments

Comments
 (0)