about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Src/hashtable.c43
2 files changed, 43 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index d51b6d12e..4a477ad8a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-09-21  Peter Stephenson  <pws@csr.com>
+
+	* users/14411: Src/hashtable.c: only hash stat-able executable
+	regular files in the command table.
+
 2009-09-19  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
 	* Darel Henman: users/14412: Doc/Zsh/builtins.yo: fix confusions
@@ -12192,5 +12197,5 @@
 
 *****************************************************
 * This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.4783 $
+* $Revision: 1.4784 $
 *****************************************************
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 2eb70c3b0..6d7179412 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -630,20 +630,50 @@ hashdir(char **dirp)
 {
     Cmdnam cn;
     DIR *dir;
-    char *fn;
+    char *fn, *unmetadir, *pathbuf, *pathptr;
+    int dirlen;
 #if defined(_WIN32) || defined(__CYGWIN__)
     char *exe;
 #endif /* _WIN32 || _CYGWIN__ */
 
-    if (isrelative(*dirp) || !(dir = opendir(unmeta(*dirp))))
+    if (isrelative(*dirp))
 	return;
+    unmetadir = unmeta(*dirp);
+    if (!(dir = opendir(unmetadir)))
+	return;
+
+    dirlen = strlen(unmetadir);
+    pathbuf = (char *)zalloc(dirlen + PATH_MAX + 2);
+    sprintf(pathbuf, "%s/", unmetadir);
+    pathptr = pathbuf + dirlen + 1;
 
     while ((fn = zreaddir(dir, 1))) {
 	if (!cmdnamtab->getnode(cmdnamtab, fn)) {
-	    cn = (Cmdnam) zshcalloc(sizeof *cn);
-	    cn->node.flags = 0;
-	    cn->u.name = dirp;
-	    cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
+	    char *fname = ztrdup(fn);
+	    struct stat statbuf;
+	    int add = 0, dummylen;
+
+	    unmetafy(fn, &dummylen);
+	    if (strlen(fn) > PATH_MAX) {
+		/* Too heavy to do all the allocation */
+		add = 1;
+	    } else {
+		strcpy(pathptr, fn);
+		/*
+		 * This is the same test as for the glob qualifier for
+		 * executable plain files.
+		 */
+		if (stat(pathbuf, &statbuf) == 0 &&
+		    S_ISREG(statbuf.st_mode) && (statbuf.st_mode & S_IXUGO))
+		    add = 1;
+	    }
+	    if (add) {
+		cn = (Cmdnam) zshcalloc(sizeof *cn);
+		cn->node.flags = 0;
+		cn->u.name = dirp;
+		cmdnamtab->addnode(cmdnamtab, fname, cn);
+	    } else
+		zsfree(fname);
 	}
 #if defined(_WIN32) || defined(__CYGWIN__)
 	/* Hash foo.exe as foo, since when no real foo exists, foo.exe
@@ -664,6 +694,7 @@ hashdir(char **dirp)
 #endif /* _WIN32 || __CYGWIN__ */
     }
     closedir(dir);
+    zfree(pathbuf, dirlen + PATH_MAX + 2);
 }
 
 /* Go through user's PATH and add everything to *