use crate::entry::Entry;
use crate::error::{Error, Result};
use std::ffi::CString;
pub struct ArchiveMatch {
matcher: *mut libarchive2_sys::archive,
}
unsafe impl Send for ArchiveMatch {}
impl ArchiveMatch {
pub fn new() -> Result<Self> {
unsafe {
let matcher = libarchive2_sys::archive_match_new();
if matcher.is_null() {
return Err(Error::NullPointer);
}
Ok(ArchiveMatch { matcher })
}
}
pub fn include_pattern(&mut self, pattern: &str) -> Result<()> {
let c_pattern = CString::new(pattern)
.map_err(|_| Error::InvalidArgument("Pattern contains null byte".to_string()))?;
unsafe {
Error::from_return_code(
libarchive2_sys::archive_match_include_pattern(self.matcher, c_pattern.as_ptr()),
self.matcher,
)?;
}
Ok(())
}
pub fn exclude_pattern(&mut self, pattern: &str) -> Result<()> {
let c_pattern = CString::new(pattern)
.map_err(|_| Error::InvalidArgument("Pattern contains null byte".to_string()))?;
unsafe {
Error::from_return_code(
libarchive2_sys::archive_match_exclude_pattern(self.matcher, c_pattern.as_ptr()),
self.matcher,
)?;
}
Ok(())
}
pub fn include_pathname(&mut self, pathname: &str) -> Result<()> {
let c_pathname = CString::new(pathname)
.map_err(|_| Error::InvalidArgument("Pathname contains null byte".to_string()))?;
unsafe {
Error::from_return_code(
libarchive2_sys::archive_match_include_file_time(
self.matcher,
libarchive2_sys::ARCHIVE_MATCH_MTIME as i32,
c_pathname.as_ptr(),
),
self.matcher,
)?;
}
Ok(())
}
pub fn exclude_pathname(&mut self, _pathname: &str) -> Result<()> {
Err(Error::InvalidArgument(
"exclude_pathname is not yet implemented. Use exclude_pattern() instead.".to_string(),
))
}
pub fn include_time_newer_than(&mut self, sec: i64, nsec: i64) -> Result<()> {
unsafe {
Error::from_return_code(
libarchive2_sys::archive_match_include_time(
self.matcher,
libarchive2_sys::ARCHIVE_MATCH_NEWER as i32,
sec,
nsec as _,
),
self.matcher,
)?;
}
Ok(())
}
pub fn include_time_older_than(&mut self, sec: i64, nsec: i64) -> Result<()> {
unsafe {
Error::from_return_code(
libarchive2_sys::archive_match_include_time(
self.matcher,
libarchive2_sys::ARCHIVE_MATCH_OLDER as i32,
sec,
nsec as _,
),
self.matcher,
)?;
}
Ok(())
}
pub fn include_uid(&mut self, uid: i64) -> Result<()> {
unsafe {
Error::from_return_code(
libarchive2_sys::archive_match_include_uid(self.matcher, uid),
self.matcher,
)?;
}
Ok(())
}
pub fn include_gid(&mut self, gid: i64) -> Result<()> {
unsafe {
Error::from_return_code(
libarchive2_sys::archive_match_include_gid(self.matcher, gid),
self.matcher,
)?;
}
Ok(())
}
pub fn exclude_uid(&mut self, _uid: i64) -> Result<()> {
Err(Error::InvalidArgument(
"exclude_uid is not supported by libarchive. Implement custom filtering.".to_string(),
))
}
pub fn exclude_gid(&mut self, _gid: i64) -> Result<()> {
Err(Error::InvalidArgument(
"exclude_gid is not supported by libarchive. Implement custom filtering.".to_string(),
))
}
pub fn matches(&mut self, entry: &Entry) -> Result<bool> {
unsafe {
let ret = libarchive2_sys::archive_match_excluded(self.matcher, entry.entry);
if ret < 0 {
Err(Error::from_archive(self.matcher))
} else {
Ok(ret == 0)
}
}
}
pub fn time_excluded(&mut self, entry: &Entry) -> Result<bool> {
unsafe {
let ret = libarchive2_sys::archive_match_time_excluded(self.matcher, entry.entry);
Ok(ret != 0)
}
}
pub fn path_excluded(&mut self, entry: &Entry) -> Result<bool> {
unsafe {
let ret = libarchive2_sys::archive_match_path_excluded(self.matcher, entry.entry);
Ok(ret != 0)
}
}
}
impl Drop for ArchiveMatch {
fn drop(&mut self) {
unsafe {
if !self.matcher.is_null() {
libarchive2_sys::archive_match_free(self.matcher);
}
}
}
}