use crate::GroupEntry;
use crate::PasswdEntry;
use std::path::PathBuf;
use std::time::Duration;
use std::time::Instant;
pub struct PasswdReader {
file: Option<PathBuf>,
cache_time: Duration,
last_check: Instant,
passwd: Vec<PasswdEntry>,
}
impl PasswdReader {
pub fn new(cache_time: Duration) -> Self {
let last_check = Instant::now() - (cache_time);
Self {
file: None,
cache_time,
last_check,
passwd: vec![],
}
}
pub fn from_file<T: Into<PathBuf>>(file: T, cache_time: Duration) -> Self {
let last_check = Instant::now() - (cache_time);
Self {
file: Some(file.into()),
cache_time,
last_check,
passwd: vec![],
}
}
fn refresh_if_needed(&mut self) -> Result<(), std::io::Error> {
if Instant::now() < (self.last_check + self.cache_time) {
return Ok(());
}
let contents =
std::fs::read_to_string(self.file.as_ref().unwrap_or(&"/etc/passwd".into()))?;
self.passwd = contents.lines().filter_map(PasswdEntry::parse).collect();
Ok(())
}
pub fn get_entries(&mut self) -> Result<&Vec<PasswdEntry>, std::io::Error> {
self.refresh_if_needed()?;
Ok(&self.passwd)
}
pub fn try_iter(&mut self) -> Result<std::slice::Iter<PasswdEntry>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self.passwd.iter())
}
pub fn get_by_username(
&mut self,
username: &str,
) -> Result<Option<PasswdEntry>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self
.passwd
.iter()
.find(|e| e.username == username)
.map(|e| e.to_owned()))
}
pub fn get_by_uid(&mut self, uid: u32) -> Result<Option<PasswdEntry>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self
.passwd
.iter()
.find(|e| e.uid == uid)
.map(|e| e.to_owned()))
}
pub fn get_username_by_uid(&mut self, uid: u32) -> Result<Option<String>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self
.passwd
.iter()
.find(|e| e.uid == uid)
.map(|e| e.username.to_owned()))
}
pub fn get_uid_by_username(&mut self, username: &str) -> Result<Option<u32>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self
.passwd
.iter()
.find(|e| e.username == username)
.map(|e| e.uid))
}
}
pub struct GroupReader {
file: Option<PathBuf>,
cache_time: Duration,
last_check: Instant,
groups: Vec<GroupEntry>,
}
impl GroupReader {
pub fn new(cache_time: Duration) -> Self {
let last_check = Instant::now() - (cache_time);
Self {
file: None,
cache_time,
last_check,
groups: vec![],
}
}
pub fn from_file<T: Into<PathBuf>>(file: T, cache_time: Duration) -> Self {
let last_check = Instant::now() - (cache_time);
Self {
file: Some(file.into()),
cache_time,
last_check,
groups: vec![],
}
}
fn refresh_if_needed(&mut self) -> Result<(), std::io::Error> {
if Instant::now() < (self.last_check + self.cache_time) {
return Ok(());
}
let contents = std::fs::read_to_string(self.file.as_ref().unwrap_or(&"/etc/group".into()))?;
self.groups = contents.lines().filter_map(GroupEntry::parse).collect();
Ok(())
}
pub fn get_groups(&mut self) -> Result<&Vec<GroupEntry>, std::io::Error> {
self.refresh_if_needed()?;
Ok(&self.groups)
}
pub fn try_iter(&mut self) -> Result<std::slice::Iter<GroupEntry>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self.groups.iter())
}
pub fn get_by_name(&mut self, name: &str) -> Result<Option<GroupEntry>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self
.groups
.iter()
.find(|e| e.name == name)
.map(|e| e.to_owned()))
}
pub fn get_by_gid(&mut self, gid: u32) -> Result<Option<GroupEntry>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self
.groups
.iter()
.find(|e| e.gid == gid)
.map(|e| e.to_owned()))
}
pub fn get_name_by_gid(&mut self, gid: u32) -> Result<Option<String>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self
.groups
.iter()
.find(|e| e.gid == gid)
.map(|e| e.name.to_owned()))
}
pub fn get_gid_by_name(&mut self, name: &str) -> Result<Option<u32>, std::io::Error> {
self.refresh_if_needed()?;
Ok(self.groups.iter().find(|e| e.name == name).map(|e| e.gid))
}
}