git-wad

Manage files via git but not their content
git clone git://git.meso-star.fr/git-wad.git
Log | Files | Refs | README | LICENSE

commit 4ba9f0473ec4eff6f71257fc0535c0a76192c3c1
parent 527ab995e78d293eeb381b8a266432d9b25d5091
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Sun, 12 Jan 2025 15:28:47 +0100

Improves checksum portability

sha256sum is no longer a prerequisite: in its absence, git-wad tries to
use shasum and, failing that, sha256. sha256sum is present by default on
GNU/Linux, where shasum should be used on Darwin or DragonFly BSD, and
sha256 on OpenBSD, NetBSD or certain versions of FreeBSD. And so cover a
wide range of POSIX systems.

Diffstat:
MREADME.md | 2+-
Mgit-wad | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 70 insertions(+), 12 deletions(-)

diff --git a/README.md b/README.md @@ -8,7 +8,7 @@ Git filters used to manage files based on their digest. - POSIX shell - curl - rsync -- sha256sum +- sha256sum, shasum or sha256 - [mandoc](https://mandoc.bsd.lv) ## Installation diff --git a/git-wad b/git-wad @@ -35,6 +35,13 @@ fi # multi-byte encoding errors. alias sed__='LC_CTYPE=C sed' +if ! command -v sha256sum 1> /dev/null 2>&1 \ +&& ! command -v shasum 2> /dev/null \ +&& ! command -v sha256 2> /dev/null; then + >&2 printf 'No tool to process SHA256 checksum\n' + die +fi + # shellcheck disable=SC2310 working_tree="$(git rev-parse --show-toplevel)" || die "$?" git_wad_tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/git_wad_XXXXXX")" || die "$?" @@ -261,6 +268,40 @@ restore() # WAD file fi } +checksum() # [-c] +{ + if command -v sha256sum 1> /dev/null 2>&1; then + sha256sum "$@" + + elif command -v shasum 1> /dev/null 2>&1; then + shasum -a 256 "$@" + + elif command -v sha256 1> /dev/null 2>&1; then + sha256re='SHA256 (\([^)]\+\)) = \([0-9a-zA-Z]\{64\}\)$' + + # Calculate checksum + if [ "$#" -eq 1 ] || [ "$1" != "-c" ]; then + sha256 | sed__ "s/${sha256re}/\2 \1/" + + # Check checksum + else + shift 1 # Discard the -c option + + in="$(cat -)" + ref="$(echo "${in}" | cut -d' ' -f1)" + file="$(echo "${in}" | cut -d' ' -f3)" + + sum="$(sha256 "${file}" | sed__ "s/${sha256re}/\2 \1/")" + if [ "${ref}" = "${sum}" ]; then + printf '%s: OK\n' "${file}" + else + printf '%s: FAILED\n' "${file}" + return 1 + fi + fi + fi +} + ######################################################################## # Git filters (plumbing) ######################################################################## @@ -275,7 +316,7 @@ log() # str [, arg...] clean() # stdin { tmpclean="${git_wad_tmpdir}/tmpclean" - digest=$(cat - | tee "${tmpclean}" | sha256sum | cut -d' ' -f1) + digest=$(cat - | tee "${tmpclean}" | checksum | cut -d' ' -f1) size=$(wc -c < "${tmpclean}") # Copy all bytes that could correspond to a WAD header. Note that null @@ -424,16 +465,33 @@ fsck() wads="${git_wad_tmpdir}/wads" all_objects > "${wads}" - - xargs -I {} sh -c \ - "printf '%s %s/%s' \"{}\" \"${GIT_WAD_OBJDIR}\" \"{}\" \ - | sha256sum -c || { \ - if [ ! ${remove} -eq 0 ]; then \ - printf '\e[0;31mremove\e[0m %s\n' \"{}\"; \ - rm -f \"${GIT_WAD_OBJDIR}/{}\"; \ - fi - }" \ - < "${wads}" + n=$(wc -l "${wads}" | cut -d' ' -f1) + [ "${n}" -eq 0 ] && return # No WAD, i.e. nothing to do + + # Prepare checksum verification of WADs, i.e. list one line per file + # starting with the WAD's checksum (actually its name) followed by 2 + # spaces and its path. + sums="${git_wad_tmpdir}/sums" + xargs -I{} printf '%s %s/%s\n' "{}" "${GIT_WAD_OBJDIR}" "{}" \ + < "${wads}" > "${sums}" + + # Check WAD checksum. + # + # Redirect the error stream to standard output to ensure that messages + # are printed in the order in which they are sent. By using a pipe, + # the shell starts a new process for the tee command which, if it only + # processes normal messages, will intertwine with the error messages + # from the checksum command. + result="${git_wad_tmpdir}/result" + checksum -c < "${sums}" 2>&1 | tee "${result}" + + # Remove corrupted files + if [ ! "${remove}" -eq 0 ]; then + corrupted_wads="${git_wad_tmpdir}/corrupted_wads" + sed__ -n 's/^\(.\+\): FAILED$/\1/p' "${result}" > "${corrupted_wads}" + sed__ 's/^/remove /g' "${corrupted_wads}" + xargs -I{} rm -f "{}" < "${corrupted_wads}" + fi } # Restore the content of WAD files