Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [Bug] Strange Globing Behaviour when used with sudo
Do we need to fix (or workaround) this problem, given that
very basic commands like "ls" are also broken on macOS?
> 2018/06/03 03:17, Daniel Tameling <tamelingdaniel@xxxxxxxxx> wrote:
>
> $ sudo zsh -c 'echo */../
> file/../
Thanks.
If we really need to workaround this bug, probably the simplest way
would be not to add a file to pathbuf as in the patch below.
I couldn't put all the patch within a single "#ifdef __APPLE__" because
the return value of addpath() is changed to int.
> Btw:
> I noticed bash manages to trigger the ls error message when zsh
> outputs "no matches found"
> $ bash -c 'ls */..'
> ls: cannot access '*/..': No such file or directory
Try 'setopt no_nomatch'. See the option NOMATCH in zshoptions(1).
diff --git a/Src/glob.c b/Src/glob.c
index 66a95329f..a36d76ac1 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -259,11 +259,28 @@ struct complist {
/* Add a component to pathbuf: This keeps track of how *
* far we are into a file name, since each path component *
* must be matched separately. */
+#ifdef __APPLE__
+#define BROKEN_STAT
+/*
+ * Workaround for broken stat()/lstat()/access() on macOS.
+ * If called by root, these syscalls mistakenly returns success for paths
+ * like "foo/bar/.", "foo/bar/..", "foo/bar/../" etc. even if bar is a file.
+ * This causes statfullpath() to also succeed for these paths.
+ * To workaround this problem, we do not add s to pathbuf if it is not a
+ * directory and return -1 instead.
+ *
+ * On systems other than macOS, always add s to pathbuf and return 0.
+ */
+#endif
/**/
-static void
+static int
addpath(char *s, int l)
{
+#ifdef BROKEN_STAT
+ struct stat stbuf;
+ int oppos = pathpos;
+#endif
DPUTS(!pathbuf, "BUG: pathbuf not initialised");
while (pathpos + l + 1 >= pathbufsz)
pathbuf = zrealloc(pathbuf, pathbufsz *= 2);
@@ -271,6 +288,14 @@ addpath(char *s, int l)
pathbuf[pathpos++] = *s++;
pathbuf[pathpos++] = '/';
pathbuf[pathpos] = '\0';
+#ifdef BROKEN_STAT
+ if (stat(unmeta(pathbuf), &stbuf) || !S_ISDIR(stbuf.st_mode)) {
+ pathbuf[pathpos = oppos] = '\0';
+ return -1;
+ }
+ else
+#endif
+ return 0;
}
/* stat the filename s appended to pathbuf. l should be true for lstat, *
@@ -531,9 +556,12 @@ scanner(Complist q, int shortcircuit)
sr.st_dev != sc.st_dev);
}
}
- if (add) {
- addpath(str, l);
- if (!closure || !statfullpath("", NULL, 1)) {
+ if (add && !addpath(str,l)) {
+ if (!closure
+#ifndef BROKEN_STAT
+ || !statfullpath("", NULL, 1)
+#endif
+ ) {
scanner((q->closure) ? q : q->next, shortcircuit);
if (shortcircuit && shortcircuit == matchct)
return;
@@ -650,15 +678,17 @@ scanner(Complist q, int shortcircuit)
for (fn = subdirs; fn < subdirs+subdirlen; ) {
int l = strlen(fn);
- addpath(fn, l);
+ int fn_is_dir = !addpath(fn, l);
fn += l + 1;
memcpy((char *)&errsfound, fn, sizeof(int));
fn += sizeof(int);
- /* scan next level */
- scanner((q->closure) ? q : q->next, shortcircuit);
- if (shortcircuit && shortcircuit == matchct)
- return;
- pathbuf[pathpos = oppos] = '\0';
+ if (fn_is_dir) {
+ /* scan next level */
+ scanner((q->closure) ? q : q->next, shortcircuit);
+ if (shortcircuit && shortcircuit == matchct)
+ return;
+ pathbuf[pathpos = oppos] = '\0';
+ }
}
hrealloc(subdirs, subdirlen, 0);
}
Messages sorted by:
Reverse Date,
Date,
Thread,
Author