Skip to content

Commit

Permalink
Fix handling contents added after header creation
Browse files Browse the repository at this point in the history
Addresses #282.

Signed-off-by: Grant Elbert <grant.elbert@smartthings.com>
  • Loading branch information
elbe0046 committed Mar 3, 2022
1 parent c3e2cb8 commit 6942937
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 5 deletions.
13 changes: 9 additions & 4 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ impl<W: Write> Builder<W> {
/// header will be modified.
///
/// Then it will append the header, followed by contents of the stream
/// specified by `data`. To produce a valid archive the `size` field of
/// `header` must be the same as the length of the stream that's being
/// specified by `data`, with the `size` field of `header` enforced as an
/// upper limit. To produce a valid archive the `size` field of `header`
/// must be less than or equal to the length of the stream that's being
/// written.
///
/// Note that this will not attempt to seek the archive to a valid position,
Expand Down Expand Up @@ -406,9 +407,13 @@ impl<W: Write> Builder<W> {
}
}

fn append(mut dst: &mut dyn Write, header: &Header, mut data: &mut dyn Read) -> io::Result<()> {
fn append(mut dst: &mut dyn Write, header: &Header, data: &mut dyn Read) -> io::Result<()> {
dst.write_all(header.as_bytes())?;
let len = io::copy(&mut data, &mut dst)?;
// Guards against there being more data than the header indicates in the case where contents
// have been appended to the file since the header was created.
let size = header.size()?;
let mut limited = data.take(size);
let len = io::copy(&mut limited, &mut dst)?;

// Pad with zeros if necessary.
let buf = [0; 512];
Expand Down
32 changes: 31 additions & 1 deletion tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1279,10 +1279,12 @@ fn append_long_multibyte() {
let mut x = tar::Builder::new(Vec::new());
let mut name = String::new();
let data: &[u8] = &[];
let mut header = Header::new_gnu();
header.set_size(data.len() as u64);
for _ in 0..512 {
name.push('a');
name.push('𑢮');
x.append_data(&mut Header::new_gnu(), &name, data).unwrap();
x.append_data(&mut header, &name, data).unwrap();
name.pop();
}
}
Expand Down Expand Up @@ -1439,3 +1441,31 @@ fn ownership_preserving() {
assert!(ar.unpack(td.path()).is_err());
}
}

#[test]
fn file_contents_appended_after_header_creation() {
let mut data = String::from("Hello");

let mut header = Header::new_gnu();
header.set_size(data.len() as u64);
header.set_cksum();

// Additional data is appended after header creation
data.push_str(", World!");

let mut ar = Builder::new(Vec::new());
t!(ar.append_data(&mut header, "test2", data.as_bytes()));

let raw = t!(ar.into_inner());
let mut ar = Archive::new(Cursor::new(raw));
let mut entries = t!(ar.entries());
let entry = t!(entries.next().unwrap());
let offset = entry.raw_file_position();
let mut raw = ar.into_inner();

let mut s = String::new();
raw.set_position(offset);
t!(raw.read_to_string(&mut s));
let s = s.trim_end_matches(char::from(0));
assert_eq!(s, "Hello");
}

0 comments on commit 6942937

Please sign in to comment.