use alloc::string::String;
use core::{
cell::{Ref, RefCell, RefMut},
time::Duration,
};
use std::path::{Path, PathBuf};
use libafl_bolts::serdeany::SerdeAnyMap;
use serde::{Deserialize, Serialize};
use crate::{
Error,
corpus::{CachedOnDiskCorpus, Corpus, CorpusId, EnableDisableCorpus, HasTestcase, Testcase},
inputs::Input,
};
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub enum OnDiskMetadataFormat {
Postcard,
Json,
#[default]
JsonPretty,
#[cfg(feature = "gzip")]
JsonGzip,
}
#[derive(Debug, Serialize)]
pub struct OnDiskMetadata<'a> {
pub metadata: &'a SerdeAnyMap,
pub exec_time: &'a Option<Duration>,
pub executions: &'a u64,
}
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
pub struct OnDiskCorpus<I> {
dir_path: PathBuf,
inner: CachedOnDiskCorpus<I>,
}
impl<I> Corpus<I> for OnDiskCorpus<I>
where
I: Input,
{
#[inline]
fn count(&self) -> usize {
self.inner.count()
}
fn count_disabled(&self) -> usize {
self.inner.count_disabled()
}
#[inline]
fn count_all(&self) -> usize {
self.inner.count_all()
}
#[inline]
fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
self.inner.add(testcase)
}
#[inline]
fn add_disabled(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error> {
self.inner.add_disabled(testcase)
}
#[inline]
fn replace(&mut self, id: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error> {
self.inner.replace(id, testcase)
}
#[inline]
fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error> {
self.inner.remove(id)
}
#[inline]
fn get(&self, id: CorpusId) -> Result<&RefCell<Testcase<I>>, Error> {
self.inner.get(id)
}
#[inline]
fn get_from_all(&self, id: CorpusId) -> Result<&RefCell<Testcase<I>>, Error> {
self.inner.get_from_all(id)
}
#[inline]
fn current(&self) -> &Option<CorpusId> {
self.inner.current()
}
#[inline]
fn current_mut(&mut self) -> &mut Option<CorpusId> {
self.inner.current_mut()
}
#[inline]
fn next(&self, id: CorpusId) -> Option<CorpusId> {
self.inner.next(id)
}
#[inline]
fn peek_free_id(&self) -> CorpusId {
self.inner.peek_free_id()
}
#[inline]
fn prev(&self, id: CorpusId) -> Option<CorpusId> {
self.inner.prev(id)
}
#[inline]
fn first(&self) -> Option<CorpusId> {
self.inner.first()
}
#[inline]
fn last(&self) -> Option<CorpusId> {
self.inner.last()
}
#[inline]
fn nth(&self, nth: usize) -> CorpusId {
self.inner.nth(nth)
}
#[inline]
fn nth_from_all(&self, nth: usize) -> CorpusId {
self.inner.nth_from_all(nth)
}
#[inline]
fn load_input_into(&self, testcase: &mut Testcase<I>) -> Result<(), Error> {
self.inner.load_input_into(testcase)
}
#[inline]
fn store_input_from(&self, testcase: &Testcase<I>) -> Result<(), Error> {
self.inner.store_input_from(testcase)
}
}
impl<I> HasTestcase<I> for OnDiskCorpus<I>
where
I: Input,
{
fn testcase(&self, id: CorpusId) -> Result<Ref<'_, Testcase<I>>, Error> {
Ok(self.get(id)?.borrow())
}
fn testcase_mut(&self, id: CorpusId) -> Result<RefMut<'_, Testcase<I>>, Error> {
Ok(self.get(id)?.borrow_mut())
}
}
impl<I> EnableDisableCorpus for OnDiskCorpus<I>
where
I: Input,
{
#[inline]
fn disable(&mut self, id: CorpusId) -> Result<(), Error> {
self.inner.disable(id)
}
#[inline]
fn enable(&mut self, id: CorpusId) -> Result<(), Error> {
self.inner.enable(id)
}
}
impl<I> OnDiskCorpus<I> {
pub fn new<P>(dir_path: P) -> Result<Self, Error>
where
P: AsRef<Path>,
{
Self::with_meta_format_and_prefix(
dir_path.as_ref(),
Some(OnDiskMetadataFormat::JsonPretty),
None,
true,
)
}
pub fn with_prefix<P>(dir_path: P, prefix: Option<String>) -> Result<Self, Error>
where
P: AsRef<Path>,
{
Self::with_meta_format_and_prefix(
dir_path.as_ref(),
Some(OnDiskMetadataFormat::JsonPretty),
prefix,
true,
)
}
pub fn with_meta_format<P>(
dir_path: P,
meta_format: OnDiskMetadataFormat,
) -> Result<Self, Error>
where
P: AsRef<Path>,
{
Self::with_meta_format_and_prefix(dir_path.as_ref(), Some(meta_format), None, true)
}
pub fn no_meta<P>(dir_path: P) -> Result<Self, Error>
where
P: AsRef<Path>,
{
Self::with_meta_format_and_prefix(dir_path.as_ref(), None, None, true)
}
pub fn with_meta_format_and_prefix(
dir_path: &Path,
meta_format: Option<OnDiskMetadataFormat>,
prefix: Option<String>,
locking: bool,
) -> Result<Self, Error> {
Ok(OnDiskCorpus {
dir_path: dir_path.into(),
inner: CachedOnDiskCorpus::with_meta_format_and_prefix(
dir_path,
1,
meta_format,
prefix,
locking,
)?,
})
}
pub fn dir_path(&self) -> &PathBuf {
&self.dir_path
}
}