diff --git a/crates/nu-command/src/filesystem/cd.rs b/crates/nu-command/src/filesystem/cd.rs index 98ff09f45..40256cce2 100644 --- a/crates/nu-command/src/filesystem/cd.rs +++ b/crates/nu-command/src/filesystem/cd.rs @@ -229,7 +229,16 @@ fn have_permission(dir: impl AsRef) -> PermissionResult<'static> { } } -#[cfg(unix)] +#[cfg(any(target_os = "linux", target_os = "android"))] +fn any_group(_current_user_gid: gid_t, owner_group: u32) -> bool { + use crate::filesystem::util::users; + let Some(user_groups) = users::current_user_groups() else { + return false; + }; + user_groups.iter().any(|gid| gid.as_raw() == owner_group) +} + +#[cfg(all(unix, not(any(target_os = "linux", target_os = "android"))))] fn any_group(current_user_gid: gid_t, owner_group: u32) -> bool { use crate::filesystem::util::users; diff --git a/crates/nu-command/src/filesystem/util.rs b/crates/nu-command/src/filesystem/util.rs index ef95953c0..2ce93176b 100644 --- a/crates/nu-command/src/filesystem/util.rs +++ b/crates/nu-command/src/filesystem/util.rs @@ -165,9 +165,8 @@ pub fn is_older(src: &Path, dst: &Path) -> Option { #[cfg(unix)] pub mod users { - use libc::{c_int, gid_t, uid_t}; + use libc::{gid_t, uid_t}; use nix::unistd::{Gid, Group, Uid, User}; - use std::ffi::CString; pub fn get_user_by_uid(uid: uid_t) -> Option { User::from_uid(Uid::from_raw(uid)).ok().flatten() @@ -185,6 +184,7 @@ pub mod users { Gid::current().as_raw() } + #[cfg(not(any(target_os = "linux", target_os = "android")))] pub fn get_current_username() -> Option { User::from_uid(Uid::current()) .ok() @@ -192,6 +192,30 @@ pub mod users { .map(|user| user.name) } + #[cfg(any(target_os = "linux", target_os = "android"))] + pub fn current_user_groups() -> Option> { + // SAFETY: + // if first arg is 0 then it ignores second argument and returns number of groups present for given user. + let ngroups = unsafe { libc::getgroups(0, core::ptr::null:: as *mut _) }; + let mut buff: Vec = vec![0; ngroups as usize]; + + // SAFETY: + // buff is the size of ngroups and getgroups reads max ngroups elements into buff + let found = unsafe { libc::getgroups(ngroups, buff.as_mut_ptr()) }; + + if found < 0 { + None + } else { + buff.truncate(found as usize); + buff.sort_unstable(); + buff.dedup(); + buff.into_iter() + .filter_map(|i| get_group_by_gid(i as gid_t)) + .map(|group| group.gid) + .collect::>() + .into() + } + } /// Returns groups for a provided user name and primary group id. /// /// # libc functions used @@ -207,7 +231,9 @@ pub mod users { /// println!("User is a member of group #{group}"); /// } /// ``` + #[cfg(not(any(target_os = "linux", target_os = "android")))] pub fn get_user_groups(username: &str, gid: gid_t) -> Option> { + use std::ffi::CString; // MacOS uses i32 instead of gid_t in getgrouplist for unknown reasons #[cfg(target_os = "macos")] let mut buff: Vec = vec![0; 1024]; @@ -218,7 +244,7 @@ pub mod users { return None; }; - let mut count = buff.len() as c_int; + let mut count = buff.len() as libc::c_int; // MacOS uses i32 instead of gid_t in getgrouplist for unknown reasons // SAFETY: