shitbox/corebox/commands/mktemp/mod.rs

86 lines
2.9 KiB
Rust

use super::Cmd;
use clap::{Arg, ArgAction, Command, ValueHint};
use std::{ffi::CString, fs, io, path::PathBuf};
#[derive(Debug, Default)]
pub struct MkTemp;
impl Cmd for MkTemp {
fn cli(&self) -> clap::Command {
Command::new("mktemp")
.about("create a unique temporary file")
.author("Nathan Fisher")
.version(env!("CARGO_PKG_VERSION"))
.args([
Arg::new("directory")
.short('d')
.long("directory")
.help("create a directory instead of a file")
.action(ArgAction::SetTrue),
Arg::new("tmpdir")
.short('p')
.long("tmpdir")
.help("specify the directory to create temporary files in")
.value_hint(ValueHint::DirPath)
.num_args(1),
Arg::new("prefix")
.short('t')
.long("template")
.help("specify a prefix to append to the created files")
.num_args(1),
Arg::new("dryrun")
.short('u')
.long("dryrun")
.help("immediately remove created files and directories")
.action(ArgAction::SetTrue),
])
}
fn run(&self, matches: &clap::ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
let mut path = if let Some(t) = matches.get_one::<String>("tmpdir") {
PathBuf::from(t)
} else {
PathBuf::from("/tmp")
};
let fname = if let Some(p) = matches.get_one::<String>("prefix") {
format!("{p}.XXXXXX")
} else {
"mktemp.XXXXXX".to_string()
};
path.push(&fname);
let fname = path
.to_str()
.ok_or(io::Error::new(io::ErrorKind::Other, "utf8 error"))?;
let cname = CString::new(fname)?;
let ptr = cname.into_raw();
if matches.get_flag("directory") {
let raw_fd = unsafe { libc::mkdtemp(ptr) };
if raw_fd.is_null() {
return Err(io::Error::last_os_error().into());
}
let cname = unsafe { CString::from_raw(ptr) };
let fname = cname.to_str()?;
println!("{fname}");
if matches.get_flag("dryrun") {
fs::remove_dir(fname)?;
}
} else {
let raw_fd = unsafe { libc::mkstemp(ptr) };
if raw_fd == -1 {
return Err(io::Error::last_os_error().into());
}
let cname = unsafe { CString::from_raw(ptr) };
let fname = cname.to_str()?;
println!("{fname}");
if matches.get_flag("dryrun") {
fs::remove_file(fname)?;
}
}
Ok(())
}
fn path(&self) -> Option<shitbox::Path> {
Some(shitbox::Path::UsrBin)
}
}