From bcf09e0dc98077966b340b44b6e1db904f4cbe7f Mon Sep 17 00:00:00 2001 From: Nikola Pajkovsky Date: Tue, 28 Mar 2023 17:33:15 +0200 Subject: [PATCH] header: set entry_size() to 0 for hardlinks Fix the error: "numeric field was not a number: t 'Regard' when getting cksum for 'a text ...'. The error is caused by wrongly setting the `self.next` position due to accounting harlinks size. According to man 5 tar, the size of the hard-links should be set to 0. size Size of file, as octal number in ASCII. For regular files only, this indicates the amount of data that follows the header. In particular, this field was ignored by early tar implementations when extracting hardlinks. Modern writers should always store a zero length for hardlink entries. But since the writer wasn't *modern*, the entry_size is 64700 which causes miscalculation of the `self.next`. [tar-rs/src/archive.rs:372] &entry.header() = UstarHeader { entry_size: 64700, size: 64700, path: "some/path", link_name: Some( "some/link", ), mode: 0o640, uid: 1058, gid: 1061, mtime: 1673424346, username: Some( "example", ), groupname: Some( "example", ), device_major: Some( 9, ), device_minor: Some( 2, ), cksum: 24700, cksum_valid: true, } [tar-rs/src/archive.rs:373] entry.header().entry_type() = Link Closes: #313 Signed-off-by: Nikola Pajkovsky --- src/header.rs | 3 +++ tests/header/mod.rs | 27 ++++++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/header.rs b/src/header.rs index 7e507fc7..c679ad5a 100644 --- a/src/header.rs +++ b/src/header.rs @@ -298,6 +298,9 @@ impl Header { /// /// May return an error if the field is corrupted. pub fn entry_size(&self) -> io::Result { + if self.entry_type().is_hard_link() { + return Ok(0); + } num_field_wrapper_from(&self.as_old().size).map_err(|err| { io::Error::new( err.kind(), diff --git a/tests/header/mod.rs b/tests/header/mod.rs index 86692e33..0acd48cd 100644 --- a/tests/header/mod.rs +++ b/tests/header/mod.rs @@ -1,12 +1,14 @@ -use std::fs::{self, File}; -use std::io::{self, Write}; -use std::path::Path; -use std::{iter, mem, thread, time}; - +use std::{ + fs::{self, File}, + io::{self, Write}, + iter, mem, + path::Path, + thread, time, +}; + +use tar::{EntryType, GnuHeader, Header, HeaderMode}; use tempfile::Builder; -use tar::{GnuHeader, Header, HeaderMode}; - #[test] fn default_gnu() { let mut h = Header::new_gnu(); @@ -244,3 +246,14 @@ fn byte_slice_conversion() { let b_conv: &[u8] = Header::from_byte_slice(h.as_bytes()).as_bytes(); assert_eq!(b, b_conv); } + +#[test] +fn hardlink_entry_size() { + let mut h = Header::new_ustar(); + let p = Path::new("a").join(&vec!["a"; 100].join("")); + h.set_entry_type(EntryType::Link); + t!(h.set_path(&p)); + t!(h.set_link_name("foo")); + h.set_size(200); + assert_eq!(t!(h.entry_size()), 0); +}