1use crate::error::Error;
2
3use crate::constants::*;
4use fehler::throws;
5use std::path::Path;
6use std::path::PathBuf;
7use tokio::fs;
8
9#[macro_export]
10macro_rules! construct_path {
11 ($root:expr, $($component:expr),*) => {
12 {
13 let mut path = $root.to_owned();
14 $(path = path.join($component);)*
15 path
16 }
17 };
18}
19#[macro_export]
20macro_rules! load_template {
21 ($file:expr) => {
22 include_str!(concat!(env!("CARGO_MANIFEST_DIR"), $file))
23 };
24}
25
26#[throws]
27pub async fn create_directory_all(path: &PathBuf) {
28 match path.exists() {
29 true => {}
30 false => {
31 fs::create_dir_all(path).await?;
32 }
33 };
34}
35
36#[throws]
37pub async fn create_file(root: &PathBuf, path: &PathBuf, content: &str) {
38 let file = path.strip_prefix(root)?.to_str().unwrap_or_default();
39
40 match path.exists() {
41 true => {
42 println!("{SKIP} [{file}] already exists")
43 }
44 false => {
45 fs::write(path, content).await?;
46 println!("{FINISH} [{file}] created");
47 }
48 };
49}
50
51#[throws]
52pub fn get_fuzz_id(fuzz_dir_path: &Path) -> i32 {
53 if fuzz_dir_path.exists() {
54 if fuzz_dir_path.read_dir()?.next().is_none() {
55 0
56 } else {
57 let entries = fuzz_dir_path.read_dir()?;
58 let mut max_num = -1;
59 for entry in entries {
60 let entry = entry?;
61 let file_name = entry.file_name().into_string().unwrap_or_default();
62 if file_name.starts_with("fuzz_") {
63 let stripped = file_name.strip_prefix("fuzz_").unwrap_or_default();
64 let num = stripped.parse::<i32>()?;
65 max_num = max_num.max(num);
66 }
67 }
68 max_num + 1
69 }
70 } else {
71 0
72 }
73}
74
75#[throws]
77pub async fn ensure_fuzz_artifacts_dir() -> PathBuf {
78 let artifacts_dir = PathBuf::from(".fuzz-artifacts");
79 create_directory_all(&artifacts_dir).await?;
80 artifacts_dir
81}
82
83#[throws]
86pub async fn generate_unique_fuzz_filename(
87 base_name: &str,
88 fuzz_test_name: &str,
89 extension: &str,
90) -> PathBuf {
91 let artifacts_dir = ensure_fuzz_artifacts_dir().await?;
92 let base_filename = format!("{}_{}.{}", base_name, fuzz_test_name, extension);
93 let mut target_path = artifacts_dir.join(&base_filename);
94
95 if target_path.exists() {
97 use chrono::DateTime;
98 use chrono::Local;
99
100 let now: DateTime<Local> = Local::now();
102
103 let timestamp = now.format("%Y-%m-%d_%H-%M-%S").to_string();
105 let unique_filename = format!(
106 "{}_{}-{}.{}",
107 base_name, fuzz_test_name, timestamp, extension
108 );
109 target_path = artifacts_dir.join(&unique_filename);
110
111 if target_path.exists() {
113 let timestamp_with_ms = now.format("%Y-%m-%d_%H-%M-%S-%3f").to_string();
114 let unique_filename = format!(
115 "{}_{}-{}.{}",
116 base_name, fuzz_test_name, timestamp_with_ms, extension
117 );
118 target_path = artifacts_dir.join(&unique_filename);
119 }
120 }
121
122 target_path
123}