#
# This is a Solaris specific patch. It was offered to
# upstream, but upstream opted for fix, which sets the
# GLOB_LIMIT at compile time. All details can be found
# here:
#	http://bugs.proftpd.org/show_bug.cgi?id=4082
#
--- a/include/glibc-glob.h
+++ b/include/glibc-glob.h
@@ -85,6 +85,7 @@ extern "C" {
 #define	GLOB_ABORTED	2	/* Read error.  */
 #define	GLOB_NOMATCH	3	/* No matches found.  */
 #define GLOB_NOSYS	4	/* Not implemented.  */
+#define GLOB_LIMIT	5       /* MAX_RESULTS limit reached */
 #ifdef _GNU_SOURCE
 /* Previous versions of this file defined GLOB_ABEND instead of
    GLOB_ABORTED.  Provide a compatibility definition here.  */
--- a/lib/glibc-glob.c
+++ b/lib/glibc-glob.c
@@ -40,6 +40,15 @@ char *alloca ();
 #define MAX_RECURSION 	PR_TUNABLE_GLOBBING_MAX_RECURSION
 #define MAX_RESULTS	PR_TUNABLE_GLOBBING_MAX_MATCHES
 
+unsigned long GlobMaxResults = 0;
+
+static unsigned long get_globmaxresults(void)
+{
+  if (GlobMaxResults > 0)
+    return GlobMaxResults;
+  return MAX_RESULTS;
+}
+
 /* Enable GNU extensions in glob.h.  */
 #ifndef _GNU_SOURCE
 # define _GNU_SOURCE	1
@@ -239,8 +248,6 @@ extern void bcopy ();
 # define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len)
 #endif
 
-static unsigned long nbresults;
-
 #ifndef	__GNU_LIBRARY__
 # ifdef	__GNUC__
 __inline
@@ -1157,7 +1164,6 @@ int
 glob (const char *pattern, int flags, int (*errfunc) __P((const char *, int)),
     glob_t *pglob)
 {
-	nbresults = 0UL;
 	return glob_limited(0U, pattern, flags, errfunc, pglob);
 }
 
@@ -1318,6 +1324,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
   size_t nfound;
   int meta;
   int save;
+  int ret_glob_limit = 0;
 
   meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
   if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
@@ -1428,10 +1435,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 #endif
 		  if (d == NULL)
 		    break;
-		  if (nbresults > MAX_RESULTS) {	
-			  break;
-		  }
-		  nbresults++;	
 		  if (! REAL_DIR_ENTRY (d))
 		    continue;
 
@@ -1463,6 +1466,14 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 		      new->next = names;
 		      names = new;
 		      ++nfound;
+
+		      if (nfound > get_globmaxresults()) {
+                        for (; names != NULL; names = names->next)
+                          free(names->name);
+                        nfound = 0;
+		        ret_glob_limit = 1;
+		        break;
+		      }
 		    }
 		}
 	    }
@@ -1516,6 +1527,9 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
     }
   __set_errno (save);
 
+  if (ret_glob_limit)
+    return GLOB_LIMIT;
+
   return nfound == 0 ? GLOB_NOMATCH : 0;
 
  memory_error:
--- a/modules/mod_core.c
+++ b/modules/mod_core.c
@@ -1048,6 +1048,26 @@ MODRET set_maxconnrate(cmd_rec *cmd) {
   return PR_HANDLED(cmd);
 }
 
+extern unsigned long GlobMaxResults;
+
+MODRET set_globmaxresults(cmd_rec *cmd) {
+  unsigned long max;
+  char *endp;
+
+  CHECK_ARGS(cmd,1);
+  CHECK_CONF(cmd,CONF_ROOT);
+
+  max = strtoul(cmd->argv[1], &endp, 10);
+
+  if ((endp && *endp) || max == 0)
+    CONF_ERROR(cmd, "argument must be greater than 0");
+
+  pr_log_debug(DEBUG1, "setting GlobMaxResults to %lu", max);
+
+  GlobMaxResults = max;
+  return PR_HANDLED(cmd);
+}
+
 MODRET set_timeoutidle(cmd_rec *cmd) {
   int timeout = -1;
   config_rec *c = NULL;
@@ -6941,6 +6961,8 @@ static conftable core_conftab[] = {
   { "From",			add_from,			NULL },
   { "FSCachePolicy",		set_fscachepolicy,		NULL },
   { "FSOptions",		set_fsoptions,			NULL },
+  { "GlobMaxResults",		set_globmaxresults,	        NULL },
+  { "Group",			set_group, 			NULL },
   { "Group",			set_group, 			NULL },
   { "GroupOwner",		add_groupowner,			NULL },
   { "HideFiles",		set_hidefiles,			NULL },
--- a/modules/mod_ls.c
+++ b/modules/mod_ls.c
@@ -2181,6 +2181,8 @@ static int dolist(cmd_rec *cmd, const char *opt, const char *resp_code,
         pr_response_add(R_226, _("Read error during globbing of %s"),
           pr_fs_encode_path(cmd->tmp_pool, arg));
 
+      } else if (a == GLOB_LIMIT) {
+        pr_response_add(R_226, _("Too many files"));
       } else if (a != GLOB_NOMATCH) {
         pr_response_add(R_226, _("Unknown error during globbing of %s"),
           pr_fs_encode_path(cmd->tmp_pool, arg));
@@ -3146,7 +3148,10 @@ MODRET ls_nlst(cmd_rec *cmd) {
           return PR_HANDLED(cmd);
         }
 
-        pr_response_add_err(R_450, _("No files found"));
+        if (res == GLOB_LIMIT)
+          pr_response_add_err(R_451, _("Too many files"));
+        else
+          pr_response_add_err(R_450, _("No files found"));
 
         pr_cmd_set_errno(cmd, ENOENT);
         errno = ENOENT;
