about summary refs log tree commit diff
path: root/Src/hashtable.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2009-09-21 09:22:20 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2009-09-21 09:22:20 +0000
commite85349fbf793f18211d9280ca80ec8911e05c708 (patch)
tree0dbd4d048a8c2d42761420a1b66a7a924606a21d /Src/hashtable.c
parent418fc360ec2b1357e9e1dc4913b119d26c6e08df (diff)
downloadzsh-e85349fbf793f18211d9280ca80ec8911e05c708.tar.gz
zsh-e85349fbf793f18211d9280ca80ec8911e05c708.tar.xz
zsh-e85349fbf793f18211d9280ca80ec8911e05c708.zip
users/14411: Src/hashtable.c: only hash stat-able executable regular
files as commands
Diffstat (limited to 'Src/hashtable.c')
-rw-r--r--Src/hashtable.c43
1 files changed, 37 insertions, 6 deletions
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 *