From 6644cc9b0e29841e3d0a85fbc672a95c4a2fd000 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 21 Jun 2025 12:25:02 +0200 Subject: [PATCH] Use statvfs on NetBSD again to fix build From commit ba00d721f49 (Correct statvfs call to statfs, 2025-06-19): > This was missed in the Rust port To elaborate: - ec176dc07e7 (Port path.h, 2023-04-09) didn't change this (as before, `statvfs` used `ST_LOCAL` and `statfs` used `MNT_LOCAL`) - 6877773fdd4 (Fix build on NetBSD (#10270), 2024-01-28) changed the `statvfs` call to `statfs`, presumably due to the libc-wrapper for `statvfs` being missing on NetBSD. This change happens to work fine on NetBSD because they do [`#define ST_LOCAL MNT_LOCAL`](https://github.com/fish-shell/fish-shell/pull/11486#discussion_r2092408952) But it was wrong on others like macOS and FreeBSD, which was fixed by ba00d721f49 (but that broke the build on NetBSD). - 7228cb15bfa (Include sys/statvfs.h for the definition of ST_LOCAL (Rust port regression), 2025-05-16) fixed a code clone left behind by the above commit (incorrectly assuming that the clone had always existed.) Fix the NetBSD build specifically by using statfs on that platform. Note that this still doesn't make the behavior equivalent to commit LastC++11. That one used ST_LOCAL if defined, and otherwise MNT_LOCAL if defined. If we want perfect equivalence, we could detect both flags in `src/build.rs`. Then we would also build on operating systems that define neither. Not sure. Closes #11596 --- src/path.rs | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/path.rs b/src/path.rs index add2b01a9..58954a501 100644 --- a/src/path.rs +++ b/src/path.rs @@ -6,8 +6,6 @@ use crate::env::{EnvMode, EnvStack, Environment}; use crate::expand::{expand_tilde, HOME_DIRECTORY}; use crate::flog::{FLOG, FLOGF}; -#[cfg(not(target_os = "linux"))] -use crate::libc::{MNT_LOCAL, ST_LOCAL}; use crate::wchar::prelude::*; use crate::wutil::{normalize_path, path_normalize_for_cd, waccess, wdirname, wstat}; use errno::{errno, set_errno, Errno}; @@ -705,25 +703,49 @@ pub fn path_remoteness(path: &wstr) -> DirRemoteness { } #[cfg(not(target_os = "linux"))] { - // ST_LOCAL is a flag to statvfs, which is itself standardized. - // In practice the only system to define it is NetBSD. - let local_flag = ST_LOCAL() | MNT_LOCAL(); - if local_flag != 0 { + fn remoteness_via_statfs( + statfn: unsafe extern "C" fn(*const i8, *mut StatFS) -> libc::c_int, + flagsfn: fn(&StatFS) -> Flags, + is_local_flag: u64, + path: &std::ffi::CStr, + ) -> DirRemoteness + where + u64: From, + { + if is_local_flag == 0 { + return DirRemoteness::unknown; + } let mut buf = MaybeUninit::uninit(); - if unsafe { libc::statfs(narrow.as_ptr(), buf.as_mut_ptr()) } < 0 { + if unsafe { (statfn)(path.as_ptr(), buf.as_mut_ptr()) } < 0 { return DirRemoteness::unknown; } let buf = unsafe { buf.assume_init() }; // statfs::f_flag is hard-coded as 64-bits on 32/64-bit FreeBSD but it's a (4-byte) // long on 32-bit NetBSD.. and always 4-bytes on macOS (even on 64-bit builds). #[allow(clippy::useless_conversion)] - return if u64::from(buf.f_flags) & local_flag != 0 { + if u64::from((flagsfn)(&buf)) & is_local_flag != 0 { DirRemoteness::local } else { DirRemoteness::remote - }; + } } - DirRemoteness::unknown + // ST_LOCAL is a flag to statvfs, which is itself standardized. + // In practice the only system to define it is NetBSD. + #[cfg(target_os = "netbsd")] + let remoteness = remoteness_via_statfs( + libc::statvfs, + |stat: &libc::statvfs| stat.f_flag, + crate::libc::ST_LOCAL(), + &narrow, + ); + #[cfg(not(target_os = "netbsd"))] + let remoteness = remoteness_via_statfs( + libc::statfs, + |stat: &libc::statfs| stat.f_flags, + crate::libc::MNT_LOCAL(), + &narrow, + ); + remoteness } }