Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Allow globbing with unreadable parent directories
- X-seq: zsh-workers 47822
- From: Devin Hussey <husseydevin@xxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: [PATCH] Allow globbing with unreadable parent directories
- Date: Tue, 12 Jan 2021 22:04:23 -0500
- Archived-at: <https://zsh.org/workers/47822>
- Archived-at: <http://www.zsh.org/sympa/arcsearch_id/zsh-workers/2021-01/CAEtFKssJf-cN_EM%2B%3D5_10seY58jqALV-YH8%2Bz5%2BLm-04v493Nw%40mail.gmail.com>
- List-id: <zsh-workers.zsh.org>
POSIX specifies that when globbing, parent directories only have to be
searchable, not readable.
Previously, globbing using NO_CASE_GLOB would fail if any of the parent
directories in the path were not readable.
This was a major issue primarily affecting Termux, a Linux environment
for Android.
Termux's $HOME is "/data/data/com.termux/files/home", and the issue is
that "/data" and sometimes even "/" are not readable without system/root
permission.
This made every full path glob with NO_CASE_GLOB fail, breaking many
scripts such as the Prezto prompt.
Now, zsh will correctly glob even if the parent directory is not readable,
while respecting the searchable bit.
See:
- https://github.com/sorin-ionescu/prezto/issues/1560
- https://github.com/termux/termux-packages/issues/1894
Signed-off-by: Devin Hussey <husseydevin@xxxxxxxxx>
---
Src/glob.c | 169 ++++++++++++++++++++++++++++-------------------------
1 file changed, 89 insertions(+), 80 deletions(-)
diff --git a/Src/glob.c b/Src/glob.c
index bee890caf..4f5c2cf8b 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -580,100 +580,109 @@ scanner(Complist q, int shortcircuit)
} else {
/* Do pattern matching on current path section. */
char *fn = pathbuf[pathbufcwd] ? unmeta(pathbuf + pathbufcwd) : ".";
- int dirs = !!q->next;
- DIR *lock = opendir(fn);
char *subdirs = NULL;
int subdirlen = 0;
- if (lock == NULL)
+ /* First check for search permission. */
+ if (access(fn, X_OK) != 0)
return;
- while ((fn = zreaddir(lock, 1)) && !errflag) {
- /* prefix and suffix are zle trickery */
- if (!dirs && !colonmod &&
- ((glob_pre && !strpfx(glob_pre, fn))
- || (glob_suf && !strsfx(glob_suf, fn))))
- continue;
- errsfound = errssofar;
- if (pattry(p, fn)) {
- /* if this name matches the pattern... */
- if (pbcwdsav == pathbufcwd &&
- strlen(fn) + pathpos - pathbufcwd >= PATH_MAX) {
- int err;
-
- DPUTS(pathpos == pathbufcwd,
- "BUG: filename longer than PATH_MAX");
- err = lchdir(unmeta(pathbuf + pathbufcwd), &ds, 0);
- if (err == -1)
- break;
- if (err) {
- zerr("current directory lost during glob");
- break;
+
+ /* Then, if we have read permission, try to open the directory. */
+ if (access(fn, R_OK) == 0) {
+ int dirs = !!q->next;
+ DIR *lock = opendir(fn);
+
+ if (lock == NULL)
+ return;
+
+ while ((fn = zreaddir(lock, 1)) && !errflag) {
+ /* prefix and suffix are zle trickery */
+ if (!dirs && !colonmod &&
+ ((glob_pre && !strpfx(glob_pre, fn))
+ || (glob_suf && !strsfx(glob_suf, fn))))
+ continue;
+ errsfound = errssofar;
+ if (pattry(p, fn)) {
+ /* if this name matches the pattern... */
+ if (pbcwdsav == pathbufcwd &&
+ strlen(fn) + pathpos - pathbufcwd >= PATH_MAX) {
+ int err;
+
+ DPUTS(pathpos == pathbufcwd,
+ "BUG: filename longer than PATH_MAX");
+ err = lchdir(unmeta(pathbuf + pathbufcwd), &ds, 0);
+ if (err == -1)
+ break;
+ if (err) {
+ zerr("current directory lost during glob");
+ break;
+ }
+ pathbufcwd = pathpos;
}
- pathbufcwd = pathpos;
- }
- if (dirs) {
- int l;
+ if (dirs) {
+ int l;
- /*
- * If not the last component in the path:
- *
- * If we made an approximation in the new path segment,
- * then it is possible we made too many errors. For
- * example, (ab)#(cb)# will match the directory abcb
- * with one error if allowed to, even though it can
- * match with none. This will stop later parts of the
- * path matching, so we need to check by reducing the
- * maximum number of errors and seeing if the directory
- * still matches. Luckily, this is not a terribly
- * common case, since complex patterns typically occur
- * in the last part of the path which is not affected
- * by this problem.
- */
- if (errsfound > errssofar) {
- forceerrs = errsfound - 1;
- while (forceerrs >= errssofar) {
- errsfound = errssofar;
- if (!pattry(p, fn))
- break;
+ /*
+ * If not the last component in the path:
+ *
+ * If we made an approximation in the new path segment,
+ * then it is possible we made too many errors. For
+ * example, (ab)#(cb)# will match the directory abcb
+ * with one error if allowed to, even though it can
+ * match with none. This will stop later parts of the
+ * path matching, so we need to check by reducing the
+ * maximum number of errors and seeing if the directory
+ * still matches. Luckily, this is not a terribly
+ * common case, since complex patterns typically occur
+ * in the last part of the path which is not affected
+ * by this problem.
+ */
+ if (errsfound > errssofar) {
forceerrs = errsfound - 1;
+ while (forceerrs >= errssofar) {
+ errsfound = errssofar;
+ if (!pattry(p, fn))
+ break;
+ forceerrs = errsfound - 1;
+ }
+ errsfound = forceerrs + 1;
+ forceerrs = -1;
}
- errsfound = forceerrs + 1;
- forceerrs = -1;
- }
- if (closure) {
- /* if matching multiple directories */
- struct stat buf;
-
- if (statfullpath(fn, &buf, !q->follow)) {
- if (errno != ENOENT && errno != EINTR &&
- errno != ENOTDIR && !errflag) {
- zwarn("%e: %s", errno, fn);
+ if (closure) {
+ /* if matching multiple directories */
+ struct stat buf;
+
+ if (statfullpath(fn, &buf, !q->follow)) {
+ if (errno != ENOENT && errno != EINTR &&
+ errno != ENOTDIR && !errflag) {
+ zwarn("%e: %s", errno, fn);
+ }
+ continue;
}
- continue;
+ if (!S_ISDIR(buf.st_mode))
+ continue;
+ }
+ l = strlen(fn) + 1;
+ subdirs = hrealloc(subdirs, subdirlen, subdirlen + l
+ + sizeof(int));
+ strcpy(subdirs + subdirlen, fn);
+ subdirlen += l;
+ /* store the count of errors made so far, too */
+ memcpy(subdirs + subdirlen, (char *)&errsfound,
+ sizeof(int));
+ subdirlen += sizeof(int);
+ } else {
+ /* if the last filename component, just add it */
+ insert(fn, 1);
+ if (shortcircuit && shortcircuit == matchct) {
+ closedir(lock);
+ return;
}
- if (!S_ISDIR(buf.st_mode))
- continue;
- }
- l = strlen(fn) + 1;
- subdirs = hrealloc(subdirs, subdirlen, subdirlen + l
- + sizeof(int));
- strcpy(subdirs + subdirlen, fn);
- subdirlen += l;
- /* store the count of errors made so far, too */
- memcpy(subdirs + subdirlen, (char *)&errsfound,
- sizeof(int));
- subdirlen += sizeof(int);
- } else {
- /* if the last filename component, just add it */
- insert(fn, 1);
- if (shortcircuit && shortcircuit == matchct) {
- closedir(lock);
- return;
}
}
}
+ closedir(lock);
}
- closedir(lock);
if (subdirs) {
int oppos = pathpos;
--
2.30.0
Messages sorted by:
Reverse Date,
Date,
Thread,
Author