use super::StrictPath;
use std::path::Path;
#[cfg(windows)]
pub(super) fn create_windows_symlink(src: &Path, link: &Path) -> std::io::Result<()> {
use std::os::windows::fs::{symlink_dir, symlink_file};
match std::fs::metadata(src) {
Ok(metadata) => {
if metadata.is_dir() {
symlink_dir(src, link)
} else {
symlink_file(src, link)
}
}
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
match symlink_file(src, link) {
Ok(()) => Ok(()),
Err(file_err) => {
if let Some(code) = file_err.raw_os_error() {
const ERROR_DIRECTORY: i32 = 267; if code == ERROR_DIRECTORY {
return symlink_dir(src, link);
}
}
Err(file_err)
}
}
}
Err(err) => Err(err),
}
}
impl<Marker> StrictPath<Marker> {
pub fn strict_symlink<P: AsRef<Path>>(&self, link_path: P) -> std::io::Result<()> {
let link_ref = link_path.as_ref();
let validated_link = if link_ref.is_absolute() {
match self.boundary().strict_join(link_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
} else {
let parent = match self.strictpath_parent() {
Ok(Some(p)) => p,
Ok(None) => match self.boundary().clone().into_strictpath() {
Ok(root) => root,
Err(e) => return Err(std::io::Error::other(e)),
},
Err(e) => return Err(std::io::Error::other(e)),
};
match parent.strict_join(link_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
};
#[cfg(unix)]
{
std::os::unix::fs::symlink(self.path(), validated_link.path())?;
}
#[cfg(windows)]
{
create_windows_symlink(self.path(), validated_link.path())?;
}
Ok(())
}
pub fn strict_read_link(&self) -> std::io::Result<Self> {
let raw_target = std::fs::read_link(self.path())?;
let resolved_target = if raw_target.is_relative() {
match self.path().parent() {
Some(parent) => parent.join(&raw_target),
None => raw_target,
}
} else {
raw_target
};
self.boundary()
.strict_join(resolved_target)
.map_err(std::io::Error::other)
}
pub fn strict_hard_link<P: AsRef<Path>>(&self, link_path: P) -> std::io::Result<()> {
let link_ref = link_path.as_ref();
let validated_link = if link_ref.is_absolute() {
match self.boundary().strict_join(link_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
} else {
let parent = match self.strictpath_parent() {
Ok(Some(p)) => p,
Ok(None) => match self.boundary().clone().into_strictpath() {
Ok(root) => root,
Err(e) => return Err(std::io::Error::other(e)),
},
Err(e) => return Err(std::io::Error::other(e)),
};
match parent.strict_join(link_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
};
std::fs::hard_link(self.path(), validated_link.path())
}
#[cfg(all(windows, feature = "junctions"))]
pub fn strict_junction<P: AsRef<Path>>(&self, link_path: P) -> std::io::Result<()> {
let link_ref = link_path.as_ref();
let validated_link = if link_ref.is_absolute() {
match self.boundary().strict_join(link_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
} else {
let parent = match self.strictpath_parent() {
Ok(Some(p)) => p,
Ok(None) => match self.boundary().clone().into_strictpath() {
Ok(root) => root,
Err(e) => return Err(std::io::Error::other(e)),
},
Err(e) => return Err(std::io::Error::other(e)),
};
match parent.strict_join(link_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
};
let meta = std::fs::metadata(self.path())?;
if !meta.is_dir() {
return Err(std::io::Error::other(
"junction targets must be directories",
));
}
let target_path = super::strip_verbatim_prefix(self.path());
let link_path = super::strip_verbatim_prefix(validated_link.path());
junction::create(target_path.as_ref(), link_path.as_ref())
}
pub fn strict_rename<P: AsRef<Path>>(&self, dest: P) -> std::io::Result<()> {
let dest_ref = dest.as_ref();
let dest_path = if dest_ref.is_absolute() {
match self.boundary().strict_join(dest_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
} else {
let parent = match self.strictpath_parent() {
Ok(Some(p)) => p,
Ok(None) => match self.boundary().clone().into_strictpath() {
Ok(root) => root,
Err(e) => return Err(std::io::Error::other(e)),
},
Err(e) => return Err(std::io::Error::other(e)),
};
match parent.strict_join(dest_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
};
std::fs::rename(self.path(), dest_path.path())
}
pub fn strict_copy<P: AsRef<Path>>(&self, dest: P) -> std::io::Result<u64> {
let dest_ref = dest.as_ref();
let dest_path = if dest_ref.is_absolute() {
match self.boundary().strict_join(dest_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
} else {
let parent = match self.strictpath_parent() {
Ok(Some(p)) => p,
Ok(None) => match self.boundary().clone().into_strictpath() {
Ok(root) => root,
Err(e) => return Err(std::io::Error::other(e)),
},
Err(e) => return Err(std::io::Error::other(e)),
};
match parent.strict_join(dest_ref) {
Ok(p) => p,
Err(e) => return Err(std::io::Error::other(e)),
}
};
std::fs::copy(self.path(), dest_path.path())
}
}