--- /dev/null
+diff -urN proftpd-1.2.1/Make.rules.in proftpd-1.2/Make.rules.in
+--- proftpd-1.2.1/Make.rules.in Thu Feb 22 05:51:10 2001
++++ proftpd-1.2/Make.rules.in Mon Mar 19 23:11:35 2001
+@@ -63,7 +63,7 @@
+ src/support.o src/inet.o src/log.o src/io.o src/ident.o \
+ src/data.o src/modules.o src/auth.o src/fs.o
+
+-LIB_OBJS=getopt.o getopt1.o pr_fnmatch.o strsep.o vsnprintf.o glob.o pwgrent.o
++LIB_OBJS=getopt.o getopt1.o pr_fnmatch.o strsep.o vsnprintf.o glibc-glob.o pwgrent.o
+
+ FTPCOUNT_OBJS=ftpcount.o pool.o log.o utils.o
+ BUILD_FTPCOUNT_OBJS=src/ftpcount.o src/pool.o src/log.o src/utils.o
+diff -urN proftpd-1.2.1/acconfig.h proftpd-1.2/acconfig.h
+--- proftpd-1.2.1/acconfig.h Wed Feb 14 05:12:48 2001
++++ proftpd-1.2/acconfig.h Mon Mar 19 23:11:35 2001
+@@ -18,12 +18,6 @@
+ /* Define if you have BSD sendfile() semantics */
+ #undef HAVE_BSD_SENDFILE
+
+-/* Define if you have the <glob.h> header file. */
+-#undef HAVE_GLOB_H
+-
+-/* Define if your <glob.h> defines GLOB_PERIOD macro. */
+-#undef HAVE_GLOB_PERIOD
+-
+ /* Define if you have Linux sendfile() semantics */
+ #undef HAVE_LINUX_SENDFILE
+
+diff -urN proftpd-1.2.1/config.h.in proftpd-1.2/config.h.in
+--- proftpd-1.2.1/config.h.in Fri Feb 23 03:47:26 2001
++++ proftpd-1.2/config.h.in Mon Mar 19 23:11:35 2001
+@@ -19,12 +19,6 @@
+ /* Define if you have BSD sendfile() semantics */
+ #undef HAVE_BSD_SENDFILE
+
+-/* Define if you have the <glob.h> header file. */
+-#undef HAVE_GLOB_H
+-
+-/* Define if your <glob.h> defines GLOB_PERIOD macro. */
+-#undef HAVE_GLOB_PERIOD
+-
+ /* Define if you have Linux sendfile() semantics */
+ #undef HAVE_LINUX_SENDFILE
+
+@@ -210,9 +204,6 @@
+ /* Define if you have the gettimeofday function. */
+ #undef HAVE_GETTIMEOFDAY
+
+-/* Define if you have the glob function. */
+-#undef HAVE_GLOB
+-
+ /* Define if you have the inet_aton function. */
+ #undef HAVE_INET_ATON
+
+@@ -320,6 +311,9 @@
+
+ /* Define if you have the <libutil.h> header file. */
+ #undef HAVE_LIBUTIL_H
++
++/* Define if you have the <limits.h> header file. */
++#undef HAVE_LIMITS_H
+
+ /* Define if you have the <memory.h> header file. */
+ #undef HAVE_MEMORY_H
+diff -urN proftpd-1.2.1/configure.in proftpd-1.2/configure.in
+--- proftpd-1.2.1/configure.in Thu Mar 1 04:18:43 2001
++++ proftpd-1.2/configure.in Mon Mar 19 23:11:35 2001
+@@ -300,14 +300,13 @@
+
+ fi
+
+-AC_CHECK_HEADERS(ctype.h getopt.h crypt.h bstring.h strings.h)
++AC_CHECK_HEADERS(ctype.h getopt.h crypt.h bstring.h strings.h limits.h)
+ AC_CHECK_HEADERS(sys/types.h sys/param.h sys/file.h sys/uio.h)
+ AC_CHECK_HEADERS(netdb.h netinet/in.h netinet/tcp.h arpa/inet.h sys/stat.h)
+ AC_CHECK_HEADERS(errno.h sys/socket.h sys/termios.h sys/termio.h)
+ AC_CHECK_HEADERS(sys/statvfs.h sys/vfs.h sys/select.h)
+ AC_CHECK_HEADERS(utmpx.h)
+ AC_CHECK_HEADERS(regex.h)
+-AC_CHECK_HEADER(glob.h,have_glob_h="yes",)
+ AC_CHECK_HEADER(syslog.h,have_syslog_h="yes",)
+
+ dnl Checks for typedefs, structures, and compiler characteristics.
+@@ -362,35 +361,6 @@
+ fi
+ fi
+
+-if test "$have_glob_h" = "yes"; then
+- dnl See if we have GLOB_PERIOD
+- AC_CACHE_CHECK(whether your glob.h defines GLOB_PERIOD,
+- pr_cv_header_glob_period,
+- AC_EGREP_CPP(yes,[
+-#include <glob.h>
+-#ifdef GLOB_PERIOD
+- yes
+-#endif
+- ],pr_cv_header_glob_period="yes",pr_cv_header_glob_period="no"))
+-
+- dnl See if we have GLOB_ALTDIRFUNC
+- if test "$pr_cv_header_glob_period" = "yes"; then
+- AC_CACHE_CHECK(whether your glob.h defines GLOB_ALTDIRFUNC,
+- pr_cv_header_glob_altdirfunc,
+- AC_EGREP_CPP(yes,[
+-#include <glob.h>
+-#ifdef GLOB_ALTDIRFUNC
+- yes
+-#endif
+- ],pr_cv_header_glob_altdirfunc="yes",pr_cv_header_glob_altdirfunc="no"))
+-
+- if test "$pr_cv_header_glob_altdirfunc" = "yes"; then
+- AC_DEFINE(HAVE_GLOB_H)
+- AC_DEFINE(HAVE_GLOB_PERIOD)
+- fi
+- fi
+-fi
+-
+ dnl See if various LOG_ macros are defined
+ if test "$have_syslog_h" = "yes"; then
+ AC_DEFINE(HAVE_SYSLOG_H)
+@@ -538,13 +508,6 @@
+ AC_DEFINE(HAVE_BSD_SENDFILE)
+ ;;
+ esac
+-fi
+-
+-dnl Only check for glob if we have glob.h, GLOB_PERIOD, and GLOB_ALTDIRFUNC
+-if test "$have_glob_h" = "yes" && \
+- test "$pr_cv_header_glob_period" = "yes" && \
+- test "$pr_cv_header_glob_altdirfunc" = "yes"; then
+- AC_CHECK_FUNCS(glob)
+ fi
+
+ dnl Check for various argv[] replacing functions on various OSs
+diff -urN proftpd-1.2.1/include/conf.h proftpd-1.2/include/conf.h
+--- proftpd-1.2.1/include/conf.h Sun Aug 13 17:19:39 2000
++++ proftpd-1.2/include/conf.h Mon Mar 19 23:11:35 2001
+@@ -38,7 +38,7 @@
+ */
+
+ /* Generic configuration and standard header file includes.
+- * $Id$
++ * $Id$
+ */
+
+ #ifndef __CONF_H
+@@ -156,10 +156,6 @@
+
+ #ifdef HAVE_SYSLOG_H
+ # include <syslog.h>
+-#endif
+-
+-#ifdef HAVE_GLOB
+-# include <glob.h>
+ #endif
+
+ #ifdef HAVE_DIRENT_H
+diff -urN proftpd-1.2.1/include/glibc-glob.h proftpd-1.2/include/glibc-glob.h
+--- proftpd-1.2.1/include/glibc-glob.h Thu Jan 1 01:00:00 1970
++++ proftpd-1.2/include/glibc-glob.h Thu Mar 22 14:43:36 2001
+@@ -0,0 +1,221 @@
++/* Copyright (C) 1991,92,95,96,97,98,2000,2001 Free Software Foundation, Inc.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the GNU C Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA. */
++
++#ifndef _GLOB_H
++#define _GLOB_H 1
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#undef __ptr_t
++#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
++# if !defined __GLIBC__ || !defined __P
++# undef __P
++# undef __PMT
++# define __P(protos) protos
++# define __PMT(protos) protos
++# if !defined __GNUC__ || __GNUC__ < 2
++# undef __const
++# define __const const
++# endif
++# endif
++# define __ptr_t void *
++#else /* Not C++ or ANSI C. */
++# undef __P
++# undef __PMT
++# define __P(protos) ()
++# define __PMT(protos) ()
++# undef __const
++# define __const
++# define __ptr_t char *
++#endif /* C++ or ANSI C. */
++
++/* We need `size_t' for the following definitions. */
++#ifndef __size_t
++# if defined __GNUC__ && __GNUC__ >= 2
++typedef __SIZE_TYPE__ __size_t;
++# ifdef _XOPEN_SOURCE
++typedef __SIZE_TYPE__ size_t;
++# endif
++# else
++/* This is a guess. */
++typedef unsigned long int __size_t;
++# endif
++#else
++/* The GNU CC stddef.h version defines __size_t as empty. We need a real
++ definition. */
++# undef __size_t
++# define __size_t size_t
++#endif
++
++/* Bits set in the FLAGS argument to `glob'. */
++#define GLOB_ERR (1 << 0)/* Return on read errors. */
++#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
++#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
++#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
++#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
++#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
++#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
++#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */
++
++#if (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _BSD_SOURCE \
++ || defined _GNU_SOURCE)
++# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
++# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
++# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
++# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
++# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
++# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
++# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error
++ if the user name is not available. */
++# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
++ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
++ GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
++ GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
++#else
++# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
++ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
++ GLOB_PERIOD)
++#endif
++
++/* Error returns from `glob'. */
++#define GLOB_NOSPACE 1 /* Ran out of memory. */
++#define GLOB_ABORTED 2 /* Read error. */
++#define GLOB_NOMATCH 3 /* No matches found. */
++#define GLOB_NOSYS 4 /* Not implemented. */
++#ifdef _GNU_SOURCE
++/* Previous versions of this file defined GLOB_ABEND instead of
++ GLOB_ABORTED. Provide a compatibility definition here. */
++# define GLOB_ABEND GLOB_ABORTED
++#endif
++
++/* Structure describing a globbing run. */
++#if !defined _AMIGA && !defined VMS /* Buggy compiler. */
++# ifdef _GNU_SOURCE
++struct stat;
++# endif
++#endif
++typedef struct
++ {
++ __size_t gl_pathc; /* Count of paths matched by the pattern. */
++ char **gl_pathv; /* List of matched pathnames. */
++ __size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
++ int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
++
++ /* If the GLOB_ALTDIRFUNC flag is set, the following functions
++ are used instead of the normal file access functions. */
++ void (*gl_closedir) __PMT ((void *));
++#ifdef _GNU_SOURCE
++ struct dirent *(*gl_readdir) __PMT ((void *));
++#else
++ void *(*gl_readdir) __PMT ((void *));
++#endif
++ __ptr_t (*gl_opendir) __PMT ((__const char *));
++#ifdef _GNU_SOURCE
++ int (*gl_lstat) __PMT ((__const char *,
++ struct stat *));
++ int (*gl_stat) __PMT ((__const char *, struct stat *));
++#else
++ int (*gl_lstat) __PMT ((__const char *, void *));
++ int (*gl_stat) __PMT ((__const char *, void *));
++#endif
++ } glob_t;
++
++#ifdef _LARGEFILE64_SOURCE
++# ifdef _GNU_SOURCE
++struct stat64;
++# endif
++typedef struct
++ {
++ __size_t gl_pathc;
++ char **gl_pathv;
++ __size_t gl_offs;
++ int gl_flags;
++
++ /* If the GLOB_ALTDIRFUNC flag is set, the following functions
++ are used instead of the normal file access functions. */
++ void (*gl_closedir) __PMT ((void *));
++# ifdef _GNU_SOURCE
++ struct dirent64 *(*gl_readdir) __PMT ((void *));
++# else
++ void *(*gl_readdir) __PMT ((void *));
++# endif
++ __ptr_t (*gl_opendir) __PMT ((__const char *));
++# ifdef _GNU_SOURCE
++ int (*gl_lstat) __PMT ((__const char *,
++ struct stat64 *));
++ int (*gl_stat) __PMT ((__const char *,
++ struct stat64 *));
++# else
++ int (*gl_lstat) __PMT ((__const char *, void *));
++ int (*gl_stat) __PMT ((__const char *, void *));
++# endif
++ } glob64_t;
++#endif
++
++#if _FILE_OFFSET_BITS == 64 && __GNUC__ < 2
++# define glob glob64
++# define globfree globfree64
++#endif
++
++/* Do glob searching for PATTERN, placing results in PGLOB.
++ The bits defined above may be set in FLAGS.
++ If a directory cannot be opened or read and ERRFUNC is not nil,
++ it is called with the pathname that caused the error, and the
++ `errno' value from the failing call; if it returns non-zero
++ `glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
++ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
++ Otherwise, `glob' returns zero. */
++#if _FILE_OFFSET_BITS != 64 || __GNUC__ < 2
++extern int glob __P ((__const char *__pattern, int __flags,
++ int (*__errfunc) (__const char *, int),
++ glob_t *__pglob));
++
++/* Free storage allocated in PGLOB by a previous `glob' call. */
++extern void globfree __P ((glob_t *__pglob));
++#else
++extern int glob __P ((__const char *__pattern, int __flags,
++ int (*__errfunc) (__const char *, int),
++ glob_t *__pglob));
++
++extern void globfree __P ((glob_t *__pglob));
++#endif
++
++#ifdef _LARGEFILE64_SOURCE
++extern int glob64 __P ((__const char *__pattern, int __flags,
++ int (*__errfunc) (__const char *, int),
++ glob64_t *__pglob));
++
++extern void globfree64 __P ((glob64_t *__pglob));
++#endif
++
++
++#ifdef _GNU_SOURCE
++/* Return nonzero if PATTERN contains any metacharacters.
++ Metacharacters can be quoted with backslashes if QUOTE is nonzero.
++
++ This function is not part of the interface specified by POSIX.2
++ but several programs want to use it. */
++extern int glob_pattern_p __P ((__const char *__pattern, int __quote));
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* glob.h */
+diff -urN proftpd-1.2.1/include/libsupp.h proftpd-1.2/include/libsupp.h
+--- proftpd-1.2.1/include/libsupp.h Wed Aug 2 07:25:24 2000
++++ proftpd-1.2/include/libsupp.h Mon Mar 19 23:11:35 2001
+@@ -23,66 +23,10 @@
+
+ /* ProFTPD support library definitions.
+ *
+- * $Id$
++ * $Id$
+ */
+
+-#if !defined HAVE_GLOB && !defined __PROFTPD_SUPPORT_LIBRARY
+-
+-#ifndef __P
+-#define __P(x) x
+-#endif
+-
+-/* Bits set in the FLAGS argument to `glob'. */
+-#define GLOB_ERR (1 << 0)/* Return on read errors. */
+-#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
+-#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
+-#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
+-#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
+-#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
+-#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
+-#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */
+-# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
+-# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
+-# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
+-# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
+-# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
+-# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
+-# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+- GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+- GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
+- GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR)
+-#define GLOB_NOSPACE 1 /* Ran out of memory. */
+-#define GLOB_ABORTED 2 /* Read error. */
+-#define GLOB_NOMATCH 3 /* No matches found. */
+-
+-/* Structure describing a globbing run. */
+-#if !defined _AMIGA && !defined VMS /* Buggy compiler. */
+-struct stat;
+-#endif
+-typedef struct
+- {
+- int gl_pathc; /* Count of paths matched by the pattern. */
+- char **gl_pathv; /* List of matched pathnames. */
+- int gl_offs; /* Slots to reserve in `gl_pathv'. */
+- int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
+-
+- /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+- are used instead of the normal file access functions. */
+- void (*gl_closedir) __P ((void *));
+- struct dirent *(*gl_readdir) __P ((void *));
+- void *(*gl_opendir) __P ((const char *));
+- int (*gl_lstat) __P ((const char *, struct stat *));
+- int (*gl_stat) __P ((const char *, struct stat *));
+- } glob_t;
+-
+-extern int glob (const char *__pattern, int __flags,
+- int (*__errfunc)(const char *, int),
+- glob_t *__pglob);
+-extern void globfree (glob_t *__pglob);
+-extern int __glob_pattern_p (const char *__pattern, int __quote);
+-extern int glob_pattern_p (const char *__pattern, int __quote);
+-
+-#endif /* HAVE_GLOB */
++#include <glibc-glob.h>
+
+ /* Bits set in the FLAGS argument to `pr_fnmatch'. */
+ #define PR_FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+diff -urN proftpd-1.2.1/lib/Makefile.in proftpd-1.2/lib/Makefile.in
+--- proftpd-1.2.1/lib/Makefile.in Thu Mar 1 17:02:10 2001
++++ proftpd-1.2/lib/Makefile.in Sun Feb 25 00:09:19 2001
+@@ -32,15 +32,15 @@
+ # Dependancies written below
+ # DO NOT DELETE
+
++pr_fnmatch.o: ../include/conf.h ../include/version.h ../config.h
++pr_fnmatch.o: ../include/default_paths.h ../include/options.h
++pr_fnmatch.o: ../include/libsupp.h pr_fnmatch_loop.c
+ getopt.o: ../include/conf.h ../include/version.h ../config.h
+ getopt.o: ../include/default_paths.h ../include/options.h getopt.h
+ getopt1.o: ../include/conf.h ../include/version.h ../config.h
+ getopt1.o: ../include/default_paths.h ../include/options.h getopt.h
+ glob.o: ../include/conf.h ../include/version.h ../config.h
+ glob.o: ../include/default_paths.h ../include/options.h ../include/libsupp.h
+-pr_fnmatch.o: ../include/conf.h ../include/version.h ../config.h
+-pr_fnmatch.o: ../include/default_paths.h ../include/options.h
+-pr_fnmatch.o: ../include/libsupp.h pr_fnmatch_loop.c
+ pwgrent.o: ../include/conf.h ../include/version.h ../config.h
+ pwgrent.o: ../include/default_paths.h ../include/options.h
+ strsep.o: ../include/conf.h ../include/version.h ../config.h
+diff -urN proftpd-1.2.1/lib/glibc-glob.c proftpd-1.2/lib/glibc-glob.c
+--- proftpd-1.2.1/lib/glibc-glob.c Thu Jan 1 01:00:00 1970
++++ proftpd-1.2/lib/glibc-glob.c Sat Mar 17 21:34:31 2001
+@@ -0,0 +1,1544 @@
++/* Copyright (C) 1991-1999, 2000, 2001 Free Software Foundation, Inc.
++
++ This library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ This library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA. */
++
++/* AIX requires this to be the first thing in the file. */
++
++#if defined _AIX && !defined __GNUC__
++ #pragma alloca
++#endif
++
++#include <config.h>
++
++#define MAX_RECURSION 8
++#define MAX_RESULTS 100000UL
++
++/* Enable GNU extensions in glob.h. */
++#ifndef _GNU_SOURCE
++# define _GNU_SOURCE 1
++#endif
++
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++
++/* Outcomment the following line for production quality code. */
++/* #define NDEBUG 1 */
++#include <assert.h>
++
++#include <stdio.h> /* Needed on stupid SunOS for assert. */
++
++
++/* Comment out all this code if we are using the GNU C Library, and are not
++ actually compiling the library itself. This code is part of the GNU C
++ Library, but also included in many other GNU distributions. Compiling
++ and linking in this code is a waste when using the GNU C library
++ (especially if it is a shared library). Rather than having every GNU
++ program understand `configure --with-gnu-libc' and omit the object files,
++ it is simpler to just do this in the source for each such file. */
++
++/* Proftpd modification: always undefine __GNU_LIBRARY__ because we are not
++ * compiling as part of glibc.
++ * jss - 3/17/2001
++ */
++
++#undef __GNU_LIBRARY__
++
++#define GLOB_INTERFACE_VERSION 1
++#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
++# include <gnu-versions.h>
++# if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION
++# define ELIDE_CODE
++# endif
++#endif
++
++#undef ELIDE_CODE
++#define __alloca alloca
++#define __readdir readdir
++
++#ifndef ELIDE_CODE
++#if !defined _LIBC || !defined GLOB_ONLY_P
++
++#if defined STDC_HEADERS || defined __GNU_LIBRARY__
++# include <stddef.h>
++#endif
++
++#if defined HAVE_UNISTD_H || defined _LIBC
++# include <unistd.h>
++# ifndef POSIX
++# ifdef _POSIX_VERSION
++# define POSIX
++# endif
++# endif
++#endif
++
++#if !defined _AMIGA && !defined VMS && !defined WINDOWS32
++# include <pwd.h>
++#endif
++
++#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
++extern int errno;
++#endif
++#ifndef __set_errno
++# define __set_errno(val) errno = (val)
++#endif
++
++#ifndef NULL
++# define NULL 0
++#endif
++
++#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
++# include <dirent.h>
++# define NAMLEN(dirent) strlen((dirent)->d_name)
++#else
++# define dirent direct
++# define NAMLEN(dirent) (dirent)->d_namlen
++# ifdef HAVE_SYS_NDIR_H
++# include <sys/ndir.h>
++# endif
++# ifdef HAVE_SYS_DIR_H
++# include <sys/dir.h>
++# endif
++# ifdef HAVE_NDIR_H
++# include <ndir.h>
++# endif
++# ifdef HAVE_VMSDIR_H
++# include "vmsdir.h"
++# endif /* HAVE_VMSDIR_H */
++#endif
++
++
++/* In GNU systems, <dirent.h> defines this macro for us. */
++#ifdef _D_NAMLEN
++# undef NAMLEN
++# define NAMLEN(d) _D_NAMLEN(d)
++#endif
++
++/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
++ if the `d_type' member for `struct dirent' is available. */
++#ifdef _DIRENT_HAVE_D_TYPE
++# define HAVE_D_TYPE 1
++#endif
++
++#if _LIBC
++# define HAVE_DIRENT64 1
++#endif
++
++/* If the system has the `struct dirent64' type we use it internally. */
++#if defined HAVE_DIRENT64 && !defined COMPILE_GLOB64
++# if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
++# define CONVERT_D_NAMLEN(d64, d32)
++# else
++# define CONVERT_D_NAMLEN(d64, d32) \
++ (d64)->d_namlen = (d32)->d_namlen;
++# endif
++
++# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
++# define CONVERT_D_INO(d64, d32)
++# else
++# define CONVERT_D_INO(d64, d32) \
++ (d64)->d_ino = (d32)->d_ino;
++# endif
++
++# ifdef HAVE_D_TYPE
++# define CONVERT_D_TYPE(d64, d32) \
++ (d64)->d_type = (d32)->d_type;
++# else
++# define CONVERT_D_TYPE(d64, d32)
++# endif
++
++# define CONVERT_DIRENT_DIRENT64(d64, d32) \
++ memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1); \
++ CONVERT_D_NAMLEN (d64, d32) \
++ CONVERT_D_INO (d64, d32) \
++ CONVERT_D_TYPE (d64, d32)
++#endif
++
++
++#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
++/* Posix does not require that the d_ino field be present, and some
++ systems do not provide it. */
++# define REAL_DIR_ENTRY(dp) 1
++#else
++# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
++#endif /* POSIX */
++
++#if defined STDC_HEADERS || defined __GNU_LIBRARY__
++# include <stdlib.h>
++# include <string.h>
++# define ANSI_STRING
++#else /* No standard headers. */
++
++extern char *getenv ();
++
++# ifdef HAVE_STRING_H
++# include <string.h>
++# define ANSI_STRING
++# else
++# include <strings.h>
++# endif
++# ifdef HAVE_MEMORY_H
++# include <memory.h>
++# endif
++
++extern char *malloc (), *realloc ();
++extern void free ();
++
++extern void qsort ();
++extern void abort (), exit ();
++
++#endif /* Standard headers. */
++
++#ifndef ANSI_STRING
++
++# ifndef bzero
++extern void bzero ();
++# endif
++# ifndef bcopy
++extern void bcopy ();
++# endif
++
++# define memcpy(d, s, n) bcopy ((s), (d), (n))
++# define strrchr rindex
++/* memset is only used for zero here, but let's be paranoid. */
++# define memset(s, better_be_zero, n) \
++ ((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0)))
++#endif /* Not ANSI_STRING. */
++
++#if !defined HAVE_STRCOLL && !defined _LIBC
++# define strcoll strcmp
++#endif
++
++#if !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1
++# define HAVE_MEMPCPY 1
++# undef mempcpy
++# define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len)
++#endif
++
++static unsigned long nbresults;
++
++#ifndef __GNU_LIBRARY__
++# ifdef __GNUC__
++__inline
++# endif
++# ifndef __SASC
++# ifdef WINDOWS32
++static void *
++# else
++static char *
++# endif
++my_realloc (p, n)
++ char *p;
++ unsigned int n;
++{
++ /* These casts are the for sake of the broken Ultrix compiler,
++ which warns of illegal pointer combinations otherwise. */
++ if (p == NULL)
++ return (char *) malloc (n);
++ return (char *) realloc (p, n);
++}
++# define realloc my_realloc
++# endif /* __SASC */
++#endif /* __GNU_LIBRARY__ */
++
++
++#if !defined __alloca && !defined __GNU_LIBRARY__
++
++# ifdef __GNUC__
++# undef alloca
++# define alloca(n) __builtin_alloca (n)
++# else /* Not GCC. */
++# ifdef HAVE_ALLOCA_H
++# include <alloca.h>
++# else /* Not HAVE_ALLOCA_H. */
++# ifndef _AIX
++# ifdef WINDOWS32
++# include <malloc.h>
++# else
++extern char *alloca ();
++# endif /* WINDOWS32 */
++# endif /* Not _AIX. */
++# endif /* sparc or HAVE_ALLOCA_H. */
++# endif /* GCC. */
++
++# define __alloca alloca
++
++#endif
++
++#ifndef __GNU_LIBRARY__
++# define __stat stat
++# ifdef STAT_MACROS_BROKEN
++# undef S_ISDIR
++# endif
++# ifndef S_ISDIR
++# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
++# endif
++#endif
++
++#ifdef _LIBC
++# undef strdup
++# define strdup(str) __strdup (str)
++# define sysconf(id) __sysconf (id)
++# define closedir(dir) __closedir (dir)
++# define opendir(name) __opendir (name)
++# define readdir(str) __readdir64 (str)
++# define getpwnam_r(name, bufp, buf, len, res) \
++ __getpwnam_r (name, bufp, buf, len, res)
++# ifndef __stat64
++# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
++# endif
++# define HAVE_STAT64 1
++#endif
++
++#ifndef HAVE_STAT64
++# define __stat64(fname, buf) __stat (fname, buf)
++/* This is the variable name we are using. */
++# define st64 st
++#endif
++
++#if !(defined STDC_HEADERS || defined __GNU_LIBRARY__)
++# undef size_t
++# define size_t unsigned int
++#endif
++
++/* Some system header files erroneously define these.
++ We want our own definitions from <fnmatch.h> to take precedence. */
++#ifndef __GNU_LIBRARY__
++# undef FNM_PATHNAME
++# undef FNM_NOESCAPE
++# undef FNM_PERIOD
++#endif
++#include <fnmatch.h>
++
++/* Some system header files erroneously define these.
++ We want our own definitions from <glob.h> to take precedence. */
++#ifndef __GNU_LIBRARY__
++# undef GLOB_ERR
++# undef GLOB_MARK
++# undef GLOB_NOSORT
++# undef GLOB_DOOFFS
++# undef GLOB_NOCHECK
++# undef GLOB_APPEND
++# undef GLOB_NOESCAPE
++# undef GLOB_PERIOD
++#endif
++#include <glibc-glob.h>
++
++#ifdef HAVE_GETLOGIN_R
++extern int getlogin_r __P ((char *, size_t));
++#else
++extern char *getlogin __P ((void));
++#endif
++\f
++static
++#if __GNUC__ - 0 >= 2
++inline
++#endif
++const char *next_brace_sub __P ((const char *begin));
++
++#endif /* GLOB_ONLY_P */
++
++static int glob_in_dir __P ((const char *pattern, const char *directory,
++ int flags,
++ int (*errfunc) (const char *, int),
++ glob_t *pglob));
++
++/* Prototype __glob_pattern_p to avoid compiler warning.
++ * jss - 3/17/2001
++ */
++#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
++/* Return nonzero if PATTERN contains any metacharacters.
++ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
++int __glob_pattern_p (const char *pattern, int quote);
++#endif /* NO_GLOB_PATTERN_P */
++
++#if !defined _LIBC || !defined GLOB_ONLY_P
++static int prefix_array __P ((const char *prefix, char **array, size_t n));
++static int collated_compare __P ((const __ptr_t, const __ptr_t));
++
++
++/* Find the end of the sub-pattern in a brace expression. We define
++ this as an inline function if the compiler permits. */
++static
++#if __GNUC__ - 0 >= 2
++inline
++#endif
++const char *
++next_brace_sub (begin)
++ const char *begin;
++{
++ unsigned int depth = 0;
++ const char *cp = begin;
++
++ while (1)
++ {
++ if (depth == 0)
++ {
++ if (*cp != ',' && *cp != '}' && *cp != '\0')
++ {
++ if (*cp == '{')
++ ++depth;
++ ++cp;
++ continue;
++ }
++ }
++ else
++ {
++ while (*cp != '\0' && (*cp != '}' || depth > 0))
++ {
++ if (*cp == '}')
++ --depth;
++ ++cp;
++ }
++ if (*cp == '\0')
++ /* An incorrectly terminated brace expression. */
++ return NULL;
++
++ continue;
++ }
++ break;
++ }
++
++ return cp;
++}
++
++#endif /* !GLOB_ONLY_P */
++
++
++/* Do glob searching for PATTERN, placing results in PGLOB.
++ The bits defined above may be set in FLAGS.
++ If a directory cannot be opened or read and ERRFUNC is not nil,
++ it is called with the pathname that caused the error, and the
++ `errno' value from the failing call; if it returns non-zero
++ `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
++ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
++ Otherwise, `glob' returns zero. */
++static int
++glob_limited (depth, pattern, flags, errfunc, pglob)
++ unsigned int depth;
++ const char *pattern;
++ int flags;
++ int (*errfunc) __P ((const char *, int));
++ glob_t *pglob;
++{
++ const char *filename;
++ const char *dirname;
++ size_t dirlen;
++ int status;
++ size_t oldcount;
++
++ if (depth > MAX_RECURSION) {
++ return GLOB_NOSPACE;
++ }
++ if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
++ {
++ __set_errno (EINVAL);
++ return -1;
++ }
++
++ if (!(flags & GLOB_DOOFFS))
++ /* Have to do this so `globfree' knows where to start freeing. It
++ also makes all the code that uses gl_offs simpler. */
++ pglob->gl_offs = 0;
++
++ if (flags & GLOB_BRACE)
++ {
++ const char *begin = strchr (pattern, '{');
++ if (begin != NULL)
++ {
++ /* Allocate working buffer large enough for our work. Note that
++ we have at least an opening and closing brace. */
++ size_t firstc;
++ char *alt_start;
++ const char *p;
++ const char *next;
++ const char *rest;
++ size_t rest_len;
++#ifdef __GNUC__
++ char onealt[strlen (pattern) - 1];
++#else
++ char *onealt = (char *) malloc (strlen (pattern) - 1);
++ if (onealt == NULL)
++ {
++ if (!(flags & GLOB_APPEND))
++ globfree (pglob);
++ return GLOB_NOSPACE;
++ }
++#endif
++
++ /* We know the prefix for all sub-patterns. */
++#ifdef HAVE_MEMPCPY
++ alt_start = mempcpy (onealt, pattern, begin - pattern);
++#else
++ memcpy (onealt, pattern, begin - pattern);
++ alt_start = &onealt[begin - pattern];
++#endif
++
++ /* Find the first sub-pattern and at the same time find the
++ rest after the closing brace. */
++ next = next_brace_sub (begin + 1);
++ if (next == NULL)
++ {
++ /* It is an illegal expression. */
++#ifndef __GNUC__
++ free (onealt);
++#endif
++ return glob_limited (depth + 1U, pattern, flags & ~GLOB_BRACE, errfunc, pglob);
++ }
++
++ /* Now find the end of the whole brace expression. */
++ rest = next;
++ while (*rest != '}')
++ {
++ rest = next_brace_sub (rest + 1);
++ if (rest == NULL)
++ {
++ /* It is an illegal expression. */
++#ifndef __GNUC__
++ free (onealt);
++#endif
++ return glob_limited (depth + 1U, pattern, flags & ~GLOB_BRACE, errfunc, pglob);
++ }
++ }
++ /* Please note that we now can be sure the brace expression
++ is well-formed. */
++ rest_len = strlen (++rest) + 1;
++
++ /* We have a brace expression. BEGIN points to the opening {,
++ NEXT points past the terminator of the first element, and END
++ points past the final }. We will accumulate result names from
++ recursive runs for each brace alternative in the buffer using
++ GLOB_APPEND. */
++
++ if (!(flags & GLOB_APPEND))
++ {
++ /* This call is to set a new vector, so clear out the
++ vector so we can append to it. */
++ pglob->gl_pathc = 0;
++ pglob->gl_pathv = NULL;
++ }
++ firstc = pglob->gl_pathc;
++
++ p = begin + 1;
++ while (1)
++ {
++ int result;
++
++ /* Construct the new glob expression. */
++#ifdef HAVE_MEMPCPY
++ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
++#else
++ memcpy (alt_start, p, next - p);
++ memcpy (&alt_start[next - p], rest, rest_len);
++#endif
++
++ result = glob_limited (depth + 1U, onealt,
++ ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC))
++ | GLOB_APPEND), errfunc, pglob);
++
++ /* If we got an error, return it. */
++ if (result && result != GLOB_NOMATCH)
++ {
++#ifndef __GNUC__
++ free (onealt);
++#endif
++ if (!(flags & GLOB_APPEND))
++ globfree (pglob);
++ return result;
++ }
++
++ if (*next == '}')
++ /* We saw the last entry. */
++ break;
++
++ p = next + 1;
++ next = next_brace_sub (p);
++ assert (next != NULL);
++ }
++
++#ifndef __GNUC__
++ free (onealt);
++#endif
++
++ if (pglob->gl_pathc != firstc)
++ /* We found some entries. */
++ return 0;
++ else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
++ return GLOB_NOMATCH;
++ }
++ }
++
++ /* Find the filename. */
++ filename = strrchr (pattern, '/');
++#if defined __MSDOS__ || defined WINDOWS32
++ /* The case of "d:pattern". Since `:' is not allowed in
++ file names, we can safely assume that wherever it
++ happens in pattern, it signals the filename part. This
++ is so we could some day support patterns like "[a-z]:foo". */
++ if (filename == NULL)
++ filename = strchr (pattern, ':');
++#endif /* __MSDOS__ || WINDOWS32 */
++ if (filename == NULL)
++ {
++ /* This can mean two things: a simple name or "~name". The latter
++ case is nothing but a notation for a directory. */
++ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
++ {
++ dirname = pattern;
++ dirlen = strlen (pattern);
++
++ /* Set FILENAME to NULL as a special flag. This is ugly but
++ other solutions would require much more code. We test for
++ this special case below. */
++ filename = NULL;
++ }
++ else
++ {
++ filename = pattern;
++#ifdef _AMIGA
++ dirname = "";
++#else
++ dirname = ".";
++#endif
++ dirlen = 0;
++ }
++ }
++ else if (filename == pattern)
++ {
++ /* "/pattern". */
++ dirname = "/";
++ dirlen = 1;
++ ++filename;
++ }
++ else
++ {
++ char *newp;
++ dirlen = filename - pattern;
++#if defined __MSDOS__ || defined WINDOWS32
++ if (*filename == ':'
++ || (filename > pattern + 1 && filename[-1] == ':'))
++ {
++ char *drive_spec;
++
++ ++dirlen;
++ drive_spec = (char *) __alloca (dirlen + 1);
++#ifdef HAVE_MEMPCPY
++ *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
++#else
++ memcpy (drive_spec, pattern, dirlen);
++ drive_spec[dirlen] = '\0';
++#endif
++ /* For now, disallow wildcards in the drive spec, to
++ prevent infinite recursion in glob. */
++ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
++ return GLOB_NOMATCH;
++ /* If this is "d:pattern", we need to copy `:' to DIRNAME
++ as well. If it's "d:/pattern", don't remove the slash
++ from "d:/", since "d:" and "d:/" are not the same.*/
++ }
++#endif
++ newp = (char *) __alloca (dirlen + 1);
++#ifdef HAVE_MEMPCPY
++ *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
++#else
++ memcpy (newp, pattern, dirlen);
++ newp[dirlen] = '\0';
++#endif
++ dirname = newp;
++ ++filename;
++
++ if (filename[0] == '\0'
++#if defined __MSDOS__ || defined WINDOWS32
++ && dirname[dirlen - 1] != ':'
++ && (dirlen < 3 || dirname[dirlen - 2] != ':'
++ || dirname[dirlen - 1] != '/')
++#endif
++ && dirlen > 1)
++ /* "pattern/". Expand "pattern", appending slashes. */
++ {
++ int val = glob_limited (depth + 1U, dirname, flags | GLOB_MARK, errfunc, pglob);
++ if (val == 0)
++ pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
++ | (flags & GLOB_MARK));
++ return val;
++ }
++ }
++
++ if (!(flags & GLOB_APPEND))
++ {
++ pglob->gl_pathc = 0;
++ if (!(flags & GLOB_DOOFFS))
++ pglob->gl_pathv = NULL;
++ else
++ {
++ size_t i;
++ pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1)
++ * sizeof (char *));
++ if (pglob->gl_pathv == NULL)
++ return GLOB_NOSPACE;
++
++ for (i = 0; i <= pglob->gl_offs; ++i)
++ pglob->gl_pathv[i] = NULL;
++ }
++ }
++
++ oldcount = pglob->gl_pathc + pglob->gl_offs;
++
++#ifndef VMS
++ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
++ {
++ if (dirname[1] == '\0' || dirname[1] == '/')
++ {
++ /* Look up home directory. */
++ const char *home_dir = getenv ("HOME");
++# ifdef _AMIGA
++ if (home_dir == NULL || home_dir[0] == '\0')
++ home_dir = "SYS:";
++# else
++# ifdef WINDOWS32
++ if (home_dir == NULL || home_dir[0] == '\0')
++ home_dir = "c:/users/default"; /* poor default */
++# else
++ if (home_dir == NULL || home_dir[0] == '\0')
++ {
++ int success;
++ char *name;
++# if defined HAVE_GETLOGIN_R || defined _LIBC
++ size_t buflen = sysconf (_SC_LOGIN_NAME_MAX) + 1;
++
++ if (buflen == 0)
++ /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
++ a moderate value. */
++ buflen = 20;
++ name = (char *) __alloca (buflen);
++
++ success = getlogin_r (name, buflen) >= 0;
++# else
++ success = (name = getlogin ()) != NULL;
++# endif
++ if (success)
++ {
++ struct passwd *p;
++# if defined HAVE_GETPWNAM_R || defined _LIBC
++ long int pwbuflen = sysconf (_SC_GETPW_R_SIZE_MAX);
++ char *pwtmpbuf;
++ struct passwd pwbuf;
++ int save = errno;
++
++ if (pwbuflen == -1)
++ /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
++ Try a moderate value. */
++ pwbuflen = 1024;
++ pwtmpbuf = (char *) __alloca (pwbuflen);
++
++ while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
++ != 0)
++ {
++ if (errno != ERANGE)
++ {
++ p = NULL;
++ break;
++ }
++ pwbuflen *= 2;
++ pwtmpbuf = (char *) __alloca (pwbuflen);
++ __set_errno (save);
++ }
++# else
++ p = getpwnam (name);
++# endif
++ if (p != NULL)
++ home_dir = p->pw_dir;
++ }
++ }
++ if (home_dir == NULL || home_dir[0] == '\0')
++ {
++ if (flags & GLOB_TILDE_CHECK)
++ return GLOB_NOMATCH;
++ else
++ home_dir = "~"; /* No luck. */
++ }
++# endif /* WINDOWS32 */
++# endif
++ /* Now construct the full directory. */
++ if (dirname[1] == '\0')
++ dirname = home_dir;
++ else
++ {
++ char *newp;
++ size_t home_len = strlen (home_dir);
++ newp = (char *) __alloca (home_len + dirlen);
++# ifdef HAVE_MEMPCPY
++ mempcpy (mempcpy (newp, home_dir, home_len),
++ &dirname[1], dirlen);
++# else
++ memcpy (newp, home_dir, home_len);
++ memcpy (&newp[home_len], &dirname[1], dirlen);
++# endif
++ dirname = newp;
++ }
++ }
++# if !defined _AMIGA && !defined WINDOWS32
++ else
++ {
++ char *end_name = strchr (dirname, '/');
++ const char *user_name;
++ const char *home_dir;
++
++ if (end_name == NULL)
++ user_name = dirname + 1;
++ else
++ {
++ char *newp;
++ newp = (char *) __alloca (end_name - dirname);
++# ifdef HAVE_MEMPCPY
++ *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
++ = '\0';
++# else
++ memcpy (newp, dirname + 1, end_name - dirname);
++ newp[end_name - dirname - 1] = '\0';
++# endif
++ user_name = newp;
++ }
++
++ /* Look up specific user's home directory. */
++ {
++ struct passwd *p;
++# if defined HAVE_GETPWNAM_R || defined _LIBC
++ long int buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
++ char *pwtmpbuf;
++ struct passwd pwbuf;
++ int save = errno;
++
++ if (buflen == -1)
++ /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
++ moderate value. */
++ buflen = 1024;
++ pwtmpbuf = (char *) __alloca (buflen);
++
++ while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
++ {
++ if (errno != ERANGE)
++ {
++ p = NULL;
++ break;
++ }
++ buflen *= 2;
++ pwtmpbuf = __alloca (buflen);
++ __set_errno (save);
++ }
++# else
++ p = getpwnam (user_name);
++# endif
++ if (p != NULL)
++ home_dir = p->pw_dir;
++ else
++ home_dir = NULL;
++ }
++ /* If we found a home directory use this. */
++ if (home_dir != NULL)
++ {
++ char *newp;
++ size_t home_len = strlen (home_dir);
++ size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
++ newp = (char *) __alloca (home_len + rest_len + 1);
++# ifdef HAVE_MEMPCPY
++ *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
++ end_name, rest_len)) = '\0';
++# else
++ memcpy (newp, home_dir, home_len);
++ memcpy (&newp[home_len], end_name, rest_len);
++ newp[home_len + rest_len] = '\0';
++# endif
++ dirname = newp;
++ }
++ else
++ if (flags & GLOB_TILDE_CHECK)
++ /* We have to regard it as an error if we cannot find the
++ home directory. */
++ return GLOB_NOMATCH;
++ }
++# endif /* Not Amiga && not WINDOWS32. */
++ }
++#endif /* Not VMS. */
++
++ /* Now test whether we looked for "~" or "~NAME". In this case we
++ can give the answer now. */
++ if (filename == NULL)
++ {
++ struct stat st;
++#ifdef HAVE_STAT64
++ struct stat64 st64;
++#endif
++
++ /* Return the directory if we don't check for error or if it exists. */
++ if ((flags & GLOB_NOCHECK)
++ || (((flags & GLOB_ALTDIRFUNC)
++ ? ((*pglob->gl_stat) (dirname, &st) == 0
++ && S_ISDIR (st.st_mode))
++ : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
++ {
++ int newcount = pglob->gl_pathc + pglob->gl_offs;
++
++ pglob->gl_pathv
++ = (char **) realloc (pglob->gl_pathv,
++ (newcount + 1 + 1) * sizeof (char *));
++ if (pglob->gl_pathv == NULL)
++ return GLOB_NOSPACE;
++
++#if defined HAVE_STRDUP || defined _LIBC
++ pglob->gl_pathv[newcount] = strdup (dirname);
++#else
++ {
++ size_t len = strlen (dirname) + 1;
++ char *dircopy = malloc (len);
++ if (dircopy != NULL)
++ pglob->gl_pathv[newcount] = memcpy (dircopy, dirname, len);
++ }
++#endif
++ if (pglob->gl_pathv[newcount] == NULL)
++ {
++ free (pglob->gl_pathv);
++ return GLOB_NOSPACE;
++ }
++ pglob->gl_pathv[++newcount] = NULL;
++ ++pglob->gl_pathc;
++ pglob->gl_flags = flags;
++
++ return 0;
++ }
++
++ /* Not found. */
++ return GLOB_NOMATCH;
++ }
++
++ if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
++ {
++ /* The directory name contains metacharacters, so we
++ have to glob for the directory, and then glob for
++ the pattern in each directory found. */
++ glob_t dirs;
++ size_t i;
++
++ if ((flags & GLOB_ALTDIRFUNC) != 0)
++ {
++ /* Use the alternative access functions also in the recursive
++ call. */
++ dirs.gl_opendir = pglob->gl_opendir;
++ dirs.gl_readdir = pglob->gl_readdir;
++ dirs.gl_closedir = pglob->gl_closedir;
++ dirs.gl_stat = pglob->gl_stat;
++ dirs.gl_lstat = pglob->gl_lstat;
++ }
++
++ status = glob_limited (depth + 1U, dirname,
++ ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
++ | GLOB_ALTDIRFUNC))
++ | GLOB_NOSORT | GLOB_ONLYDIR),
++ errfunc, &dirs);
++ if (status != 0)
++ return status;
++
++ /* We have successfully globbed the preceding directory name.
++ For each name we found, call glob_in_dir on it and FILENAME,
++ appending the results to PGLOB. */
++ for (i = 0; i < dirs.gl_pathc; ++i)
++ {
++ int old_pathc;
++
++#ifdef SHELL
++ {
++ /* Make globbing interruptible in the bash shell. */
++ extern int interrupt_state;
++
++ if (interrupt_state)
++ {
++ globfree (&dirs);
++ return GLOB_ABORTED;
++ }
++ }
++#endif /* SHELL. */
++
++ old_pathc = pglob->gl_pathc;
++ status = glob_in_dir (filename, dirs.gl_pathv[i],
++ ((flags | GLOB_APPEND) & ~GLOB_NOCHECK),
++ errfunc, pglob);
++ if (status == GLOB_NOMATCH)
++ /* No matches in this directory. Try the next. */
++ continue;
++
++ if (status != 0)
++ {
++ globfree (&dirs);
++ globfree (pglob);
++ return status;
++ }
++
++ /* Stick the directory on the front of each name. */
++ if (prefix_array (dirs.gl_pathv[i],
++ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
++ pglob->gl_pathc - old_pathc))
++ {
++ globfree (&dirs);
++ globfree (pglob);
++ return GLOB_NOSPACE;
++ }
++ }
++
++ flags |= GLOB_MAGCHAR;
++
++ /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
++ But if we have not found any matching entry and the GLOB_NOCHECK
++ flag was set we must return the list consisting of the disrectory
++ names followed by the filename. */
++ if (pglob->gl_pathc + pglob->gl_offs == oldcount)
++ {
++ /* No matches. */
++ if (flags & GLOB_NOCHECK)
++ {
++ size_t filename_len = strlen (filename) + 1;
++ char **new_pathv;
++ int newcount = pglob->gl_pathc + pglob->gl_offs;
++ struct stat st;
++#ifdef HAVE_STAT64
++ struct stat64 st64;
++#endif
++
++ /* This is an pessimistic guess about the size. */
++ pglob->gl_pathv
++ = (char **) realloc (pglob->gl_pathv,
++ (newcount + dirs.gl_pathc + 1)
++ * sizeof (char *));
++ if (pglob->gl_pathv == NULL)
++ {
++ globfree (&dirs);
++ return GLOB_NOSPACE;
++ }
++
++ for (i = 0; i < dirs.gl_pathc; ++i)
++ {
++ const char *dir = dirs.gl_pathv[i];
++ size_t dir_len = strlen (dir);
++
++ /* First check whether this really is a directory. */
++ if (((flags & GLOB_ALTDIRFUNC)
++ ? ((*pglob->gl_stat) (dir, &st) != 0
++ || !S_ISDIR (st.st_mode))
++ : (__stat64 (dir, &st64) != 0
++ || !S_ISDIR (st64.st_mode))))
++ /* No directory, ignore this entry. */
++ continue;
++
++ pglob->gl_pathv[newcount] = malloc (dir_len + 1
++ + filename_len);
++ if (pglob->gl_pathv[newcount] == NULL)
++ {
++ globfree (&dirs);
++ globfree (pglob);
++ return GLOB_NOSPACE;
++ }
++
++#ifdef HAVE_MEMPCPY
++ mempcpy (mempcpy (mempcpy (pglob->gl_pathv[newcount],
++ dir, dir_len),
++ "/", 1),
++ filename, filename_len);
++#else
++ memcpy (pglob->gl_pathv[newcount], dir, dir_len);
++ pglob->gl_pathv[newcount][dir_len] = '/';
++ memcpy (&pglob->gl_pathv[newcount][dir_len + 1],
++ filename, filename_len);
++#endif
++ ++pglob->gl_pathc;
++ ++newcount;
++ }
++
++ pglob->gl_pathv[newcount] = NULL;
++ pglob->gl_flags = flags;
++
++ /* Now we know how large the gl_pathv vector must be. */
++ new_pathv = (char **) realloc (pglob->gl_pathv,
++ ((newcount + 1)
++ * sizeof (char *)));
++ if (new_pathv != NULL)
++ pglob->gl_pathv = new_pathv;
++ }
++ else
++ {
++ globfree (&dirs);
++ return GLOB_NOMATCH;
++ }
++ }
++
++ globfree (&dirs);
++ }
++ else
++ {
++ int old_pathc = pglob->gl_pathc;
++
++ status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
++ if (status != 0)
++ return status;
++
++ if (dirlen > 0)
++ {
++ /* Stick the directory on the front of each name. */
++ if (prefix_array (dirname,
++ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
++ pglob->gl_pathc - old_pathc))
++ {
++ globfree (pglob);
++ return GLOB_NOSPACE;
++ }
++ }
++ }
++
++ if (flags & GLOB_MARK)
++ {
++ /* Append slashes to directory names. */
++ size_t i;
++ struct stat st;
++#ifdef HAVE_STAT64
++ struct stat64 st64;
++#endif
++
++ for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
++ if (((flags & GLOB_ALTDIRFUNC)
++ ? ((*pglob->gl_stat) (pglob->gl_pathv[i], &st) == 0
++ && S_ISDIR (st.st_mode))
++ : (__stat64 (pglob->gl_pathv[i], &st64) == 0
++ && S_ISDIR (st64.st_mode))))
++ {
++ size_t len = strlen (pglob->gl_pathv[i]) + 2;
++ char *new = realloc (pglob->gl_pathv[i], len);
++ if (new == NULL)
++ {
++ globfree (pglob);
++ return GLOB_NOSPACE;
++ }
++ strcpy (&new[len - 2], "/");
++ pglob->gl_pathv[i] = new;
++ }
++ }
++
++ if (!(flags & GLOB_NOSORT))
++ {
++ /* Sort the vector. */
++ qsort ((__ptr_t) &pglob->gl_pathv[oldcount],
++ pglob->gl_pathc + pglob->gl_offs - oldcount,
++ sizeof (char *), collated_compare);
++ }
++
++ return 0;
++}
++
++int
++glob (pattern, flags, errfunc, pglob)
++
++ const char *pattern;
++ int flags;
++ int (*errfunc) __P ((const char *, int));
++ glob_t *pglob;
++{
++ nbresults = 0UL;
++ return glob_limited(0U, pattern, flags, errfunc, pglob);
++}
++
++#if !defined _LIBC || !defined GLOB_ONLY_P
++
++/* Free storage allocated in PGLOB by a previous `glob' call. */
++void
++globfree (pglob)
++ register glob_t *pglob;
++{
++ if (pglob->gl_pathv != NULL)
++ {
++ size_t i;
++ for (i = 0; i < pglob->gl_pathc; ++i)
++ if (pglob->gl_pathv[pglob->gl_offs + i] != NULL)
++ free ((__ptr_t) pglob->gl_pathv[pglob->gl_offs + i]);
++ free ((__ptr_t) pglob->gl_pathv);
++ }
++}
++
++
++/* Do a collated comparison of A and B. */
++static int
++collated_compare (a, b)
++ const __ptr_t a;
++ const __ptr_t b;
++{
++ const char *const s1 = *(const char *const * const) a;
++ const char *const s2 = *(const char *const * const) b;
++
++ if (s1 == s2)
++ return 0;
++ if (s1 == NULL)
++ return 1;
++ if (s2 == NULL)
++ return -1;
++ return strcoll (s1, s2);
++}
++
++
++/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
++ elements in place. Return nonzero if out of memory, zero if successful.
++ A slash is inserted between DIRNAME and each elt of ARRAY,
++ unless DIRNAME is just "/". Each old element of ARRAY is freed. */
++static int
++prefix_array (dirname, array, n)
++ const char *dirname;
++ char **array;
++ size_t n;
++{
++ register size_t i;
++ size_t dirlen = strlen (dirname);
++#if defined __MSDOS__ || defined WINDOWS32
++ int sep_char = '/';
++# define DIRSEP_CHAR sep_char
++#else
++# define DIRSEP_CHAR '/'
++#endif
++
++ if (dirlen == 1 && dirname[0] == '/')
++ /* DIRNAME is just "/", so normal prepending would get us "//foo".
++ We want "/foo" instead, so don't prepend any chars from DIRNAME. */
++ dirlen = 0;
++#if defined __MSDOS__ || defined WINDOWS32
++ else if (dirlen > 1)
++ {
++ if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
++ /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */
++ --dirlen;
++ else if (dirname[dirlen - 1] == ':')
++ {
++ /* DIRNAME is "d:". Use `:' instead of `/'. */
++ --dirlen;
++ sep_char = ':';
++ }
++ }
++#endif
++
++ for (i = 0; i < n; ++i)
++ {
++ size_t eltlen = strlen (array[i]) + 1;
++ char *new = (char *) malloc (dirlen + 1 + eltlen);
++ if (new == NULL)
++ {
++ while (i > 0)
++ free ((__ptr_t) array[--i]);
++ return 1;
++ }
++
++#ifdef HAVE_MEMPCPY
++ {
++ char *endp = (char *) mempcpy (new, dirname, dirlen);
++ *endp++ = DIRSEP_CHAR;
++ mempcpy (endp, array[i], eltlen);
++ }
++#else
++ memcpy (new, dirname, dirlen);
++ new[dirlen] = DIRSEP_CHAR;
++ memcpy (&new[dirlen + 1], array[i], eltlen);
++#endif
++ free ((__ptr_t) array[i]);
++ array[i] = new;
++ }
++
++ return 0;
++}
++
++
++/* We must not compile this function twice. */
++#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
++/* Return nonzero if PATTERN contains any metacharacters.
++ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
++int
++__glob_pattern_p (pattern, quote)
++ const char *pattern;
++ int quote;
++{
++ register const char *p;
++ int open = 0;
++
++ for (p = pattern; *p != '\0'; ++p)
++ switch (*p)
++ {
++ case '?':
++ case '*':
++ return 1;
++
++ case '\\':
++ if (quote && p[1] != '\0')
++ ++p;
++ break;
++
++ case '[':
++ open = 1;
++ break;
++
++ case ']':
++ if (open)
++ return 1;
++ break;
++ }
++
++ return 0;
++}
++# ifdef _LIBC
++weak_alias (__glob_pattern_p, glob_pattern_p)
++# endif
++#endif
++
++#endif /* !GLOB_ONLY_P */
++
++
++/* Like `glob', but PATTERN is a final pathname component,
++ and matches are searched for in DIRECTORY.
++ The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
++ The GLOB_APPEND flag is assumed to be set (always appends). */
++static int
++glob_in_dir (pattern, directory, flags, errfunc, pglob)
++ const char *pattern;
++ const char *directory;
++ int flags;
++ int (*errfunc) __P ((const char *, int));
++ glob_t *pglob;
++{
++ __ptr_t stream = NULL;
++ struct globlink
++ {
++ struct globlink *next;
++ char *name;
++ };
++ struct globlink *names = NULL;
++ size_t nfound;
++ int meta;
++ int save;
++
++ meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
++ if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
++ {
++ /* We need not do any tests. The PATTERN contains no meta
++ characters and we must not return an error therefore the
++ result will always contain exactly one name. */
++ flags |= GLOB_NOCHECK;
++ nfound = 0;
++ }
++ else if (meta == 0 &&
++ ((flags & GLOB_NOESCAPE) || strchr(pattern, '\\') == NULL))
++ {
++ /* Since we use the normal file functions we can also use stat()
++ to verify the file is there. */
++ struct stat st;
++# ifdef HAVE_STAT64
++ struct stat64 st64;
++# endif
++ size_t patlen = strlen (pattern);
++ size_t dirlen = strlen (directory);
++ char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1);
++
++# ifdef HAVE_MEMPCPY
++ mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
++ "/", 1),
++ pattern, patlen + 1);
++# else
++ memcpy (fullname, directory, dirlen);
++ fullname[dirlen] = '/';
++ memcpy (&fullname[dirlen + 1], pattern, patlen + 1);
++# endif
++ if (((flags & GLOB_ALTDIRFUNC)
++ ? (*pglob->gl_stat) (fullname, &st)
++ : __stat64 (fullname, &st64)) == 0)
++ /* We found this file to be existing. Now tell the rest
++ of the function to copy this name into the result. */
++ flags |= GLOB_NOCHECK;
++
++ nfound = 0;
++ }
++ else
++ {
++ if (pattern[0] == '\0')
++ {
++ /* This is a special case for matching directories like in
++ "*a/". */
++ names = (struct globlink *) __alloca (sizeof (struct globlink));
++ names->name = (char *) malloc (1);
++ if (names->name == NULL)
++ goto memory_error;
++ names->name[0] = '\0';
++ names->next = NULL;
++ nfound = 1;
++ meta = 0;
++ }
++ else
++ {
++ stream = ((flags & GLOB_ALTDIRFUNC)
++ ? (*pglob->gl_opendir) (directory)
++ : (__ptr_t) opendir (directory));
++ if (stream == NULL)
++ {
++ if (errno != ENOTDIR
++ && ((errfunc != NULL && (*errfunc) (directory, errno))
++ || (flags & GLOB_ERR)))
++ return GLOB_ABORTED;
++ nfound = 0;
++ meta = 0;
++ }
++ else
++ {
++ int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
++ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
++#if defined _AMIGA || defined VMS
++ | FNM_CASEFOLD
++#endif
++ );
++ nfound = 0;
++ flags |= GLOB_MAGCHAR;
++
++ while (1)
++ {
++ const char *name;
++ size_t len;
++#if defined HAVE_DIRENT64 && !defined COMPILE_GLOB64
++ struct dirent64 *d;
++ struct dirent64 d64;
++
++ if (flags & GLOB_ALTDIRFUNC)
++ {
++ struct dirent *d32 = (*pglob->gl_readdir) (stream);
++ if (d32 != NULL)
++ {
++ CONVERT_DIRENT_DIRENT64 (&d64, d32);
++ d = &d64;
++ }
++ else
++ d = NULL;
++ }
++ else
++ d = __readdir64 ((DIR *) stream);
++#else
++ struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
++ ? ((struct dirent *)
++ (*pglob->gl_readdir) (stream))
++ : __readdir ((DIR *) stream));
++#endif
++ if (d == NULL)
++ break;
++ if (nbresults > MAX_RESULTS) {
++ break;
++ }
++ nbresults++;
++ if (! REAL_DIR_ENTRY (d))
++ continue;
++
++#ifdef HAVE_D_TYPE
++ /* If we shall match only directories use the information
++ provided by the dirent call if possible. */
++ if ((flags & GLOB_ONLYDIR)
++ && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
++ continue;
++#endif
++
++ name = d->d_name;
++
++ if (fnmatch (pattern, name, fnm_flags) == 0)
++ {
++ struct globlink *new = (struct globlink *)
++ __alloca (sizeof (struct globlink));
++ len = NAMLEN (d);
++ new->name = (char *) malloc (len + 1);
++ if (new->name == NULL)
++ goto memory_error;
++#ifdef HAVE_MEMPCPY
++ *((char *) mempcpy ((__ptr_t) new->name, name, len))
++ = '\0';
++#else
++ memcpy ((__ptr_t) new->name, name, len);
++ new->name[len] = '\0';
++#endif
++ new->next = names;
++ names = new;
++ ++nfound;
++ }
++ }
++ }
++ }
++ }
++
++ if (nfound == 0 && (flags & GLOB_NOCHECK))
++ {
++ size_t len = strlen (pattern);
++ nfound = 1;
++ names = (struct globlink *) __alloca (sizeof (struct globlink));
++ names->next = NULL;
++ names->name = (char *) malloc (len + 1);
++ if (names->name == NULL)
++ goto memory_error;
++#ifdef HAVE_MEMPCPY
++ *((char *) mempcpy (names->name, pattern, len)) = '\0';
++#else
++ memcpy (names->name, pattern, len);
++ names->name[len] = '\0';
++#endif
++ }
++
++ if (nfound != 0)
++ {
++ pglob->gl_pathv
++ = (char **) realloc (pglob->gl_pathv,
++ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
++ * sizeof (char *));
++ if (pglob->gl_pathv == NULL)
++ goto memory_error;
++
++ for (; names != NULL; names = names->next)
++ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc++] = names->name;
++ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
++
++ pglob->gl_flags = flags;
++ }
++
++ save = errno;
++ if (stream != NULL)
++ {
++ if (flags & GLOB_ALTDIRFUNC)
++ (*pglob->gl_closedir) (stream);
++ else
++ closedir ((DIR *) stream);
++ }
++ __set_errno (save);
++
++ return nfound == 0 ? GLOB_NOMATCH : 0;
++
++ memory_error:
++ {
++ int save = errno;
++ if (flags & GLOB_ALTDIRFUNC)
++ (*pglob->gl_closedir) (stream);
++ else
++ closedir ((DIR *) stream);
++ __set_errno (save);
++ }
++ while (names != NULL)
++ {
++ if (names->name != NULL)
++ free ((__ptr_t) names->name);
++ names = names->next;
++ }
++ return GLOB_NOSPACE;
++}
++
++#endif /* Not ELIDE_CODE. */
+diff -urN proftpd-1.2.1/lib/glob.c proftpd-1.2/lib/glob.c
+--- proftpd-1.2.1/lib/glob.c Wed Jul 26 10:16:33 2000
++++ proftpd-1.2/lib/glob.c Thu Jan 1 01:00:00 1970
+@@ -1,1108 +0,0 @@
+-/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
+-
+- This library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public License as
+- published by the Free Software Foundation; either version 2 of the
+- License, or (at your option) any later version.
+-
+- This library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with this library; see the file COPYING.LIB. If not,
+- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+- Boston, MA 02111-1307, USA. */
+-
+-/* AIX requires this to be the first thing in the file. */
+-#if defined _AIX && !defined __GNUC__
+- #pragma alloca
+-#endif
+-
+-/* Enable GNU extensions in glob.h. */
+-#ifndef _GNU_SOURCE
+-# define _GNU_SOURCE 1
+-#endif
+-
+-/* Required to tell conf.h not to include the standard ProFTPD
+- * header files
+- */
+-
+-#define __PROFTPD_SUPPORT_LIBRARY
+-
+-#include <conf.h>
+-
+-#include <errno.h>
+-#include <sys/types.h>
+-#include <sys/stat.h>
+-
+-#include <assert.h>
+-#include <stdio.h> /* Needed on stupid SunOS for assert. */
+-
+-#include <libsupp.h>
+-
+-#undef _LIBC
+-#undef __GNU_LIBRARY__
+-
+-#ifndef HAVE_GLOB
+-
+-/* Comment out all this code if we are using the GNU C Library, and are not
+- actually compiling the library itself. This code is part of the GNU C
+- Library, but also included in many other GNU distributions. Compiling
+- and linking in this code is a waste when using the GNU C library
+- (especially if it is a shared library). Rather than having every GNU
+- program understand `configure --with-gnu-libc' and omit the object files,
+- it is simpler to just do this in the source for each such file. */
+-
+-#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
+-# include <stddef.h>
+-#endif
+-
+-#if defined(HAVE_UNISTD_H) || defined(_LIBC)
+-# include <unistd.h>
+-# ifndef POSIX
+-# ifdef _POSIX_VERSION
+-# define POSIX
+-# endif
+-# endif
+-#endif
+-
+-#if !defined(_AMIGA) && !defined(VMS) && !defined(WINDOWS32)
+-# include <pwd.h>
+-#endif
+-
+-#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+-extern int errno;
+-#endif
+-#ifndef __set_errno
+-# define __set_errno(val) errno = (val)
+-#endif
+-
+-#ifndef NULL
+-# define NULL 0
+-#endif
+-
+-#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+-# include <dirent.h>
+-# define NAMLEN(dirent) strlen((dirent)->d_name)
+-#else
+-# define dirent direct
+-# define NAMLEN(dirent) (dirent)->d_namlen
+-# ifdef HAVE_SYS_NDIR_H
+-# include <sys/ndir.h>
+-# endif
+-# ifdef HAVE_SYS_DIR_H
+-# include <sys/dir.h>
+-# endif
+-# ifdef HAVE_NDIR_H
+-# include <ndir.h>
+-# endif
+-# ifdef HAVE_VMSDIR_H
+-# include "vmsdir.h"
+-# endif /* HAVE_VMSDIR_H */
+-#endif
+-
+-/* In GNU systems, <dirent.h> defines this macro for us. */
+-#ifdef _D_NAMLEN
+-# undef NAMLEN
+-# define NAMLEN(d) _D_NAMLEN(d)
+-#endif
+-
+-#ifdef _DIRENT_HAVE_D_TYPE
+-# define HAVE_D_TYPE 1
+-#endif
+-
+-#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+-/* Posix does not require that the d_ino field be present, and some
+- systems do not provide it. */
+-# define REAL_DIR_ENTRY(dp) 1
+-#else
+-# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+-#endif /* POSIX */
+-
+-#if defined STDC_HEADERS || defined __GNU_LIBRARY__
+-# include <stdlib.h>
+-# include <string.h>
+-# define ANSI_STRING
+-#else /* No standard headers. */
+-
+-extern char *getenv ();
+-
+-# ifdef HAVE_STRING_H
+-# include <string.h>
+-# define ANSI_STRING
+-# else
+-# include <strings.h>
+-# endif
+-# ifdef HAVE_MEMORY_H
+-# include <memory.h>
+-# endif
+-
+-#ifndef __osf__
+-extern char *malloc (), *realloc ();
+-extern void free ();
+-
+-extern void qsort ();
+-extern void abort (), exit ();
+-#endif /* __osf__ */
+-
+-#endif /* Standard headers. */
+-
+-#ifndef ANSI_STRING
+-
+-# ifndef bzero
+-extern void bzero ();
+-# endif
+-# ifndef bcopy
+-extern void bcopy ();
+-# endif
+-
+-# undef memcpy
+-# define memcpy(d, s, n) bcopy ((s), (d), (n))
+-# undef strrchr
+-# define strrchr rindex
+-/* memset is only used for zero here, but let's be paranoid. */
+-# undef memset
+-# define memset(s, better_be_zero, n) \
+- ((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0)))
+-#endif /* Not ANSI_STRING. */
+-
+-#if !defined HAVE_STRCOLL && !defined _LIBC
+-# define strcoll strcmp
+-#endif
+-
+-#if !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1
+-# define HAVE_MEMPCPY 1
+-# define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len)
+-#endif
+-
+-#ifndef __GNU_LIBRARY__
+-# ifdef __GNUC__
+-__inline
+-# endif
+-# ifndef __SASC
+-# ifdef WINDOWS32
+-static void *
+-# else
+-static char *
+-# endif
+-my_realloc (p, n)
+- char *p;
+- unsigned int n;
+-{
+- /* These casts are the for sake of the broken Ultrix compiler,
+- which warns of illegal pointer combinations otherwise. */
+- if (p == NULL)
+- return (char *) malloc (n);
+- return (char *) realloc (p, n);
+-}
+-# define realloc my_realloc
+-# endif /* __SASC */
+-#endif /* __GNU_LIBRARY__ */
+-
+-
+-#if !defined __alloca && !defined __GNU_LIBRARY__
+-
+-# ifdef __GNUC__
+-# undef alloca
+-# define alloca(n) __builtin_alloca (n)
+-# else /* Not GCC. */
+-# ifdef HAVE_ALLOCA_H
+-# include <alloca.h>
+-# else /* Not HAVE_ALLOCA_H. */
+-# ifndef _AIX
+-# ifdef WINDOWS32
+-# include <malloc.h>
+-# else
+-extern char *alloca ();
+-# endif /* WINDOWS32 */
+-# endif /* Not _AIX. */
+-# endif /* sparc or HAVE_ALLOCA_H. */
+-# endif /* GCC. */
+-
+-# define __alloca alloca
+-
+-#endif
+-
+-#ifndef __GNU_LIBRARY__
+-# define __stat stat
+-# ifdef STAT_MACROS_BROKEN
+-# undef S_ISDIR
+-# endif
+-# ifndef S_ISDIR
+-# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+-# endif
+-#endif
+-
+-#if !(defined STDC_HEADERS || defined __GNU_LIBRARY__)
+-# undef size_t
+-# define size_t unsigned int
+-#endif
+-
+-/* Some system header files erroneously define these.
+- We want our own definitions from <glob.h> to take precedence. */
+-#undef GLOB_ERR
+-#undef GLOB_MARK
+-#undef GLOB_NOSORT
+-#undef GLOB_DOOFFS
+-#undef GLOB_NOCHECK
+-#undef GLOB_APPEND
+-#undef GLOB_NOESCAPE
+-#undef GLOB_PERIOD
+-#include "glob.h"
+-
+-static
+-#if __GNUC__ - 0 >= 2
+-inline
+-#endif
+-const char *next_brace_sub __P ((const char *begin));
+-static int glob_in_dir __P ((const char *pattern, const char *directory,
+- int flags,
+- int (*errfunc) __P ((const char *, int)),
+- glob_t *pglob));
+-static int prefix_array __P ((const char *prefix, char **array, size_t n));
+-static int collated_compare __P ((const __ptr_t, const __ptr_t));
+-
+-
+-/* Find the end of the sub-pattern in a brace expression. We define
+- this as an inline function if the compiler permits. */
+-static
+-#if __GNUC__ - 0 >= 2
+-inline
+-#endif
+-const char *
+-next_brace_sub (begin)
+- const char *begin;
+-{
+- unsigned int depth = 0;
+- const char *cp = begin;
+-
+- while (1)
+- {
+- if (depth == 0)
+- {
+- if (*cp != ',' && *cp != '}' && *cp != '\0')
+- {
+- if (*cp == '{')
+- ++depth;
+- ++cp;
+- continue;
+- }
+- }
+- else
+- {
+- while (*cp != '\0' && (*cp != '}' || depth > 0))
+- {
+- if (*cp == '}')
+- --depth;
+- ++cp;
+- }
+- if (*cp == '\0')
+- /* An incorrectly terminated brace expression. */
+- return NULL;
+-
+- continue;
+- }
+- break;
+- }
+-
+- return cp;
+-}
+-
+-/* Do glob searching for PATTERN, placing results in PGLOB.
+- The bits defined above may be set in FLAGS.
+- If a directory cannot be opened or read and ERRFUNC is not nil,
+- it is called with the pathname that caused the error, and the
+- `errno' value from the failing call; if it returns non-zero
+- `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+- If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+- Otherwise, `glob' returns zero. */
+-int
+-glob (pattern, flags, errfunc, pglob)
+- const char *pattern;
+- int flags;
+- int (*errfunc) __P ((const char *, int));
+- glob_t *pglob;
+-{
+- const char *filename;
+- char *dirname;
+- size_t dirlen;
+- int status;
+- int oldcount;
+-
+- if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
+- {
+- __set_errno (EINVAL);
+- return -1;
+- }
+-
+- if (flags & GLOB_BRACE)
+- {
+- const char *begin = strchr (pattern, '{');
+- if (begin != NULL)
+- {
+- /* Allocate working buffer large enough for our work. Note that
+- we have at least an opening and closing brace. */
+- int firstc;
+- char *alt_start;
+- const char *p;
+- const char *next;
+- const char *rest;
+- size_t rest_len;
+-#ifdef __GNUC__
+- char onealt[strlen (pattern) - 1];
+-#else
+- char *onealt = (char *) malloc (strlen (pattern) - 1);
+- if (onealt == NULL)
+- {
+- if (!(flags & GLOB_APPEND))
+- globfree (pglob);
+- return GLOB_NOSPACE;
+- }
+-#endif
+-
+- /* We know the prefix for all sub-patterns. */
+-#ifdef HAVE_MEMPCPY
+- alt_start = mempcpy (onealt, pattern, begin - pattern);
+-#else
+- memcpy (onealt, pattern, begin - pattern);
+- alt_start = &onealt[begin - pattern];
+-#endif
+-
+- /* Find the first sub-pattern and at the same time find the
+- rest after the closing brace. */
+- next = next_brace_sub (begin + 1);
+- if (next == NULL)
+- {
+- /* It is an illegal expression. */
+-#ifndef __GNUC__
+- free (onealt);
+-#endif
+- return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+- }
+-
+- /* Now find the end of the whole brace expression. */
+- rest = next;
+- while (*rest != '}')
+- {
+- rest = next_brace_sub (rest + 1);
+- if (rest == NULL)
+- {
+- /* It is an illegal expression. */
+-#ifndef __GNUC__
+- free (onealt);
+-#endif
+- return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+- }
+- }
+- /* Please note that we now can be sure the brace expression
+- is well-formed. */
+- rest_len = strlen (++rest) + 1;
+-
+- /* We have a brace expression. BEGIN points to the opening {,
+- NEXT points past the terminator of the first element, and END
+- points past the final }. We will accumulate result names from
+- recursive runs for each brace alternative in the buffer using
+- GLOB_APPEND. */
+-
+- if (!(flags & GLOB_APPEND))
+- {
+- /* This call is to set a new vector, so clear out the
+- vector so we can append to it. */
+- pglob->gl_pathc = 0;
+- pglob->gl_pathv = NULL;
+- }
+- firstc = pglob->gl_pathc;
+-
+- p = begin + 1;
+- while (1)
+- {
+- int result;
+-
+- /* Construct the new glob expression. */
+-#ifdef HAVE_MEMPCPY
+- mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+-#else
+- memcpy (alt_start, p, next - p);
+- memcpy (&alt_start[next - p], rest, rest_len);
+-#endif
+-
+- result = glob (onealt,
+- ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC))
+- | GLOB_APPEND), errfunc, pglob);
+-
+- /* If we got an error, return it. */
+- if (result && result != GLOB_NOMATCH)
+- {
+-#ifndef __GNUC__
+- free (onealt);
+-#endif
+- if (!(flags & GLOB_APPEND))
+- globfree (pglob);
+- return result;
+- }
+-
+- if (*next == '}')
+- /* We saw the last entry. */
+- break;
+-
+- p = next + 1;
+- next = next_brace_sub (p);
+- assert (next != NULL);
+- }
+-
+-#ifndef __GNUC__
+- free (onealt);
+-#endif
+-
+- if (pglob->gl_pathc != firstc)
+- /* We found some entries. */
+- return 0;
+- else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+- return GLOB_NOMATCH;
+- }
+- }
+-
+- /* Find the filename. */
+- filename = strrchr (pattern, '/');
+- if (filename == NULL)
+- {
+- filename = pattern;
+-#ifdef _AMIGA
+- dirname = (char *) "";
+-#else
+- dirname = (char *) ".";
+-#endif
+- dirlen = 0;
+- }
+- else if (filename == pattern)
+- {
+- /* "/pattern". */
+- dirname = (char *) "/";
+- dirlen = 1;
+- ++filename;
+- }
+- else
+- {
+- dirlen = filename - pattern;
+- dirname = (char *) __alloca (dirlen + 1);
+-#ifdef HAVE_MEMPCPY
+- *((char *) mempcpy (dirname, pattern, dirlen)) = '\0';
+-#else
+- memcpy (dirname, pattern, dirlen);
+- dirname[dirlen] = '\0';
+-#endif
+- ++filename;
+- }
+-
+- if (filename[0] == '\0' && dirlen > 1)
+- /* "pattern/". Expand "pattern", appending slashes. */
+- {
+- int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+- if (val == 0)
+- pglob->gl_flags = (pglob->gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK);
+- return val;
+- }
+-
+- if (!(flags & GLOB_APPEND))
+- {
+- pglob->gl_pathc = 0;
+- pglob->gl_pathv = NULL;
+- }
+-
+- oldcount = pglob->gl_pathc;
+-
+-#ifndef VMS
+- if ((flags & GLOB_TILDE) && dirname[0] == '~')
+- {
+- if (dirname[1] == '\0' || dirname[1] == '/')
+- {
+- /* Look up home directory. */
+- char *home_dir = getenv ("HOME");
+-# ifdef _AMIGA
+- if (home_dir == NULL || home_dir[0] == '\0')
+- home_dir = "SYS:";
+-# else
+-# ifdef WINDOWS32
+- if (home_dir == NULL || home_dir[0] == '\0')
+- home_dir = "c:/users/default"; /* poor default */
+-# else
+- if (home_dir == NULL || home_dir[0] == '\0')
+- {
+- int success;
+-# if defined HAVE_GETLOGIN_R || defined _LIBC
+- extern int getlogin_r __P ((char *, size_t));
+- size_t buflen = sysconf (_SC_LOGIN_NAME_MAX) + 1;
+- char *name;
+-
+- if (buflen == 0)
+- /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
+- a moderate value. */
+- buflen = 16;
+- name = (char *) __alloca (buflen);
+-
+- success = getlogin_r (name, buflen) >= 0;
+-# else
+- extern char *getlogin __P ((void));
+- char *name;
+-
+- success = (name = getlogin ()) != NULL;
+-# endif
+- if (success)
+- {
+-# if defined HAVE_GETPWNAM_R || defined _LIBC
+- size_t pwbuflen = sysconf (_SC_GETPW_R_SIZE_MAX);
+- char *pwtmpbuf;
+- struct passwd pwbuf, *p;
+-
+- pwtmpbuf = (char *) __alloca (pwbuflen);
+-
+- success = (__getpwnam_r (name, &pwbuf, pwtmpbuf,
+- pwbuflen, &p) >= 0);
+-# else
+- struct passwd *p = getpwnam (name);
+- success = p != NULL;
+-# endif
+- if (success)
+- home_dir = p->pw_dir;
+- }
+- }
+- if (home_dir == NULL || home_dir[0] == '\0')
+- home_dir = (char *) "~"; /* No luck. */
+-# endif /* WINDOWS32 */
+-# endif
+- /* Now construct the full directory. */
+- if (dirname[1] == '\0')
+- dirname = home_dir;
+- else
+- {
+- char *newp;
+- size_t home_len = strlen (home_dir);
+- newp = (char *) __alloca (home_len + dirlen);
+-# ifdef HAVE_MEMPCPY
+- mempcpy (mempcpy (newp, home_dir, home_len),
+- &dirname[1], dirlen);
+-# else
+- memcpy (newp, home_dir, home_len);
+- memcpy (&newp[home_len], &dirname[1], dirlen);
+-# endif
+- dirname = newp;
+- }
+- }
+-# if !defined _AMIGA && !defined WINDOWS32
+- else
+- {
+- char *end_name = strchr (dirname, '/');
+- char *user_name;
+- char *home_dir;
+-
+- if (end_name == NULL)
+- user_name = dirname + 1;
+- else
+- {
+- user_name = (char *) __alloca (end_name - dirname);
+-# ifdef HAVE_MEMPCPY
+- *((char *) mempcpy (user_name, dirname + 1, end_name - dirname))
+- = '\0';
+-# else
+- memcpy (user_name, dirname + 1, end_name - dirname);
+- user_name[end_name - dirname - 1] = '\0';
+-# endif
+- }
+-
+- /* Look up specific user's home directory. */
+- {
+-# if defined HAVE_GETPWNAM_R || defined _LIBC
+- size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
+- char *pwtmpbuf = (char *) __alloca (buflen);
+- struct passwd pwbuf, *p;
+- if (__getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) >= 0)
+- home_dir = p->pw_dir;
+- else
+- home_dir = NULL;
+-# else
+- struct passwd *p = getpwnam (user_name);
+- if (p != NULL)
+- home_dir = p->pw_dir;
+- else
+- home_dir = NULL;
+-# endif
+- }
+- /* If we found a home directory use this. */
+- if (home_dir != NULL)
+- {
+- char *newp;
+- size_t home_len = strlen (home_dir);
+- size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+- newp = (char *) __alloca (home_len + rest_len + 1);
+-# ifdef HAVE_MEMPCPY
+- *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
+- end_name, rest_len)) = '\0';
+-# else
+- memcpy (newp, home_dir, home_len);
+- memcpy (&newp[home_len], end_name, rest_len);
+- newp[home_len + rest_len] = '\0';
+-# endif
+- dirname = newp;
+- }
+- }
+-# endif /* Not Amiga && not WINDOWS32. */
+- }
+-#endif /* Not VMS. */
+-
+- if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
+- {
+- /* The directory name contains metacharacters, so we
+- have to glob for the directory, and then glob for
+- the pattern in each directory found. */
+- glob_t dirs;
+- register int i;
+-
+- status = glob (dirname,
+- ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE))
+- | GLOB_NOSORT | GLOB_ONLYDIR),
+- errfunc, &dirs);
+- if (status != 0)
+- return status;
+-
+- /* We have successfully globbed the preceding directory name.
+- For each name we found, call glob_in_dir on it and FILENAME,
+- appending the results to PGLOB. */
+- for (i = 0; i < dirs.gl_pathc; ++i)
+- {
+- int oldcount;
+-
+-#ifdef SHELL
+- {
+- /* Make globbing interruptible in the bash shell. */
+- extern int interrupt_state;
+-
+- if (interrupt_state)
+- {
+- globfree (&dirs);
+- globfree (&files);
+- return GLOB_ABORTED;
+- }
+- }
+-#endif /* SHELL. */
+-
+- oldcount = pglob->gl_pathc;
+- status = glob_in_dir (filename, dirs.gl_pathv[i],
+- ((flags | GLOB_APPEND)
+- & ~(GLOB_NOCHECK | GLOB_ERR)),
+- errfunc, pglob);
+- if (status == GLOB_NOMATCH)
+- /* No matches in this directory. Try the next. */
+- continue;
+-
+- if (status != 0)
+- {
+- globfree (&dirs);
+- globfree (pglob);
+- return status;
+- }
+-
+- /* Stick the directory on the front of each name. */
+- if (prefix_array (dirs.gl_pathv[i],
+- &pglob->gl_pathv[oldcount],
+- pglob->gl_pathc - oldcount))
+- {
+- globfree (&dirs);
+- globfree (pglob);
+- return GLOB_NOSPACE;
+- }
+- }
+-
+- flags |= GLOB_MAGCHAR;
+-
+- if (pglob->gl_pathc == oldcount)
+- {
+- /* No matches. */
+- if (flags & GLOB_NOCHECK)
+- {
+- size_t len = strlen (pattern) + 1;
+- char *patcopy = (char *) malloc (len);
+- if (patcopy == NULL)
+- return GLOB_NOSPACE;
+- memcpy (patcopy, pattern, len);
+-
+- pglob->gl_pathv
+- = (char **) realloc (pglob->gl_pathv,
+- (pglob->gl_pathc +
+- ((flags & GLOB_DOOFFS) ?
+- pglob->gl_offs : 0) +
+- 1 + 1) *
+- sizeof (char *));
+- if (pglob->gl_pathv == NULL)
+- {
+- free (patcopy);
+- return GLOB_NOSPACE;
+- }
+-
+- if (flags & GLOB_DOOFFS)
+- while (pglob->gl_pathc < pglob->gl_offs)
+- pglob->gl_pathv[pglob->gl_pathc++] = NULL;
+-
+- pglob->gl_pathv[pglob->gl_pathc++] = patcopy;
+- pglob->gl_pathv[pglob->gl_pathc] = NULL;
+- pglob->gl_flags = flags;
+- }
+- else {
+- return GLOB_NOMATCH;
+- }
+- }
+- }
+- else
+- {
+- status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
+- if (status != 0)
+- return status;
+-
+- if (dirlen > 0)
+- {
+- /* Stick the directory on the front of each name. */
+- if (prefix_array (dirname,
+- &pglob->gl_pathv[oldcount],
+- pglob->gl_pathc - oldcount))
+- {
+- globfree (pglob);
+- return GLOB_NOSPACE;
+- }
+- }
+- }
+-
+- if (flags & GLOB_MARK)
+- {
+- /* Append slashes to directory names. */
+- int i;
+- struct stat st;
+- for (i = oldcount; i < pglob->gl_pathc; ++i)
+- if (((flags & GLOB_ALTDIRFUNC) ?
+- (*pglob->gl_stat) (pglob->gl_pathv[i], &st) :
+- __stat (pglob->gl_pathv[i], &st)) == 0 &&
+- S_ISDIR (st.st_mode))
+- {
+- size_t len = strlen (pglob->gl_pathv[i]) + 2;
+- char *new = realloc (pglob->gl_pathv[i], len);
+- if (new == NULL)
+- {
+- globfree (pglob);
+- return GLOB_NOSPACE;
+- }
+- strncpy (&new[len - 2], "/", 2);
+- pglob->gl_pathv[i] = new;
+- }
+- }
+-
+- if (!(flags & GLOB_NOSORT))
+- /* Sort the vector. */
+- qsort ((__ptr_t) &pglob->gl_pathv[oldcount],
+- pglob->gl_pathc - oldcount,
+- sizeof (char *), collated_compare);
+-
+- return 0;
+-}
+-
+-
+-/* Free storage allocated in PGLOB by a previous `glob' call. */
+-void
+-globfree (pglob)
+- register glob_t *pglob;
+-{
+- if (pglob->gl_pathv != NULL)
+- {
+- register int i;
+- for (i = 0; i < pglob->gl_pathc; ++i)
+- if (pglob->gl_pathv[i] != NULL)
+- free ((__ptr_t) pglob->gl_pathv[i]);
+- free ((__ptr_t) pglob->gl_pathv);
+- }
+-}
+-
+-
+-/* Do a collated comparison of A and B. */
+-static int
+-collated_compare (a, b)
+- const __ptr_t a;
+- const __ptr_t b;
+-{
+- const char *const s1 = *(const char *const * const) a;
+- const char *const s2 = *(const char *const * const) b;
+-
+- if (s1 == s2)
+- return 0;
+- if (s1 == NULL)
+- return 1;
+- if (s2 == NULL)
+- return -1;
+- return strcoll (s1, s2);
+-}
+-
+-
+-/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
+- elements in place. Return nonzero if out of memory, zero if successful.
+- A slash is inserted between DIRNAME and each elt of ARRAY,
+- unless DIRNAME is just "/". Each old element of ARRAY is freed. */
+-static int
+-prefix_array (dirname, array, n)
+- const char *dirname;
+- char **array;
+- size_t n;
+-{
+- register size_t i;
+- size_t dirlen = strlen (dirname);
+-
+- if (dirlen == 1 && dirname[0] == '/')
+- /* DIRNAME is just "/", so normal prepending would get us "//foo".
+- We want "/foo" instead, so don't prepend any chars from DIRNAME. */
+- dirlen = 0;
+-
+- for (i = 0; i < n; ++i)
+- {
+- size_t eltlen = strlen (array[i]) + 1;
+- char *new = (char *) malloc (dirlen + 1 + eltlen);
+- if (new == NULL)
+- {
+- while (i > 0)
+- free ((__ptr_t) array[--i]);
+- return 1;
+- }
+-
+-#ifdef HAVE_MEMPCPY
+- {
+- char *endp = (char *) mempcpy (new, dirname, dirlen);
+- *endp++ = '/';
+- mempcpy (endp, array[i], eltlen);
+- }
+-#else
+- memcpy (new, dirname, dirlen);
+- new[dirlen] = '/';
+- memcpy (&new[dirlen + 1], array[i], eltlen);
+-#endif
+- free ((__ptr_t) array[i]);
+- array[i] = new;
+- }
+-
+- return 0;
+-}
+-
+-
+-/* Return nonzero if PATTERN contains any metacharacters.
+- Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
+-int
+-__glob_pattern_p (pattern, quote)
+- const char *pattern;
+- int quote;
+-{
+- register const char *p;
+- int open = 0;
+-
+- for (p = pattern; *p != '\0'; ++p)
+- switch (*p)
+- {
+- case '?':
+- case '*':
+- return 1;
+-
+- case '\\':
+- if (quote && p[1] != '\0')
+- ++p;
+- break;
+-
+- case '[':
+- open = 1;
+- break;
+-
+- case ']':
+- if (open)
+- return 1;
+- break;
+- }
+-
+- return 0;
+-}
+-#ifdef _LIBC
+-weak_alias (__glob_pattern_p, glob_pattern_p)
+-#endif
+-
+-
+-/* Like `glob', but PATTERN is a final pathname component,
+- and matches are searched for in DIRECTORY.
+- The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
+- The GLOB_APPEND flag is assumed to be set (always appends). */
+-static int
+-glob_in_dir (pattern, directory, flags, errfunc, pglob)
+- const char *pattern;
+- const char *directory;
+- int flags;
+- int (*errfunc) __P ((const char *, int));
+- glob_t *pglob;
+-{
+- __ptr_t stream;
+-
+- struct globlink
+- {
+- struct globlink *next;
+- char *name;
+- };
+- struct globlink *names = NULL;
+- size_t nfound;
+- int meta;
+- int save;
+-
+- stream = ((flags & GLOB_ALTDIRFUNC) ?
+- (*pglob->gl_opendir) (directory) :
+- (__ptr_t) opendir (directory));
+- if (stream == NULL)
+- {
+- if ((errfunc != NULL && (*errfunc) (directory, errno)) ||
+- (flags & GLOB_ERR))
+- return GLOB_ABORTED;
+- nfound = 0;
+- meta = 0;
+- }
+- else if (pattern[0] == '\0')
+- {
+- /* This is a special case for matching directories like in
+- "*a/". */
+- names = (struct globlink *) __alloca (sizeof (struct globlink));
+- names->name = (char *) malloc (1);
+- if (names->name == NULL)
+- goto memory_error;
+- names->name[0] = '\0';
+- names->next = NULL;
+- nfound = 1;
+- meta = 0;
+- }
+- else
+- {
+- nfound = 0;
+- meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
+- if(meta)
+- flags |= GLOB_MAGCHAR;
+-
+- while (1)
+- {
+- const char *name;
+- size_t len;
+- struct dirent *d = ((flags & GLOB_ALTDIRFUNC) ?
+- (*pglob->gl_readdir) (stream) :
+- readdir ((DIR *) stream));
+- if (d == NULL)
+- break;
+- if (! REAL_DIR_ENTRY (d))
+- continue;
+-
+-#ifdef HAVE_D_TYPE
+- /* If we shall match only directories use the information
+- provided by the dirent call if possible. */
+- if ((flags & GLOB_ONLYDIR)
+- && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
+- continue;
+-#endif
+-
+- name = d->d_name;
+-
+- if ((!meta && strcmp (pattern, name) == 0)
+- || pr_fnmatch (pattern, name,
+- (!(flags & GLOB_PERIOD) ? PR_FNM_PERIOD : 0) |
+- ((flags & GLOB_NOESCAPE) ? PR_FNM_NOESCAPE : 0)
+-#ifdef _AMIGA
+- | FNM_CASEFOLD
+-#endif
+- ) == 0)
+- {
+- struct globlink *new
+- = (struct globlink *) __alloca (sizeof (struct globlink));
+- len = NAMLEN (d);
+- new->name = (char *) malloc (len + 1);
+- if (new->name == NULL)
+- goto memory_error;
+-#ifdef HAVE_MEMPCPY
+- *((char *) mempcpy ((__ptr_t) new->name, name, len)) = '\0';
+-#else
+- memcpy ((__ptr_t) new->name, name, len);
+- new->name[len] = '\0';
+-#endif
+- new->next = names;
+- names = new;
+- ++nfound;
+- if (!meta)
+- break;
+- }
+- }
+- }
+-
+- if (nfound == 0 && (flags & GLOB_NOMAGIC) && !meta)
+- flags |= GLOB_NOCHECK;
+-
+- if (nfound == 0 && (flags & GLOB_NOCHECK))
+- {
+- size_t len = strlen (pattern);
+- nfound = 1;
+- names = (struct globlink *) __alloca (sizeof (struct globlink));
+- names->next = NULL;
+- names->name = (char *) malloc (len + 1);
+- if (names->name == NULL)
+- goto memory_error;
+-#ifdef HAVE_MEMPCPY
+- *((char *) mempcpy (names->name, pattern, len)) = '\0';
+-#else
+- memcpy (names->name, pattern, len);
+- names->name[len] = '\0';
+-#endif
+- }
+-
+- if (nfound != 0)
+- {
+- pglob->gl_pathv
+- = (char **) realloc (pglob->gl_pathv,
+- (pglob->gl_pathc +
+- ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) +
+- nfound + 1) *
+- sizeof (char *));
+- if (pglob->gl_pathv == NULL)
+- goto memory_error;
+-
+- if (flags & GLOB_DOOFFS)
+- while (pglob->gl_pathc < pglob->gl_offs)
+- pglob->gl_pathv[pglob->gl_pathc++] = NULL;
+-
+- for (; names != NULL; names = names->next)
+- pglob->gl_pathv[pglob->gl_pathc++] = names->name;
+- pglob->gl_pathv[pglob->gl_pathc] = NULL;
+-
+- pglob->gl_flags = flags;
+- }
+-
+- save = errno;
+- if(stream) {
+- if (flags & GLOB_ALTDIRFUNC)
+- (*pglob->gl_closedir) (stream);
+- else
+- closedir ((DIR *) stream);
+- }
+- __set_errno (save);
+-
+- return nfound == 0 ? GLOB_NOMATCH : 0;
+-
+- memory_error:
+- {
+- int save = errno;
+- if (flags & GLOB_ALTDIRFUNC)
+- (*pglob->gl_closedir) (stream);
+- else
+- closedir ((DIR *) stream);
+- __set_errno (save);
+- }
+- while (names != NULL)
+- {
+- if (names->name != NULL)
+- free ((__ptr_t) names->name);
+- names = names->next;
+- }
+- return GLOB_NOSPACE;
+-}
+-
+-#endif /* HAVE_GLOB */
+diff -urN proftpd-1.2.1/lib/glob.h proftpd-1.2/lib/glob.h
+--- proftpd-1.2.1/lib/glob.h Sun Oct 18 04:24:41 1998
++++ proftpd-1.2/lib/glob.h Thu Jan 1 01:00:00 1970
+@@ -1,133 +0,0 @@
+-/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Library General Public License as
+- published by the Free Software Foundation; either version 2 of the
+- License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Library General Public License for more details.
+-
+- You should have received a copy of the GNU Library General Public
+- License along with the GNU C Library; see the file COPYING.LIB. If not,
+- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+- Boston, MA 02111-1307, USA. */
+-
+-#ifndef _GLOB_H
+-#define _GLOB_H 1
+-
+-#ifdef __cplusplus
+-extern "C"
+-{
+-#endif
+-
+-#undef __ptr_t
+-#if (defined __cplusplus || (defined __STDC__ && __STDC__) \
+- || defined WINDOWS32)
+-# undef __P
+-# define __P(protos) protos
+-# define __ptr_t void *
+-# if !defined __GNUC__ || __GNUC__ < 2
+-# undef __const
+-# define __const const
+-# endif
+-#else /* Not C++ or ANSI C. */
+-# undef __P
+-# define __P(protos) ()
+-# undef __const
+-# define __const
+-# define __ptr_t char *
+-#endif /* C++ or ANSI C. */
+-
+-/* Bits set in the FLAGS argument to `glob'. */
+-#define GLOB_ERR (1 << 0)/* Return on read errors. */
+-#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
+-#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
+-#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
+-#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
+-#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
+-#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
+-#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */
+-
+-#if (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _BSD_SOURCE \
+- || defined _GNU_SOURCE)
+-# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
+-# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
+-# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
+-# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
+-# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
+-# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
+-# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+- GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+- GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
+- GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR)
+-#else
+-# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+- GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
+- GLOB_PERIOD)
+-#endif
+-
+-/* Error returns from `glob'. */
+-#define GLOB_NOSPACE 1 /* Ran out of memory. */
+-#define GLOB_ABORTED 2 /* Read error. */
+-#define GLOB_NOMATCH 3 /* No matches found. */
+-
+-#ifdef _GNU_SOURCE
+-/* Previous versions of this file defined GLOB_ABEND instead of
+- GLOB_ABORTED. Provide a compatibility definition here. */
+-# define GLOB_ABEND GLOB_ABORTED
+-#endif
+-
+-/* Structure describing a globbing run. */
+-#if !defined _AMIGA && !defined VMS /* Buggy compiler. */
+-struct stat;
+-#endif
+-typedef struct
+- {
+- int gl_pathc; /* Count of paths matched by the pattern. */
+- char **gl_pathv; /* List of matched pathnames. */
+- int gl_offs; /* Slots to reserve in `gl_pathv'. */
+- int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
+-
+- /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+- are used instead of the normal file access functions. */
+- void (*gl_closedir) __P ((void *));
+- struct dirent *(*gl_readdir) __P ((void *));
+- __ptr_t (*gl_opendir) __P ((__const char *));
+- int (*gl_lstat) __P ((__const char *, struct stat *));
+- int (*gl_stat) __P ((__const char *, struct stat *));
+- } glob_t;
+-
+-/* Do glob searching for PATTERN, placing results in PGLOB.
+- The bits defined above may be set in FLAGS.
+- If a directory cannot be opened or read and ERRFUNC is not nil,
+- it is called with the pathname that caused the error, and the
+- `errno' value from the failing call; if it returns non-zero
+- `glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
+- If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+- Otherwise, `glob' returns zero. */
+-extern int glob __P ((__const char *__pattern, int __flags,
+- int (*__errfunc) __P ((__const char *, int)),
+- glob_t *__pglob));
+-
+-/* Free storage allocated in PGLOB by a previous `glob' call. */
+-extern void globfree __P ((glob_t *__pglob));
+-
+-
+-#ifdef _GNU_SOURCE
+-/* Return nonzero if PATTERN contains any metacharacters.
+- Metacharacters can be quoted with backslashes if QUOTE is nonzero.
+-
+- This function is not part of the interface specified by POSIX.2
+- but several programs want to use it. */
+-extern int __glob_pattern_p __P ((__const char *__pattern, int __quote));
+-extern int glob_pattern_p __P ((__const char *__pattern, int __quote));
+-#endif
+-
+-#ifdef __cplusplus
+-}
+-#endif
+-
+-#endif /* glob.h */
+diff -urN proftpd-1.2.1/src/fs.c proftpd-1.2/src/fs.c
+--- proftpd-1.2.1/src/fs.c Sat Feb 3 00:09:26 2001
++++ proftpd-1.2/src/fs.c Mon Mar 19 23:11:36 2001
+@@ -19,7 +19,7 @@
+ */
+
+ /* ProFTPD virtual/modular file-system support
+- * $Id$
++ * $Id$
+ */
+
+ #include "conf.h"
+@@ -1132,10 +1132,10 @@
+ flags |= GLOB_ALTDIRFUNC;
+
+ pglob->gl_closedir = (void (*)(void*))fs_closedir;
+- pglob->gl_readdir = fs_readdir;
++ pglob->gl_readdir = (void*(*)(void*))fs_readdir;
+ pglob->gl_opendir = fs_opendir;
+- pglob->gl_lstat = fs_lstat;
+- pglob->gl_stat = fs_stat;
++ pglob->gl_lstat = (int (*)(const char *,void*))fs_lstat;
++ pglob->gl_stat = (int (*)(const char *,void*))fs_stat;
+ }
+
+ return glob(pattern,flags,errfunc,pglob);
+