forked from brl/citadel-tools
138 lines
3.6 KiB
Rust
138 lines
3.6 KiB
Rust
use std::path::Path;
|
|
use std::fs;
|
|
use std::os::unix::ffi::OsStrExt;
|
|
use std::os::unix::fs::MetadataExt;
|
|
use std::ffi::CString;
|
|
use std::io::{self,Write};
|
|
|
|
use libc;
|
|
use walkdir::WalkDir;
|
|
|
|
use Result;
|
|
|
|
|
|
pub fn path_filename(path: &Path) -> &str {
|
|
if let Some(osstr) = path.file_name() {
|
|
if let Some(name) = osstr.to_str() {
|
|
return name;
|
|
}
|
|
}
|
|
""
|
|
}
|
|
|
|
fn is_alphanum_or_dash(c: char) -> bool {
|
|
is_ascii(c) && (c.is_alphanumeric() || c == '-')
|
|
}
|
|
|
|
fn is_ascii(c: char) -> bool {
|
|
c as u32 <= 0x7F
|
|
}
|
|
|
|
pub fn is_first_char_alphabetic(s: &str) -> bool {
|
|
if let Some(c) = s.chars().next() {
|
|
return is_ascii(c) && c.is_alphabetic()
|
|
}
|
|
false
|
|
}
|
|
|
|
const MAX_REALM_NAME_LEN:usize = 128;
|
|
|
|
/// Valid realm names:
|
|
/// * must start with an alphabetic ascii letter character
|
|
/// * may only contain ascii characters which are letters, numbers, or the dash '-' symbol
|
|
/// * must not be empty or have a length exceeding 128 characters
|
|
pub fn is_valid_realm_name(name: &str) -> bool {
|
|
name.len() <= MAX_REALM_NAME_LEN &&
|
|
// Also false on empty string
|
|
is_first_char_alphabetic(name) &&
|
|
name.chars().all(is_alphanum_or_dash)
|
|
}
|
|
|
|
pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
|
|
let cstr = CString::new(path.as_os_str().as_bytes())?;
|
|
unsafe {
|
|
if libc::chown(cstr.as_ptr(), uid, gid) == -1 {
|
|
return Err(io::Error::last_os_error());
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn copy_path(from: &Path, to: &Path) -> Result<()> {
|
|
if to.exists() {
|
|
bail!("destination path {} already exists which is not expected", to.display());
|
|
}
|
|
|
|
let meta = from.metadata()?;
|
|
|
|
if from.is_dir() {
|
|
fs::create_dir(to)?;
|
|
} else {
|
|
fs::copy(&from, &to)?;
|
|
}
|
|
|
|
chown(to, meta.uid(), meta.gid())?;
|
|
Ok(())
|
|
|
|
}
|
|
pub fn copy_tree(from_base: &Path, to_base: &Path) -> Result<()> {
|
|
for entry in WalkDir::new(from_base) {
|
|
let path = entry?.path().to_owned();
|
|
let to = to_base.join(path.strip_prefix(from_base)?);
|
|
if &to != to_base {
|
|
copy_path(&path, &to)
|
|
.map_err(|e| format_err!("failed to copy {} to {}: {}", path.display(), to.display(), e))?;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
use termcolor::{ColorChoice,Color,ColorSpec,WriteColor,StandardStream};
|
|
|
|
pub struct ColoredOutput {
|
|
color_bright: ColorSpec,
|
|
color_bold: ColorSpec,
|
|
color_dim: ColorSpec,
|
|
stream: StandardStream,
|
|
}
|
|
|
|
|
|
impl ColoredOutput {
|
|
pub fn new() -> ColoredOutput {
|
|
ColoredOutput::new_with_colors(Color::Rgb(0, 110, 180), Color::Rgb(100, 100, 80))
|
|
}
|
|
|
|
pub fn new_with_colors(bright: Color, dim: Color) -> ColoredOutput {
|
|
let mut out = ColoredOutput {
|
|
color_bright: ColorSpec::new(),
|
|
color_bold: ColorSpec::new(),
|
|
color_dim: ColorSpec::new(),
|
|
stream: StandardStream::stdout(ColorChoice::AlwaysAnsi),
|
|
};
|
|
out.color_bright.set_fg(Some(bright.clone()));
|
|
out.color_bold.set_fg(Some(bright)).set_bold(true);
|
|
out.color_dim.set_fg(Some(dim));
|
|
|
|
out
|
|
}
|
|
|
|
pub fn write(&mut self, s: &str) -> &mut Self {
|
|
write!(&mut self.stream, "{}", s).unwrap();
|
|
self.stream.reset().unwrap();
|
|
self
|
|
}
|
|
pub fn bright(&mut self, s: &str) -> &mut Self {
|
|
self.stream.set_color(&self.color_bright).unwrap();
|
|
self.write(s)
|
|
}
|
|
pub fn bold(&mut self, s: &str) -> &mut Self {
|
|
self.stream.set_color(&self.color_bold).unwrap();
|
|
self.write(s)
|
|
}
|
|
pub fn dim(&mut self, s: &str) -> &mut Self {
|
|
self.stream.set_color(&self.color_dim).unwrap();
|
|
self.write(s)
|
|
}
|
|
|
|
}
|