From 2fef8819c6c0e1e32f6ed4c4b477071b49c05d8a Mon Sep 17 00:00:00 2001 From: naoNao89 Date: Sun, 15 Feb 2026 05:20:13 +0000 Subject: [PATCH] df(windows): fix Avail/Use% by using number_of_free_clusters for bavail Fix Windows df incorrectly reporting 0 bytes available and 100% usage for all filesystems. The issue was caused by hardcoding bavail (blocks available to non-privileged processes) to 0 instead of using the actual free clusters from Windows API. Changes: - Set bavail to number_of_free_clusters on Windows (was: 0) - Add regression test test_windows_avail_column_not_zero Fixes #7461 --- src/uucore/src/lib/features/fsext.rs | 4 ++- tests/by-util/test_df.rs | 51 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index 173fe918fd2..135c71fe8bb 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -657,7 +657,9 @@ impl FsUsage { // Total number of free blocks. bfree: number_of_free_clusters as u64, // Total number of free blocks available to non-privileged processes. - bavail: 0, + // Windows: 'bavail' should reflect free clusters available to non-privileged processes. + // See: https://github.com/uutils/coreutils/issues/7461 + bavail: number_of_free_clusters as u64, bavail_top_bit_set: ((bytes_per_sector as u64) & (1u64.rotate_right(1))) != 0, // Total number of file nodes (inodes) on the file system. files: 0, // Not available on windows diff --git a/tests/by-util/test_df.rs b/tests/by-util/test_df.rs index c1cf50d2518..bf507ce9761 100644 --- a/tests/by-util/test_df.rs +++ b/tests/by-util/test_df.rs @@ -1152,3 +1152,54 @@ fn test_df_masked_proc_fallback() { } } } + +#[test] +#[cfg(target_os = "windows")] +fn test_windows_avail_column_not_zero() { + // Regression test for issue #7461: Avail column should not be 0 on Windows + let output = new_ucmd!() + .args(&["--output=source,avail"]) + .succeeds() + .stdout_str_lossy(); + + let lines: Vec<&str> = output.lines().skip(1).collect(); + assert!(!lines.is_empty(), "Should have at least one filesystem"); + + // At least one filesystem should have non-zero avail (not all are 0) + let has_non_zero = lines.iter().any(|line| { + let parts: Vec<&str> = line.split_whitespace().collect(); + if parts.len() >= 2 { + parts[1].parse::().map(|v| v > 0).unwrap_or(false) + } else { + false + } + }); + + assert!( + has_non_zero, + "At least one filesystem should have non-zero available space. Got output:\n{output}" + ); +} + +/// Test that df --total includes a total row in output. +/// Verifies basic functionality of --total flag. +#[test] +#[cfg(not(target_os = "freebsd"))] +fn test_total_row_exists() { + // Get df output with totals + let output = new_ucmd!() + .args(&["--total", "-P", "--block-size=512"]) + .succeeds() + .stdout_str_lossy(); + + // Just verify that a total row exists in the output + // The exact calculation verification is environment-dependent + let has_total_row = output + .lines() + .any(|line| line.split_whitespace().next() == Some("total")); + + assert!( + has_total_row, + "Output should contain a 'total' row. Got:\n{output}" + ); +}