15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/bin/bash -p 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# usage: dirdiffer.sh old_dir new_dir patch_dir 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# dirdiffer creates a patch directory patch_dir that represents the difference 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# between old_dir and new_dir. patch_dir can be used with dirpatcher to 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# recreate new_dir given old_dir. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# dirdiffer operates recursively, properly handling ordinary files, symbolic 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# links, and directories, as they are found in new_dir. Symbolic links and 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# directories are always replicated as-is in patch_dir. Ordinary files will 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# be represented at the appropriate location in patch_dir by one of the 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# following: 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - a binary diff prepared by goobsdiff that can transform the file at the 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# same position in old_dir to the version in new_dir, but only when such a 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# file already exists in old_dir and is an ordinary file. These files are 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# given a "$gbs" suffix. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - a bzip2-compressed copy of the new file from new_dir; in patch_dir, the 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# new file will have a "$bz2" suffix. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - a gzip-compressed copy of the new file from new_dir; in patch_dir, the 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# new file will have a "$gz" suffix. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - an xz/lzma2-compressed copy of the new file from new_dir; in patch_dir, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the new file will have an "$xz" suffix. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - an uncompressed copy of the new file from new_dir; in patch_dir, the 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# new file will have a "$raw" suffix. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The unconventional suffixes are used because they aren't likely to occur in 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# filenames. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Of these options, the smallest possible representation is chosen. Note that 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# goobsdiff itself will also compress various sections of a binary diff with 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# bzip2, gzip, or xz/lzma2, or leave them uncompressed, according to which is 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# smallest. The approach of choosing the smallest possible representation is 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# time-consuming but given the choices of compressors results in an overall 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# size reduction of about 3%-5% relative to using bzip2 as the only 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# compressor; bzip2 is generally more effective for these data sets than gzip, 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# and xz/lzma2 more effective than bzip2. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# For large input files, goobsdiff is also very time-consuming and 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# memory-intensive. The overall "wall clock time" spent preparing a patch_dir 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# representing the differences between Google Chrome's 6.0.422.0 and 6.0.427.0 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# versioned directories from successive weekly dev channel releases on a 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 2.53GHz dual-core 4GB MacBook Pro is 3 minutes. Reconstructing new_dir with 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# dirpatcher is much quicker; in the above configuration, only 10 seconds are 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# needed for reconstruction. 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# After creating a full patch_dir structure, but before returning, dirpatcher 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# is invoked to attempt to recreate new_dir in a temporary location given 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# old_dir and patch_dir. The recreated new_dir is then compared against the 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# original new_dir as a verification step. Should verification fail, dirdiffer 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# exits with a nonzero status, and patch_dir should not be used. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Environment variables: 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# DIRDIFFER_EXCLUDE 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# When an entry in new_dir matches this regular expression, it will not be 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# included in patch_dir. All prospective paths in new_dir will be matched 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# against this regular expression, including directories. If a directory 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# matches this pattern, dirdiffer will also ignore the directory's contents. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# DIRDIFFER_NO_DIFF 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# When an entry in new_dir matches this regular expression, it will not be 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# represented in patch_dir by a $gbs file prepared by goobsdiff. It will only 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# appear as a $bz2, $gz, or $raw file. Only files in new_dir, not 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# directories, will be matched against this regular expression. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Exit codes: 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 0 OK 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1 Unknown failure 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 2 Incorrect number of parameters 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 3 Input directories do not exist or are not directories 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 4 Output directory already exists 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 5 Parent of output directory does not exist or is not a directory 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 6 An input or output directories contains another 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 7 Could not create output directory 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 8 File already exists in output directory 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 9 Found an irregular file (non-directory, file, or symbolic link) in input 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 10 Could not create symbolic link 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 11 File copy failed 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 12 bzip2 compression failed 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 13 gzip compression failed 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 14 xz/lzma2 compression failed 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 15 Patch creation failed 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 16 Verification failed 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 17 Could not set mode (permissions) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 18 Could not set modification time 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 19 Invalid regular expression (irregular expression?) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set -eu 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Environment sanitization. Set a known-safe PATH. Clear environment variables 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# that might impact the interpreter's operation. The |bash -p| invocation 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# on the #! line takes the bite out of BASH_ENV, ENV, and SHELLOPTS (among 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# other features), but clearing them here ensures that they won't impact any 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# shell scripts used as utility programs. SHELLOPTS is read-only and can't be 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# unset, only unexported. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export PATH="/usr/bin:/bin:/usr/sbin:/sbin" 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unset BASH_ENV CDPATH ENV GLOBIGNORE IFS POSIXLY_CORRECT 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export -n SHELLOPTS 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)shopt -s dotglob nullglob 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# find_tool looks for an executable file named |tool_name|: 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - in the same directory as this script, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - if this script is located in a Chromium source tree, at the expected 1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Release output location in the Mac out directory, 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - as above, but in the Debug output location 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If found in any of the above locations, the script's path is output. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Otherwise, this function outputs |tool_name| as a fallback, allowing it to 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# be found (or not) by an ordinary ${PATH} search. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)find_tool() { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local tool_name="${1}" 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local script_dir 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) script_dir="$(dirname "${0}")" 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local tool="${script_dir}/${tool_name}" 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${tool}" 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local script_dir_phys 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) script_dir_phys="$(cd "${script_dir}" && pwd -P)" 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${script_dir_phys}" =~ ^(.*)/src/chrome/installer/mac$ ]]; then 1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) tool="${BASH_REMATCH[1]}/src/out/Release/${tool_name}" 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${tool}" 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) tool="${BASH_REMATCH[1]}/src/out/Debug/${tool_name}" 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${tool}" 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${tool_name}" 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ME="$(basename "${0}")" 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly ME 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DIRPATCHER="$(dirname "${0}")/dirpatcher.sh" 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly DIRPATCHER 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GOOBSDIFF="$(find_tool goobsdiff)" 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly GOOBSDIFF 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly BZIP2="bzip2" 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly GZIP="gzip" 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XZ="$(find_tool xz)" 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly XZ 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly GBS_SUFFIX='$gbs' 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly BZ2_SUFFIX='$bz2' 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly GZ_SUFFIX='$gz' 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly XZ_SUFFIX='$xz' 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly PLAIN_SUFFIX='$raw' 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Workaround for http://code.google.com/p/chromium/issues/detail?id=83180#c3 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# In bash 4.0, "declare VAR" no longer initializes VAR if not already set. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles): ${DIRDIFFER_EXCLUDE:=} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles): ${DIRDIFFER_NO_DIFF:=} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)err() { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local error="${1}" 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${ME}: ${error}" >& 2 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)declare -a g_cleanup g_verify_exclude 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cleanup() { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local status=${?} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap - EXIT 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap '' HUP INT QUIT TERM 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ ${status} -ge 128 ]]; then 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "Caught signal $((${status} - 128))" 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${#g_cleanup[@]}" -gt 0 ]]; then 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -rf "${g_cleanup[@]}" 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit ${status} 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)copy_mode_and_time() { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${1}" 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${2}" 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local mode 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mode="$(stat "-f%OMp%OLp" "${new_file}")" 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! chmod -h "${mode}" "${patch_file}"; then 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 17 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ -L "${patch_file}" ]]; then 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Symbolic link modification times can't be copied because there's no 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # shell tool that provides direct access to lutimes. Instead, the symbolic 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # link was created with rsync, which already copied the timestamp with 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # lutimes. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! touch -r "${new_file}" "${patch_file}"; then 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 18 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)file_size() { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local file="${1}" 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stat -f %z "${file}" 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)make_patch_file() { 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_file="${1}" 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${2}" 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${3}" 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local uncompressed_file="${patch_file}${PLAIN_SUFFIX}" 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! cp "${new_file}" "${uncompressed_file}"; then 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 11 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local uncompressed_size 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uncompressed_size="$(file_size "${new_file}")" 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local keep_file="${uncompressed_file}" 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local keep_size="${uncompressed_size}" 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local bz2_file="${patch_file}${BZ2_SUFFIX}" 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${bz2_file}" ]]; then 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "${bz2_file} already exists" 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 8 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${BZIP2}" -9c < "${new_file}" > "${bz2_file}"; then 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "couldn't compress ${new_file} to ${bz2_file} with ${BZIP2}" 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 12 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local bz2_size 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bz2_size="$(file_size "${bz2_file}")" 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${bz2_size}" -ge "${keep_size}" ]]; then 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "${bz2_file}" 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "${keep_file}" 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_file="${bz2_file}" 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_size="${bz2_size}" 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local gz_file="${patch_file}${GZ_SUFFIX}" 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${gz_file}" ]]; then 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "${gz_file} already exists" 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 8 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${GZIP}" -9cn < "${new_file}" > "${gz_file}"; then 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "couldn't compress ${new_file} to ${gz_file} with ${GZIP}" 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local gz_size 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gz_size="$(file_size "${gz_file}")" 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${gz_size}" -ge "${keep_size}" ]]; then 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "${gz_file}" 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "${keep_file}" 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_file="${gz_file}" 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_size="${gz_size}" 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local xz_flags=("-c") 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If the file looks like a Mach-O file, including a universal/fat file, add 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # the x86 BCJ filter, which results in slightly better compression of x86 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # and x86_64 executables. Mach-O files might contain other architectures, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # but they aren't currently expected in Chrome. 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local file_output 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file_output="$(file "${new_file}" 2> /dev/null || true)" 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${file_output}" =~ Mach-O ]]; then 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xz_flags+=("--x86") 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Use an lzma2 encoder. This is equivalent to xz -9 -e, but allows filters 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # to precede the compressor. 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xz_flags+=("--lzma2=preset=9e") 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local xz_file="${patch_file}${XZ_SUFFIX}" 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${xz_file}" ]]; then 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "${xz_file} already exists" 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 8 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${XZ}" "${xz_flags[@]}" < "${new_file}" > "${xz_file}"; then 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "couldn't compress ${new_file} to ${xz_file} with ${XZ}" 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 14 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local xz_size 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xz_size="$(file_size "${xz_file}")" 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${xz_size}" -ge "${keep_size}" ]]; then 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "${xz_file}" 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "${keep_file}" 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_file="${xz_file}" 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_size="${xz_size}" 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -f "${old_file}" ]] && ! [[ -L "${old_file}" ]] && 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ! [[ "${new_file}" =~ ${DIRDIFFER_NO_DIFF} ]]; then 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local gbs_file="${patch_file}${GBS_SUFFIX}" 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${gbs_file}" ]]; then 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "${gbs_file} already exists" 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 8 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${GOOBSDIFF}" "${old_file}" "${new_file}" "${gbs_file}"; then 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "couldn't create ${gbs_file} by comparing ${old_file} to ${new_file}" 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 15 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local gbs_size 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gbs_size="$(file_size "${gbs_file}")" 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${gbs_size}" -ge "${keep_size}" ]]; then 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "${gbs_file}" 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -f "${keep_file}" 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_file="${gbs_file}" 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keep_size="${gbs_size}" 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copy_mode_and_time "${new_file}" "${keep_file}" 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)make_patch_symlink() { 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${1}" 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${2}" 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # local target 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # target="$(readlink "${new_file}")" 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # ln -s "${target}" "${patch_file}" 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Use rsync instead of the above, as it's the only way to preserve the 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # timestamp of a symbolic link using shell tools. 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! rsync -lt "${new_file}" "${patch_file}"; then 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 10 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copy_mode_and_time "${new_file}" "${patch_file}" 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)make_patch_dir() { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_dir="${1}" 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_dir="${2}" 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_dir="${3}" 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! mkdir "${patch_dir}"; then 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 7 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for new_file in "${new_dir}/"*; do 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local file="${new_file:${#new_dir} + 1}" 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_file="${old_dir}/${file}" 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${patch_dir}/${file}" 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${new_file}" =~ ${DIRDIFFER_EXCLUDE} ]]; then 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_verify_exclude+=("${new_file}") 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${patch_file}" ]]; then 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "${patch_file} already exists" 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 8 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -L "${new_file}" ]]; then 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_patch_symlink "${new_file}" "${patch_file}" 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ -d "${new_file}" ]]; then 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_patch_dir "${old_file}" "${new_file}" "${patch_file}" 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ ! -f "${new_file}" ]]; then 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "can't handle irregular file ${new_file}" 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 9 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_patch_file "${old_file}" "${new_file}" "${patch_file}" 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copy_mode_and_time "${new_dir}" "${patch_dir}" 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)verify_patch_dir() { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_dir="${1}" 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_dir="${2}" 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_dir="${3}" 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local verify_temp_dir verify_dir 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verify_temp_dir="$(mktemp -d -t "${ME}")" 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_cleanup+=("${verify_temp_dir}") 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verify_dir="${verify_temp_dir}/patched" 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${DIRPATCHER}" "${old_dir}" "${patch_dir}" "${verify_dir}"; then 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "patch application for verification failed" 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 16 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # rsync will print a line for any file, directory, or symbolic link that 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # differs or exists only in one directory. As used here, it correctly 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # considers link targets, file contents, permissions, and timestamps. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local rsync_command=(rsync -clprt --delete --out-format=%n \ 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${new_dir}/" "${verify_dir}") 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ ${#g_verify_exclude[@]} -gt 0 ]]; then 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local exclude 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for exclude in "${g_verify_exclude[@]}"; do 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # ${g_verify_exclude[@]} contains paths in ${new_dir}. Strip off 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # ${new_dir} from the beginning of each, but leave a leading "/" so that 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # rsync treats them as being at the root of the "transfer." 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rsync_command+=("--exclude" "${exclude:${#new_dir}}") 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local rsync_output 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! rsync_output="$("${rsync_command[@]}")"; then 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "rsync for verification failed" 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 16 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -rf "${verify_temp_dir}" 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unset g_cleanup[${#g_cleanup[@]}] 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -n "${rsync_output}" ]]; then 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "verification failed" 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 16 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# shell_safe_path ensures that |path| is safe to pass to tools as a 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# command-line argument. If the first character in |path| is "-", "./" is 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# prepended to it. The possibly-modified |path| is output. 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)shell_safe_path() { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local path="${1}" 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${path:0:1}" = "-" ]]; then 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "./${path}" 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${path}" 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)dirs_contained() { 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local dir1="${1}/" 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local dir2="${2}/" 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${dir1:0:${#dir2}}" = "${dir2}" ]] || 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [[ "${dir2:0:${#dir1}}" = "${dir1}" ]]; then 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)usage() { 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "usage: ${ME} old_dir new_dir patch_dir" >& 2 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)main() { 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_dir new_dir patch_dir 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_dir="$(shell_safe_path "${1}")" 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_dir="$(shell_safe_path "${2}")" 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dir="$(shell_safe_path "${3}")" 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap cleanup EXIT HUP INT QUIT TERM 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ -d "${old_dir}" ]] || ! [[ -d "${new_dir}" ]]; then 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "old_dir and new_dir must exist and be directories" 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 3 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${patch_dir}" ]]; then 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "patch_dir must not exist" 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 4 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_dir_parent 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dir_parent="$(dirname "${patch_dir}")" 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ -d "${patch_dir_parent}" ]]; then 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "patch_dir parent directory must exist and be a directory" 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 5 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The weird conditional structure is because the status of the RE comparison 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # needs to be available in ${?} without conflating it with other conditions 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # or negating it. Only a status of 2 from the =~ operator indicates an 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # invalid regular expression. 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -n "${DIRDIFFER_EXCLUDE}" ]]; then 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "" =~ ${DIRDIFFER_EXCLUDE} ]]; then 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ ${?} -eq 2 ]]; then 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "DIRDIFFER_EXCLUDE contains an invalid regular expression" 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 19 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -n "${DIRDIFFER_NO_DIFF}" ]]; then 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "" =~ ${DIRDIFFER_NO_DIFF} ]]; then 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ ${?} -eq 2 ]]; then 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "DIRDIFFER_NO_DIFF contains an invalid regular expression" 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 19 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_dir_phys new_dir_phys patch_dir_parent_phys patch_dir_phys 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_dir_phys="$(cd "${old_dir}" && pwd -P)" 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_dir_phys="$(cd "${new_dir}" && pwd -P)" 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dir_parent_phys="$(cd "${patch_dir_parent}" && pwd -P)" 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dir_phys="${patch_dir_parent_phys}/$(basename "${patch_dir}")" 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if dirs_contained "${old_dir_phys}" "${new_dir_phys}" || 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dirs_contained "${old_dir_phys}" "${patch_dir_phys}" || 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dirs_contained "${new_dir_phys}" "${patch_dir_phys}"; then 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "directories must not contain one another" 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 6 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_cleanup[${#g_cleanup[@]}]="${patch_dir}" 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_patch_dir "${old_dir}" "${new_dir}" "${patch_dir}" 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verify_patch_dir "${old_dir}" "${new_dir}" "${patch_dir}" 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unset g_cleanup[${#g_cleanup[@]}] 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap - EXIT 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if [[ ${#} -ne 3 ]]; then 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 2 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fi 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)main "${@}" 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)exit ${?} 546