restructure
This commit is contained in:
		
							parent
							
								
									1ab0adbc06
								
							
						
					
					
						commit
						063fb41708
					
				
							
								
								
									
										129
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										129
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -5,7 +5,9 @@ name = "adduser"
 | 
				
			|||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "lazy_static",
 | 
					 "lazy_static",
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
 "regex",
 | 
					 "regex",
 | 
				
			||||||
 | 
					 "simplelog",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
@ -17,18 +19,77 @@ dependencies = [
 | 
				
			|||||||
 "memchr",
 | 
					 "memchr",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "autocfg"
 | 
				
			||||||
 | 
					version = "1.0.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cfg-if"
 | 
				
			||||||
 | 
					version = "0.1.10"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "chrono"
 | 
				
			||||||
 | 
					version = "0.4.19"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "num-integer",
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					 "time",
 | 
				
			||||||
 | 
					 "winapi",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "lazy_static"
 | 
					name = "lazy_static"
 | 
				
			||||||
version = "1.4.0"
 | 
					version = "1.4.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 | 
					checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "libc"
 | 
				
			||||||
 | 
					version = "0.2.78"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "log"
 | 
				
			||||||
 | 
					version = "0.4.11"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "memchr"
 | 
					name = "memchr"
 | 
				
			||||||
version = "2.3.3"
 | 
					version = "2.3.3"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
 | 
					checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num-integer"
 | 
				
			||||||
 | 
					version = "0.1.43"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "autocfg",
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num-traits"
 | 
				
			||||||
 | 
					version = "0.2.12"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "autocfg",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "regex"
 | 
					name = "regex"
 | 
				
			||||||
version = "1.3.9"
 | 
					version = "1.3.9"
 | 
				
			||||||
@ -47,6 +108,26 @@ version = "0.6.18"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
 | 
					checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "simplelog"
 | 
				
			||||||
 | 
					version = "0.8.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "2b2736f58087298a448859961d3f4a0850b832e72619d75adc69da7993c2cd3c"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "chrono",
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
 | 
					 "termcolor",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "termcolor"
 | 
				
			||||||
 | 
					version = "1.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "winapi-util",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "thread_local"
 | 
					name = "thread_local"
 | 
				
			||||||
version = "1.0.1"
 | 
					version = "1.0.1"
 | 
				
			||||||
@ -55,3 +136,51 @@ checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
 | 
				
			|||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "lazy_static",
 | 
					 "lazy_static",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "time"
 | 
				
			||||||
 | 
					version = "0.1.44"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "wasi",
 | 
				
			||||||
 | 
					 "winapi",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "wasi"
 | 
				
			||||||
 | 
					version = "0.10.0+wasi-snapshot-preview1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "winapi"
 | 
				
			||||||
 | 
					version = "0.3.9"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "winapi-i686-pc-windows-gnu",
 | 
				
			||||||
 | 
					 "winapi-x86_64-pc-windows-gnu",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "winapi-i686-pc-windows-gnu"
 | 
				
			||||||
 | 
					version = "0.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "winapi-util"
 | 
				
			||||||
 | 
					version = "0.1.5"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "winapi",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "winapi-x86_64-pc-windows-gnu"
 | 
				
			||||||
 | 
					version = "0.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 | 
				
			||||||
 | 
				
			|||||||
@ -9,3 +9,5 @@ edition = "2018"
 | 
				
			|||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
regex = "1"
 | 
					regex = "1"
 | 
				
			||||||
lazy_static = "1.4"
 | 
					lazy_static = "1.4"
 | 
				
			||||||
 | 
					log = "0.4"
 | 
				
			||||||
 | 
					simplelog = "0.8"
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,19 @@ use std::fs::File;
 | 
				
			|||||||
use std::io::{prelude::*, BufReader};
 | 
					use std::io::{prelude::*, BufReader};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
 | 
					    simplelog::CombinedLogger::init(vec![simplelog::TermLogger::new(
 | 
				
			||||||
 | 
					        simplelog::LevelFilter::Warn,
 | 
				
			||||||
 | 
					        simplelog::Config::default(),
 | 
				
			||||||
 | 
					        simplelog::TerminalMode::Mixed,
 | 
				
			||||||
 | 
					    )])
 | 
				
			||||||
 | 
					    .unwrap();
 | 
				
			||||||
    let file = File::open("/etc/passwd").unwrap();
 | 
					    let file = File::open("/etc/passwd").unwrap();
 | 
				
			||||||
    let reader = BufReader::new(file);
 | 
					    let reader = BufReader::new(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for line in reader.lines() {
 | 
					    for line in reader.lines() {
 | 
				
			||||||
        println!("{}", Passwd::new_from_string(&line.unwrap()).unwrap());
 | 
					        let line = line.unwrap();
 | 
				
			||||||
 | 
					        println!("{}", line);
 | 
				
			||||||
 | 
					        println!("{}", Passwd::new_from_string(&line).unwrap());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // let pwd = Passwd::default();
 | 
					    // let pwd = Passwd::default();
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
extern crate lazy_static;
 | 
					extern crate lazy_static;
 | 
				
			||||||
 | 
					extern crate log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod passwd;
 | 
					pub mod passwd;
 | 
				
			||||||
pub mod userlib_error;
 | 
					pub mod userlib_error;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										322
									
								
								src/passwd.rs
									
									
									
									
									
								
							
							
						
						
									
										322
									
								
								src/passwd.rs
									
									
									
									
									
								
							@ -7,6 +7,7 @@
 | 
				
			|||||||
)]
 | 
					)]
 | 
				
			||||||
#![allow(clippy::non_ascii_literal)]
 | 
					#![allow(clippy::non_ascii_literal)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use log::warn;
 | 
				
			||||||
use regex::Regex;
 | 
					use regex::Regex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::userlib_error::UserLibError;
 | 
					use crate::userlib_error::UserLibError;
 | 
				
			||||||
@ -25,11 +26,50 @@ pub struct Username<'a> {
 | 
				
			|||||||
    username: &'a str,
 | 
					    username: &'a str,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for Username<'_> {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "{}", self.username,)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> TryFrom<&'a str> for Username<'a> {
 | 
				
			||||||
 | 
					    type Error = UserLibError;
 | 
				
			||||||
 | 
					    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        lazy_static! {
 | 
				
			||||||
 | 
					            static ref USERVALIDATION: Regex =
 | 
				
			||||||
 | 
					                Regex::new("^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\\$)$").unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if USERVALIDATION.is_match(source) {
 | 
				
			||||||
 | 
					            Ok(Self { username: source })
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Err(UserLibError::Message("Invalid username".into()))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, PartialEq, Eq)]
 | 
					#[derive(Debug, PartialEq, Eq)]
 | 
				
			||||||
pub struct Password<'a> {
 | 
					pub struct Password<'a> {
 | 
				
			||||||
    password: &'a str,
 | 
					    password: &'a str,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for Password<'_> {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "{}", self.password,)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> TryFrom<&'a str> for Password<'a> {
 | 
				
			||||||
 | 
					    type Error = UserLibError;
 | 
				
			||||||
 | 
					    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        if source == "x" {
 | 
				
			||||||
 | 
					            warn!("password from shadow not loaded!")
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            warn!("Password field has an unexpected value")
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        Ok(Self { password: source })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, PartialEq, Eq)]
 | 
					#[derive(Debug, PartialEq, Eq)]
 | 
				
			||||||
pub struct Uid {
 | 
					pub struct Uid {
 | 
				
			||||||
    uid: u32,
 | 
					    uid: u32,
 | 
				
			||||||
@ -39,6 +79,7 @@ pub struct Uid {
 | 
				
			|||||||
pub struct Gid {
 | 
					pub struct Gid {
 | 
				
			||||||
    gid: u32,
 | 
					    gid: u32,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The gecos field of a user.
 | 
					/// The gecos field of a user.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// In the `/etc/passwd` file this field is a `,` sepparated list of items.
 | 
					/// In the `/etc/passwd` file this field is a `,` sepparated list of items.
 | 
				
			||||||
@ -59,6 +100,129 @@ pub enum Gecos<'a> {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> Gecos<'a> {
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn get_comment(&'a self) -> Option<&'a str> {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Gecos::Simple { comment, .. } => Some(comment),
 | 
				
			||||||
 | 
					            Gecos::Detail { .. } => None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn get_full_name(&'a self) -> Option<&'a str> {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Gecos::Simple { .. } => None,
 | 
				
			||||||
 | 
					            Gecos::Detail { full_name, .. } => {
 | 
				
			||||||
 | 
					                if full_name.is_empty() {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Some(full_name)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn get_room(&'a self) -> Option<&'a str> {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Gecos::Simple { .. } => None,
 | 
				
			||||||
 | 
					            Gecos::Detail { room, .. } => {
 | 
				
			||||||
 | 
					                if room.is_empty() {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Some(room)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn get_phone_work(&'a self) -> Option<&'a str> {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Gecos::Simple { .. } => None,
 | 
				
			||||||
 | 
					            Gecos::Detail { phone_work, .. } => {
 | 
				
			||||||
 | 
					                if phone_work.is_empty() {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Some(phone_work)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn get_phone_home(&'a self) -> Option<&'a str> {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Gecos::Simple { .. } => None,
 | 
				
			||||||
 | 
					            Gecos::Detail { phone_home, .. } => {
 | 
				
			||||||
 | 
					                if phone_home.is_empty() {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Some(phone_home)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn get_other(&'a self) -> Option<&Vec<&'a str>> {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Gecos::Simple { .. } => None,
 | 
				
			||||||
 | 
					            Gecos::Detail { other, .. } => match other {
 | 
				
			||||||
 | 
					                None => None,
 | 
				
			||||||
 | 
					                Some(comments) => Some(comments),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for Gecos<'_> {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
 | 
					        match &self {
 | 
				
			||||||
 | 
					            Gecos::Simple { comment } => write!(f, "{}", comment),
 | 
				
			||||||
 | 
					            Gecos::Detail {
 | 
				
			||||||
 | 
					                full_name,
 | 
				
			||||||
 | 
					                room,
 | 
				
			||||||
 | 
					                phone_work,
 | 
				
			||||||
 | 
					                phone_home,
 | 
				
			||||||
 | 
					                other,
 | 
				
			||||||
 | 
					            } => write!(
 | 
				
			||||||
 | 
					                f,
 | 
				
			||||||
 | 
					                "{},{},{},{}{}",
 | 
				
			||||||
 | 
					                full_name,
 | 
				
			||||||
 | 
					                room,
 | 
				
			||||||
 | 
					                phone_work,
 | 
				
			||||||
 | 
					                phone_home,
 | 
				
			||||||
 | 
					                match other {
 | 
				
			||||||
 | 
					                    None => "".to_string(),
 | 
				
			||||||
 | 
					                    Some(cont) => format!(",{}", cont.join(",")),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> TryFrom<&'a str> for Gecos<'a> {
 | 
				
			||||||
 | 
					    type Error = UserLibError;
 | 
				
			||||||
 | 
					    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        let vals: Vec<&str> = source.split(',').collect();
 | 
				
			||||||
 | 
					        if vals.len() > 3 {
 | 
				
			||||||
 | 
					            Ok(Gecos::Detail {
 | 
				
			||||||
 | 
					                full_name: vals[0],
 | 
				
			||||||
 | 
					                room: vals[1],
 | 
				
			||||||
 | 
					                phone_work: vals[2],
 | 
				
			||||||
 | 
					                phone_home: vals[3],
 | 
				
			||||||
 | 
					                other: if vals.len() == 4 {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Some(vals[4..].to_vec())
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        } else if vals.len() == 1 {
 | 
				
			||||||
 | 
					            Ok(Gecos::Simple {
 | 
				
			||||||
 | 
					                comment: vals.get(0).unwrap(),
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            panic!(format!("Could not parse this string: {}", source))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
/// The home directory of a user
 | 
					/// The home directory of a user
 | 
				
			||||||
#[derive(Debug, PartialEq, Eq)]
 | 
					#[derive(Debug, PartialEq, Eq)]
 | 
				
			||||||
pub struct HomeDir<'a> {
 | 
					pub struct HomeDir<'a> {
 | 
				
			||||||
@ -142,78 +306,6 @@ impl<'a> Passwd<'a> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Gecos<'a> {
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_comment(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { comment, .. } => Some(comment),
 | 
					 | 
				
			||||||
            Gecos::Detail { .. } => None,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_full_name(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { full_name, .. } => {
 | 
					 | 
				
			||||||
                if full_name.is_empty() {
 | 
					 | 
				
			||||||
                    None
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Some(full_name)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_room(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { room, .. } => {
 | 
					 | 
				
			||||||
                if room.is_empty() {
 | 
					 | 
				
			||||||
                    None
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Some(room)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_phone_work(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { phone_work, .. } => {
 | 
					 | 
				
			||||||
                if phone_work.is_empty() {
 | 
					 | 
				
			||||||
                    None
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Some(phone_work)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_phone_home(&'a self) -> Option<&'a str> {
 | 
					 | 
				
			||||||
        match *self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { phone_home, .. } => {
 | 
					 | 
				
			||||||
                if phone_home.is_empty() {
 | 
					 | 
				
			||||||
                    None
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Some(phone_home)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    pub const fn get_other(&'a self) -> Option<&Vec<&'a str>> {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Gecos::Simple { .. } => None,
 | 
					 | 
				
			||||||
            Gecos::Detail { other, .. } => match other {
 | 
					 | 
				
			||||||
                None => None,
 | 
					 | 
				
			||||||
                Some(comments) => Some(comments),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Default for Passwd<'_> {
 | 
					impl Default for Passwd<'_> {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
        Passwd {
 | 
					        Passwd {
 | 
				
			||||||
@ -252,40 +344,6 @@ impl Display for Passwd<'_> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Display for Username<'_> {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        write!(f, "{}", self.username,)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> TryFrom<&'a str> for Username<'a> {
 | 
					 | 
				
			||||||
    type Error = UserLibError;
 | 
					 | 
				
			||||||
    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
					 | 
				
			||||||
        lazy_static! {
 | 
					 | 
				
			||||||
            static ref USERVALIDATION: Regex =
 | 
					 | 
				
			||||||
                Regex::new("^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\\$)$").unwrap();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if USERVALIDATION.is_match(source) {
 | 
					 | 
				
			||||||
            Ok(Self { username: source })
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            Err(UserLibError::Message("Invalid username".into()))
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Display for Password<'_> {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        write!(f, "{}", self.password,)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> TryFrom<&'a str> for Password<'a> {
 | 
					 | 
				
			||||||
    type Error = UserLibError;
 | 
					 | 
				
			||||||
    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
					 | 
				
			||||||
        Ok(Self { password: source })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Display for Uid {
 | 
					impl Display for Uid {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
        write!(f, "{}", self.uid,)
 | 
					        write!(f, "{}", self.uid,)
 | 
				
			||||||
@ -316,58 +374,6 @@ impl TryFrom<&str> for Gid {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Display for Gecos<'_> {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        match &self {
 | 
					 | 
				
			||||||
            Gecos::Simple { comment } => write!(f, "{}", comment),
 | 
					 | 
				
			||||||
            Gecos::Detail {
 | 
					 | 
				
			||||||
                full_name,
 | 
					 | 
				
			||||||
                room,
 | 
					 | 
				
			||||||
                phone_work,
 | 
					 | 
				
			||||||
                phone_home,
 | 
					 | 
				
			||||||
                other,
 | 
					 | 
				
			||||||
            } => write!(
 | 
					 | 
				
			||||||
                f,
 | 
					 | 
				
			||||||
                "{},{},{},{}{}",
 | 
					 | 
				
			||||||
                full_name,
 | 
					 | 
				
			||||||
                room,
 | 
					 | 
				
			||||||
                phone_work,
 | 
					 | 
				
			||||||
                phone_home,
 | 
					 | 
				
			||||||
                match other {
 | 
					 | 
				
			||||||
                    None => "".to_string(),
 | 
					 | 
				
			||||||
                    Some(cont) => format!(",{}", cont.join(",")),
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<'a> TryFrom<&'a str> for Gecos<'a> {
 | 
					 | 
				
			||||||
    type Error = UserLibError;
 | 
					 | 
				
			||||||
    fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
 | 
					 | 
				
			||||||
        let vals: Vec<&str> = source.split(',').collect();
 | 
					 | 
				
			||||||
        if vals.len() > 3 {
 | 
					 | 
				
			||||||
            Ok(Gecos::Detail {
 | 
					 | 
				
			||||||
                full_name: vals[0],
 | 
					 | 
				
			||||||
                room: vals[1],
 | 
					 | 
				
			||||||
                phone_work: vals[2],
 | 
					 | 
				
			||||||
                phone_home: vals[3],
 | 
					 | 
				
			||||||
                other: if vals.len() == 4 {
 | 
					 | 
				
			||||||
                    None
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Some(vals[4..].to_vec())
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        } else if vals.len() == 1 {
 | 
					 | 
				
			||||||
            Ok(Gecos::Simple {
 | 
					 | 
				
			||||||
                comment: vals.get(0).unwrap(),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            panic!(format!("Could not parse this string: {}", source))
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Display for HomeDir<'_> {
 | 
					impl Display for HomeDir<'_> {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
				
			||||||
        write!(f, "{}", self.dir,)
 | 
					        write!(f, "{}", self.dir,)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user