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
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.
-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