gitapply.sh: Rewrite script to improve performance on huge font patches.

This commit is contained in:
Sebastian Lackner 2014-08-07 03:26:33 +02:00
parent 1ca9157daa
commit 5d5b230c5a

View File

@ -19,38 +19,14 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#
# Setup parser variables
nogit=0
lineno=0
verbose=0
patch_mode=0
patch_tmpfile=""
# Macros
abort()
{
if [ ! -z "$patch_tmpfile" ]; then
rm "$patch_tmpfile"
patch_tmpfile=""
fi
echo "[PATCH:$lineno] ERR: $1" >&2
exit 1
}
invalid_parser_state()
{
abort "Invalid parser state (patch_mode=$patch_mode)!"
}
warning()
{
echo "[PATCH:$lineno] WRN: $1" >&2
}
tmpfile=""
# Show usage information about gitapply script
usage()
{
echo ""
echo "Usage: ./gitapply [--nogit] [-v] [-d DIRECTORY]"
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."
@ -60,9 +36,41 @@ usage()
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()
{
echo -en "blob $(du -b "$1" | cut -f1)\x00" | cat - "$1" | sha1sum | cut -d' ' -f1
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"
}
@ -76,7 +84,6 @@ while [[ $# > 0 ]]; do
;;
-v)
verbose=1
;;
--directory=*)
@ -87,8 +94,7 @@ while [[ $# > 0 ]]; do
;;
-R)
echo "Reverse applying patches not supported yet with this tool." >&2
exit 1
abort "Reverse applying patches not supported yet with this tool."
;;
--help)
@ -108,21 +114,21 @@ if [ "$nogit" -eq 0 ] && command -v git >/dev/null 2>&1; then
exit 1
fi
# Check for missing depdencies
for dependency in awk chmod cut dd du 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
# Detect BSD
# 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
# Decode base85 git data, prepend with a gzip header
awk_b85='
BEGIN{
@ -193,7 +199,7 @@ BEGIN{
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_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;
@ -207,405 +213,227 @@ BEGIN{
printf("E 0 0\n");
}'
# Parse lines of the patch
while IFS= read -r line; do
(( lineno++ ))
# In verbose mode we print each line of the patch to stdout
if [ "$verbose" -ne 0 ]; then
echo "$lineno: $line"
fi
# MODE 1: Parse header
# Fall-through to 2
if [ "$patch_mode" -eq 1 ]; then
if [[ "$line" =~ ^---\ (.*)$ ]]; then
patch_oldname="${BASH_REMATCH[1]}"
echo "$line" >> "$patch_tmpfile"
continue
elif [[ "$line" =~ ^\+\+\+\ (.*)$ ]]; then
patch_newname="${BASH_REMATCH[1]}"
echo "$line" >> "$patch_tmpfile"
continue
elif [ "${line:0:8}" == "old mode" ] || [ "${line:0:17}" == "deleted file mode" ]; then
# ignore
echo "$line" >> "$patch_tmpfile"
continue
elif [[ "$line" =~ ^new\ mode\ ([0-9]*)$ ]] || [[ "$line" =~ ^new\ file\ mode\ ([0-9]*)$ ]]; then
patch_filemode="${BASH_REMATCH[1]}"
echo "$line" >> "$patch_tmpfile"
continue
elif [ "${line:0:8}" == "new mode" ] || [ "${line:0:13}" == "new file mode" ]; then
patch_errors+=("$lineno: Unable to parse header line '$line'.")
patch_invalid=1
echo "$line" >> "$patch_tmpfile"
continue
elif [ "${line:0:9}" == "copy from" ] || [ "${line:0:7}" == "copy to" ]; then
patch_errors+=("$lineno: Copy header not implemented yet.")
patch_invalid=1
echo "$line" >> "$patch_tmpfile"
continue
elif [ "${line:0:7}" == "rename " ]; then
patch_errors+=("$lineno: Patch rename header not implemented yet.")
patch_invalid=1
echo "$line" >> "$patch_tmpfile"
continue
elif [ "${line:0:16}" == "similarity index" ] || [ "${line:0:19}" == "dissimilarity index" ]; then
# ignore
echo "$line" >> "$patch_tmpfile"
continue
elif [[ "$line" =~ ^index\ ([a-fA-F0-9]*)\.\.([a-fA-F0-9]*) ]]; then
patch_oldsha1="${BASH_REMATCH[1]}"
patch_newsha1="${BASH_REMATCH[2]}"
echo "$line" >> "$patch_tmpfile"
continue
elif [ "${line:0:6}" == "index " ]; then
patch_errors+=("$lineno: Unable to parse header line '$line'.")
patch_invalid=1
echo "$line" >> "$patch_tmpfile"
continue
else
# 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
patch_mode=2
# fall-through
fi
fi
# MODE 2: Decide between binary and textual patch data
# Fall-through to 200, 0
if [ "$patch_mode" -eq 2 ]; then
if [[ "$line" == "GIT binary patch" ]]; then
if [ -z "$patch_oldsha1" ] || [ -z "$patch_newsha1" ]; then
patch_errors+=("$lineno: Missing index header, sha1 sums required for binary patch.")
patch_invalid=1
fi
if [ "$patch_oldname" != "$patch_newname" ]; then
patch_errors+=("$lineno: Stripped old- and new name doesn't match for binary patch.")
patch_invalid=1
fi
if [ "$patch_invalid" -ne 0 ]; then
for error in "${patch_errors[@]}"; do echo "$error" >&2; done
abort "Unable to continue."
fi
patch_mode=100
continue
elif [ "${line:0:4}" == "@@ -" ]; then
# We count the number of lines added/removed for informational purposes
patch_total_add=0
patch_total_rem=0
patch_mode=200
# fall-through
elif [ "${line:0:11}" == "diff --git " ]; then
if [ "$patch_oldname" != "$patch_newname" ]; then
patch_errors+=("$lineno: Stripped old- and new name doesn't match.")
patch_invalid=1
fi
if [ "$patch_invalid" -ne 0 ]; then
for error in "${patch_errors[@]}"; do echo "$error" >&2; done
abort "Unable to continue."
fi
if [ ! -z "$patch_filemode" ]; then
echo "patching $patch_newname"
chmod "${patch_filemode: -3}" "$patch_oldname" # we ignore failures for now
fi
patch_mode=0
# fall-through
elif [ ! -z "$line" ]; then
abort "Unknown patch format."
fi
fi
# MODE 100: Decide between binary literal/delta patch
if [ "$patch_mode" -eq 100 ]; then
if [[ "$line" =~ ^(literal|delta)\ ([0-9]+)$ ]]; then
binary_patch_type="${BASH_REMATCH[1]}"
binary_patch_size="${BASH_REMATCH[2]}"
# Check shasum if its not a patch creating a new file
if [ "$patch_oldsha1" != "0000000000000000000000000000000000000000" ] || [ "$binary_patch_type" == "delta" ] || [ -f "$patch_oldname" ]; then
if [ -f "$patch_oldname" ]; then
sha=$(gitsha1 "$patch_oldname")
else
sha="0000000000000000000000000000000000000000"
fi
if [ "$patch_oldsha1" != "$sha" ]; then
echo "$lineno: Expected $patch_oldsha1" >&2
echo "$lineno: Got $sha" >&2
abort "Unable to continue because of sha1 mismatch of original file."
fi
fi
# Is it a patch deleting this file
if [ "$patch_newsha1" == "0000000000000000000000000000000000000000" ] && [ "$binary_patch_size" -eq 0 ] && [ "$binary_patch_type" == "literal" ]; then
echo "patching $patch_newname"
# Apply the patch: Just delete the file
if [ -f "$patch_oldname" ] && ! rm "$patch_oldname"; then
abort "Unable to delete file $patch_oldname."
fi
# We are ready with this one
patch_mode=0
continue
fi
# Clear temporary file, we will use it to decode the binary block
echo -en "" > "$patch_tmpfile"
patch_mode=101
continue
else
abort "Only literal/delta patches are supported."
fi
fi
# MODE 101: Decode data
if [ "$patch_mode" -eq 101 ]; then
if [ ! -z "$line" ]; then
# Append this binary chunk in the temp file
echo "$line" >> "$patch_tmpfile"
else
echo "patching $patch_newname"
decoded_tmpfile=$(mktemp)
if [ ! -f "$decoded_tmpfile" ]; then
abort "Unable to create temporary file for patch."
fi
# Decode base85 and add a gzip header
awk "$awk_b85" < "$patch_tmpfile" | gzip -dc > "$decoded_tmpfile" 2>/dev/null
# The new temp file replaces the old one
rm "$patch_tmpfile"
patch_tmpfile="$decoded_tmpfile"
# Ensure that resulting binary patch has the correct size
if [ "$binary_patch_size" -ne "$(du -b "$patch_tmpfile" | cut -f 1)" ]; then
abort "Uncompressed binary patch has wrong size."
fi
# Apply git delta path
if [ "$binary_patch_type" == "delta" ]; then
decoded_tmpfile=$(mktemp)
if [ ! -f "$decoded_tmpfile" ]; then
abort "Unable to create temporary file for patch."
fi
binary_patch_complete=0
binary_patch_destsize=""
while read cmd arg1 arg2; do
if [ "$cmd" == "S" ]; then
binary_patch_destsize="$arg2"
[ "$arg1" -eq "$(du -b "$patch_oldname" | cut -f 1)" ] || break
elif [ "$cmd" == "1" ]; then
dd if="$patch_oldname" bs=1 skip="$arg1" count="$arg2" >> "$decoded_tmpfile" 2>/dev/null || break
elif [ "$cmd" == "2" ]; then
dd if="$patch_tmpfile" bs=1 skip="$arg1" count="$arg2" >> "$decoded_tmpfile" 2>/dev/null || break
elif [ "$cmd" == "E" ]; then
binary_patch_complete=1
else break; fi
done < <(hexdump -v -e '32/1 "%02X" "\n"' "$patch_tmpfile" | awk "$awk_gitpatch")
# The new temp file replaces the old one
rm "$patch_tmpfile"
patch_tmpfile="$decoded_tmpfile"
if [ "$binary_patch_complete" -ne 1 ]; then
abort "Unable to parse full patch."
elif [ "$binary_patch_destsize" -ne "$(du -b "$patch_tmpfile" | cut -f 1)" ]; then
abort "Unpacked delta patch has wrong size."
fi
elif [ "$binary_patch_type" != "literal" ]; then
invalid_parser_state
fi
# Check shasum if its not a patch creating a new file
sha=$(gitsha1 "$patch_tmpfile")
if [ "$patch_newsha1" != "$sha" ]; then
echo "$lineno: Expected $patch_newsha1" >&2
echo "$lineno: Got $sha" >&2
abort "Unable to continue because of sha1 mismatch after applying the patch."
fi
if ! cp "$patch_tmpfile" "$patch_oldname"; then
abort "Unable to replace original file."
fi
if [ ! -z "$patch_filemode" ]; then
chmod "${patch_filemode: -3}" "$patch_oldname" # we ignore failures for now
fi
# We're ready with this patch
patch_mode=0
continue
fi
fi
# MODE 200: Text patch
# Fall-through to 0
if [ "$patch_mode" -eq 200 ]; then
hunk="^@@\ -(([0-9]+),)?([0-9]+)\ \+(([0-9]+),)?([0-9]+)\ @@"
if [[ "$line" =~ $hunk ]]; then
# ${BASH_REMATCH[2]} - source line
# ${BASH_REMATCH[5]} - end line
hunk_src_lines="${BASH_REMATCH[3]}"
hunk_dst_lines="${BASH_REMATCH[6]}"
if [ "$hunk_src_lines" -eq 0 ] && [ "$hunk_dst_lines" -eq 0 ]; then
abort "Empty hunk doesn't make sense."
fi
# Start of a new hunk, append it
echo "$line" >> "$patch_tmpfile"
patch_mode=201
continue
elif [ "${line:0:2}" == "\\ " ]; then
# ignore
echo "$line" >> "$patch_tmpfile"
continue
else
echo "patching $patch_newname"
# Try to apply the patch using 'patch'
if ! patch -p1 -s -f < "$patch_tmpfile"; then
abort "Patch did not apply, aborting."
fi
patch_mode=0
# fall-through
fi
fi
# MODE 201: Wait until we reach the end of a hunk
if [ "$patch_mode" -eq 201 ]; then
# These lines are part of a hunk, append it
echo "$line" >> "$patch_tmpfile"
if [ "${line:0:1}" == " " ] && [ "$hunk_src_lines" -gt 0 ] && [ "$hunk_dst_lines" -gt 0 ]; then
(( hunk_src_lines-- ))
(( hunk_dst_lines-- ))
elif [ "${line:0:1}" == "-" ] && [ "$hunk_src_lines" -gt 0 ]; then
(( hunk_src_lines-- ))
(( patch_total_rem++ ))
elif [ "${line:0:1}" == "+" ] && [ "$hunk_dst_lines" -gt 0 ]; then
(( hunk_dst_lines-- ))
(( patch_total_add++ ))
elif [ "${line:0:2}" == "\\ " ]; then
continue # ignore "\\ No newline ..."
else
abort "Unexpected line in hunk."
fi
# If it was the last line of this hunk then go back to mode 200
if [ "$hunk_src_lines" -eq 0 ] && [ "$hunk_dst_lines" -eq 0 ]; then
patch_mode=200
continue
fi
fi
# MODE 0: Search for patch header
if [ "$patch_mode" -eq 0 ]; then
if [[ "$line" =~ ^diff\ --git\ ([^ ]*)\ ([^ ]*)$ ]]; then
# Is this patch valid? The array will contain a list of detected errors
patch_invalid=0
patch_errors=()
# Setup name and sha1 sum variables
patch_oldname="${BASH_REMATCH[1]}"
patch_newname="${BASH_REMATCH[2]}"
patch_oldsha1=""
patch_newsha1=""
# Filemode
patch_filemode=""
if [ ! -z "$patch_tmpfile" ]; then
rm "$patch_tmpfile"
fi
patch_tmpfile=$(mktemp)
if [ ! -f "$patch_tmpfile" ]; then
abort "Unable to create temporary file for patch."
fi
echo "$line" >> "$patch_tmpfile"
patch_mode=1
continue
elif [ "${line:0:4}" == "@@ -" ] || [ "${line:0:4}" == "--- " ] || [ "${line:0:4}" == "+++ " ]; then
# 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
done
# Find out the size of the patch header
tmpoffset=$((offset + 1))
tmpoffset=$(sed -n "$tmpoffset,\$ p" "$tmpfile" |
awk '!/^(--- |\+\+\+ |old |new |copy |rename |similarity |index |GIT |literal |delta )/{ exit 42; } END{ print FNR; }')
if [ "$?" -ne 42 ]; then
tmpoffset=$((tmpoffset + 1))
fi
hdroffset=$((offset + tmpoffset))
# Apply last text patch (if any)
if [ "$patch_mode" -eq 200 ]; then
echo "patching $patch_newname"
# 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=""
# Try to apply the patch using 'patch'
if ! patch -p1 -s -f < "$patch_tmpfile"; then
abort "Patch did not apply, aborting."
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
patch_mode=0
# 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 '!/^(@| |+|-|\\)/{ exit 42; } END{ print FNR; }')
if [ "$?" -ne 42 ]; then
tmpoffset=$((tmpoffset + 1))
fi
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 '!/^[A-Za-z]/{ exit 42; } END{ print FNR; }')
if [ "$?" -ne 42 ]; then
tmpoffset=$((tmpoffset + 1))
fi
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_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 [ "$binary_patch_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_gitpatch")
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 patch
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
# Make sure we're not just parsing a patch
if [ "$patch_mode" -ne 0 ]; then
abort "File ended in the middle of a patch!"
fi
# Clean up temp files if any
if [ ! -z "$patch_tmpfile" ]; then
rm "$patch_tmpfile"
patch_tmpfile=""
# Delete temp file (if any)
if [ ! -z "$tmpfile" ]; then
rm "$tmpfile"
tmpfile=""
fi
# Success