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.
---
 eclass/cdrom.eclass | 48 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 14 deletions(-)

diff --git a/eclass/cdrom.eclass b/eclass/cdrom.eclass
index 41488d2446c2..de72f15563db 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
+               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 -a cdset <<< "${*}"
+
                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,27 @@ _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. The
+# first person to make this work without an eval wins a cookie.
+_cdrom_glob_match() {
+       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
+               eval "ARRAY=( ${p} )"
+               echo ${ARRAY[0]}
+       )
+}
+
 fi
-- 
2.11.0


Reply via email to