commit: 6659c00a580254f68460608b4cdc5df8e057d17c Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Sun Oct 26 09:41:09 2014 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Sun Nov 2 23:15:38 2014 +0000 URL: http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=6659c00a
etc-update: symlink support for bug #485598 This includes numerous logic adjustments that are needed to support protected symlinks. The show_diff function now supports arbitrary file types. For example, a diff between two symlinks looks like this: -SYM: /foo/bar -> baz +SYM: /foo/bar -> blah X-Gentoo-Bug: 485598 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=485598 --- bin/etc-update | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 8 deletions(-) diff --git a/bin/etc-update b/bin/etc-update index 7ac6f0b..1d78e96 100755 --- a/bin/etc-update +++ b/bin/etc-update @@ -51,11 +51,15 @@ do_mv_ln() { local src=${@:$(( $# - 1 )):1} local dst=${@:$(( $# - 0 )):1} - if [[ -L ${dst} ]] ; then #330221 + if [[ ! -L ${src} && -L ${dst} ]] ; then #330221 local lfile=$(readlink "${dst}") [[ ${lfile} == /* ]] || lfile="${dst%/*}/${lfile}" echo " Target is a symlink; replacing ${lfile}" dst=${lfile} + elif [[ -d ${dst} && ! -L ${dst} ]] ; then + # If ${dst} is a directory, do not move the file + # inside of it if this fails. + rmdir "${dst}" || return fi mv "${opts[@]}" "${src}" "${dst}" @@ -115,6 +119,24 @@ scan() { continue 2 fi done + if [[ -L ${file} ]] ; then + if [[ -L ${live_file} && \ + $(readlink "${live_file}") == $(readlink "${file}") ]] + then + rm -f "${file}" + continue + fi + if [[ "${ofile:10}" != "${rfile:10}" ]] || + [[ ${opath} != ${rpath} ]] + then + : $(( ++count )) + echo "${live_file}" > "${TMP}"/files/${count} + fi + echo "${cfg_file}" >> "${TMP}"/files/${count} + ofile="${rfile}" + opath="${rpath}" + continue + fi if [[ ! -f ${file} ]] ; then ${QUIET} || echo "Skipping non-file ${file} ..." continue @@ -124,7 +146,9 @@ scan() { [[ ${opath} != ${rpath} ]] then MATCHES=0 - if [[ ${eu_automerge} == "yes" ]] ; then + if ! [[ -f ${cfg_file} && -f ${live_file} ]] ; then + MATCHES=0 + elif [[ ${eu_automerge} == "yes" ]] ; then if [[ ! -e ${cfg_file} || ! -e ${live_file} ]] ; then MATCHES=0 else @@ -377,17 +401,50 @@ do_file() { show_diff() { clear - local file1=$1 file2=$2 + local file1=$1 file2=$2 files=("$1" "$2") \ + diff_files=() file i tmpdir + + if [[ -L ${file1} && ! -L ${file2} && + -f ${file1} && -f ${file2} ]] ; then + # If a regular file replaces a symlink to a regular file, then + # show the diff between the regular files (bug #330221). + diff_files=("${file1}" "${file2}") + else + for i in 0 1 ; do + if [[ ! -L ${files[$i]} && -f ${files[$i]} ]] ; then + diff_files[$i]=${files[$i]} + continue + fi + [[ -n ${tmpdir} ]] || \ + tmpdir=$(mktemp -d "${TMP}/symdiff-XXX") + diff_files[$i]=${tmpdir}/${i} + if [[ ! -L ${files[$i]} && ! -e ${files[$i]} ]] ; then + echo "/dev/null" > "${diff_files[$i]}" + elif [[ -L ${files[$i]} ]] ; then + echo "SYM: ${file1} -> $(readlink "${files[$i]}")" > \ + "${diff_files[$i]}" + elif [[ -d ${files[$i]} ]] ; then + echo "DIR: ${file1}" > "${diff_files[$i]}" + elif [[ -p ${files[$i]} ]] ; then + echo "FIF: ${file1}" > "${diff_files[$i]}" + else + echo "DEV: ${file1}" > "${diff_files[$i]}" + fi + done + fi + if [[ ${using_editor} == 0 ]] ; then ( echo "Showing differences between ${file1} and ${file2}" - diff_command "${file1}" "${file2}" + diff_command "${diff_files[0]}" "${diff_files[1]}" ) | ${pager} else echo "Beginning of differences between ${file1} and ${file2}" - diff_command "${file1}" "${file2}" + diff_command "${diff_files[0]}" "${diff_files[1]}" echo "End of differences between ${file1} and ${file2}" fi + + [[ -n ${tmpdir} ]] && rm -rf "${tmpdir}" } do_cfg() { @@ -395,14 +452,14 @@ do_cfg() { local ofile=$2 local -i my_input=0 - until (( my_input == -1 )) || [ ! -f "${file}" ] ; do + until (( my_input == -1 )) || [[ ! -f ${file} && ! -L ${file} ]] ; do if [[ "${OVERWRITE_ALL}" == "yes" ]] && ! user_special "${ofile}"; then my_input=1 elif [[ "${DELETE_ALL}" == "yes" ]] && ! user_special "${ofile}"; then my_input=2 else show_diff "${ofile}" "${file}" - if [[ -L ${file} ]] ; then + if [[ -L ${file} && ! -L ${ofile} ]] ; then cat <<-EOF ------------------------------------------------------------- @@ -461,6 +518,19 @@ do_merge() { local ofile="${2}" local mfile="${TMP}/${2}.merged" local -i my_input=0 + + if [[ -L ${file} && -L ${ofile} ]] ; then + echo "Both files are symlinks, so they will not be merged." + return 0 + elif [[ ! -f ${file} ]] ; then + echo "Non-regular file cannot be merged: ${file}" + return 0 + elif [[ ! -f ${ofile} ]] ; then + echo "Non-regular file cannot be merged: ${ofile}" + return 0 + fi + + echo "${file} ${ofile} ${mfile}" if [[ -e ${mfile} ]] ; then @@ -533,9 +603,18 @@ do_distconf() { for (( count = 0; count <= 9999; ++count )) ; do suffix=$(printf ".dist_%04i" ${count}) efile="${ofile}${suffix}" - if [[ ! -f ${efile} ]] ; then + if [[ ! -f ${efile} && ! -L ${efile} ]] ; then mv ${mv_opts} "${file}" "${efile}" break + elif [[ -L ${efile} && -L ${file} ]] ; then + if [[ $(readlink "${efile}") == $(readlink "${file}") ]] ; then + # replace identical copy + mv "${file}" "${efile}" + break + fi + elif [[ -L ${efile} || -L ${file} ]] ; then + # not the same file types + continue elif diff_command "${file}" "${efile}" &> /dev/null; then # replace identical copy mv "${file}" "${efile}"