On pon, 2017-04-17 at 22:53 +0100, James Le Cuirot wrote:
> 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=:
'local', please.
> + 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 <<< "${*}"
-r to avoid handling escapes; -d '' to avoid finishing on newline.
> +
> 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)\)
Explanatory comment needed, i.e. what gets converted into what, and why.
> + (
> + cd "$1" 2>/dev/null || return
> + shopt -s extglob nocaseglob nullglob || die
> + eval "ARRAY=( ${p} )"
> + echo ${ARRAY[0]}
> + )
> +}
> +
> fi
--
Best regards,
Michał Górny
signature.asc
Description: This is a digitally signed message part
