use std::{
fs::File,
io::{self, BufRead, BufReader},
path::Path,
};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum EtcPasswdError {
#[error("failed to parse the passwd file")]
IOError(#[from] io::Error),
#[error("invalid passwd file entry")]
InvalidEntryFormat,
}
pub struct User {
pub name: String,
pub id: u32,
pub group_id: u32,
}
pub struct EtcPasswd {
user_list: Vec<User>,
}
impl EtcPasswd {
pub fn new<AsPathRef: AsRef<Path>>(path: AsPathRef) -> Result<Self, EtcPasswdError> {
Ok(Self {
user_list: Self::parse_file(path)?,
})
}
pub fn iter(&self) -> std::slice::Iter<'_, User> {
self.user_list.iter()
}
fn parse_file<AsPathRef: AsRef<Path>>(path: AsPathRef) -> Result<Vec<User>, EtcPasswdError> {
let mut user_list = Vec::new();
let file = File::open(path)?;
let reader = BufReader::new(file);
for line in reader.lines() {
let line = line?;
let field_list: Vec<&str> = line.split(':').collect();
if field_list.len() != 7 {
return Err(EtcPasswdError::InvalidEntryFormat);
}
let user = User {
name: field_list[0].to_string(),
id: field_list[2].parse().unwrap_or(0),
group_id: field_list[3].parse().unwrap_or(0),
};
user_list.push(user);
}
Ok(user_list)
}
}