| Index: chrome/tools/build/mac/keystone_install.sh
|
| ===================================================================
|
| --- chrome/tools/build/mac/keystone_install.sh (revision 30708)
|
| +++ chrome/tools/build/mac/keystone_install.sh (working copy)
|
| @@ -22,6 +22,99 @@
|
|
|
| set -e
|
|
|
| +# Returns 0 (true) if the parameter exists, is a symbolic link, and appears
|
| +# writeable on the basis of its POSIX permissions. This is used to determine
|
| +# writeability like test's -w primary, but -w resolves symbolic links and this
|
| +# function does not.
|
| +function is_writeable_symlink() {
|
| + SYMLINK=${1}
|
| + LINKMODE=$(stat -f %Sp "${SYMLINK}" 2> /dev/null || true)
|
| + if [ -z "${LINKMODE}" ] || [ "${LINKMODE:0:1}" != "l" ] ; then
|
| + return 1
|
| + fi
|
| + LINKUSER=$(stat -f %u "${SYMLINK}" 2> /dev/null || true)
|
| + LINKGROUP=$(stat -f %g "${SYMLINK}" 2> /dev/null || true)
|
| + if [ -z "${LINKUSER}" ] || [ -z "${LINKGROUP}" ] ; then
|
| + return 1
|
| + fi
|
| +
|
| + # If the users match, check the owner-write bit.
|
| + if [ ${EUID} -eq ${LINKUSER} ] ; then
|
| + if [ "${LINKMODE:2:1}" = "w" ] ; then
|
| + return 0
|
| + fi
|
| + return 1
|
| + fi
|
| +
|
| + # If the file's group matches any of the groups that this process is a
|
| + # member of, check the group-write bit.
|
| + GROUPMATCH=
|
| + for group in ${GROUPS[@]} ; do
|
| + if [ ${group} -eq ${LINKGROUP} ] ; then
|
| + GROUPMATCH=1
|
| + break
|
| + fi
|
| + done
|
| + if [ -n "${GROUPMATCH}" ] ; then
|
| + if [ "${LINKMODE:5:1}" = "w" ] ; then
|
| + return 0
|
| + fi
|
| + return 1
|
| + fi
|
| +
|
| + # Check the other-write bit.
|
| + if [ "${LINKMODE:8:1}" = "w" ] ; then
|
| + return 0
|
| + fi
|
| + return 1
|
| +}
|
| +
|
| +# If SYMLINK exists and is a symbolic link, but is not writeable according to
|
| +# is_writeable_symlink, this function attempts to replace it with a new
|
| +# writeable symbolic link. If FROM does not exist, is not a symbolic link, or
|
| +# is already writeable, this function does nothing. This function always
|
| +# returns 0 (true).
|
| +function ensure_writeable_symlink() {
|
| + SYMLINK=${1}
|
| + if [ -L "${SYMLINK}" ] && ! is_writeable_symlink "${SYMLINK}" ; then
|
| + # If ${SYMLINK} refers to a directory, doing this naively might result in
|
| + # the new link being placed in that directory, instead of replacing the
|
| + # existing link. ln -fhs is supposed to handle this case, but it does so
|
| + # by unlinking (removing) the existing symbolic link before creating a new
|
| + # one. That leaves a small window during which the symbolic link is not
|
| + # present on disk at all.
|
| + #
|
| + # To avoid that possibility, a new symbolic link is created in a temporary
|
| + # location and then swapped into place with mv. An extra temporary
|
| + # directory is used to convince mv to replace the symbolic link: again, if
|
| + # the existing link refers to a directory, "mv newlink oldlink" will
|
| + # actually leave oldlink alone and place newlink into the directory.
|
| + # "mv newlink dirname(oldlink)" works as expected, but in order to replace
|
| + # oldlink, newlink must have the same basename, hence the temporary
|
| + # directory.
|
| +
|
| + TARGET=$(readlink "${SYMLINK}" 2> /dev/null || true)
|
| + if [ -z "${TARGET}" ] ; then
|
| + return 0
|
| + fi
|
| +
|
| + SYMLINKDIR=$(dirname "${SYMLINK}")
|
| + TEMPLINKDIR="${SYMLINKDIR}/.symlink_temp.${$}.${RANDOM}"
|
| + TEMPLINK="${TEMPLINKDIR}/$(basename "${SYMLINK}")"
|
| +
|
| + # Don't bail out here if this fails. Something else will probably fail.
|
| + # Let it, it'll probably be easier to understand that failure than this
|
| + # one.
|
| + (mkdir "${TEMPLINKDIR}" && \
|
| + ln -fhs "${TARGET}" "${TEMPLINK}" && \
|
| + chmod -h 755 "${TEMPLINK}" && \
|
| + mv -f "${TEMPLINK}" "${SYMLINKDIR}") || true
|
| + rm -rf "${TEMPLINKDIR}"
|
| + fi
|
| +
|
| + return 0
|
| +}
|
| +
|
| # The argument should be the disk image path. Make sure it exists.
|
| if [ $# -lt 1 ] || [ ! -d "${1}" ]; then
|
| exit 10
|
| @@ -78,17 +171,65 @@
|
| NEEDS_TOUCH=1
|
| fi
|
|
|
| +# In some very weird and rare cases, it is possible to wind up with a user
|
| +# installation that contains symbolic links that the user does not have write
|
| +# permission over. More on how that might happen later.
|
| +#
|
| +# If a weird and rare case like this is observed, rsync will exit with an
|
| +# error when attempting to update the times on these symbolic links. rsync
|
| +# may not be intelligent enough to try creating a new symbolic link in these
|
| +# cases, but this script can be.
|
| +#
|
| +# This fix-up is not necessary when running as root, because root will always
|
| +# be able to write everything needed.
|
| +#
|
| +# The problem occurs when an administrative user first drag-installs the
|
| +# application to /Applications, resulting in the program's user being set to
|
| +# the user's own ID. If, subsequently, a .pkg package is installed over that,
|
| +# the existing directory ownership will be preserved, but file ownership will
|
| +# be changed to whateer is specified by the package, typically root. This
|
| +# applies to symbolic links as well. On a subsequent update, rsync will
|
| +# be able to copy the new files into place, because the user still has
|
| +# permission to write to the directories. If the symbolic link targets are
|
| +# not changing, though, rsync will not replace them, and they will remain
|
| +# owned by root. The user will not have permission to update the time on
|
| +# the symbolic links, resulting in an rsync error.
|
| +if [ ${EUID} -ne 0 ] ; then
|
| + # This step isn't critical.
|
| + set +e
|
| +
|
| + # Reset ${IFS} to deal with spaces in the for loop by not breaking the
|
| + # list up when they're encountered.
|
| + IFS_OLD="${IFS}"
|
| + IFS=$(printf '\n\t')
|
| +
|
| + # Only consider symbolic links in ${SRC}. If there are any other links in
|
| + # ${DEST} not present in ${SRC}, rsync will delete them as needed later.
|
| + LINKS=$(cd "${SRC}" && find . -type l)
|
| +
|
| + for link in ${LINKS} ; do
|
| + # ${link} is relative to ${SRC}. Prepending ${DEST} looks for the same
|
| + # link already on disk.
|
| + DESTLINK="${DEST}/${link}"
|
| + ensure_writeable_symlink "${DESTLINK}"
|
| + done
|
| +
|
| + # Go back to how things were.
|
| + IFS="${IFS_OLD}"
|
| + set -e
|
| +fi
|
| +
|
| # Don't use rsync -a, because -a expands to -rlptgoD. -g and -o copy owners
|
| # and groups, respectively, from the source, and that is undesirable in this
|
| # case. -D copies devices and special files; copying devices only works
|
| # when running as root, so for consistency between privileged and unprivileged
|
| # operation, this option is omitted as well.
|
| -# -c, --checksum skip based on checksum, not mod-time & size
|
| +# -I, --ignore-times don't skip files that match in size and mod-time
|
| # -l, --links copy symlinks as symlinks
|
| # -r, --recursive recurse into directories
|
| # -p, --perms preserve permissions
|
| # -t, --times preserve times
|
| -RSYNC_FLAGS="-clprt"
|
| +RSYNC_FLAGS="-Ilprt"
|
|
|
| # By copying to ${DEST}, the existing application name will be preserved, even
|
| # if the user has renamed the application on disk. Respecting the user's
|
|
|