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: dirpatcher.sh old_dir patch_dir new_dir 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# dirpatcher creates new_dir from patch_dir by decompressing and copying 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# files, and using goobspatch to apply binary diffs to files in old_dir. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# dirpatcher performs the inverse operation to dirdiffer. For more details, 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# consult dirdiffer.sh. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Exit codes: 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 0 OK 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1 Unknown failure 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 2 Incorrect number of parameters 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 3 Input directories do not exist or are not directories 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 4 Output directory already exists 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 5 Parent of output directory does not exist or is not a directory 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 6 An input or output directories contains another 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 7 Could not create output directory 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 8 File already exists in output directory 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 9 Found an irregular file (non-directory, file, or symbolic link) in input 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 10 Could not create symbolic link 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 11 Unrecognized file extension 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 12 Attempt to patch a nonexistent or non-regular file 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 13 Patch application failed 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 14 File decompression failed 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 15 File copy failed 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 16 Could not set mode (permissions) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 17 Could not set modification time 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set -eu 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Environment sanitization. Set a known-safe PATH. Clear environment variables 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# that might impact the interpreter's operation. The |bash -p| invocation 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# on the #! line takes the bite out of BASH_ENV, ENV, and SHELLOPTS (among 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# other features), but clearing them here ensures that they won't impact any 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# shell scripts used as utility programs. SHELLOPTS is read-only and can't be 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# unset, only unexported. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export PATH="/usr/bin:/bin:/usr/sbin:/sbin" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unset BASH_ENV CDPATH ENV GLOBIGNORE IFS POSIXLY_CORRECT 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export -n SHELLOPTS 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)shopt -s dotglob nullglob 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# find_tool looks for an executable file named |tool_name|: 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - in the same directory as this script, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - if this script is located in a Chromium source tree, at the expected 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Release output location in the Mac xcodebuild directory, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# - as above, but in the Debug output location 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If found in any of the above locations, the script's path is output. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Otherwise, this function outputs |tool_name| as a fallback, allowing it to 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# be found (or not) by an ordinary ${PATH} search. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)find_tool() { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local tool_name="${1}" 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local script_dir 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) script_dir="$(dirname "${0}")" 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local tool="${script_dir}/${tool_name}" 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${tool}" 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local script_dir_phys 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) script_dir_phys="$(cd "${script_dir}" && pwd -P)" 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${script_dir_phys}" =~ ^(.*)/src/chrome/installer/mac$ ]]; then 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tool="${BASH_REMATCH[1]}/src/xcodebuild/Release/${tool_name}" 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${tool}" 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tool="${BASH_REMATCH[1]}/src/xcodebuild/Debug/${tool_name}" 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${tool}" 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${tool_name}" 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ME="$(basename "${0}")" 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly ME 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GOOBSPATCH="$(find_tool goobspatch)" 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly GOOBSPATCH 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly BUNZIP2="bunzip2" 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly GUNZIP="gunzip" 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XZDEC="$(find_tool xzdec)" 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly XZDEC 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly GBS_SUFFIX='$gbs' 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly BZ2_SUFFIX='$bz2' 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly GZ_SUFFIX='$gz' 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly XZ_SUFFIX='$xz' 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly PLAIN_SUFFIX='$raw' 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)err() { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local error="${1}" 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${ME}: ${error}" >& 2 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)declare -a g_cleanup 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cleanup() { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local status=${?} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap - EXIT 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap '' HUP INT QUIT TERM 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ ${status} -ge 128 ]]; then 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "Caught signal $((${status} - 128))" 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${#g_cleanup[@]}" -gt 0 ]]; then 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -rf "${g_cleanup[@]}" 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit ${status} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)copy_mode_and_time() { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${1}" 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${2}" 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local mode 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mode="$(stat "-f%OMp%OLp" "${patch_file}")" 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! chmod -h "${mode}" "${new_file}"; then 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 16 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ -L "${new_file}" ]]; then 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Symbolic link modification times can't be copied because there's no 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # shell tool that provides direct access to lutimes. Instead, the symbolic 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # link was created with rsync, which already copied the timestamp with 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # lutimes. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! touch -r "${patch_file}" "${new_file}"; then 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 17 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)apply_patch() { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_file="${1}" 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${2}" 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${3}" 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patcher="${4}" 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -L "${old_file}" ]] || ! [[ -f "${old_file}" ]]; then 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "can't patch nonexistent or irregular file ${old_file}" 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 12 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${patcher}" "${old_file}" "${new_file}" "${patch_file}"; then 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "couldn't create ${new_file} by applying ${patch_file} to ${old_file}" 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)decompress_file() { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_file="${1}" 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${2}" 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${3}" 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local decompressor="${4}" 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${decompressor}" -c < "${patch_file}" > "${new_file}"; then 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "couldn't decompress ${patch_file} to ${new_file} with ${decompressor}" 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 14 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)copy_file() { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_file="${1}" 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${2}" 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${3}" 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local extra="${4}" 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! cp "${patch_file}" "${new_file}"; then 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 15 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)patch_file() { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_file="${1}" 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${2}" 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${3}" 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local operation extra strip_length 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${patch_file: -${#GBS_SUFFIX}}" = "${GBS_SUFFIX}" ]]; then 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operation="apply_patch" 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra="${GOOBSPATCH}" 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strip_length=${#GBS_SUFFIX} 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ "${patch_file: -${#BZ2_SUFFIX}}" = "${BZ2_SUFFIX}" ]]; then 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operation="decompress_file" 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra="${BUNZIP2}" 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strip_length=${#BZ2_SUFFIX} 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ "${patch_file: -${#GZ_SUFFIX}}" = "${GZ_SUFFIX}" ]]; then 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operation="decompress_file" 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra="${GUNZIP}" 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strip_length=${#GZ_SUFFIX} 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ "${patch_file: -${#XZ_SUFFIX}}" = "${XZ_SUFFIX}" ]]; then 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operation="decompress_file" 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra="${XZDEC}" 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strip_length=${#XZ_SUFFIX} 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ "${patch_file: -${#PLAIN_SUFFIX}}" = "${PLAIN_SUFFIX}" ]]; then 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operation="copy_file" 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extra="patch" 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strip_length=${#PLAIN_SUFFIX} 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "don't know how to operate on ${patch_file}" 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 11 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_file="${old_file:0:${#old_file} - ${strip_length}}" 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_file="${new_file:0:${#new_file} - ${strip_length}}" 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${new_file}" ]]; then 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "${new_file} already exists" 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 8 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${operation}" "${old_file}" "${patch_file}" "${new_file}" "${extra}" 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copy_mode_and_time "${patch_file}" "${new_file}" 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)patch_symlink() { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file="${1}" 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${2}" 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # local target 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # target="$(readlink "${patch_file}")" 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # ln -s "${target}" "${new_file}" 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Use rsync instead of the above, as it's the only way to preserve the 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # timestamp of a symbolic link using shell tools. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! rsync -lt "${patch_file}" "${new_file}"; then 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 10 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copy_mode_and_time "${patch_file}" "${new_file}" 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)patch_dir() { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_dir="${1}" 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_dir="${2}" 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_dir="${3}" 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! mkdir "${new_dir}"; then 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 7 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_file 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for patch_file in "${patch_dir}/"*; do 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local file="${patch_file:${#patch_dir} + 1}" 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_file="${old_dir}/${file}" 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_file="${new_dir}/${file}" 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${new_file}" ]]; then 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "${new_file} already exists" 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 8 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -L "${patch_file}" ]]; then 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_symlink "${patch_file}" "${new_file}" 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ -d "${patch_file}" ]]; then 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dir "${old_file}" "${patch_file}" "${new_file}" 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif ! [[ -f "${patch_file}" ]]; then 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "can't handle irregular file ${patch_file}" 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 9 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_file "${old_file}" "${patch_file}" "${new_file}" 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copy_mode_and_time "${patch_dir}" "${new_dir}" 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# shell_safe_path ensures that |path| is safe to pass to tools as a 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# command-line argument. If the first character in |path| is "-", "./" is 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# prepended to it. The possibly-modified |path| is output. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)shell_safe_path() { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local path="${1}" 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${path:0:1}" = "-" ]]; then 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "./${path}" 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${path}" 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)dirs_contained() { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local dir1="${1}/" 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local dir2="${2}/" 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${dir1:0:${#dir2}}" = "${dir2}" ]] || 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [[ "${dir2:0:${#dir1}}" = "${dir1}" ]]; then 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)usage() { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "usage: ${ME} old_dir patch_dir new_dir" >& 2 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)main() { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_dir patch_dir new_dir 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_dir="$(shell_safe_path "${1}")" 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dir="$(shell_safe_path "${2}")" 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_dir="$(shell_safe_path "${3}")" 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap cleanup EXIT HUP INT QUIT TERM 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ -d "${old_dir}" ]] || ! [[ -d "${patch_dir}" ]]; then 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "old_dir and patch_dir must exist and be directories" 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 3 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${new_dir}" ]]; then 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "new_dir must not exist" 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 4 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_dir_parent 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_dir_parent="$(dirname "${new_dir}")" 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ -d "${new_dir_parent}" ]]; then 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "new_dir parent directory must exist and be a directory" 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 5 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_dir_phys patch_dir_phys new_dir_parent_phys new_dir_phys 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_dir_phys="$(cd "${old_dir}" && pwd -P)" 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dir_phys="$(cd "${patch_dir}" && pwd -P)" 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_dir_parent_phys="$(cd "${new_dir_parent}" && pwd -P)" 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_dir_phys="${new_dir_parent_phys}/$(basename "${new_dir}")" 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if dirs_contained "${old_dir_phys}" "${patch_dir_phys}" || 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dirs_contained "${old_dir_phys}" "${new_dir_phys}" || 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dirs_contained "${patch_dir_phys}" "${new_dir_phys}"; then 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "directories must not contain one another" 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 6 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_cleanup+=("${new_dir}") 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dir "${old_dir}" "${patch_dir}" "${new_dir}" 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unset g_cleanup[${#g_cleanup[@]}] 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap - EXIT 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if [[ ${#} -ne 3 ]]; then 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 2 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fi 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)main "${@}" 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)exit ${?} 369