From ad96a1b8a065fa42903079d9c2b296700954908b Mon Sep 17 00:00:00 2001 From: Frantisek Kropac Date: Sat, 10 Jun 2023 09:22:01 +0200 Subject: [PATCH] Find MountInfo properly when symlink is used (#4929) * Find MountInfo properly when symlink is entered According to GNU implementation the entered path is being compared with the canonicalized device name in MountInfo. Co-authored-by: Frantisek Kropac Co-authored-by: Sylvestre Ledru --- Cargo.lock | 1 + src/uu/df/Cargo.toml | 3 +++ src/uu/df/src/filesystem.rs | 24 ++++++++++++++++++++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0357f7fe0..b7f071c5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2562,6 +2562,7 @@ name = "uu_df" version = "0.0.19" dependencies = [ "clap", + "tempfile", "unicode-width", "uucore", ] diff --git a/src/uu/df/Cargo.toml b/src/uu/df/Cargo.toml index 0974a443c..2be3967af 100644 --- a/src/uu/df/Cargo.toml +++ b/src/uu/df/Cargo.toml @@ -19,6 +19,9 @@ clap = { workspace = true } uucore = { workspace = true, features = ["libc", "fsext"] } unicode-width = { workspace = true } +[dev-dependencies] +tempfile = "3" + [[bin]] name = "df" path = "src/main.rs" diff --git a/src/uu/df/src/filesystem.rs b/src/uu/df/src/filesystem.rs index 461815e67..813846a6c 100644 --- a/src/uu/df/src/filesystem.rs +++ b/src/uu/df/src/filesystem.rs @@ -42,7 +42,7 @@ pub(crate) struct Filesystem { /// This function returns the element of `mounts` on which `path` is /// mounted. If there are no matches, this function returns /// [`None`]. If there are two or more matches, then the single -/// [`MountInfo`] with the longest mount directory is returned. +/// [`MountInfo`] with the device name corresponding to the entered path. /// /// If `canonicalize` is `true`, then the `path` is canonicalized /// before checking whether it matches any mount directories. @@ -68,9 +68,19 @@ where path.as_ref().to_path_buf() }; + // Find the potential mount point that matches entered path let maybe_mount_point = mounts .iter() - .find(|mi| mi.dev_name.eq(&path.to_string_lossy())); + // Create pair MountInfo, canonicalized device name + // TODO Abstract from accessing real filesystem to + // make code more testable + .map(|m| (m, std::fs::canonicalize(&m.dev_name))) + // Ignore non existing paths + .filter(|m| m.1.is_ok()) + .map(|m| (m.0, m.1.ok().unwrap())) + // Try to find canonicalized device name corresponding to entered path + .find(|m| m.1.eq(&path)) + .map(|m| m.0); maybe_mount_point.or_else(|| { mounts @@ -211,10 +221,16 @@ mod tests { #[test] fn test_dev_name_match() { + let tmp = tempfile::TempDir::new().expect("Failed to create temp dir"); + let dev_name = std::fs::canonicalize(tmp.path()) + .expect("Failed to canonicalize tmp path") + .to_string_lossy() + .to_string(); + let mut mount_info = mount_info("/foo"); - mount_info.dev_name = "/dev/sda2".to_string(); + mount_info.dev_name = dev_name.clone(); let mounts = [mount_info]; - let actual = mount_info_from_path(&mounts, "/dev/sda2", false).unwrap(); + let actual = mount_info_from_path(&mounts, dev_name, false).unwrap(); assert!(mount_info_eq(actual, &mounts[0])); } }