use super::*;
#[cfg(unix)]
pub(super) fn owner_of(metadata: &fs::Metadata) -> String {
use std::os::unix::fs::MetadataExt;
let (uid, gid) = (metadata.uid(), metadata.gid());
format!("{}:{}", user_name(uid), group_name(gid))
}
#[cfg(unix)]
pub fn user_name(uid: u32) -> String {
lookup_entry(|entry: &mut libc::passwd, buffer, length, found| unsafe { libc::getpwuid_r(uid, entry, buffer, length, found) }, |entry| c_name(entry.pw_name)).unwrap_or_else(|| uid.to_string())
}
#[cfg(unix)]
pub fn group_name(gid: u32) -> String {
lookup_entry(|entry: &mut libc::group, buffer, length, found| unsafe { libc::getgrgid_r(gid, entry, buffer, length, found) }, |entry| c_name(entry.gr_name)).unwrap_or_else(|| gid.to_string())
}
#[cfg(unix)]
pub fn user_id(name: &str) -> Option<u32> {
if let Ok(uid) = name.parse() {
return Some(uid);
}
let name = std::ffi::CString::new(name).ok()?;
lookup_entry(|entry: &mut libc::passwd, buffer, length, found| unsafe { libc::getpwnam_r(name.as_ptr(), entry, buffer, length, found) }, |entry| Some(entry.pw_uid))
}
#[cfg(unix)]
pub fn group_id(name: &str) -> Option<u32> {
if let Ok(gid) = name.parse() {
return Some(gid);
}
let name = std::ffi::CString::new(name).ok()?;
lookup_entry(|entry: &mut libc::group, buffer, length, found| unsafe { libc::getgrnam_r(name.as_ptr(), entry, buffer, length, found) }, |entry| Some(entry.gr_gid))
}
#[cfg(unix)]
fn c_name(pointer: *const libc::c_char) -> Option<String> {
(!pointer.is_null()).then(|| unsafe { std::ffi::CStr::from_ptr(pointer) }.to_string_lossy().into_owned())
}
#[cfg(unix)]
fn lookup_entry<E, T>(call: impl Fn(&mut E, *mut libc::c_char, libc::size_t, *mut *mut E) -> libc::c_int, pick: impl Fn(&E) -> Option<T>) -> Option<T> {
let mut buffer: Vec<libc::c_char> = vec![0; 1024];
loop {
let mut entry: E = unsafe { std::mem::zeroed() };
let mut found: *mut E = std::ptr::null_mut();
let status = call(&mut entry, buffer.as_mut_ptr(), buffer.len(), &mut found);
if status == libc::ERANGE && buffer.len() < 1 << 20 {
buffer.resize(buffer.len() * 2, 0);
continue;
}
if status != 0 || found.is_null() {
return None;
}
return pick(&entry);
}
}
#[cfg(not(unix))]
pub(super) fn owner_of(_metadata: &fs::Metadata) -> String {
String::new()
}