about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDaniel Shahaf <danielsh@apache.org>2020-01-13 00:27:24 +0000
committerdana <dana@dana.is>2020-01-15 19:20:33 -0600
commitedc04bd94656a152e17f06188bcef172d62a3ad4 (patch)
tree3f8eb8f9889fe502bd1134ffb1c3a9042b94e0ad
parente899c21863a69226b4e650940c327a3b460023c0 (diff)
downloadzsh-edc04bd94656a152e17f06188bcef172d62a3ad4.tar.gz
zsh-edc04bd94656a152e17f06188bcef172d62a3ad4.tar.xz
zsh-edc04bd94656a152e17f06188bcef172d62a3ad4.zip
45291: A glob with a trailing slash will now match unreadable/unexecutable directories.
-rw-r--r--ChangeLog5
-rw-r--r--Src/glob.c49
-rw-r--r--Test/D02glob.ztst2
3 files changed, 45 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 44b45ce07..d6ad77e3b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2020-01-15  dana  <dana@dana.is>
+
+	* Daniel: 45291: Src/glob.c, Test/D02glob.ztst: A glob with a
+	trailing slash will now match unreadable/unexecutable directories.
+
 2020-01-15  Daniel Shahaf  <danielsh@apache.org>
 
 	* 45288: Completion/Unix/Command/_git: Complete bisect/new as
diff --git a/Src/glob.c b/Src/glob.c
index f67a376b9..bee890caf 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -279,11 +279,11 @@ addpath(char *s, int l)
  * foo/ can be used to reference a non-directory foo.  Returns nonzero if   *
  * the file does not exists.                                                */
 
-/**/
 static int
 statfullpath(const char *s, struct stat *st, int l)
 {
     char buf[PATH_MAX+1];
+    int check_for_being_a_directory = 0;
 
     DPUTS(strlen(s) + !*s + pathpos - pathbufcwd >= PATH_MAX,
 	  "BUG: statfullpath(): pathname too long");
@@ -294,16 +294,44 @@ statfullpath(const char *s, struct stat *st, int l)
 	 * Don't add the '.' if the path so far is empty, since
 	 * then we get bogus empty strings inserted as files.
 	 */
-	buf[pathpos - pathbufcwd] = '.';
-	buf[pathpos - pathbufcwd + 1] = '\0';
-	l = 0;
+	if (st) {
+	    buf[pathpos - pathbufcwd] = '.';
+	    buf[pathpos - pathbufcwd + 1] = '\0';
+	    l = 0;
+	}
+	else {
+	    check_for_being_a_directory = 1;
+	}
     }
     unmetafy(buf, NULL);
-    if (!st) {
+    if (st) {
+	return l ? lstat(buf, st) : stat(buf, st);
+    }
+    else if (check_for_being_a_directory) {
+	struct stat tmp;
+	if (stat(buf, &tmp))
+	    return -1;
+
+	return S_ISDIR(tmp.st_mode) ? 0 : -1;
+    }
+    else {
 	char lbuf[1];
-	return access(buf, F_OK) && (!l || readlink(buf, lbuf, 1) < 0);
+
+	/* If it exists, signal success. */
+	if (access(buf, F_OK) == 0)
+	    return 0;
+
+	/* Would a dangling symlink be good enough? */
+	if (l == 0)
+	    return -1;
+
+	/* Is it a dangling symlink? */
+	if (readlink(buf, lbuf, 1) >= 0)
+	    return 0;
+
+	/* Guess it doesn't exist, then. */
+	return -1;
     }
-    return l ? lstat(buf, st) : stat(buf, st);
 }
 
 /* This may be set by qualifier functions to an array of strings to insert
@@ -327,11 +355,13 @@ insert(char *s, int checked)
     if (gf_listtypes || gf_markdirs) {
 	/* Add the type marker to the end of the filename */
 	mode_t mode;
-	checked = statted = 1;
 	if (statfullpath(s, &buf, 1)) {
 	    unqueue_signals();
 	    return;
 	}
+	else {
+	    checked = statted = 1;
+	}
 	mode = buf.st_mode;
 	if (gf_follow) {
 	    if (!S_ISLNK(mode) || statfullpath(s, &buf2, 0))
@@ -387,11 +417,10 @@ insert(char *s, int checked)
 	    qn = qn->next;
 	}
     } else if (!checked) {
-	if (statfullpath(s, &buf, 1)) {
+	if (statfullpath(s, NULL, 1)) {
 	    unqueue_signals();
 	    return;
 	}
-	statted = 1;
 	news = dyncat(pathbuf, news);
     } else
 	news = dyncat(pathbuf, news);
diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index 3d7df94c9..b8946c5b1 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -734,7 +734,7 @@
  mkdir -m 444 glob.tmp/secret-d444
  for 1 in 000 111 444 ; do ln -s secret-d$1 glob.tmp/secret-s$1; done
  print -rC 2 -- glob.tmp/secret-*/ glob.tmp/secret-*(-/)
--f:unreadable directories can be globbed (users/24619, users/24626)
+0:unreadable directories can be globbed (users/24619, users/24626)
 >glob.tmp/secret-d000/  glob.tmp/secret-d000
 >glob.tmp/secret-d111/  glob.tmp/secret-d111
 >glob.tmp/secret-d444/  glob.tmp/secret-d444