110 lines
2.9 KiB
Rust
110 lines
2.9 KiB
Rust
use super::WriteEntry;
|
|
use crate::error::ArchiveError;
|
|
use crate::Entry;
|
|
use crate::Handle;
|
|
use libarchive3_sys::ffi;
|
|
use std::fs;
|
|
use std::io;
|
|
use std::io::Read;
|
|
use std::path::Path;
|
|
|
|
pub struct FileWriter {
|
|
handle: *mut ffi::Struct_archive,
|
|
closed: bool,
|
|
}
|
|
|
|
impl Handle for FileWriter {
|
|
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 FileWriter {
|
|
pub fn new(handle: *mut ffi::Struct_archive) -> Self {
|
|
FileWriter {
|
|
handle,
|
|
closed: false,
|
|
}
|
|
}
|
|
|
|
pub fn append_data<R: Read>(&mut self, entry: &mut WriteEntry, r: &mut R) -> crate::Result<()> {
|
|
unsafe {
|
|
match ffi::archive_write_header(self.handle_mut(), entry.entry_mut()) {
|
|
ffi::ARCHIVE_OK => (),
|
|
_ => return Err(ArchiveError::from(self as &dyn Handle).into()),
|
|
}
|
|
}
|
|
|
|
let mut buf = [0; 4096];
|
|
|
|
loop {
|
|
match r.read(&mut buf) {
|
|
Ok(0) => return Ok(()),
|
|
// Write entire buffer
|
|
Ok(buf_len) => {
|
|
let mut written: usize = 0;
|
|
|
|
while written < buf_len {
|
|
let res = unsafe {
|
|
ffi::archive_write_data(
|
|
self.handle_mut(),
|
|
&buf[written] as *const u8 as *const _,
|
|
buf_len - written,
|
|
)
|
|
} as isize;
|
|
|
|
// Negative values signal errors
|
|
if res < 0 {
|
|
return Err(ArchiveError::from(self as &dyn Handle).into());
|
|
}
|
|
|
|
written += usize::try_from(res).unwrap();
|
|
}
|
|
}
|
|
Err(err) => match err.kind() {
|
|
io::ErrorKind::Interrupted => (),
|
|
_ => return Err(err.into()),
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
pub fn append_path<P: AsRef<Path>>(
|
|
&mut self,
|
|
entry: &mut WriteEntry,
|
|
path: P,
|
|
) -> crate::Result<()> {
|
|
let mut f = fs::File::open(path)?;
|
|
self.append_data(entry, &mut f)
|
|
}
|
|
|
|
pub fn close(&mut self) -> crate::Result<()> {
|
|
unsafe {
|
|
match ffi::archive_write_close(self.handle_mut()) {
|
|
ffi::ARCHIVE_OK => {
|
|
self.closed = true;
|
|
|
|
Ok(())
|
|
}
|
|
_ => Err(ArchiveError::from(self as &dyn Handle)),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for FileWriter {
|
|
fn drop(&mut self) {
|
|
if !self.closed {
|
|
let _ = self.close();
|
|
}
|
|
|
|
unsafe {
|
|
ffi::archive_write_free(self.handle_mut());
|
|
}
|
|
}
|
|
}
|