use std::io;
use std::os::unix::fs::{lchown, MetadataExt};
use std::sync::Mutex;
use std::{fs, path::Path};
use lazy_static::lazy_static;
use uzers::{Groups, Users, UsersCache};
use super::Owner;
lazy_static! {
static ref USERS_CACHE: Mutex<UsersCache> = Mutex::new(UsersCache::new());
}
impl From<&fs::Metadata> for Owner {
fn from(mdata: &fs::Metadata) -> Self {
let users_cache = USERS_CACHE.lock().unwrap();
let user: Option<String> = users_cache
.get_user_by_uid(mdata.uid())
.and_then(|user| user.name().to_str().map(String::from));
let group: Option<String> = users_cache
.get_group_by_gid(mdata.gid())
.and_then(|group| group.name().to_str().map(String::from));
Self { user, group }
}
}
#[mutants::skip] pub(crate) fn set_owner(owner: &Owner, path: &Path) -> io::Result<()> {
let users_cache = USERS_CACHE.lock().unwrap();
let uid_opt = owner
.user
.as_ref()
.and_then(|user| users_cache.get_user_by_name(&user))
.map(|user| user.uid());
let gid_opt = owner
.group
.as_ref()
.and_then(|group| users_cache.get_group_by_name(&group))
.map(|group| group.gid());
drop(users_cache);
match lchown(path, uid_opt, gid_opt) {
Ok(()) => Ok(()),
Err(err) if err.kind() == io::ErrorKind::PermissionDenied => {
Ok(())
}
Err(err) => Err(err),
}
}