]> git.pld-linux.org Git - packages/proftpd.git/commitdiff
fix for recently found critical bug
authorArkadiusz Miśkiewicz <arekm@maven.pl>
Sat, 24 Mar 2001 13:55:52 +0000 (13:55 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    proftpd-glob.patch -> 1.1

proftpd-glob.patch [new file with mode: 0644]

diff --git a/proftpd-glob.patch b/proftpd-glob.patch
new file mode 100644 (file)
index 0000000..4d60955
--- /dev/null
@@ -0,0 +1,3299 @@
+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);
+
This page took 0.542753 seconds and 4 git commands to generate.