Gentoo Archives: gentoo-dev

From: James Le Cuirot <chewi@g.o>
To: gentoo-dev <gentoo-dev@l.g.o>
Cc: James Le Cuirot <chewi@g.o>
Subject: [gentoo-dev] [PATCH 01/14] cdrom.eclass: Detect case-insensitively and handle special characters
Date: Mon, 17 Apr 2017 21:58:04
Message-Id: 20170417215359.30641-2-chewi@gentoo.org
In Reply to: [gentoo-dev] [PATCH] cdrom.eclass: Near rewrite by James Le Cuirot
1 This eclass previously used "find -iname" but it only checked the file
2 case-insensitively and not the directories. There is "find -ipath" but
3 this does not intelligently skip non-matching paths, making it
4 slow. Globbing is used here instead.
5
6 The : character has always been used to delimit paths given to
7 cdrom_get_cds, which makes sense because : generally isn't allowed on
8 CDs, while whitespace is. Despite that, whitespace was not being
9 handled properly and neither were wildcard characters. Now all special
10 characters are automatically escaped.
11 ---
12 eclass/cdrom.eclass | 48 ++++++++++++++++++++++++++++++++++--------------
13 1 file changed, 34 insertions(+), 14 deletions(-)
14
15 diff --git a/eclass/cdrom.eclass b/eclass/cdrom.eclass
16 index 41488d2446c2..de72f15563db 100644
17 --- a/eclass/cdrom.eclass
18 +++ b/eclass/cdrom.eclass
19 @@ -79,12 +79,13 @@ cdrom_get_cds() {
20 export CDROM_ROOT=${CD_ROOT_1:-${CD_ROOT}}
21 einfo "Found CD #${CDROM_CURRENT_CD} root at ${CDROM_ROOT}"
22 export CDROM_SET=-1
23 - for f in ${CDROM_CHECK_1//:/ } ; do
24 + IFS=:
25 + for f in ${CDROM_CHECK_1} ; do
26 + unset IFS
27 ((++CDROM_SET))
28 - [[ -e ${CDROM_ROOT}/${f} ]] && break
29 + export CDROM_MATCH=$(_cdrom_glob_match "${CDROM_ROOT}" "${f}")
30 + [[ -n ${CDROM_MATCH} ]] && return
31 done
32 - export CDROM_MATCH=${f}
33 - return
34 fi
35
36 # User didn't help us out so lets make sure they know they can
37 @@ -181,28 +182,24 @@ _cdrom_locate_file_on_cd() {
38 local showedmsg=0 showjolietmsg=0
39
40 while [[ -z ${CDROM_ROOT} ]] ; do
41 - local i=0
42 - local -a cdset=(${*//:/ })
43 + local i=0 cdset
44 + IFS=: read -a cdset <<< "${*}"
45 +
46 if [[ -n ${CDROM_SET} ]] ; then
47 - cdset=(${cdset[${CDROM_SET}]})
48 + cdset=( "${cdset[${CDROM_SET}]}" )
49 fi
50
51 while [[ -n ${cdset[${i}]} ]] ; do
52 - local dir=$(dirname ${cdset[${i}]})
53 - local file=$(basename ${cdset[${i}]})
54 -
55 local point= node= fs= foo=
56 while read point node fs foo ; do
57 [[ " cd9660 iso9660 udf " != *" ${fs} "* ]] && \
58 ! [[ ${fs} == "subfs" && ",${opts}," == *",fs=cdfss,"* ]] \
59 && continue
60 point=${point//\040/ }
61 - [[ ! -d ${point}/${dir} ]] && continue
62 - [[ -z $(find "${point}/${dir}" -maxdepth 1 -iname "${file}") ]] \
63 - && continue
64 + export CDROM_MATCH=$(_cdrom_glob_match "${point}" "${cdset[${i}]}")
65 + [[ -z ${CDROM_MATCH} ]] && continue
66 export CDROM_ROOT=${point}
67 export CDROM_SET=${i}
68 - export CDROM_MATCH=${cdset[${i}]}
69 return
70 done <<< "$(get_mounts)"
71
72 @@ -243,4 +240,27 @@ _cdrom_locate_file_on_cd() {
73 done
74 }
75
76 +# @FUNCTION: _cdrom_glob_match
77 +# @USAGE: <root directory> <path>
78 +# @INTERNAL
79 +# @DESCRIPTION:
80 +# Locates the given path ($2) within the given root directory ($1)
81 +# case-insensitively and returns the first actual matching path. This
82 +# eclass previously used "find -iname" but it only checked the file
83 +# case-insensitively and not the directories. There is "find -ipath" but
84 +# this does not intelligently skip non-matching paths, making it
85 +# slow. Case-insensitive matching can only be applied to patterns so
86 +# extended globbing is used to turn regular strings into patterns. All
87 +# special characters are escaped so don't worry about breaking this. The
88 +# first person to make this work without an eval wins a cookie.
89 +_cdrom_glob_match() {
90 + local p=\?\($(sed -e 's:[^A-Za-z0-9/]:\\\0:g' -e 's:/:)/?(:g' <<< "$2" || die)\)
91 + (
92 + cd "$1" 2>/dev/null || return
93 + shopt -s extglob nocaseglob nullglob || die
94 + eval "ARRAY=( ${p} )"
95 + echo ${ARRAY[0]}
96 + )
97 +}
98 +
99 fi
100 --
101 2.11.0

Replies