mmdebstrap/tests/tarfilter-idshift
2024-10-11 11:16:14 +02:00

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