768f9f80f6
When we generate the taballs off a local working copy of a VCS tree, the umask is the one that we enforce in out top-level Makefile. However, it is possible that a user manually tinkers in said working copy (e.g. to check an upstream bug fix, or regression). If the user umask is different from the one Buildroot enfirces, such tinkering can impact the mode bits of the files, even if their content is not modified. When we eventually need to create a tarball from said working copy, the VCS (e.g. git) will only be interested in checking whether the content of the files have changed before chcking them out, and will not look at, and restore/fix the mode bits. As a consequence, we may create non-reproducible archives. We fix that by enforcing the mode bits on the files before we create the tarball: we disable the write and execute bits, and only set the execute bit if the user execute bit is set. Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr> Cc: Vincent Fazio <vfazio@xes-inc.com> Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
102 lines
3.0 KiB
Bash
Executable File
102 lines
3.0 KiB
Bash
Executable File
# Generate a reproducible archive from the content of a directory
|
|
#
|
|
# $1 : input directory
|
|
# $2 : leading component in archive
|
|
# $3 : ISO8601 date: YYYY-MM-DDThh:mm:ssZZ
|
|
# $4 : output file
|
|
# $5... : globs of filenames to exclude from the archive, suitable for
|
|
# find's -path option, and relative to the input directory $1
|
|
#
|
|
# Notes :
|
|
# - the timestamp is internally rounded to the highest entire second
|
|
# less than or equal to the timestamp (i.e. any sub-second fractional
|
|
# part is ignored)
|
|
# - must not be called with CWD as, or below, the input directory
|
|
# - some temporary files are created in CWD, and removed at the end
|
|
#
|
|
# Example:
|
|
# $ find /path/to/temp/dir
|
|
# /path/to/temp/dir/
|
|
# /path/to/temp/dir/some-file
|
|
# /path/to/temp/dir/some-dir/
|
|
# /path/to/temp/dir/some-dir/some-other-file
|
|
#
|
|
# $ mk_tar_gz /path/to/some/dir \
|
|
# foo_bar-1.2.3 \
|
|
# 1970-01-01T00:00:00Z \
|
|
# /path/to/foo.tar.gz \
|
|
# '.git/*' '.svn/*'
|
|
#
|
|
# $ tar tzf /path/to/foo.tar.gz
|
|
# foo_bar-1.2.3/some-file
|
|
# foo_bar-1.2.3/some-dir/some-other-file
|
|
#
|
|
mk_tar_gz() {
|
|
local in_dir="${1}"
|
|
local base_dir="${2}"
|
|
local date="${3}"
|
|
local out="${4}"
|
|
shift 4
|
|
local glob tmp pax_options
|
|
local -a find_opts
|
|
|
|
for glob; do
|
|
find_opts+=( -or -path "./${glob#./}" )
|
|
done
|
|
|
|
# Drop sub-second precision to play nice with GNU tar's valid_timespec check
|
|
date="$(date -d "${date}" -u +%Y-%m-%dT%H:%M:%S+00:00)"
|
|
|
|
pax_options="delete=atime,delete=ctime,delete=mtime"
|
|
pax_options+=",exthdr.name=%d/PaxHeaders/%f,exthdr.mtime={${date}}"
|
|
|
|
tmp="$(mktemp --tmpdir="$(pwd)")"
|
|
pushd "${in_dir}" >/dev/null
|
|
|
|
# Enforce group/others mode bits
|
|
chmod -R go-wx+X .
|
|
|
|
# Establish list
|
|
find . -not -type d -and -not \( -false "${find_opts[@]}" \) >"${tmp}.list"
|
|
# Sort list for reproducibility
|
|
LC_ALL=C sort <"${tmp}.list" >"${tmp}.sorted"
|
|
|
|
# Create POSIX tarballs, since that's the format the most reproducible
|
|
tar cf - --transform="s#^\./#${base_dir}/#S" \
|
|
--numeric-owner --owner=0 --group=0 --mtime="${date}" \
|
|
--format=posix --pax-option="${pax_options}" \
|
|
-T "${tmp}.sorted" >"${tmp}.tar"
|
|
|
|
# Compress the archive
|
|
gzip -6 -n <"${tmp}.tar" >"${out}"
|
|
|
|
rm -f "${tmp}"{.list,.sorted,.tar}
|
|
|
|
popd >/dev/null
|
|
}
|
|
|
|
post_process_unpack() {
|
|
local dest="${1}"
|
|
local tarball="${2}"
|
|
local one_file
|
|
|
|
mkdir "${dest}"
|
|
tar -C "${dest}" --strip-components=1 -xzf "${tarball}"
|
|
one_file="$(find "${dest}" -type f -print0 |LC_ALL=C sort -z |sed 's/\x0.*//')"
|
|
touch -r "${one_file}" "${dest}.timestamp"
|
|
}
|
|
|
|
post_process_repack() {
|
|
local in_dir="${1}"
|
|
local base_dir="${2}"
|
|
local out="${3}"
|
|
local date
|
|
|
|
date="@$(stat -c '%Y' "${in_dir}/${base_dir}.timestamp")"
|
|
|
|
mk_tar_gz "${in_dir}/${base_dir}" "${base_dir}" "${date}" "${out}"
|
|
}
|
|
|
|
# Keep this line and the following as last lines in this file.
|
|
# vim: ft=bash
|