You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-09-12 18:50:20 -07:00
Move gitapply.sh into patches/, remove unused Makefile.in file.
This commit is contained in:
473
patches/gitapply.sh
Executable file
473
patches/gitapply.sh
Executable file
@@ -0,0 +1,473 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Wrapper to apply binary patches without git.
|
||||
#
|
||||
# Copyright (C) 2014-2015 Sebastian Lackner
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
#
|
||||
|
||||
nogit=0
|
||||
tmpfile=""
|
||||
|
||||
# Show usage information about gitapply script
|
||||
usage()
|
||||
{
|
||||
echo ""
|
||||
echo "Usage: ./gitapply.sh [--nogit] [-d DIRECTORY]"
|
||||
echo ""
|
||||
echo "Reads patch data from stdin and applies the patch to the current"
|
||||
echo "directory or the directory given via commandline."
|
||||
echo ""
|
||||
echo "The patch file can contain both unified text patches as well as"
|
||||
echo "git binary patches."
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Critical error, abort
|
||||
abort()
|
||||
{
|
||||
if [ ! -z "$tmpfile" ]; then
|
||||
rm "$tmpfile"
|
||||
tmpfile=""
|
||||
fi
|
||||
echo "[PATCH] ERR: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Show a warning
|
||||
warning()
|
||||
{
|
||||
echo "[PATCH] WRN: $1" >&2
|
||||
}
|
||||
|
||||
# Calculate git sha1 hash
|
||||
gitsha1()
|
||||
{
|
||||
if [ -f "$1" ]; then
|
||||
echo -en "blob $(du -b "$1" | cut -f1)\x00" | cat - "$1" | sha1sum | cut -d' ' -f1
|
||||
else
|
||||
echo "0000000000000000000000000000000000000000"
|
||||
fi
|
||||
}
|
||||
|
||||
# Determine size of a file (or zero, if it doesn't exist)
|
||||
filesize()
|
||||
{
|
||||
local size=$(du -b "$1" | cut -f1)
|
||||
if [ -z "$size" ]; then
|
||||
size="0"
|
||||
fi
|
||||
echo "$size"
|
||||
}
|
||||
|
||||
|
||||
# Parse environment variables
|
||||
while [ "$#" -gt 0 ]; do
|
||||
cmd="$1"; shift
|
||||
case "$cmd" in
|
||||
|
||||
--nogit)
|
||||
nogit=1
|
||||
;;
|
||||
|
||||
-v)
|
||||
;;
|
||||
|
||||
--directory=*)
|
||||
cd "${cmd#*=}"
|
||||
;;
|
||||
-d)
|
||||
cd "$1"; shift
|
||||
;;
|
||||
|
||||
-R)
|
||||
abort "Reverse applying patches not supported yet with this tool."
|
||||
;;
|
||||
|
||||
--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
|
||||
*)
|
||||
warning "Unknown argument $cmd."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Redirect to git apply if available
|
||||
if [ "$nogit" -eq 0 ] && command -v git >/dev/null 2>&1; then
|
||||
exec git apply --whitespace=nowarn "$@"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect BSD - we check this first to error out as early as possible
|
||||
if gzip -V 2>&1 | grep "BSD" &> /dev/null; then
|
||||
echo "This script is not compatible with *BSD utilities. Please install git," >&2
|
||||
echo "which provides the same functionality and will be used instead." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for missing depdencies
|
||||
for dependency in awk cut dd du grep gzip hexdump patch sha1sum; do
|
||||
if ! command -v "$dependency" >/dev/null 2>&1; then
|
||||
echo "Missing dependency: $dependency - please install this program and try again." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Workaround for new versions of awk, which assume that we want to use unicode
|
||||
export LANG=C
|
||||
export LC_ALL=C
|
||||
|
||||
# Decode base85 git data, prepend with a gzip header
|
||||
awk_decode_b85='
|
||||
BEGIN{
|
||||
git="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
b85="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
|
||||
printf("\x1f\x8b\x08\x00\x00\x00\x00\x00");
|
||||
while (getline > 0){
|
||||
l = index(git, substr($0, 1, 1));
|
||||
if (l == 0){ exit 1; }
|
||||
p=2;
|
||||
while (l > 0 && p <= length($0)){
|
||||
a = index(b85, substr($0, p++, 1));
|
||||
b = index(b85, substr($0, p++, 1));
|
||||
c = index(b85, substr($0, p++, 1));
|
||||
d = index(b85, substr($0, p++, 1));
|
||||
e = index(b85, substr($0, p++, 1));
|
||||
if (a-- == 0 || b-- == 0 || c-- == 0 || d-- == 0 || e-- == 0){ exit 1; }
|
||||
n = (((a * 85 + b) * 85 + c) * 85 + d) * 85 + e;
|
||||
if (n > 4294967295){ exit 1; }
|
||||
a = n % 256; n /= 256;
|
||||
b = n % 256; n /= 256;
|
||||
c = n % 256; n /= 256;
|
||||
d = n % 256;
|
||||
if (l-- > 0) printf("%c", d);
|
||||
if (l-- > 0) printf("%c", c);
|
||||
if (l-- > 0) printf("%c", b);
|
||||
if (l-- > 0) printf("%c", a);
|
||||
}
|
||||
if (p != length($0) + 1 || l != 0){ exit 1; }
|
||||
}
|
||||
}'
|
||||
|
||||
# Decodes the information from a git delta patch passed in as hex encoded
|
||||
awk_decode_binarypatch='
|
||||
function get_byte(a, b){ # usage: get_byte()
|
||||
if (length(__buffer) == 0){ if(getline __buffer <= 0){ exit 1; } }
|
||||
a = index(hex, substr(__buffer, 1, 1));
|
||||
b = index(hex, substr(__buffer, 2, 1));
|
||||
if (a-- == 0 || b-- == 0){ exit 1; }
|
||||
__buffer = substr(__buffer, 3); __pos++;
|
||||
return a * 16 + b;
|
||||
}
|
||||
function skip_bytes(n, m){ # usage: skip_bytes(n)
|
||||
if (length(__buffer) == 0){ if(getline __buffer <= 0){ exit 1; } }
|
||||
while (n >= (length(__buffer) / 2)){
|
||||
m = length(__buffer) / 2; n -= m; __pos += m;
|
||||
if(getline __buffer <= 0){ exit 1; }
|
||||
}
|
||||
if (n > 0){ __buffer = substr(__buffer, 1 + 2 * n); __pos += n; }
|
||||
}
|
||||
function get_delta_hdr_size(){ # usage: get_delta_hdr_size()
|
||||
cmd = get_byte(); size = and(cmd, 0x7f); i = 7;
|
||||
while (and(cmd, 0x80)){
|
||||
cmd = get_byte(); size += lshift(and(cmd, 0x7f), i); i += 7;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
BEGIN{
|
||||
hex="0123456789ABCDEF"
|
||||
src_size = get_delta_hdr_size(); dst_size = get_delta_hdr_size();
|
||||
printf("S %d %d\n", src_size, dst_size);
|
||||
while (dst_size > 0){
|
||||
cmd = get_byte();
|
||||
if (and(cmd, 0x80)){
|
||||
cp_offs = 0; cp_size = 0;
|
||||
if (and(cmd, 0x01)){ cp_offs = get_byte(); }
|
||||
if (and(cmd, 0x02)){ cp_offs += lshift(get_byte(), 8); }
|
||||
if (and(cmd, 0x04)){ cp_offs += lshift(get_byte(), 16); }
|
||||
if (and(cmd, 0x08)){ cp_offs += lshift(get_byte(), 24); }
|
||||
if (and(cmd, 0x10)){ cp_size = get_byte(); }
|
||||
if (and(cmd, 0x20)){ cp_size += lshift(get_byte(), 8); }
|
||||
if (and(cmd, 0x40)){ cp_size += lshift(get_byte(), 16); }
|
||||
if (cp_size == 0){ cp_size = 0x10000; }
|
||||
if (cp_offs + cp_size > src_size || cp_size > dst_size){ exit 1; }
|
||||
printf("1 %d %d\n", cp_offs, cp_size);
|
||||
dst_size -= cp_size;
|
||||
}else if (cmd){
|
||||
if (cmd > dst_size){ exit 1; }
|
||||
printf("2 %d %d\n", __pos, cmd);
|
||||
skip_bytes(cmd);
|
||||
dst_size -= cmd;
|
||||
}else{ exit 1; }
|
||||
}
|
||||
printf("E 0 0\n");
|
||||
}'
|
||||
|
||||
# Find end of patch header
|
||||
awk_eof_header='
|
||||
BEGIN{
|
||||
ofs=1;
|
||||
}
|
||||
!/^(--- |\+\+\+ |old |new |copy |rename |similarity |index |GIT |literal |delta )/{
|
||||
ofs=0; exit 0;
|
||||
}
|
||||
END{
|
||||
print FNR+ofs;
|
||||
}'
|
||||
|
||||
# Find end of text patch
|
||||
awk_eof_textpatch='
|
||||
BEGIN{
|
||||
ofs=1;
|
||||
}
|
||||
!/^(@| |+|-|\\)/{
|
||||
ofs=0; exit 0;
|
||||
}
|
||||
END{
|
||||
print FNR+ofs;
|
||||
}'
|
||||
|
||||
# Find end of git binary patch
|
||||
awk_eof_binarypatch='
|
||||
BEGIN{
|
||||
ofs=1;
|
||||
}
|
||||
!/^[A-Za-z]/{
|
||||
ofs=0; exit 0;
|
||||
}
|
||||
END{
|
||||
print FNR+ofs;
|
||||
}'
|
||||
|
||||
|
||||
# Create a temporary file containing the patch - NOTE: even if the user
|
||||
# provided a filename it still makes sense to work with a temporary file,
|
||||
# to avoid changes of the content while this script is active.
|
||||
tmpfile=$(mktemp)
|
||||
if [ ! -f "$tmpfile" ]; then
|
||||
tmpfile=""
|
||||
abort "Unable to create temporary file for patch."
|
||||
elif ! cat > "$tmpfile"; then
|
||||
abort "Patch truncated."
|
||||
fi
|
||||
|
||||
# Go through the different patch sections
|
||||
lastoffset=1
|
||||
for offset in $(awk '/^diff --git /{ print FNR; }' "$tmpfile"); do
|
||||
|
||||
# Check part between end of last patch and start of current patch
|
||||
if [ "$lastoffset" -gt "$offset" ]; then
|
||||
abort "Unable to split patch. Is this a proper git patch?"
|
||||
elif [ "$lastoffset" -lt "$offset" ]; then
|
||||
tmpoffset=$((offset - 1))
|
||||
if sed -n "$lastoffset,$tmpoffset p" "$tmpfile" | grep -q '^\(@@ -\|--- \|+++ \)'; then
|
||||
abort "Patch corrupted or not created with git."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Find out the size of the patch header
|
||||
tmpoffset=$((offset + 1))
|
||||
tmpoffset=$(sed -n "$tmpoffset,\$ p" "$tmpfile" | awk "$awk_eof_header")
|
||||
hdroffset=$((offset + tmpoffset))
|
||||
|
||||
# Parse all important fields of the header
|
||||
patch_oldname=""
|
||||
patch_newname=""
|
||||
patch_oldsha1=""
|
||||
patch_newsha1=""
|
||||
patch_is_binary=0
|
||||
patch_binary_type=""
|
||||
patch_binary_size=""
|
||||
|
||||
tmpoffset=$((hdroffset - 1))
|
||||
while IFS= read -r line; do
|
||||
if [ "$line" == "GIT binary patch" ]; then
|
||||
patch_is_binary=1
|
||||
|
||||
elif [[ "$line" =~ ^diff\ --git\ ([^ ]*)\ ([^ ]*)$ ]]; then
|
||||
patch_oldname="${BASH_REMATCH[1]}"
|
||||
patch_newname="${BASH_REMATCH[2]}"
|
||||
|
||||
elif [[ "$line" =~ ^---\ (.*)$ ]]; then
|
||||
patch_oldname="${BASH_REMATCH[1]}"
|
||||
|
||||
elif [[ "$line" =~ ^\+\+\+\ (.*)$ ]]; then
|
||||
patch_newname="${BASH_REMATCH[1]}"
|
||||
|
||||
elif [[ "$line" =~ ^index\ ([a-fA-F0-9]*)\.\.([a-fA-F0-9]*) ]]; then
|
||||
patch_oldsha1="${BASH_REMATCH[1]}"
|
||||
patch_newsha1="${BASH_REMATCH[2]}"
|
||||
|
||||
elif [[ "$line" =~ ^(literal|delta)\ ([0-9]+)$ ]]; then
|
||||
patch_binary_type="${BASH_REMATCH[1]}"
|
||||
patch_binary_size="${BASH_REMATCH[2]}"
|
||||
|
||||
fi
|
||||
done < <(sed -n "$offset,$tmpoffset p" "$tmpfile")
|
||||
|
||||
# Remove first path components, which are always a/ and b/ for git patches
|
||||
if [[ "$patch_oldname" =~ ^a/(.*)$ ]]; then
|
||||
patch_oldname="${BASH_REMATCH[1]}"
|
||||
elif [ "$patch_oldname" != "/dev/null" ]; then
|
||||
abort "Old name doesn't start with a/."
|
||||
fi
|
||||
if [[ "$patch_newname" =~ ^b/(.*)$ ]]; then
|
||||
patch_newname="${BASH_REMATCH[1]}"
|
||||
elif [ "$patch_newname" != "/dev/null" ]; then
|
||||
abort "New name doesn't start with b/."
|
||||
fi
|
||||
|
||||
# Short progress message
|
||||
echo "patching $patch_newname"
|
||||
|
||||
# If its a textual patch, then use 'patch' to apply it.
|
||||
if [ "$patch_is_binary" -eq 0 ]; then
|
||||
|
||||
# Find end of textual patch
|
||||
tmpoffset=$(sed -n "$hdroffset,\$ p" "$tmpfile" | awk "$awk_eof_textpatch")
|
||||
lastoffset=$((hdroffset + tmpoffset - 1))
|
||||
|
||||
# Apply textual patch
|
||||
tmpoffset=$((lastoffset - 1))
|
||||
if ! sed -n "$offset,$tmpoffset p" "$tmpfile" | patch -p1 -s -f; then
|
||||
abort "Textual patch did not apply, aborting."
|
||||
fi
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
# It is a binary patch - check that requirements are fulfilled
|
||||
if [ "$patch_binary_type" != "literal" ] && [ "$patch_binary_type" != "delta" ]; then
|
||||
abort "Unknown binary patch type."
|
||||
|
||||
elif [ -z "$patch_oldsha1" ] || [ -z "$patch_newsha1" ]; then
|
||||
abort "Missing index header, sha1 sums required for binary patch."
|
||||
|
||||
elif [ "$patch_oldname" != "$patch_newname" ]; then
|
||||
abort "Stripped old and new name doesn't match for binary patch."
|
||||
fi
|
||||
|
||||
# Ensure that checksum of old file matches
|
||||
sha=$(gitsha1 "$patch_oldname")
|
||||
if [ "$patch_oldsha1" != "$sha" ]; then
|
||||
abort "Checksum mismatch for $patch_oldname (expected $patch_oldsha1, got $sha)."
|
||||
fi
|
||||
|
||||
# Find end of binary patch
|
||||
tmpoffset=$(sed -n "$hdroffset,\$ p" "$tmpfile" | awk "$awk_eof_binarypatch")
|
||||
lastoffset=$((hdroffset + tmpoffset - 1))
|
||||
|
||||
# Special case - deleting the whole file
|
||||
if [ "$patch_newsha1" == "0000000000000000000000000000000000000000" ] &&
|
||||
[ "$patch_binary_size" -eq 0 ] && [ "$patch_binary_type" == "literal" ]; then
|
||||
|
||||
# Applying the patch just means deleting the file
|
||||
if [ -f "$patch_oldname" ] && ! rm "$patch_oldname"; then
|
||||
abort "Unable to delete file $patch_oldname."
|
||||
fi
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
# Create temporary file for literal patch
|
||||
literal_tmpfile=$(mktemp)
|
||||
if [ ! -f "$literal_tmpfile" ]; then
|
||||
abort "Unable to create temporary file for binary patch."
|
||||
fi
|
||||
|
||||
# Decode base85 and gzip compression
|
||||
tmpoffset=$((lastoffset - 1))
|
||||
sed -n "$hdroffset,$tmpoffset p" "$tmpfile" | awk "$awk_decode_b85" | gzip -dc > "$literal_tmpfile" 2>/dev/null
|
||||
if [ "$patch_binary_size" -ne "$(filesize "$literal_tmpfile")" ]; then
|
||||
rm "$literal_tmpfile"
|
||||
abort "Uncompressed binary patch has wrong size."
|
||||
fi
|
||||
|
||||
# Convert delta to literal patch
|
||||
if [ "$patch_binary_type" == "delta" ]; then
|
||||
|
||||
# Create new temporary file for literal patch
|
||||
delta_tmpfile="$literal_tmpfile"
|
||||
literal_tmpfile=$(mktemp)
|
||||
if [ ! -f "$literal_tmpfile" ]; then
|
||||
rm "$delta_tmpfile"
|
||||
abort "Unable to create temporary file for binary patch."
|
||||
fi
|
||||
|
||||
patch_binary_complete=0
|
||||
patch_binary_destsize=0
|
||||
|
||||
while read cmd arg1 arg2; do
|
||||
if [ "$cmd" == "S" ]; then
|
||||
[ "$arg1" -eq "$(filesize "$patch_oldname")" ] || break
|
||||
patch_binary_destsize="$arg2"
|
||||
|
||||
elif [ "$cmd" == "1" ]; then
|
||||
dd if="$patch_oldname" bs=1 skip="$arg1" count="$arg2" >> "$literal_tmpfile" 2>/dev/null || break
|
||||
|
||||
elif [ "$cmd" == "2" ]; then
|
||||
dd if="$delta_tmpfile" bs=1 skip="$arg1" count="$arg2" >> "$literal_tmpfile" 2>/dev/null || break
|
||||
|
||||
elif [ "$cmd" == "E" ]; then
|
||||
patch_binary_complete=1
|
||||
|
||||
else break; fi
|
||||
done < <(hexdump -v -e '32/1 "%02X" "\n"' "$delta_tmpfile" | awk "$awk_decode_binarypatch")
|
||||
|
||||
rm "$delta_tmpfile"
|
||||
|
||||
if [ "$patch_binary_complete" -eq 0 ]; then
|
||||
rm "$literal_tmpfile"
|
||||
abort "Unable to parse full patch."
|
||||
|
||||
elif [ "$patch_binary_destsize" -ne "$(filesize "$literal_tmpfile")" ]; then
|
||||
rm "$literal_tmpfile"
|
||||
abort "Unpacked delta patch has wrong size."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure that checksum of literal patch matches
|
||||
sha=$(gitsha1 "$literal_tmpfile")
|
||||
if [ "$patch_newsha1" != "$sha" ]; then
|
||||
rm "$literal_tmpfile"
|
||||
abort "Checksum mismatch for patched $patch_newname (expected $patch_newsha1, got $sha)."
|
||||
fi
|
||||
|
||||
# Apply the patch - copy literal patch to destination path
|
||||
if ! cp "$literal_tmpfile" "$patch_newname"; then
|
||||
rm "$literal_tmpfile"
|
||||
abort "Unable to replace $patch_newname with patched file."
|
||||
fi
|
||||
|
||||
rm "$literal_tmpfile"
|
||||
done
|
||||
|
||||
# Check last remaining part for unparsed patches
|
||||
if sed -n "$lastoffset,\$ p" "$tmpfile" | grep -q '^\(@@ -\|--- \|+++ \)'; then
|
||||
abort "Patch corrupted or not created with git."
|
||||
fi
|
||||
|
||||
# Delete temp file (if any)
|
||||
if [ ! -z "$tmpfile" ]; then
|
||||
rm "$tmpfile"
|
||||
tmpfile=""
|
||||
fi
|
||||
|
||||
# Success
|
||||
exit 0
|
@@ -929,7 +929,7 @@ if test "$backend" = "patch"; then
|
||||
patch_apply_file ()
|
||||
{
|
||||
echo "Applying $1"
|
||||
if ! "$patchdir/../debian/tools/gitapply.sh" $gitapply_args < "$1"; then
|
||||
if ! "$patchdir/gitapply.sh" $gitapply_args < "$1"; then
|
||||
abort "Failed to apply patch, aborting!"
|
||||
fi
|
||||
}
|
||||
@@ -955,7 +955,7 @@ elif test "$backend" = "epatch"; then
|
||||
shortname="$(basename "$1")"
|
||||
if grep -q "^GIT binary patch" "$1"; then
|
||||
ebegin "Applying $shortname"
|
||||
"$patchdir/../debian/tools/gitapply.sh" $gitapply_args < "$1" || \
|
||||
"$patchdir/gitapply.sh" $gitapply_args < "$1" || \
|
||||
die "Failed Patch: $1!"
|
||||
eend
|
||||
|
||||
|
Reference in New Issue
Block a user