use std::{
fs::{self, File},
io::Write,
path::{Path, PathBuf},
};
#[cfg(target_family = "unix")]
use std::os::unix::{self, fs::PermissionsExt};
use crate::Mistrust;
#[derive(Debug)]
pub(crate) struct Dir {
toplevel: tempfile::TempDir,
canonical_root: PathBuf,
}
#[cfg(target_family = "unix")]
#[derive(Copy, Clone, Debug)]
pub(crate) enum LinkType {
Dir,
File,
}
impl Dir {
pub(crate) fn new() -> Self {
let toplevel = tempfile::TempDir::new().expect("Can't get tempfile");
let canonical_root = toplevel.path().canonicalize().expect("Can't canonicalize");
Dir {
toplevel,
canonical_root,
}
}
pub(crate) fn canonical_root(&self) -> &Path {
self.canonical_root.as_path()
}
pub(crate) fn relative_root(&self) -> PathBuf {
let mut cwd = std::env::current_dir().expect("no cwd");
let mut relative = PathBuf::new();
while !self.toplevel.path().starts_with(&cwd) {
assert!(cwd.pop());
relative.push("..");
}
relative.join(
self.toplevel
.path()
.strip_prefix(cwd)
.expect("error computing common ancestor"),
)
}
pub(crate) fn path(&self, p: impl AsRef<Path>) -> PathBuf {
let p = p.as_ref();
assert!(p.is_relative());
self.canonical_root.join(p)
}
pub(crate) fn dir(&self, p: impl AsRef<Path>) {
fs::create_dir_all(self.path(p)).expect("Can't create directory.");
}
pub(crate) fn file(&self, p: impl AsRef<Path>) {
self.dir(p.as_ref().parent().expect("Tempdir had no parent"));
let mut f = File::create(self.path(p)).expect("Can't create file");
f.write_all(&b"This space is intentionally left blank"[..])
.expect("Can't write");
}
#[cfg(target_family = "unix")]
pub(crate) fn link_rel(
&self,
link_type: LinkType,
original: impl AsRef<Path>,
link: impl AsRef<Path>,
) {
{
let _ = link_type;
unix::fs::symlink(original.as_ref(), self.path(link)).expect("Can't symlink");
}
}
#[cfg(target_family = "unix")]
pub(crate) fn link_abs(
&self,
link_type: LinkType,
original: impl AsRef<Path>,
link: impl AsRef<Path>,
) {
self.link_rel(link_type, self.path(original), link);
}
pub(crate) fn chmod(&self, p: impl AsRef<Path>, mode: u32) {
#[cfg(target_family = "unix")]
{
let perm = fs::Permissions::from_mode(mode);
fs::set_permissions(self.path(p), perm).expect("can't chmod");
}
#[cfg(not(target_family = "unix"))]
{
let (_, _) = (p, mode);
}
}
}
#[derive(Debug)]
pub(crate) enum MistrustOp<'a> {
IgnorePrefix(&'a Path),
DangerouslyTrustEveryone(),
TrustNoGroupId(),
#[cfg(target_family = "unix")]
TrustAdminOnly(),
#[cfg(target_family = "unix")]
TrustGroup(u32),
}
pub(crate) fn mistrust_build(ops: &[MistrustOp]) -> Mistrust {
ops.iter()
.fold(&mut Mistrust::builder(), |m, op| {
match op {
MistrustOp::IgnorePrefix(prefix) => m.ignore_prefix(prefix),
MistrustOp::DangerouslyTrustEveryone() => m.dangerously_trust_everyone(),
MistrustOp::TrustNoGroupId() => {
#[cfg(all(
target_family = "unix",
not(target_os = "ios"),
not(target_os = "android"),
not(target_os = "tvos")
))]
return m.trust_no_group_id();
#[cfg(not(all(
target_family = "unix",
not(target_os = "ios"),
not(target_os = "android"),
not(target_os = "tvos")
)))]
return m;
}
#[cfg(target_family = "unix")]
MistrustOp::TrustAdminOnly() => {
#[cfg(all(
target_family = "unix",
not(target_os = "ios"),
not(target_os = "android")
))]
return m.trust_admin_only();
#[cfg(not(all(
target_family = "unix",
not(target_os = "ios"),
not(target_os = "android")
)))]
return m;
}
#[cfg(target_family = "unix")]
MistrustOp::TrustGroup(gid) => {
#[cfg(all(
target_family = "unix",
not(target_os = "ios"),
not(target_os = "android")
))]
return m.trust_group(*gid);
#[cfg(not(all(
target_family = "unix",
not(target_os = "ios"),
not(target_os = "android")
)))]
return m;
}
}
})
.build()
.expect("Unable to build Mistrust object")
}