add option for writing an archive's entries with a prefix

This commit is contained in:
Jamie Winsor
2016-01-12 00:00:30 -08:00
parent a069bd2a98
commit 39b37933d7
3 changed files with 37 additions and 16 deletions
+11 -2
View File
@@ -1,9 +1,10 @@
use std::default::Default; use std::default::Default;
use std::ffi::{CStr, CString};
use std::path::PathBuf;
use std::str; use std::str;
use std::ffi::CStr;
use libarchive3_sys::ffi; use libarchive3_sys::ffi;
use error::ErrCode; use error::{ArchiveResult, ErrCode};
pub enum ReadCompression { pub enum ReadCompression {
All, All,
@@ -120,6 +121,14 @@ pub trait Entry {
fn size(&self) -> i64 { fn size(&self) -> i64 {
unsafe { ffi::archive_entry_size(self.entry()) } unsafe { ffi::archive_entry_size(self.entry()) }
} }
fn set_pathname(&mut self, path: PathBuf) -> ArchiveResult<()> {
unsafe {
let c_str = CString::new(path.to_str().unwrap()).unwrap();
ffi::archive_entry_set_pathname(self.entry(), c_str.as_ptr());
}
Ok(())
}
} }
pub enum ExtractOption { pub enum ExtractOption {
+17 -6
View File
@@ -94,14 +94,19 @@ impl Disk {
} }
// * Failures - HeaderPosition // * Failures - HeaderPosition
pub fn write<T: Reader>(&self, reader: &mut T) -> ArchiveResult<()> { pub fn write<T: Reader>(&self, reader: &mut T, prefix: Option<&str>) -> ArchiveResult<usize> {
if reader.header_position() != 0 { if reader.header_position() != 0 {
return Err(ArchiveError::HeaderPosition); return Err(ArchiveError::HeaderPosition);
} }
let mut bytes: usize = 0;
let mut write_pending: bool = false; let mut write_pending: bool = false;
loop { loop {
{ {
if let Some(entry) = reader.next_header() { if let Some(entry) = reader.next_header() {
if let Some(pfx) = prefix {
let path = Path::new(pfx).join(entry.pathname());
try!(entry.set_pathname(path));
}
match self.write_header(entry) { match self.write_header(entry) {
Ok(()) => (), Ok(()) => (),
Err(e) => return Err(e), Err(e) => return Err(e),
@@ -110,14 +115,20 @@ impl Disk {
write_pending = true write_pending = true
} }
} else { } else {
return Ok(()); break;
} }
} }
if write_pending { if write_pending {
try!(self.write_data(reader)); bytes += try!(self.write_data(reader));
write_pending = false; write_pending = false;
} }
} }
unsafe {
match ffi::archive_write_finish_entry(self.handle()) {
ffi::ARCHIVE_OK => Ok(bytes),
_ => Err(ArchiveError::from(self as &Handle)),
}
}
} }
pub fn close(&self) -> ArchiveResult<()> { pub fn close(&self) -> ArchiveResult<()> {
@@ -127,19 +138,19 @@ impl Disk {
ArchiveResult::from(self as &Handle) ArchiveResult::from(self as &Handle)
} }
fn write_data<T: Reader>(&self, reader: &T) -> ArchiveResult<()> { fn write_data<T: Reader>(&self, reader: &T) -> ArchiveResult<usize> {
let mut buff = ptr::null(); let mut buff = ptr::null();
let mut size = 0; let mut size = 0;
let mut offset = 0; let mut offset = 0;
unsafe { unsafe {
match ffi::archive_read_data_block(reader.handle(), &mut buff, &mut size, &mut offset) { match ffi::archive_read_data_block(reader.handle(), &mut buff, &mut size, &mut offset) {
ffi::ARCHIVE_EOF => Ok(()), ffi::ARCHIVE_EOF => Ok(size),
ffi::ARCHIVE_OK => { ffi::ARCHIVE_OK => {
if ffi::archive_write_data_block(self.handle, buff, size, offset) < 0 { if ffi::archive_write_data_block(self.handle, buff, size, offset) < 0 {
Err(ArchiveError::from(self as &Handle)) Err(ArchiveError::from(self as &Handle))
} else { } else {
Ok(()) Ok(size)
} }
} }
_ => Err(ArchiveError::from(reader as &Handle)), _ => Err(ArchiveError::from(reader as &Handle)),
+9 -8
View File
@@ -35,11 +35,12 @@ fn read_archive_from_stream() {
builder.support_filter(ReadFilter::All).ok(); builder.support_filter(ReadFilter::All).ok();
match builder.open_stream(f) { match builder.open_stream(f) {
Ok(mut reader) => { Ok(mut reader) => {
println!("{:?}", reader.header_position()); assert_eq!(reader.header_position(), 0);
let writer = writer::Disk::new(); let writer = writer::Disk::new();
writer.write(&mut reader).ok(); let count = writer.write(&mut reader, Some("/opt/bldr/fucks")).ok().unwrap();
println!("{:?}", reader.header_position()); assert_eq!(count, 14);
assert_eq!(4, 4) assert_eq!(reader.header_position(), 1024);
assert_eq!(4, 4);
}, },
Err(e) => { Err(e) => {
println!("{:?}", e); println!("{:?}", e);
@@ -56,7 +57,7 @@ fn extracting_from_file() {
let mut reader = builder.open_file(tar).ok().unwrap(); let mut reader = builder.open_file(tar).ok().unwrap();
println!("{:?}", reader.header_position()); println!("{:?}", reader.header_position());
let writer = writer::Disk::new(); let writer = writer::Disk::new();
writer.write(&mut reader).ok(); writer.write(&mut reader, None).ok();
println!("{:?}", reader.header_position()); println!("{:?}", reader.header_position());
assert_eq!(4, 4) assert_eq!(4, 4)
} }
@@ -73,7 +74,7 @@ fn extracting_an_archive_with_options() {
opts.add(archive::ExtractOption::Time); opts.add(archive::ExtractOption::Time);
let writer = writer::Disk::new(); let writer = writer::Disk::new();
writer.set_options(&opts).ok(); writer.set_options(&opts).ok();
writer.write(&mut reader).ok(); writer.write(&mut reader, None).ok();
println!("{:?}", reader.header_position()); println!("{:?}", reader.header_position());
assert_eq!(4, 4) assert_eq!(4, 4)
} }
@@ -87,9 +88,9 @@ fn extracting_a_reader_twice() {
let mut reader = builder.open_file(tar).ok().unwrap(); let mut reader = builder.open_file(tar).ok().unwrap();
println!("{:?}", reader.header_position()); println!("{:?}", reader.header_position());
let writer = writer::Disk::new(); let writer = writer::Disk::new();
writer.write(&mut reader).ok(); writer.write(&mut reader, None).ok();
println!("{:?}", reader.header_position()); println!("{:?}", reader.header_position());
match writer.write(&mut reader) { match writer.write(&mut reader, None) {
Ok(_) => println!("oops"), Ok(_) => println!("oops"),
Err(_) => println!("nice") Err(_) => println!("nice")
} }