summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Le Cuirot <chewi@gentoo.org>2017-04-16 10:36:07 +0100
committerJames Le Cuirot <chewi@gentoo.org>2017-04-27 22:41:21 +0100
commitfde70c442fd394bfd912d266b8442d86b76dea1a (patch)
tree9ce06d8f0b474cec328899d15b1c2c98222f2f3e /eclass/cdrom.eclass
parentnet-p2p/syncthing: remove myself as maintainer (diff)
downloadgentoo-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.
Diffstat (limited to 'eclass/cdrom.eclass')
-rw-r--r--eclass/cdrom.eclass58
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