extern crate nc;
use nc::Errno;
use crate::expand_env;
pub struct LnOptions {
pub expand_env: bool,
pub force: bool,
pub physical: bool,
pub logical: bool,
pub symbolic: bool,
}
impl Default for LnOptions {
fn default() -> LnOptions {
LnOptions {
expand_env: true,
force: false,
physical: true,
logical: false,
symbolic: false,
}
}
}
pub fn ln<T: AsRef<str>>(src: T, target: T, options: &LnOptions) -> Result<(), Errno> {
let src = if options.expand_env {
expand_env(src)
} else {
src.as_ref().to_string()
};
let logical_src: String = if options.logical {
let mut stat = nc::stat_t::default();
let _ret = nc::newfstatat(nc::AT_FDCWD, &src, &mut stat, 0)?;
if stat.st_mode == nc::S_IFLNK {
let mut buf: Vec<u8> = Vec::with_capacity(nc::PATH_MAX as usize);
let read_size = nc::readlinkat(nc::AT_FDCWD, &src, &mut buf)?;
let mut real_src = String::from_utf8_lossy(&buf).into_owned();
real_src.truncate((read_size + 1) as usize);
real_src
} else {
src
}
} else {
src
};
let target = if options.expand_env {
expand_env(target)
} else {
target.as_ref().to_string()
};
if options.force {
let _ret = nc::unlink(&target);
}
if options.symbolic {
return nc::symlink(&logical_src, &target);
} else {
return nc::link(&logical_src, &target);
}
}