forked from josch/mmdebstrap
111 lines
3.9 KiB
Bash
111 lines
3.9 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
export LC_ALL=C.UTF-8
|
|
|
|
trap "rm -f /tmp/mkpaxtar.pl /tmp/orig.tar /tmp/file /tmp/expected /tmp/filtered.tar" EXIT INT TERM
|
|
|
|
cat <<'END' >/tmp/mkpaxtar.pl
|
|
#!/usr/bin/env perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
my @entries = (
|
|
# filename mode type content
|
|
['./PaxHeaders/file', oct(644), 'x', "57 SCHILY.xattr.security.capability=\x01\0\0\x02\0\x20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a"],
|
|
['./file', oct(644), 0, 'test'],
|
|
);
|
|
|
|
my $num_entries = 0;
|
|
|
|
foreach my $file (@entries) {
|
|
my ($fname, $mode, $type, $content) = @{$file};
|
|
my $entry = pack(
|
|
'a100 a8 a8 a8 a12 a12 A8 a1 a100 a6 a2 a32 a32 a8 a8 a155 x12',
|
|
$fname,
|
|
sprintf('%07o', $mode),
|
|
sprintf('%07o', 0), # uid
|
|
sprintf('%07o', 0), # gid
|
|
sprintf('%011o', length $content), # size
|
|
sprintf('%011o', 0), # mtime
|
|
'', # checksum
|
|
$type,
|
|
'', # linkname
|
|
"ustar", # magic
|
|
"00", # version
|
|
'', # username
|
|
'', # groupname
|
|
'', # dev major
|
|
'', # dev minor
|
|
'', # prefix
|
|
);
|
|
|
|
# compute and insert checksum
|
|
substr($entry, 148, 7)
|
|
= sprintf("%06o\0", unpack("%16C*", $entry));
|
|
print $entry;
|
|
$num_entries += 1;
|
|
|
|
if (length $content) {
|
|
print(pack 'a512', $content);
|
|
$num_entries += 1;
|
|
}
|
|
}
|
|
|
|
# https://www.gnu.org/software/tar/manual/html_node/Standard.html
|
|
#
|
|
# Physically, an archive consists of a series of file entries terminated by an
|
|
# end-of-archive entry, which consists of two 512 blocks of zero bytes. At the
|
|
# end of the archive file there are two 512-byte blocks filled with binary
|
|
# zeros as an end-of-file marker.
|
|
|
|
print(pack 'a512', '');
|
|
print(pack 'a512', '');
|
|
$num_entries += 2;
|
|
|
|
# https://www.gnu.org/software/tar/manual/html_section/tar_76.html
|
|
#
|
|
# Some devices requires that all write operations be a multiple of a certain
|
|
# size, and so, tar pads the archive out to the next record boundary.
|
|
#
|
|
# The default blocking factor is 20. With a block size of 512 bytes, we get a
|
|
# record size of 10240.
|
|
|
|
for (my $i = $num_entries ; $i < 20 ; $i++) {
|
|
print(pack 'a512', '');
|
|
}
|
|
END
|
|
|
|
MMTARFILTER=
|
|
[ -x /usr/bin/mmtarfilter ] && MMTARFILTER=/usr/bin/mmtarfilter
|
|
[ -x ./tarfilter ] && MMTARFILTER=./tarfilter
|
|
|
|
perl /tmp/mkpaxtar.pl | "$MMTARFILTER" >/tmp/orig.tar
|
|
# make sure that xattrs are set in the original tarball
|
|
tar --xattrs --xattrs-include='*' --directory /tmp/ -xf /tmp/orig.tar ./file
|
|
echo "/tmp/file cap_net_raw=ep" >/tmp/expected
|
|
getcap /tmp/file | diff -u /tmp/expected - >&2
|
|
# make sure that the file content is as expected
|
|
printf test | diff -u /tmp/file - >&2
|
|
# make sure that uid/gid are as expected in the original tarball
|
|
echo "0 0 644" >/tmp/expected
|
|
stat --format="%u %g %a" /tmp/file | diff -u /tmp/expected - >&2
|
|
rm /tmp/file
|
|
# tarball must be bit by-bit-identical after round-trip
|
|
"$MMTARFILTER" --idshift 0 </tmp/orig.tar >/tmp/filtered.tar
|
|
cmp /tmp/orig.tar /tmp/filtered.tar
|
|
|
|
# now shift uid/gid
|
|
"$MMTARFILTER" --idshift 100000 </tmp/orig.tar >/tmp/filtered.tar
|
|
# make sure that uid/gid are as expected in the filtered tarball
|
|
tar --xattrs --xattrs-include='*' --directory /tmp/ -xf /tmp/filtered.tar ./file
|
|
echo "100000 100000 644" >/tmp/expected
|
|
stat --format="%u %g %a" /tmp/file | diff -u /tmp/expected - >&2
|
|
rm /tmp/file
|
|
|
|
# now shift uid/gid back to create a round-trip
|
|
"$MMTARFILTER" --idshift -100000 </tmp/filtered.tar >/tmp/filtered2.tar
|
|
|
|
# the result must be identical to the original and will thus also include the
|
|
# correct xattr information
|
|
cmp /tmp/orig.tar /tmp/filtered2.tar
|