]> git.proxmox.com Git - pxar.git/commitdiff
pxarcmd example: implement 'cat'
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 19 Feb 2020 15:10:18 +0000 (16:10 +0100)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 19 Feb 2020 15:31:23 +0000 (16:31 +0100)
and fix FileContentImpl offsets

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
examples/pxarcmd.rs
src/accessor.rs
src/decoder.rs
src/lib.rs

index 8539aff48cd8c52255ea9f6218c44ce499bea2cb..4e0c5ac3ad4583f02ff501c3d132c24de980839f 100644 (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);
         }
     }
 
index ec236566b2901e0dd14b23a6263d435cbd4442e0..a543b4f9ab1bbb8d401eb1e8a31ac48075a29c11 100644 (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
     }
 }
 
index b7f143ec7568b6bb083c4bc047e1d6c87b392d7b..5570b34fb3ef30c68b405595b787879aa6e83ce7 100644 (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);
index 24b49551d248791c9f2d1058cc58187a92055cec..cac7b45b454501a7550a83cb5c0fda1c9882c212 100644 (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 {