diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-10-25 00:19:45 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-10-25 00:19:45 +0200 |
commit | 34ac18d20c13a78914d447fee83204811a27b1e4 (patch) | |
tree | 56763d4ea46927105fcc6a71e03d5bd75a6947a6 /crates/runner/src/util/fs.rs | |
parent | a1a185370da27f2cc3df84d3a8d7141f9ce7db16 (diff) | |
download | rebel-34ac18d20c13a78914d447fee83204811a27b1e4.tar rebel-34ac18d20c13a78914d447fee83204811a27b1e4.zip |
Move runner into separate crate
Diffstat (limited to 'crates/runner/src/util/fs.rs')
-rw-r--r-- | crates/runner/src/util/fs.rs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/crates/runner/src/util/fs.rs b/crates/runner/src/util/fs.rs new file mode 100644 index 0000000..099a339 --- /dev/null +++ b/crates/runner/src/util/fs.rs @@ -0,0 +1,122 @@ +use std::{ + fs::{self, File}, + io, + os::unix::prelude::*, + path::{Path, PathBuf}, +}; + +use nix::{ + fcntl::OFlag, + mount::{self, MsFlags}, + unistd, +}; + +use common::error::*; + +pub fn open<P: AsRef<Path>>(path: P) -> Result<fs::File> { + fs::File::open(path.as_ref()) + .with_context(|| format!("Failed to open file {:?} for reading", path.as_ref())) +} + +pub fn create<P: AsRef<Path>>(path: P) -> Result<fs::File> { + fs::File::create(path.as_ref()) + .with_context(|| format!("Failed to open file {:?} for writing", path.as_ref())) +} + +pub fn rename<P1: AsRef<Path>, P2: AsRef<Path>>(from: P1, to: P2) -> Result<()> { + fs::rename(from.as_ref(), to.as_ref()) + .with_context(|| format!("Failed to rename {:?} to {:?}", from.as_ref(), to.as_ref())) +} + +// Unlike fs::copy, this doesn't preserve file flags +pub fn copy<P1: AsRef<Path>, P2: AsRef<Path>>(from: P1, to: P2) -> Result<()> { + (|| -> Result<()> { + let mut src = open(from.as_ref())?; + let mut dest = create(to.as_ref())?; + io::copy(&mut src, &mut dest)?; + dest.sync_all()?; + Ok(()) + })() + .with_context(|| format!("Failed to copy {:?} to {:?}", from.as_ref(), to.as_ref())) +} + +pub fn mkdir<P: AsRef<Path>>(path: P) -> Result<()> { + let mut builder = fs::DirBuilder::new(); + builder.recursive(true); + builder + .create(path.as_ref()) + .with_context(|| format!("Failed to create directory {:?}", path.as_ref())) +} + +pub fn ensure_removed<P: AsRef<Path>>(path: P) -> Result<()> { + fs::remove_dir_all(path.as_ref()) + .or_else(|err| match err.kind() { + io::ErrorKind::NotFound => Ok(()), + _ => Err(err), + }) + .with_context(|| format!("Failed to delete directory {:?}", path.as_ref())) +} + +pub fn is_dir_empty<P: AsRef<Path>>(path: P) -> Result<bool> { + Ok(fs::read_dir(path)?.next().is_none()) +} + +/// Fixes up weirdness of set-group-ID or bsdgroups +pub fn fixup_permissions<P: AsRef<Path>>(path: P) -> Result<()> { + let path = path.as_ref(); + let gid = unistd::getegid(); + + let metadata = path + .metadata() + .with_context(|| format!("Failed to get metadata of {:?}", path))?; + + if metadata.gid() != gid.as_raw() { + unistd::chown(path, None, Some(gid)) + .with_context(|| format!("Failed to set group of {:?}", path))?; + } + + let mut perms = metadata.permissions(); + let mode = perms.mode(); + if (mode & 0o777) != mode { + perms.set_mode(mode & 0o777); + std::fs::set_permissions(path, perms) + .with_context(|| format!("Failed to set mode of {:?}", path))?; + } + + Ok(()) +} + +#[must_use] +pub struct Mount(PathBuf); + +impl Drop for Mount { + fn drop(&mut self) { + mount::umount(&self.0) + .with_context(|| format!("Failed to unmount {:?}", self.0)) + .unwrap(); + } +} + +pub fn mount<P1: AsRef<Path>, P2: AsRef<Path>>( + source: P1, + target: P2, + fstype: Option<&str>, + flags: MsFlags, + data: Option<&str>, +) -> Result<Mount> { + mkdir(target.as_ref()).with_context(|| format!("Failed to create {:?}", target.as_ref()))?; + + let canon_target = target + .as_ref() + .canonicalize() + .with_context(|| format!("Failed to get absolute path for {:?}", target.as_ref()))?; + mount::mount(Some(source.as_ref()), &canon_target, fstype, flags, data) + .with_context(|| format!("Failed to mount {:?}", canon_target))?; + Ok(Mount(canon_target)) +} + +pub fn pipe() -> Result<(File, File)> { + unistd::pipe2(OFlag::O_CLOEXEC) + .context("pipe2()") + .map(|(piper, pipew)| unsafe { (File::from_raw_fd(piper), File::from_raw_fd(pipew)) }) +} |