Repository navigation
df: report an over-mounted device instead of falling back to statfs - #15977
Conversation
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues were identified for the change restricting df’s statfs fallback to operands without a matching mount-table entry.
No open issues 🎉
What changed in this PR
Fixes #15799 by restricting df’s statfs fallback to cases where no mount-table entry covers the operand, preserving errors for over-mounted devices and inaccessible mount points.
Changes:
- Moves the fallback decision into
Filesystem::from_path(). - Removes the Unix caller’s catch-all fallback.
- Adds three unit tests covering over-mount errors, mount-point statfs failures, and successful fallback.
| File | Description |
|---|---|
src/uu/df/src/platform/unix.rs |
Removes catch-all fallback, exposes the fallback helper, and adds regression tests. |
src/uu/df/src/filesystem.rs |
Limits fallback to missing mount entries and documents error propagation. |
Review effort: Balanced
|
GNU testsuite comparison: |
|
|
||
| assert_eq!( | ||
| filesystem_for_path(&mounts, false, "/dev/null").unwrap_err(), | ||
| FsError::MountMissing |
There was a problem hiding this comment.
exit 1 now, good, but the user gets "no file systems processed" here while GNU says "Permission denied" on the mount point
maybe keep the io error for a follow-up?
There was a problem hiding this comment.
Done in this PR (8c44d93): when statfs fails on the mount point, df now reports it like GNU, e.g. df: /mnt: Permission denied, and still exits 1.
`df DEVICE` printed the row of the file system holding the device node (usually `/dev`) and exited 0 when the device's mount point was over-mounted, or when its mount point could not be statfs'd. The statfs fallback in `filesystem_for_path()` ran on every error of the mount table lookup, not only when no entry covered the operand. Move the decision into `Filesystem::from_path()`, the one place that can tell "no entry covers the path" from an error about the mount that was found, and let the latter reach the caller as before. Fixes uutils#15799
Like GNU, print the statfs error for the mount point, e.g. "Permission denied", instead of "no file systems processed".
8c44d93 to
47b7daf
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
4 open issues
Filesystem::from_path()now unconditionally referencesplatform::from_path_direct_with_mounts.… · New Storing the underlyingstatfsfailure as aStringloses structured error information… · New This doc comment describes Unix-only behavior (statfsfallback andFsError::OverMounted). On… · New This test compares anOsString(path) to a string literal, relying on platform-specific… · New
Review effort: Lite
| match mount_info_from_path(mounts, &path, canonicalize) { | ||
| Ok(mount_info) => platform::filesystem_from_mount(mounts, mount_info, Some(file)), | ||
| // Only an empty lookup may fall back to `statfs`: an error about | ||
| // the mount that was found is the answer for `path`. | ||
| Err(FsError::MountMissing) => platform::from_path_direct_with_mounts(mounts, path), | ||
| Err(e) => Err(e), | ||
| } |
There was a problem hiding this comment.
Filesystem::from_path() is #[cfg(unix)], as is FsError::StatFailed, so Windows never compiles this arm or references from_path_direct_with_mounts.
| /// `statfs` failed on the mount point at `path` with `error`. | ||
| #[cfg(not(windows))] | ||
| StatFailed { | ||
| path: OsString, | ||
| error: String, | ||
| }, |
| /// longest mount directory is returned. If no element of `mounts` | ||
| /// covers `path`, the filesystem is looked up through `statfs` | ||
| /// instead. An error about the mount that was found, such as | ||
| /// [`FsError::OverMounted`], is returned as is. |
|
|
||
| assert!(matches!( | ||
| filesystem_for_path(&mounts, false, "/dev/null").unwrap_err(), | ||
| FsError::StatFailed { path, .. } if path == "/non-existent-dir" |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
6 open issues
MountInfo::dev_nameis aString(seeMountInfousage elsewhere), so… · NewFilesystem::from_path()now unconditionally referencesplatform::from_path_direct_with_mounts.…pathinFsError::StatFailedis anOsString, and comparing it directly to a&str(`path ==… · New This doc comment describes Unix-only behavior (statfsfallback andFsError::OverMounted). On… Storing the underlyingstatfsfailure as aStringloses structured error information… This test compares anOsString(path) to a string literal, relying on platform-specific…
Review effort: Lite
| /// The path `statfs` is called on to query the filesystem at `mount_info`. | ||
| fn stat_path(mount_info: &MountInfo) -> &OsStr { | ||
| if mount_info.mount_dir.is_empty() { | ||
| mount_info.dev_name.as_ref() | ||
| } else { | ||
| mount_info.mount_dir.as_os_str() | ||
| }; | ||
| Some(FsUsage::new(statfs(stat_path).ok()?)) | ||
| } | ||
| } |
|
|
||
| assert!(matches!( | ||
| filesystem_for_path(&mounts, false, "/dev/null").unwrap_err(), | ||
| FsError::StatFailed { path, .. } if path == "/non-existent-dir" |
|
Thanks for your PR |



df DEVICEprinted the row of the file system holding the device node (usually/dev) and exited 0 when the device's mount point was over-mounted, or when that mount point could not be statfs'd. The statfs fallback added for a mount table with no entry covering the path ran on every error of the lookup, includingFsError::OverMounted.This moves the decision into
Filesystem::from_path(), the only place that can tell "no entry covers the path" from an error about the mount that was found, and lets the latter reach the caller as it did in 0.10.0. Three unit tests with a synthetic mount table cover the over-mounted case, the unreachable mount point, and the fallback still working when nothing covers the path.Fixes #15799