diff --git a/src/archive.rs b/src/archive.rs index a3ae6f01..68db456d 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -120,7 +120,18 @@ impl Archive { /// ``` pub fn unpack>(&mut self, dst: P) -> io::Result<()> { let me: &mut Archive = self; - me._unpack(dst.as_ref()) + me._unpack(dst.as_ref(), |_| {}) + } + + /// Same as [`unpack`][Self::unpack], but allows mapping entries during the + /// iteration. + pub fn unpack_mapped>( + &mut self, + dst: P, + map_entry: impl Fn(&mut Entry), + ) -> io::Result<()> { + let me: &mut Archive = self; + me._unpack(dst.as_ref(), map_entry) } /// Set the mask of the permission bits when unpacking this entry. @@ -226,7 +237,7 @@ impl Archive { }) } - fn _unpack(&mut self, dst: &Path) -> io::Result<()> { + fn _unpack(&mut self, dst: &Path, map_entry: impl Fn(&mut Entry)) -> io::Result<()> { if dst.symlink_metadata().is_err() { fs::create_dir_all(dst) .map_err(|e| TarError::new(format!("failed to create `{}`", dst.display()), e))?; @@ -245,6 +256,11 @@ impl Archive { let mut directories = Vec::new(); for entry in self._entries(None)? { let mut file = entry.map_err(|e| TarError::new("failed to iterate over archive", e))?; + + // Map the entry if needed (e.g. to map its path). + // In most cases, this will be a no-op. + map_entry(&mut file); + if file.header().entry_type() == crate::EntryType::Directory { directories.push(file); } else { diff --git a/src/entry.rs b/src/entry.rs index fbc2efb9..3a90fadd 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -88,6 +88,14 @@ impl<'a, R: Read> Entry<'a, R> { self.fields.path_bytes() } + /// Sets the raw bytes listed for this entry. + /// + /// Subsequent calls to [`path_bytes`][Self::path_bytes] will return the + /// provided value. + pub fn set_path_bytes(&mut self, path_bytes: Vec) { + self.fields.long_pathname = Some(path_bytes); + } + /// Returns the link name for this entry, if any is found. /// /// This method may fail if the pathname is not valid Unicode and this is