summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <andreas.gruenbacher@gmail.com>2024-02-11 13:13:24 +0100
committerAndreas Gruenbacher <andreas.gruenbacher@gmail.com>2024-02-12 00:15:15 +0100
commit802b5827e320a89dc15fbd1d4caf8f6ce22c443a (patch)
treebeffac131578c56376562c383216e7ea98149634
parent88c38ad4e27eacdd7888ecc16c45958226726a5b (diff)
downloadquilt-tar-wrapper-experiment.tar.gz
tar-wrapper experimenttar-wrapper-experiment
This is an attempt to create a better tar-wrapper that can be run in %prep context in a scratch directory, and create a copy of the extracted files in QUILT_WORKDIR. Try out as follows: $ cd experiment $ export QUILT_WORKDIR=work $ mkdir work $ PATH=.:$PATH $ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.4.tar.xz $ tar -xaf linux-6.7.4.tar.xz # this creates linux-6.7.4/ and work/linux-6.7.4/ $ tar -xaf linux-6.7.4.tar.xz # when run again: Refusing to overwrite linux-6.7.4
l---------experiment/tar1
-rwxr-xr-xexperiment/tar-wrapper215
2 files changed, 216 insertions, 0 deletions
diff --git a/experiment/tar b/experiment/tar
new file mode 120000
index 0000000..cfd1adf
--- /dev/null
+++ b/experiment/tar
@@ -0,0 +1 @@
+tar-wrapper \ No newline at end of file
diff --git a/experiment/tar-wrapper b/experiment/tar-wrapper
new file mode 100755
index 0000000..0730203
--- /dev/null
+++ b/experiment/tar-wrapper
@@ -0,0 +1,215 @@
+#! /bin/bash
+
+# Recognizes tar archive extraction using the options listed below. Any other
+# operations or options will cause the tar command to be executed directly,
+# with no special processing.
+
+declare -r short_opts=ajJvxzZ
+declare -r short_opts_arg=CfI
+declare -r -A long_opts=(
+ [--auto-compress]=1 [--bzip2]=1 [--compress]=1 [--extract]=1 [--file]=1
+ [--get]=1 [--gunzip]=1 [--gzip]=1 [--lzip]=1 [--lzma]=1 [--lzop]=1
+ [--no-auto-compress]=1 [--uncompress]=1 [--ungzip]=1 [--verbose]=1
+ [--xz]=1 [--zstd]=1
+)
+declare -r -A long_opts_arg=(
+ [--use-compress-program]=1
+)
+
+command=${0##*/}
+original_args=("$@")
+args=()
+
+opt_extract=
+opt_directory=
+opt_file=
+
+PATH=${PATH#*:}
+
+traditional_to_unix() {
+ local opts=$1 args=()
+ shift
+
+ [[ "$opts" =~ ^[Acdrtux] ]] || return
+
+ while [ -n "$opts" ]; do
+ args+=("-${opts:0:1}")
+ if [[ "$opts" =~ ^[$short_opts_arg] ]]; then
+ [ $# -ge 1 ] || return 1
+ args+=("$1")
+ shift
+ else
+ [[ "$opts" =~ ^[$short_opts] ]] || return
+ fi
+ opts="${opts:1}"
+ done
+
+ printf "%q " "${args[@]}" "$@"
+}
+
+debug() {
+ echo "$@">&2
+}
+
+fallback() {
+ debug "falling back to $command"
+ exec "$command" "${original_args[@]}"
+}
+
+[ $# -gt 0 ] || fallback
+
+if ! [[ "$1" =~ ^- ]]; then
+ args=$(traditional_to_unix "$@") || fallback
+ set -- $args
+fi
+
+set_opt_file() {
+ [ -n "$1" ] || fallback
+ opt_file=$1
+}
+
+set_opt_directory() {
+ [ -n "$1" ] || fallback
+ opt_directory=$1
+}
+
+short_opt() {
+ debug option "$1"
+ case "$1" in
+ -x)
+ opt_extract=1
+ ;;
+ esac
+ args+=("$1")
+}
+
+short_opt_arg() {
+ debug option "$1" "$2"
+ case "$1" in
+ -C)
+ set_opt_directory "$2"
+ ;;
+ -f)
+ set_opt_file "$2"
+ ;;
+ *)
+ args+=("$1$2")
+ ;;
+ esac
+}
+
+long_opt() {
+ debug option "$1" "$2"
+ case "$1" in
+ --extract|--get)
+ opt_extract=1
+ ;;
+ esac
+ args+=("$1")
+}
+
+long_opt_arg() {
+ debug option "$1" "$2"
+ case "$1" in
+ --directory)
+ set_opt_directory "$2"
+ ;;
+ --file)
+ set_opt_file "$2"
+ ;;
+ *)
+ args+=("$1=$2")
+ ;;
+ esac
+}
+
+while [ $# -gt 0 ]; do
+ if [[ "$1" =~ ^-- ]]; then
+ [ "$1" != -- ] || break
+ if [[ "$1" =~ ^(--.*)=(.*) ]]; then
+ [ -n "${long_opts_arg[${BASH_REMATCH[1]}]}" ] || fallback
+ long_opt_arg "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
+ shift
+ elif [ -n "${long_opts_arg[$1]}" ]; then
+ [ $# -ge 2 ] || fallback
+ long_opt_arg "$1" "$2"
+ shift 2
+ elif [ -n "${long_opts[$1]}" ]; then
+ long_opt "$1"
+ shift
+ else
+ fallback
+ fi
+ elif [[ "$1" =~ ^- ]]; then
+ [ "$1" != - ] || break
+ if [[ "$1" =~ ^(-[$short_opts])(.*) ]]; then
+ short_opt "${BASH_REMATCH[1]}"
+ shift
+ if [ -n "${BASH_REMATCH[2]}" ]; then
+ set -- "-${BASH_REMATCH[2]}" "$@"
+ fi
+ elif [[ "$1" =~ ^(-[$short_opts_arg])(.*) ]]; then
+ if [ -z "${BASH_REMATCH[2]}" ]; then
+ [ $# -ge 2 ] || fallback
+ short_opt_arg "${BASH_REMATCH[1]}" "$2"
+ shift 2
+ else
+ short_opt_arg "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
+ shift
+ fi
+ else
+ fallback
+ fi
+ else
+ break
+ fi
+done
+
+[ -n "$opt_extract" ] || fallback
+! [[ "/${opt_directory:-.}/" =~ /\.\./|^// ]] || fallback
+
+mkpath() {
+ if [ "$1" == . ]; then
+ echo "$2"
+ elif [ "$2" == . ]; then
+ echo "$1"
+ else
+ echo "$1/$2"
+ fi
+}
+
+if [ -n "$QUILT_WORKDIR" ]; then
+ cleanup() {
+ rm -rf "$tmpdir"
+ }
+
+ dir=${opt_directory:-.}
+ pattern=$(mkpath "$dir" ".$command.XXXXXX")
+ tmpdir=$(mktemp -d "$pattern" 2> /dev/null) || fallback
+ trap cleanup EXIT
+ opt_directory=$tmpdir
+fi
+
+[ -z "$opt_directory" ] || args+=("-C$opt_directory")
+[ -z "$opt_file" ] || args+=("-f$opt_file")
+
+args+=("$@")
+
+"$command" "${args[@]}" || exit
+
+if [ -n "$QUILT_WORKDIR" ]; then
+ workdir=$(mkpath "$QUILT_WORKDIR" "$dir")
+ shopt -s dotglob
+ files=( "$opt_directory"/* )
+ for file in "${files[@]##*/}"; do
+ if [ -e "$(mkpath "$dir" "$file")" -o \
+ -e "$(mkpath "$workdir" "$file")" ]; then
+ printf $"Refusing to overwrite %s\n" \
+ "$(mkpath "$dir" "$file")"
+ exit 1
+ fi
+ done
+ mkdir -p "$workdir" || exit
+ cp -dlR "${files[@]}" "$workdir/" || exit
+ mv "${files[@]}" "$dir/" || exit
+fi