]> git.proxmox.com Git - pxar.git/commitdiff
encoder: introduce LinkOffset
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 5 Jun 2020 11:17:02 +0000 (13:17 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 5 Jun 2020 11:17:03 +0000 (13:17 +0200)
To create hardlinks we need to reference the
in-archive-offset of the file we want to link to.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
src/encoder/aio.rs
src/encoder/mod.rs
src/encoder/sync.rs

index 1df75791f87bfafa8b383958598ebad7d778f2a1..5a337d24a9fa16ba388156377491b16bd72fb0b6 100644 (file)
@@ -5,7 +5,7 @@ use std::path::Path;
 use std::pin::Pin;
 use std::task::{Context, Poll};
 
-use crate::encoder::{self, SeqWrite};
+use crate::encoder::{self, SeqWrite, LinkOffset};
 use crate::format;
 use crate::Metadata;
 
@@ -138,7 +138,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         metadata: &Metadata,
         file_name: PF,
         target: PT,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         self.inner
             .add_symlink(metadata, file_name.as_ref(), target.as_ref())
             .await
@@ -149,7 +149,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         &mut self,
         file_name: PF,
         target: PT,
-        offset: u64,
+        offset: LinkOffset,
     ) -> io::Result<()> {
         self.inner
             .add_hardlink(file_name.as_ref(), target.as_ref(), offset)
@@ -162,7 +162,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         metadata: &Metadata,
         file_name: P,
         device: format::Device,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         self.inner
             .add_device(metadata, file_name.as_ref(), device)
             .await
@@ -173,7 +173,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         &mut self,
         metadata: &Metadata,
         file_name: P,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         self.inner.add_fifo(metadata, file_name.as_ref()).await
     }
 
@@ -182,7 +182,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         &mut self,
         metadata: &Metadata,
         file_name: P,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         self.inner.add_socket(metadata, file_name.as_ref()).await
     }
 }
@@ -192,6 +192,23 @@ pub struct File<'a> {
     inner: encoder::FileImpl<'a>,
 }
 
+impl<'a> File<'a> {
+    /// Get the file offset to be able to reference it with `add_hardlink`.
+    pub fn file_offset(&self) -> LinkOffset {
+        self.inner.file_offset()
+    }
+
+    /// Write file data for the current file entry in a pxar archive.
+    pub async fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        self.inner.write(data).await
+    }
+
+    /// Completely write file data for the current file entry in a pxar archive.
+    pub async fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
+        self.inner.write_all(data).await
+    }
+}
+
 #[cfg(feature = "futures-io")]
 impl<'a> futures::io::AsyncWrite for File<'a> {
     fn poll_write(self: Pin<&mut Self>, cx: &mut Context, data: &[u8]) -> Poll<io::Result<usize>> {
index 20ba1ee7f11d95d2101345f2cbd6ead42a69d104..79f6db54fd089fca0158add87b47f1951efc8309 100644 (file)
@@ -23,6 +23,17 @@ pub mod sync;
 #[doc(inline)]
 pub use sync::Encoder;
 
+/// File reference used to create hard links.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub struct LinkOffset(u64);
+
+impl LinkOffset {
+    #[inline]
+    pub fn raw(self) -> u64 {
+        self.0
+    }
+}
+
 /// Sequential write interface used by the encoder's state machine.
 ///
 /// This is our internal writer trait which is available for `std::io::Write` types in the
@@ -310,13 +321,14 @@ impl<'a, T: SeqWrite + 'a> EncoderImpl<'a, T> {
         })
     }
 
+    /// Return a file offset usable with `add_hardlink`.
     pub async fn add_file(
         &mut self,
         metadata: &Metadata,
         file_name: &Path,
         file_size: u64,
         content: &mut dyn SeqRead,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         let mut file = self.create_file(metadata, file_name, file_size).await?;
         let mut buf = crate::util::vec_new(4096);
         loop {
@@ -327,15 +339,16 @@ impl<'a, T: SeqWrite + 'a> EncoderImpl<'a, T> {
                 file.write_all(&buf[..got]).await?;
             }
         }
-        Ok(())
+        Ok(file.file_offset())
     }
 
+    /// Return a file offset usable with `add_hardlink`.
     pub async fn add_symlink(
         &mut self,
         metadata: &Metadata,
         file_name: &Path,
         target: &Path,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         self.add_file_entry(
             Some(metadata),
             file_name,
@@ -344,14 +357,15 @@ impl<'a, T: SeqWrite + 'a> EncoderImpl<'a, T> {
         .await
     }
 
+    /// Return a file offset usable with `add_hardlink`.
     pub async fn add_hardlink(
         &mut self,
         file_name: &Path,
         target: &Path,
-        offset: u64,
+        offset: LinkOffset,
     ) -> io::Result<()> {
         let hardlink = format::Hardlink {
-            offset,
+            offset: offset.0,
             data: target.as_os_str().as_bytes().to_vec(),
         };
         let hardlink = unsafe {
@@ -360,20 +374,22 @@ impl<'a, T: SeqWrite + 'a> EncoderImpl<'a, T> {
                 size_of::<format::Hardlink>(),
             )
         };
-        self.add_file_entry(
+        let _this_offset: LinkOffset = self.add_file_entry(
             None,
             file_name,
             Some((format::PXAR_HARDLINK, hardlink)),
         )
-        .await
+        .await?;
+        Ok(())
     }
 
+    /// Return a file offset usable with `add_hardlink`.
     pub async fn add_device(
         &mut self,
         metadata: &Metadata,
         file_name: &Path,
         device: format::Device,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         if !metadata.is_device() {
             io_bail!("entry added via add_device must have a device mode in its metadata");
         }
@@ -393,7 +409,8 @@ impl<'a, T: SeqWrite + 'a> EncoderImpl<'a, T> {
         .await
     }
 
-    pub async fn add_fifo(&mut self, metadata: &Metadata, file_name: &Path) -> io::Result<()> {
+    /// Return a file offset usable with `add_hardlink`.
+    pub async fn add_fifo(&mut self, metadata: &Metadata, file_name: &Path) -> io::Result<LinkOffset> {
         if !metadata.is_fifo() {
             io_bail!("entry added via add_device must be of type fifo in its metadata");
         }
@@ -401,7 +418,8 @@ impl<'a, T: SeqWrite + 'a> EncoderImpl<'a, T> {
         self.add_file_entry(Some(metadata), file_name, None).await
     }
 
-    pub async fn add_socket(&mut self, metadata: &Metadata, file_name: &Path) -> io::Result<()> {
+    /// Return a file offset usable with `add_hardlink`.
+    pub async fn add_socket(&mut self, metadata: &Metadata, file_name: &Path) -> io::Result<LinkOffset> {
         if !metadata.is_socket() {
             io_bail!("entry added via add_device must be of type socket in its metadata");
         }
@@ -409,12 +427,13 @@ impl<'a, T: SeqWrite + 'a> EncoderImpl<'a, T> {
         self.add_file_entry(Some(metadata), file_name, None).await
     }
 
+    /// Return a file offset usable with `add_hardlink`.
     async fn add_file_entry(
         &mut self,
         metadata: Option<&Metadata>,
         file_name: &Path,
         entry_htype_data: Option<(u64, &[u8])>,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         self.check()?;
 
         let file_offset = seq_write_position(&mut self.output).await?;
@@ -434,7 +453,7 @@ impl<'a, T: SeqWrite + 'a> EncoderImpl<'a, T> {
             size: end_offset - file_offset,
         });
 
-        Ok(())
+        Ok(LinkOffset(file_offset))
     }
 
     /// Helper
@@ -673,6 +692,11 @@ impl<'a> Drop for FileImpl<'a> {
 }
 
 impl<'a> FileImpl<'a> {
+    /// Get the file offset to be able to reference it with `add_hardlink`.
+    pub fn file_offset(&self) -> LinkOffset {
+        LinkOffset(self.goodbye_item.offset)
+    }
+
     fn check_remaining(&self, size: usize) -> io::Result<()> {
         if size as u64 > self.remaining_size {
             io_bail!("attempted to write more than previously allocated");
index c50087715f4806bdbffab38c87cf47758a015b4d..d32d8f62b5aa1c0949f96ee3a87a8d5322d64a18 100644 (file)
@@ -6,7 +6,7 @@ use std::pin::Pin;
 use std::task::{Context, Poll};
 
 use crate::decoder::sync::StandardReader;
-use crate::encoder::{self, SeqWrite};
+use crate::encoder::{self, SeqWrite, LinkOffset};
 use crate::format;
 use crate::util::poll_result_once;
 use crate::Metadata;
@@ -84,7 +84,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         file_name: P,
         file_size: u64,
         content: &mut dyn io::Read,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         poll_result_once(self.inner.add_file(
             metadata,
             file_name.as_ref(),
@@ -119,7 +119,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         metadata: &Metadata,
         file_name: PF,
         target: PT,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         poll_result_once(
             self.inner
                 .add_symlink(metadata, file_name.as_ref(), target.as_ref()),
@@ -131,7 +131,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         &mut self,
         file_name: PF,
         target: PT,
-        offset: u64,
+        offset: LinkOffset,
     ) -> io::Result<()> {
         poll_result_once(self.inner.add_hardlink(file_name.as_ref(), target.as_ref(), offset))
     }
@@ -142,7 +142,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         metadata: &Metadata,
         file_name: P,
         device: format::Device,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         poll_result_once(self.inner.add_device(metadata, file_name.as_ref(), device))
     }
 
@@ -151,7 +151,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         &mut self,
         metadata: &Metadata,
         file_name: P,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         poll_result_once(self.inner.add_fifo(metadata, file_name.as_ref()))
     }
 
@@ -160,7 +160,7 @@ impl<'a, T: SeqWrite + 'a> Encoder<'a, T> {
         &mut self,
         metadata: &Metadata,
         file_name: P,
-    ) -> io::Result<()> {
+    ) -> io::Result<LinkOffset> {
         poll_result_once(self.inner.add_socket(metadata, file_name.as_ref()))
     }
 }
@@ -170,6 +170,13 @@ pub struct File<'a> {
     inner: encoder::FileImpl<'a>,
 }
 
+impl<'a> File<'a> {
+    /// Get the file offset to be able to reference it with `add_hardlink`.
+    pub fn file_offset(&self) -> LinkOffset {
+        self.inner.file_offset()
+    }
+}
+
 impl<'a> io::Write for File<'a> {
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         poll_result_once(self.inner.write(data))