5
0
mirror of git://git.proxmox.com/git/pxar.git synced 2025-01-08 01:17:40 +03:00

pxarcmd example: implement 'cat'

and fix FileContentImpl offsets

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-02-19 16:10:18 +01:00
parent dc4a2854c0
commit c76d3f980b
4 changed files with 35 additions and 38 deletions

View File

@ -1,3 +1,4 @@
use std::io::{self, Read, Write};
use std::os::unix::ffi::OsStrExt;
use std::sync::Arc;
@ -25,16 +26,27 @@ fn main() -> Result<(), Error> {
let mut accessor = Accessor::open(file)?;
let mut dir = accessor.open_root_ref()?;
let mut buf = Vec::new();
for file in args {
let entry = dir
.lookup(&file)?
.ok_or_else(|| format_err!("no such file in archive: {:?}", file))?;
if file.as_bytes().ends_with(b"/") {
for file in entry.enter_directory()?.read_dir() {
println!("{:?}", file?.file_name());
if cmd == "ls" {
if file.as_bytes().ends_with(b"/") {
for file in entry.enter_directory()?.read_dir() {
println!("{:?}", file?.file_name());
}
} else {
println!("{:?}", entry.metadata());
}
} else if cmd == "cat" {
buf.clear();
entry.contents()?.read_to_end(&mut buf)?;
io::stdout().write_all(&buf)?;
} else {
println!("{:?}", entry.metadata());
bail!("unknown command: {}", cmd);
}
}

View File

@ -272,11 +272,10 @@ impl<T: Clone + ReadAt> DirectoryImpl<T> {
}
async fn lookup_self(&self) -> io::Result<FileEntryImpl<T>> {
let (entry, decoder) = self.decode_one_entry(self.entry_range(), None).await?;
let (entry, _decoder) = self.decode_one_entry(self.entry_range(), None).await?;
Ok(FileEntryImpl {
input: self.input.clone(),
entry,
decoder: Some(decoder),
end_offset: self.end_offset(),
})
}
@ -400,7 +399,6 @@ impl<T: Clone + ReadAt> DirectoryImpl<T> {
pub struct FileEntryImpl<T: Clone + ReadAt> {
input: T,
entry: Entry,
decoder: Option<DecoderImpl<SeqReadAtAdapter<T>>>,
end_offset: u64,
}
@ -415,12 +413,14 @@ impl<T: Clone + ReadAt> FileEntryImpl<T> {
}
pub async fn contents(&self) -> io::Result<FileContentsImpl<T>> {
let offset = self
.entry
.offset
.ok_or_else(|| io_format_err!("cannot open file, reader provided no offset"))?;
match self.entry.kind {
EntryKind::File { size } => Ok(FileContentsImpl::new(
EntryKind::File { offset: None, .. } => {
io_bail!("cannot open file, reader provided no offset")
}
EntryKind::File {
size,
offset: Some(offset),
} => Ok(FileContentsImpl::new(
self.input.clone(),
offset..(offset + size),
)),
@ -494,16 +494,14 @@ impl<'a, T: Clone + ReadAt> DirEntryImpl<'a, T> {
pub async fn get_entry(&self) -> io::Result<FileEntryImpl<T>> {
let end_offset = self.entry_range.end;
let (entry, decoder) = self
let (entry, _decoder) = self
.dir
.decode_one_entry(self.entry_range.clone(), Some(&self.file_name))
.await?;
let decoder = if entry.is_dir() { Some(decoder) } else { None };
Ok(FileEntryImpl {
input: self.dir.input.clone(),
entry,
decoder,
end_offset,
})
}
@ -538,7 +536,9 @@ impl<T: Clone + ReadAt> FileContentsImpl<T> {
buf = &mut buf[..(remaining as usize)];
}
(&self.input as &dyn ReadAt).read_at(buf, offset).await
(&self.input as &dyn ReadAt)
.read_at(buf, self.range.start + offset)
.await
}
}

View File

@ -185,11 +185,7 @@ impl<T: SeqRead> DecoderImpl<T> {
Self::new_full(input, "/".into()).await
}
pub(crate) async fn new_full(mut input: T, path: PathBuf) -> io::Result<Self> {
let offset = (&mut input as &mut dyn SeqRead)
.position()
.await
.transpose()?;
pub(crate) async fn new_full(input: T, path: PathBuf) -> io::Result<Self> {
let this = DecoderImpl {
input,
current_header: unsafe { mem::zeroed() },
@ -197,7 +193,6 @@ impl<T: SeqRead> DecoderImpl<T> {
path,
kind: EntryKind::EndOfDirectory,
metadata: Metadata::default(),
offset,
},
path_lengths: Vec::new(),
state: State::Begin,
@ -239,11 +234,6 @@ impl<T: SeqRead> DecoderImpl<T> {
format::PXAR_GOODBYE => {
if self.with_goodbye_tables {
self.entry.kind = EntryKind::EndOfDirectory;
let offset = (&mut self.input as &mut dyn SeqRead)
.position()
.await
.transpose()?;
self.entry.offset = offset;
self.state = State::InPayload;
return Ok(Some(self.entry.take()));
}
@ -432,8 +422,13 @@ impl<T: SeqRead> DecoderImpl<T> {
return Ok(ItemResult::Entry);
}
format::PXAR_PAYLOAD => {
let offset = (&mut self.input as &mut dyn SeqRead)
.position()
.await
.transpose()?;
self.entry.kind = EntryKind::File {
size: self.current_header.content_size(),
offset,
};
self.state = State::InPayload;
return Ok(ItemResult::Entry);

View File

@ -80,7 +80,7 @@ pub enum EntryKind {
Device(format::Device),
/// Regular file.
File { size: u64 },
File { size: u64, offset: Option<u64> },
/// Directory entry. When iterating through an archive, the contents follow next.
Directory,
@ -97,7 +97,6 @@ pub struct Entry {
path: PathBuf,
metadata: Metadata,
kind: EntryKind,
offset: Option<u64>,
}
/// General accessors.
@ -106,7 +105,6 @@ impl Entry {
fn clear_data(&mut self) {
self.metadata = Metadata::default();
self.kind = EntryKind::EndOfDirectory;
self.offset = None;
}
fn internal_default() -> Self {
@ -114,7 +112,6 @@ impl Entry {
path: PathBuf::default(),
metadata: Metadata::default(),
kind: EntryKind::EndOfDirectory,
offset: None,
}
}
@ -124,13 +121,6 @@ impl Entry {
this
}
/// If the underlying I/O implementation supports seeking, this will be filled with the start
/// offset of this entry, allowing one to jump back to this entry later on.
#[inline]
pub fn offset(&self) -> Option<u64> {
self.offset
}
/// Get the full path of this file within the current pxar directory structure.
#[inline]
pub fn path(&self) -> &Path {