@@ -161,64 +161,79 @@ impl Filesystem {
161
161
}
162
162
}
163
163
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.
164
174
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 ( )
222
237
}
223
238
224
239
/// Convert `value` to a human readable string based on `base`.
0 commit comments