//! Utility functions. use std::{fs, io, path::Path}; #[cfg(unix)] use nix::unistd::{self, Gid, Uid}; use super::error::Result; #[cfg(not(unix))] pub mod nix { //! Stub mod on non-unix systems. pub mod unistd { pub enum Uid {} pub enum Gid {} } } /// Recursively copy the *contents* of the given directory to the given path. pub fn copy_recursive, D: AsRef>(source: S, destination: D) -> io::Result<()> { copy_inner(source.as_ref(), destination.as_ref()) } fn copy_inner(source: &Path, destination: &Path) -> io::Result<()> { for item in fs::read_dir(source)? { let item = item?; let metadata = item.metadata()?; let item_destination = destination.join(item.file_name()); if metadata.is_file() { fs::copy(&item.path(), &item_destination)?; } else if metadata.is_dir() { fs::create_dir(&item_destination)?; copy_inner(&item.path(), &item_destination)?; } } Ok(()) } /// Recursively change the owner of the given path to the given ones. /// /// Note that this function only works on Unix systems. **It will panic on other systems!** pub fn chown_recursive>(path: P, uid: Option, gid: Option) -> Result<()> { chown_inner(path.as_ref(), uid, gid) } #[cfg(unix)] fn chown_inner(path: &Path, uid: Option, gid: Option) -> Result<()> { unistd::chown(path, uid, gid)?; let metadata = fs::metadata(path)?; if metadata.is_dir() { for item in fs::read_dir(path)? { let item = item?; chown_inner(&item.path(), uid, gid)?; } } Ok(()) } #[cfg(not(unix))] fn chown_inner(_: &Path, _: Option, _: Option) -> Result<()> { panic!("chown() is not available on non-Unix systems!"); }