feat: start forking libarchive, no biggy
This commit is contained in:
parent
51cda94c1a
commit
5743f4a3a5
9 changed files with 730 additions and 1 deletions
178
libarchive/src/read/builder.rs
Normal file
178
libarchive/src/read/builder.rs
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
use crate::archive::{Handle, ReadCompression, ReadFilter, ReadFormat};
|
||||
use libarchive3_sys::ffi;
|
||||
use crate::error::{ArchiveError, Result};
|
||||
use std::ffi::CString;
|
||||
use std::mem;
|
||||
use std::path::Path;
|
||||
use super::file::ArchiveFile;
|
||||
use crate::read::Archive;
|
||||
|
||||
/// A struct that allows configuration of the reader before it is created.
|
||||
pub struct Builder {
|
||||
handle: *mut ffi::Struct_archive,
|
||||
consumed: bool,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new() -> Self {
|
||||
Builder::default()
|
||||
}
|
||||
|
||||
/// Enable support for a given compression method.
|
||||
pub fn support_compression(&mut self, compression: ReadCompression) -> Result<()> {
|
||||
#[rustfmt::skip]
|
||||
let result = match compression {
|
||||
ReadCompression::All => unsafe { ffi::archive_read_support_compression_all(self.handle_mut()) },
|
||||
ReadCompression::Bzip2 => unsafe { ffi::archive_read_support_compression_bzip2(self.handle_mut()) },
|
||||
ReadCompression::Compress => unsafe { ffi::archive_read_support_compression_compress(self.handle_mut()) },
|
||||
ReadCompression::Gzip => unsafe { ffi::archive_read_support_compression_gzip(self.handle_mut()) },
|
||||
ReadCompression::Lzip => unsafe { ffi::archive_read_support_compression_lzip(self.handle_mut()) },
|
||||
ReadCompression::Lzma => unsafe { ffi::archive_read_support_compression_lzma(self.handle_mut()) },
|
||||
ReadCompression::None => unsafe { ffi::archive_read_support_compression_none(self.handle_mut()) },
|
||||
ReadCompression::Rpm => unsafe { ffi::archive_read_support_compression_rpm(self.handle_mut()) },
|
||||
ReadCompression::Uu => unsafe { ffi::archive_read_support_compression_uu(self.handle_mut()) },
|
||||
ReadCompression::Xz => unsafe { ffi::archive_read_support_compression_xz(self.handle_mut()) },
|
||||
ReadCompression::Program(prog) => {
|
||||
let c_prog = CString::new(prog).unwrap();
|
||||
unsafe {
|
||||
ffi::archive_read_support_compression_program(
|
||||
self.handle_mut(),
|
||||
c_prog.as_ptr(),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
match result {
|
||||
ffi::ARCHIVE_OK => Ok(()),
|
||||
_ => Result::from(self as &dyn Handle),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable support for a given filter
|
||||
pub fn support_filter(&mut self, filter: ReadFilter) -> Result<()> {
|
||||
#[rustfmt::skip]
|
||||
let result = match filter {
|
||||
ReadFilter::All => unsafe { ffi::archive_read_support_filter_all(self.handle_mut()) },
|
||||
ReadFilter::Bzip2 => unsafe { ffi::archive_read_support_filter_bzip2(self.handle_mut()) },
|
||||
ReadFilter::Compress => unsafe { ffi::archive_read_support_filter_compress(self.handle_mut()) },
|
||||
ReadFilter::Grzip => unsafe { ffi::archive_read_support_filter_grzip(self.handle_mut()) },
|
||||
ReadFilter::Gzip => unsafe { ffi::archive_read_support_filter_gzip(self.handle_mut()) },
|
||||
ReadFilter::Lrzip => unsafe { ffi::archive_read_support_filter_lrzip(self.handle_mut()) },
|
||||
ReadFilter::Lzip => unsafe { ffi::archive_read_support_filter_lzip(self.handle_mut()) },
|
||||
ReadFilter::Lzma => unsafe { ffi::archive_read_support_filter_lzma(self.handle_mut()) },
|
||||
ReadFilter::Lzop => unsafe { ffi::archive_read_support_filter_lzop(self.handle_mut()) },
|
||||
ReadFilter::None => unsafe { ffi::archive_read_support_filter_none(self.handle_mut()) },
|
||||
ReadFilter::Rpm => unsafe { ffi::archive_read_support_filter_rpm(self.handle_mut()) },
|
||||
ReadFilter::Uu => unsafe { ffi::archive_read_support_filter_uu(self.handle_mut()) },
|
||||
ReadFilter::Xz => unsafe { ffi::archive_read_support_filter_xz(self.handle_mut()) },
|
||||
ReadFilter::Program(prog) => {
|
||||
let c_prog = CString::new(prog).unwrap();
|
||||
unsafe {
|
||||
ffi::archive_read_support_filter_program(self.handle_mut(), c_prog.as_ptr())
|
||||
}
|
||||
}
|
||||
ReadFilter::ProgramSignature(prog, cb, size) => {
|
||||
let c_prog = CString::new(prog).unwrap();
|
||||
unsafe {
|
||||
ffi::archive_read_support_filter_program_signature(
|
||||
self.handle_mut(),
|
||||
c_prog.as_ptr(),
|
||||
mem::transmute(cb),
|
||||
size,
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
match result {
|
||||
ffi::ARCHIVE_OK => Ok(()),
|
||||
_ => Result::from(self as &dyn Handle),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable support for a given format.
|
||||
pub fn support_format(&mut self, format: ReadFormat) -> Result<()> {
|
||||
// SAFETY: Casting to *mut because these c functions take T* not const T*. They do not
|
||||
// modify the pointer, so this is sound.
|
||||
#[rustfmt::skip]
|
||||
let result = match format {
|
||||
ReadFormat::SevenZip => unsafe { ffi::archive_read_support_format_7zip(self.handle_mut()) },
|
||||
ReadFormat::All => unsafe { ffi::archive_read_support_format_all(self.handle_mut()) },
|
||||
ReadFormat::Ar => unsafe { ffi::archive_read_support_format_ar(self.handle_mut()) },
|
||||
ReadFormat::Cab => unsafe { ffi::archive_read_support_format_cab(self.handle_mut()) },
|
||||
ReadFormat::Cpio => unsafe { ffi::archive_read_support_format_cpio(self.handle_mut()) },
|
||||
ReadFormat::Empty => unsafe { ffi::archive_read_support_format_empty(self.handle_mut()) },
|
||||
ReadFormat::Gnutar => unsafe { ffi::archive_read_support_format_gnutar(self.handle_mut()) },
|
||||
ReadFormat::Iso9660 => unsafe { ffi::archive_read_support_format_iso9660(self.handle_mut()) },
|
||||
ReadFormat::Lha => unsafe { ffi::archive_read_support_format_lha(self.handle_mut()) },
|
||||
ReadFormat::Mtree => unsafe { ffi::archive_read_support_format_mtree(self.handle_mut()) },
|
||||
ReadFormat::Rar => unsafe { ffi::archive_read_support_format_rar(self.handle_mut()) },
|
||||
ReadFormat::Raw => unsafe { ffi::archive_read_support_format_raw(self.handle_mut()) },
|
||||
ReadFormat::Tar => unsafe { ffi::archive_read_support_format_tar(self.handle_mut()) },
|
||||
ReadFormat::Xar => unsafe { ffi::archive_read_support_format_xar(self.handle_mut()) },
|
||||
ReadFormat::Zip => unsafe { ffi::archive_read_support_format_zip(self.handle_mut()) },
|
||||
};
|
||||
match result {
|
||||
ffi::ARCHIVE_OK => Ok(()),
|
||||
_ => Result::from(self as &dyn Handle),
|
||||
}
|
||||
}
|
||||
|
||||
/// Open a file with this builder, consuming it and returning a `FileReader`
|
||||
pub fn open_file<T: AsRef<Path>>(self, file: T) -> Result<ArchiveFile> {
|
||||
self.check_consumed()?;
|
||||
ArchiveFile::open(self, file)
|
||||
}
|
||||
|
||||
/// Open a stream with this builder, consuming it and returning a `StreamReader`
|
||||
// pub fn open_stream<T: Any + Read>(self, src: T) -> Result<StreamReader> {
|
||||
// self.check_consumed()?;
|
||||
// StreamReader::open(self, src)
|
||||
// }
|
||||
|
||||
pub fn check_consumed(&self) -> Result<()> {
|
||||
if self.consumed {
|
||||
Err(ArchiveError::Consumed)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume(&mut self) {
|
||||
self.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Handle for Builder {
|
||||
unsafe fn handle(&self) -> *const ffi::Struct_archive {
|
||||
self.handle as *const _
|
||||
}
|
||||
|
||||
unsafe fn handle_mut(&mut self) -> *mut ffi::Struct_archive {
|
||||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Builder {
|
||||
fn drop(&mut self) {
|
||||
if !self.consumed {
|
||||
unsafe {
|
||||
ffi::archive_read_free(self.handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
fn default() -> Self {
|
||||
unsafe {
|
||||
let handle = ffi::archive_read_new();
|
||||
if handle.is_null() {
|
||||
panic!("Allocation error");
|
||||
}
|
||||
Builder {
|
||||
handle,
|
||||
consumed: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
54
libarchive/src/read/file.rs
Normal file
54
libarchive/src/read/file.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
use libarchive3_sys::ffi;
|
||||
use super::builder::Builder;
|
||||
use crate::read::{Handle, Archive};
|
||||
use std::ffi::CString;
|
||||
use std::path::Path;
|
||||
use crate::error::ArchiveError;
|
||||
|
||||
const BLOCK_SIZE: usize = 10240;
|
||||
|
||||
pub struct ArchiveFile {
|
||||
handle: *mut ffi::Struct_archive,
|
||||
// entry: ReaderEntry,
|
||||
}
|
||||
|
||||
impl Handle for ArchiveFile {
|
||||
unsafe fn handle(&self) -> *const ffi::Struct_archive {
|
||||
self.handle as *const _
|
||||
}
|
||||
|
||||
unsafe fn handle_mut(&mut self) -> *mut ffi::Struct_archive {
|
||||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ArchiveFile {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ffi::archive_read_free(self.handle_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Archive for ArchiveFile {
|
||||
fn new(handle: *mut ffi::Struct_archive) -> Self {
|
||||
Self {
|
||||
handle
|
||||
}
|
||||
}
|
||||
|
||||
fn open<P: AsRef<Path>>(mut builder: Builder, path: P) -> crate::Result<Self> {
|
||||
builder.check_consumed()?;
|
||||
let c_file = CString::new(path.as_ref().to_string_lossy().as_bytes()).unwrap();
|
||||
unsafe {
|
||||
match ffi::archive_read_open_filename(builder.handle_mut(), c_file.as_ptr(), BLOCK_SIZE)
|
||||
{
|
||||
ffi::ARCHIVE_OK => {
|
||||
builder.consume();
|
||||
Ok(Self::new(builder.handle_mut()))
|
||||
}
|
||||
_ => Err(ArchiveError::from(&builder as &dyn Handle)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
libarchive/src/read/mod.rs
Normal file
15
libarchive/src/read/mod.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
mod builder;
|
||||
mod file;
|
||||
|
||||
use crate::archive::Handle;
|
||||
use builder::Builder;
|
||||
use std::path::Path;
|
||||
use libarchive3_sys::ffi;
|
||||
|
||||
// Represents a read view of an archive
|
||||
pub trait Archive: Handle + Sized {
|
||||
fn new(handle: *mut ffi::Struct_archive) -> Self;
|
||||
|
||||
fn open<P: AsRef<Path>>(builder: Builder, path: P) -> crate::Result<Self>;
|
||||
// entries
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue