From 0e3016589fe524cf6e5e4a1025eefe6c1041a8df Mon Sep 17 00:00:00 2001 From: kevin9327 <5299031+kevin9327@users.noreply.github.com> Date: Mon, 5 Oct 2026 13:41:04 +0900 Subject: [PATCH] Decode every escape in /proc/self/mounts, not only spaces --- crates/disktree-core/src/space.rs | 33 +++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/crates/disktree-core/src/space.rs b/crates/disktree-core/src/space.rs index 8a2bc4e..a939204 100644 --- a/crates/disktree-core/src/space.rs +++ b/crates/disktree-core/src/space.rs @@ -96,11 +96,9 @@ pub fn device_in(table: &str, path: &Path) -> Option { .lines() .filter_map(|line| { let mut fields = line.split_whitespace(); - let device = fields.next()?; - // Spaces in mount points are escaped as \040. - let mount = fields.next()?.replace("\\040", " "); - path.starts_with(&mount) - .then(|| (mount.len(), device.to_string())) + let device = unescape_octal(fields.next()?); + let mount = unescape_octal(fields.next()?); + path.starts_with(&mount).then_some((mount.len(), device)) }) .max_by_key(|(length, _)| *length) .map(|(_, device)| device) @@ -122,9 +120,9 @@ pub fn parse_mounts(table: &str) -> Vec { .lines() .filter_map(|line| { let mut fields = line.split_whitespace(); - let source = fields.next()?.to_string(); - // Spaces in mount points are escaped as \040. - let point = PathBuf::from(fields.next()?.replace("\\040", " ")); + // Escaped as in mountinfo: space, tab, newline and backslash. + let source = unescape_octal(fields.next()?); + let point = PathBuf::from(unescape_octal(fields.next()?)); let fstype = fields.next()?.to_string(); let options = fields.next().unwrap_or_default().to_string(); Some(Mount { @@ -996,6 +994,25 @@ portal /run/user/1000/doc fuse.portal rw 0 0 assert_eq!(mounts[0].fstype, "ext4"); } + #[test] + fn mounts_escapes_are_decoded_once() { + let table = "/dev/sda1 /media/My\\040Disk\\134040 ext4 rw 0 0\n\ + //nas/My\\040Share /mnt/tab\\011name cifs rw 0 0\n"; + let mounts = parse_mounts(table); + assert_eq!(mounts.len(), 2); + assert_eq!(mounts[0].point, Path::new("/media/My Disk\\040")); + assert_eq!(mounts[1].point, Path::new("/mnt/tab\tname")); + assert_eq!(mounts[1].source, "//nas/My Share"); + assert_eq!( + device_in(table, Path::new("/media/My Disk\\040/a")).as_deref(), + Some("/dev/sda1") + ); + assert_eq!( + device_in(table, Path::new("/mnt/tab\tname/a")).as_deref(), + Some("//nas/My Share") + ); + } + #[test] fn volumes_with_least_space_come_first_and_unknowns_last() { let volume = |name: &str, available: Option| Volume {