diff options
author | James Le Cuirot <chewi@gentoo.org> | 2017-04-16 10:36:07 +0100 |
---|---|---|
committer | James Le Cuirot <chewi@gentoo.org> | 2017-04-27 22:41:21 +0100 |
commit | fde70c442fd394bfd912d266b8442d86b76dea1a (patch) | |
tree | 9ce06d8f0b474cec328899d15b1c2c98222f2f3e | |
parent | net-p2p/syncthing: remove myself as maintainer (diff) | |
download | gentoo-fde70c442fd394bfd912d266b8442d86b76dea1a.tar.gz gentoo-fde70c442fd394bfd912d266b8442d86b76dea1a.tar.bz2 gentoo-fde70c442fd394bfd912d266b8442d86b76dea1a.zip |
cdrom.eclass: Detect case-insensitively and handle special characters
This eclass previously used "find -iname" but it only checked the file
case-insensitively and not the directories. There is "find -ipath" but
this does not intelligently skip non-matching paths, making it
slow. Globbing is used here instead.
The : character has always been used to delimit paths given to
cdrom_get_cds, which makes sense because : generally isn't allowed on
CDs, while whitespace is. Despite that, whitespace was not being
handled properly and neither were wildcard characters. Now all special
characters are automatically escaped.
-rw-r--r-- | eclass/cdrom.eclass | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/eclass/cdrom.eclass b/eclass/cdrom.eclass index 41488d2446c2..a51270d33e94 100644 --- a/eclass/cdrom.eclass +++ b/eclass/cdrom.eclass @@ -79,12 +79,13 @@ cdrom_get_cds() { export CDROM_ROOT=${CD_ROOT_1:-${CD_ROOT}} einfo "Found CD #${CDROM_CURRENT_CD} root at ${CDROM_ROOT}" export CDROM_SET=-1 - for f in ${CDROM_CHECK_1//:/ } ; do + local IFS=: + for f in ${CDROM_CHECK_1} ; do + unset IFS ((++CDROM_SET)) - [[ -e ${CDROM_ROOT}/${f} ]] && break + export CDROM_MATCH=$(_cdrom_glob_match "${CDROM_ROOT}" "${f}") + [[ -n ${CDROM_MATCH} ]] && return done - export CDROM_MATCH=${f} - return fi # User didn't help us out so lets make sure they know they can @@ -181,28 +182,24 @@ _cdrom_locate_file_on_cd() { local showedmsg=0 showjolietmsg=0 while [[ -z ${CDROM_ROOT} ]] ; do - local i=0 - local -a cdset=(${*//:/ }) + local i=0 cdset + IFS=: read -r -a cdset -d "" <<< "${*}" + if [[ -n ${CDROM_SET} ]] ; then - cdset=(${cdset[${CDROM_SET}]}) + cdset=( "${cdset[${CDROM_SET}]}" ) fi while [[ -n ${cdset[${i}]} ]] ; do - local dir=$(dirname ${cdset[${i}]}) - local file=$(basename ${cdset[${i}]}) - local point= node= fs= foo= while read point node fs foo ; do [[ " cd9660 iso9660 udf " != *" ${fs} "* ]] && \ ! [[ ${fs} == "subfs" && ",${opts}," == *",fs=cdfss,"* ]] \ && continue point=${point//\040/ } - [[ ! -d ${point}/${dir} ]] && continue - [[ -z $(find "${point}/${dir}" -maxdepth 1 -iname "${file}") ]] \ - && continue + export CDROM_MATCH=$(_cdrom_glob_match "${point}" "${cdset[${i}]}") + [[ -z ${CDROM_MATCH} ]] && continue export CDROM_ROOT=${point} export CDROM_SET=${i} - export CDROM_MATCH=${cdset[${i}]} return done <<< "$(get_mounts)" @@ -243,4 +240,37 @@ _cdrom_locate_file_on_cd() { done } +# @FUNCTION: _cdrom_glob_match +# @USAGE: <root directory> <path> +# @INTERNAL +# @DESCRIPTION: +# Locates the given path ($2) within the given root directory ($1) +# case-insensitively and returns the first actual matching path. This +# eclass previously used "find -iname" but it only checked the file +# case-insensitively and not the directories. There is "find -ipath" +# but this does not intelligently skip non-matching paths, making it +# slow. Case-insensitive matching can only be applied to patterns so +# extended globbing is used to turn regular strings into patterns. All +# special characters are escaped so don't worry about breaking this. +_cdrom_glob_match() { + # The following line turns this: + # foo*foo/bar bar/baz/file.zip + # + # Into this: + # ?(foo\*foo)/?(bar\ bar)/?(baz)/?(file\.zip) + # + # This turns every path component into an escaped extended glob + # pattern to allow case-insensitive matching. Globs cannot span + # directories so each component becomes an individual pattern. + local p=\?\($(sed -e 's:[^A-Za-z0-9/]:\\\0:g' -e 's:/:)/?(:g' <<< "$2" || die)\) + ( + cd "$1" 2>/dev/null || return + shopt -s extglob nocaseglob nullglob || die + # The first person to make this work without an eval wins a + # cookie. It breaks without it when spaces are present. + eval "ARRAY=( ${p} )" + echo ${ARRAY[0]} + ) +} + fi |