summaryrefslogtreecommitdiff
path: root/libc/misc/glob/glob.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2006-07-04 10:59:15 +0000
committerEric Andersen <andersen@codepoet.org>2006-07-04 10:59:15 +0000
commitc3f8ec2942f0ccf54125c67442168cb983366987 (patch)
treebc30b54db26ca5ac3a7fba95aa959895cb2e0e32 /libc/misc/glob/glob.c
parent06980c0e6d7f025cc891537f3b7670e3e86693a1 (diff)
gcc 4.1.x is apparently miscompiling gnu glob on mips. This ports the latest and
massivly bloated greatest from glibc. And fixes things so the gnu glob interface is no longer the default.
Diffstat (limited to 'libc/misc/glob/glob.c')
-rw-r--r--libc/misc/glob/glob.c989
1 files changed, 764 insertions, 225 deletions
diff --git a/libc/misc/glob/glob.c b/libc/misc/glob/glob.c
index f1875e8e3..d36d048bf 100644
--- a/libc/misc/glob/glob.c
+++ b/libc/misc/glob/glob.c
@@ -26,6 +26,7 @@ Cambridge, MA 02139, USA. */
#include <malloc.h>
#include <fnmatch.h>
#include <glob.h>
+#include <pwd.h>
libc_hidden_proto(memcpy)
libc_hidden_proto(strcat)
@@ -38,66 +39,129 @@ libc_hidden_proto(closedir)
libc_hidden_proto(fnmatch)
libc_hidden_proto(qsort)
libc_hidden_proto(lstat)
+libc_hidden_proto(getpwnam_r)
+
+/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
+ if the `d_type' member for `struct dirent' is available.
+ HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */
+#if defined _DIRENT_HAVE_D_TYPE
+/* True if the directory entry D must be of type T. */
+# define DIRENT_MUST_BE(d, t) ((d)->d_type == (t))
+
+/* True if the directory entry D might be a symbolic link. */
+# define DIRENT_MIGHT_BE_SYMLINK(d) \
+ ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
+
+/* True if the directory entry D might be a directory. */
+# define DIRENT_MIGHT_BE_DIR(d) \
+ ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
+
+#else /* !HAVE_D_TYPE */
+# define DIRENT_MUST_BE(d, t) false
+# define DIRENT_MIGHT_BE_SYMLINK(d) true
+# define DIRENT_MIGHT_BE_DIR(d) true
+#endif /* HAVE_D_TYPE */
+
+
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#ifdef _D_NAMLEN
+# undef NAMLEN
+# define NAMLEN(d) _D_NAMLEN(d)
+#endif
+
+# if defined _DIRENT_HAVE_D_NAMLEN
+# define CONVERT_D_NAMLEN(d64, d32) (d64)->d_namlen = (d32)->d_namlen;
+# else
+# define CONVERT_D_NAMLEN(d64, d32)
+# endif
+
+# define CONVERT_D_INO(d64, d32) (d64)->d_ino = (d32)->d_ino;
+
+# ifdef _DIRENT_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)
extern __ptr_t (*__glob_opendir_hook) (const char *directory) attribute_hidden;
extern void (*__glob_closedir_hook) (__ptr_t stream) attribute_hidden;
extern const char *(*__glob_readdir_hook) (__ptr_t stream) attribute_hidden;
-extern int __collated_compare (const __ptr_t a, const __ptr_t b) attribute_hidden;
-extern int __prefix_array (const char *dirname, char **array, size_t n, int add_slash) attribute_hidden;
+extern int collated_compare (const __ptr_t a, const __ptr_t b);
+extern int prefix_array (const char *dirname, char **array, size_t n);
+extern const char * next_brace_sub (const char *cp, int flags);
+
+static int link_exists_p (const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob, int flags);
+static int glob_in_dir (const char *pattern, const char *directory, int flags,
+ int (*errfunc) (const char *, int),
+ glob_t *pglob);
libc_hidden_proto(glob_pattern_p)
-#ifdef __GLOB64
+libc_hidden_proto(collated_compare)
+libc_hidden_proto(prefix_array)
+libc_hidden_proto(next_brace_sub)
+#ifdef COMPILE_GLOB64
libc_hidden_proto(glob64)
libc_hidden_proto(globfree64)
libc_hidden_proto(readdir64)
-#define __readdir readdir64
+# define struct_stat64 struct stat64
+# define __stat64(fname, buf) stat64 (fname, buf)
#else
libc_hidden_proto(glob)
libc_hidden_proto(globfree)
#define __readdir readdir
+#define __readdir64 readdir64
+//#define __stat64(fname, buf) stat64 (fname, buf)
libc_hidden_proto(readdir)
+# define struct_stat64 struct stat
+# define __stat64(fname, buf) stat (fname, buf)
/* 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)
{
- const char *p;
- int open = 0;
+ register const char *p;
+ int open = 0;
- for (p = pattern; *p != '\0'; ++p)
- switch (*p)
- {
- case '?':
- case '*':
- return 1;
+ for (p = pattern; *p != '\0'; ++p)
+ switch (*p)
+ {
+ case '?':
+ case '*':
+ return 1;
- case '\\':
- if (quote && p[1] != '\0')
- ++p;
- break;
+ case '\\':
+ if (quote && p[1] != '\0')
+ ++p;
+ break;
- case '[':
- open = 1;
- break;
+ case '[':
+ open = 1;
+ break;
- case ']':
- if (open)
- return 1;
- break;
- }
+ case ']':
+ if (open)
+ return 1;
+ break;
+ }
- return 0;
+ return 0;
}
libc_hidden_def(glob_pattern_p)
/* Do a collated comparison of A and B. */
-int
-__collated_compare (const __ptr_t a, const __ptr_t b)
+int collated_compare (const void *a, const void *b)
{
- const char *const s1 = *(const char *const *) a;
- const char *const s2 = *(const char *const *) b;
+ const char *const s1 = *(const char *const * const) a;
+ const char *const s2 = *(const char *const * const) b;
if (s1 == s2)
return 0;
@@ -108,18 +172,15 @@ __collated_compare (const __ptr_t a, const __ptr_t b)
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.
- If ADD_SLASH is non-zero, allocate one character more than
- necessary, so that a slash can be appended later. */
-int
-__prefix_array (const char *dirname, char **array, size_t n, int add_slash)
+ unless DIRNAME is just "/". Each old element of ARRAY is freed. */
+int prefix_array (const char *dirname, char **array, size_t n)
{
register size_t i;
size_t dirlen = strlen (dirname);
+# define DIRSEP_CHAR '/'
if (dirlen == 1 && dirname[0] == '/')
/* DIRNAME is just "/", so normal prepending would get us "//foo".
@@ -129,105 +190,224 @@ __prefix_array (const char *dirname, char **array, size_t n, int add_slash)
for (i = 0; i < n; ++i)
{
size_t eltlen = strlen (array[i]) + 1;
- char *new = (char *) malloc (dirlen + 1 + eltlen + (add_slash ? 1 : 0));
+ char *new = (char *) malloc (dirlen + 1 + eltlen);
if (new == NULL)
{
while (i > 0)
- free ((__ptr_t) array[--i]);
+ free (array[--i]);
return 1;
}
- memcpy (new, dirname, dirlen);
- new[dirlen] = '/';
- memcpy (&new[dirlen + 1], array[i], eltlen);
- free ((__ptr_t) array[i]);
+ {
+ char *endp = mempcpy (new, dirname, dirlen);
+ *endp++ = DIRSEP_CHAR;
+ mempcpy (endp, array[i], eltlen);
+ }
+ free (array[i]);
array[i] = new;
}
return 0;
}
+
+/* Find the end of the sub-pattern in a brace expression. */
+const char *
+next_brace_sub (const char *cp, int flags)
+{
+ unsigned int depth = 0;
+ while (*cp != '\0')
+ if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
+ {
+ if (*++cp == '\0')
+ break;
+ ++cp;
+ }
+ else
+ {
+ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
+ break;
+
+ if (*cp++ == '{')
+ depth++;
+ }
+
+ return *cp != '\0' ? cp : NULL;
+}
#endif
+static int
+link_exists_p (const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob, int flags)
+{
+ size_t fnamelen = strlen (fname);
+ char *fullname = (char *) alloca (dirlen + 1 + fnamelen + 1);
+ struct stat st;
+ struct_stat64 st64;
+
+ mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
+ fname, fnamelen + 1);
+
+ return (((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_stat) (fullname, &st)
+ : __stat64 (fullname, &st64)) == 0);
+}
/* 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 (const char *pattern, const char *directory, int flags, int (*errfunc) (const char *, int), glob_t *pglob)
+static int glob_in_dir (const char *pattern, const char *directory, int flags,
+ int (*errfunc) (const char *, int),
+ glob_t *pglob)
{
- __ptr_t stream;
-
+ size_t dirlen = strlen (directory);
+ void *stream = NULL;
struct globlink
{
struct globlink *next;
char *name;
};
struct globlink *names = NULL;
- size_t nfound = 0;
+ size_t nfound;
int meta;
+ int save;
- stream = (__glob_opendir_hook ? (*__glob_opendir_hook) (directory)
- : (__ptr_t) opendir (directory));
- if (stream == NULL)
+ meta = glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
+ if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
{
- if ((errfunc != NULL && (*errfunc) (directory, errno)) ||
- (flags & GLOB_ERR))
- return GLOB_ABORTED;
+ /* 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;
+ struct_stat64 st64;
+ size_t patlen = strlen (pattern);
+ char *fullname = (char *) alloca (dirlen + 1 + patlen + 1);
- meta = glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
-
- if (meta)
- flags |= GLOB_MAGCHAR;
+ mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
+ "/", 1),
+ pattern, patlen + 1);
+ 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;
- while (1)
+ nfound = 0;
+ }
+ else
{
- const char *name;
- size_t len;
-
- if (__glob_readdir_hook)
+ if (pattern[0] == '\0')
{
- name = (*__glob_readdir_hook) (stream);
- if (name == NULL)
- break;
- len = 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
{
- struct dirent *d = __readdir ((DIR *) stream);
- if (d == NULL)
- break;
- if (! (d->d_ino != 0))
- continue;
- name = d->d_name;
-#ifdef _DIRENT_HAVE_D_NAMLEN
- len = d->d_namlen;
+ stream = ((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_opendir) (directory)
+ : 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)
+ );
+ nfound = 0;
+ flags |= GLOB_MAGCHAR;
+
+ while (1)
+ {
+ const char *name;
+ size_t len;
+#if !defined COMPILE_GLOB64
+ struct dirent64 *d;
+ union
+ {
+ struct dirent64 d64;
+ char room [offsetof (struct dirent64, d_name[0])
+ + NAME_MAX + 1];
+ }
+ d64buf;
+
+ if (flags & GLOB_ALTDIRFUNC)
+ {
+ struct dirent *d32 = (*pglob->gl_readdir) (stream);
+ if (d32 != NULL)
+ {
+ CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
+ d = &d64buf.d64;
+ }
+ else
+ d = NULL;
+ }
+ else
+ d = __readdir64 (stream);
#else
- len = 0;
+ struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
+ ? ((struct dirent *)
+ (*pglob->gl_readdir) (stream))
+ : __readdir (stream));
#endif
- }
-
- if ((!meta && strcmp (pattern, name) == 0)
- || fnmatch (pattern, name,
- (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) |
- ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)) == 0)
- {
- struct globlink *new
- = (struct globlink *) alloca (sizeof (struct globlink));
- if (len == 0)
- len = strlen (name);
- new->name
- = (char *) malloc (len + ((flags & GLOB_MARK) ? 1 : 0) + 1);
- if (new->name == NULL)
- goto memory_error;
- memcpy ((__ptr_t) new->name, name, len);
- new->name[len] = '\0';
- new->next = names;
- names = new;
- ++nfound;
- if (!meta)
- break;
+ if (d == NULL)
+ break;
+# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+ if (! REAL_DIR_ENTRY (d))
+ continue;
+
+ /* If we shall match only directories use the information
+ provided by the dirent call if possible. */
+ if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
+ continue;
+
+ name = d->d_name;
+
+ if (fnmatch (pattern, name, fnm_flags) == 0)
+ {
+ /* If the file we found is a symlink we have to
+ make sure the target file exists. */
+ if (!DIRENT_MIGHT_BE_SYMLINK (d)
+ || link_exists_p (directory, dirlen, name, pglob,
+ flags))
+ {
+ 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;
+ *((char *) mempcpy (new->name, name, len)) = '\0';
+ new->next = names;
+ names = new;
+ ++nfound;
+ }
+ }
+ }
+ }
}
}
@@ -237,60 +417,62 @@ glob_in_dir (const char *pattern, const char *directory, int flags, int (*errfun
nfound = 1;
names = (struct globlink *) alloca (sizeof (struct globlink));
names->next = NULL;
- names->name = (char *) malloc (len + (flags & GLOB_MARK ? 1 : 0) + 1);
+ names->name = (char *) malloc (len + 1);
if (names->name == NULL)
goto memory_error;
- memcpy (names->name, pattern, len);
- names->name[len] = '\0';
+ *((char *) mempcpy (names->name, pattern, len)) = '\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 (nfound != 0)
+ {
+ char **new_gl_pathv;
- if (flags & GLOB_DOOFFS)
- while (pglob->gl_pathc < pglob->gl_offs)
- pglob->gl_pathv[pglob->gl_pathc++] = NULL;
+ new_gl_pathv
+ = (char **) realloc (pglob->gl_pathv,
+ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+ * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ goto memory_error;
+ pglob->gl_pathv = new_gl_pathv;
- for (; names != NULL; names = names->next)
- pglob->gl_pathv[pglob->gl_pathc++] = names->name;
- pglob->gl_pathv[pglob->gl_pathc] = NULL;
+ 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;
+ pglob->gl_flags = flags;
+ }
+
+ save = errno;
+ if (stream != NULL)
+ {
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir (stream);
+ }
+ __set_errno (save);
- {
- int save = errno;
- if (__glob_closedir_hook)
- (*__glob_closedir_hook) (stream);
- else
- (void) closedir ((DIR *) stream);
- errno = save;
- }
return nfound == 0 ? GLOB_NOMATCH : 0;
memory_error:
{
- int save = errno;
- if (__glob_closedir_hook)
- (*__glob_closedir_hook) (stream);
+ int save2 = errno;
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
else
- (void) closedir ((DIR *) stream);
- errno = save;
+ closedir (stream);
+ __set_errno (save2);
}
while (names != NULL)
{
if (names->name != NULL)
- free ((__ptr_t) names->name);
+ free (names->name);
names = names->next;
}
return GLOB_NOSPACE;
}
+
/* 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,
@@ -307,57 +489,385 @@ glob (pattern, flags, errfunc, pglob)
glob_t *pglob;
{
const char *filename;
- char *dirname;
+ const char *dirname;
size_t dirlen;
int status;
- int oldcount;
+ size_t oldcount;
if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
{
- errno = EINVAL;
+ __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;
+
+ if (flags & GLOB_NOESCAPE)
+ begin = strchr (pattern, '{');
+ else
+ {
+ begin = pattern;
+ while (1)
+ {
+ if (*begin == '\0')
+ {
+ begin = NULL;
+ break;
+ }
+
+ if (*begin == '\\' && begin[1] != '\0')
+ ++begin;
+ else if (*begin == '{')
+ break;
+
+ ++begin;
+ }
+ }
+
+ 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;
+ char onealt[strlen (pattern) - 1];
+
+ /* We know the prefix for all sub-patterns. */
+ alt_start = mempcpy (onealt, pattern, begin - pattern);
+
+ /* Find the first sub-pattern and at the same time find the
+ rest after the closing brace. */
+ next = next_brace_sub (begin + 1, flags);
+ if (next == NULL)
+ {
+ /* It is an illegal expression. */
+ 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, flags);
+ if (rest == NULL)
+ {
+ /* It is an illegal expression. */
+ 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. */
+ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+
+ result = glob (onealt,
+ ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+ | GLOB_APPEND), errfunc, pglob);
+
+ /* If we got an error, return it. */
+ if (result && result != GLOB_NOMATCH)
+ {
+ if (!(flags & GLOB_APPEND))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ }
+ return result;
+ }
+
+ if (*next == '}')
+ /* We saw the last entry. */
+ break;
+
+ p = next + 1;
+ next = next_brace_sub (p, flags);
+ /* assert (next != NULL); */
+ }
+
+
+ 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;
- dirname = (char *) ".";
- dirlen = 0;
+ /* 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;
+ dirname = ".";
+ dirlen = 0;
+ }
}
else if (filename == pattern)
{
/* "/pattern". */
- dirname = (char *) "/";
+ dirname = "/";
dirlen = 1;
++filename;
}
else
{
+ char *newp;
dirlen = filename - pattern;
- dirname = (char *) alloca (dirlen + 1);
- memcpy (dirname, pattern, dirlen);
- dirname[dirlen] = '\0';
+ newp = (char *) alloca (dirlen + 1);
+ *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
+ dirname = newp;
++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 (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;
+ 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;
+
+ 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");
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ int success;
+ char *name;
+# define GET_LOGIN_NAME_MAX() sysconf (_SC_LOGIN_NAME_MAX)
+ size_t buflen = GET_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;
+ if (success)
+ {
+ struct passwd *p;
+# define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX)
+ long int pwbuflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int save = errno;
+
+ pwtmpbuf = (char *) alloca (pwbuflen);
+
+ while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
+ != 0)
+ {
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+ pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
+ 2 * pwbuflen);
+ __set_errno (save);
+ }
+ 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. */
+ }
+ /* 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);
+ mempcpy (mempcpy (newp, home_dir, home_len),
+ &dirname[1], dirlen);
+ dirname = newp;
+ }
+ }
+ 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);
+ *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+ = '\0';
+ user_name = newp;
+ }
+
+ /* Look up specific user's home directory. */
+ {
+ struct passwd *p;
+ long int buflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int save = errno;
+
+ pwtmpbuf = (char *) alloca (buflen);
+
+ while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+ {
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+ pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
+ __set_errno (save);
+ }
+ 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);
+ *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
+ end_name, rest_len)) = '\0';
+ 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;
+ }
}
- oldcount = pglob->gl_pathc;
+ /* Now test whether we looked for "~" or "~NAME". In this case we
+ can give the answer now. */
+ if (filename == NULL)
+ {
+ struct stat st;
+ struct_stat64 st64;
+
+ /* 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;
+ char **new_gl_pathv;
+
+ new_gl_pathv
+ = (char **) realloc (pglob->gl_pathv,
+ (newcount + 1 + 1) * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ {
+ nospace:
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[newcount] = strdup (dirname);
+ if (pglob->gl_pathv[newcount] == NULL)
+ goto 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)))
{
@@ -365,11 +875,23 @@ glob (pattern, flags, errfunc, pglob)
have to glob for the directory, and then glob for
the pattern in each directory found. */
glob_t dirs;
- register int i;
+ 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 (dirname,
- ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) |
- GLOB_NOSORT),
+ ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
+ | GLOB_ALTDIRFUNC))
+ | GLOB_NOSORT | GLOB_ONLYDIR),
errfunc, &dirs);
if (status != 0)
return status;
@@ -379,23 +901,12 @@ glob (pattern, flags, errfunc, pglob)
appending the results to PGLOB. */
for (i = 0; i < dirs.gl_pathc; ++i)
{
-#ifdef SHELL
- {
- /* Make globbing interruptible in the bash shell. */
- extern int interrupt_state;
-
- if (interrupt_state)
- {
- globfree (&dirs);
- globfree (&files);
- return GLOB_ABEND;
- }
- }
-#endif /* SHELL. */
+ int old_pathc;
- oldcount = pglob->gl_pathc;
+ old_pathc = pglob->gl_pathc;
status = glob_in_dir (filename, dirs.gl_pathv[i],
- (flags | GLOB_APPEND) & ~GLOB_NOCHECK,
+ ((flags | GLOB_APPEND)
+ & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
errfunc, pglob);
if (status == GLOB_NOMATCH)
/* No matches in this directory. Try the next. */
@@ -405,63 +916,73 @@ glob (pattern, flags, errfunc, pglob)
{
globfree (&dirs);
globfree (pglob);
+ pglob->gl_pathc = 0;
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,
- flags & GLOB_MARK))
+ if (prefix_array (dirs.gl_pathv[i],
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
{
globfree (&dirs);
globfree (pglob);
+ pglob->gl_pathc = 0;
return GLOB_NOSPACE;
}
}
flags |= GLOB_MAGCHAR;
- if (pglob->gl_pathc == oldcount)
- {
- /* No matches. */
- if (flags & GLOB_NOCHECK)
+ /* 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 input pattern itself. */
+ if (pglob->gl_pathc + pglob->gl_offs == oldcount)
{
- 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;
- }
+ /* No matches. */
+ if (flags & GLOB_NOCHECK)
+ {
+ int newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
- if (flags & GLOB_DOOFFS)
- while (pglob->gl_pathc < pglob->gl_offs)
- pglob->gl_pathv[pglob->gl_pathc++] = NULL;
+ new_gl_pathv = (char **) realloc (pglob->gl_pathv,
+ (newcount + 2)
+ * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ {
+ globfree (&dirs);
+ return GLOB_NOSPACE;
+ }
+ pglob->gl_pathv = new_gl_pathv;
- pglob->gl_pathv[pglob->gl_pathc++] = patcopy;
- pglob->gl_pathv[pglob->gl_pathc] = NULL;
- pglob->gl_flags = flags;
- }
- else
- {
- return GLOB_NOMATCH;
+ pglob->gl_pathv[newcount] = strdup (pattern);
+ if (pglob->gl_pathv[newcount] == NULL)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+
+ ++pglob->gl_pathc;
+ ++newcount;
+
+ pglob->gl_pathv[newcount] = NULL;
+ pglob->gl_flags = flags;
+ }
+ 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;
@@ -469,12 +990,12 @@ glob (pattern, flags, errfunc, pglob)
if (dirlen > 0)
{
/* Stick the directory on the front of each name. */
- if (__prefix_array (dirname,
- &pglob->gl_pathv[oldcount],
- pglob->gl_pathc - oldcount,
- flags & GLOB_MARK))
+ if (prefix_array (dirname,
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
{
globfree (pglob);
+ pglob->gl_pathc = 0;
return GLOB_NOSPACE;
}
}
@@ -482,25 +1003,42 @@ glob (pattern, flags, errfunc, pglob)
if (flags & GLOB_MARK)
{
- /* Append slashes to directory names. glob_in_dir has already
- allocated the extra character for us. */
- int i;
+ /* Append slashes to directory names. */
+ size_t i;
struct stat st;
- for (i = oldcount; i < pglob->gl_pathc; ++i)
- if (lstat (pglob->gl_pathv[i], &st) == 0 &&
- S_ISDIR (st.st_mode))
- strcat (pglob->gl_pathv[i], "/");
+ struct_stat64 st64;
+
+ 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);
+ pglob->gl_pathc = 0;
+ 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 - oldcount,
- sizeof (char *), (__compar_fn_t)__collated_compare);
+ {
+ /* Sort the vector. */
+ qsort (&pglob->gl_pathv[oldcount],
+ pglob->gl_pathc + pglob->gl_offs - oldcount,
+ sizeof (char *), collated_compare);
+ }
return 0;
}
-#ifdef __GLOB64
+#ifdef COMPILE_GLOB64
libc_hidden_def(glob64)
#else
libc_hidden_def(glob)
@@ -514,14 +1052,15 @@ globfree (pglob)
{
if (pglob->gl_pathv != NULL)
{
- register int i = pglob->gl_flags & GLOB_DOOFFS? pglob->gl_offs : 0;
- for (; i < pglob->gl_pathc; ++i)
- if (pglob->gl_pathv[i] != NULL)
- free ((__ptr_t) pglob->gl_pathv[i]);
- free ((__ptr_t) pglob->gl_pathv);
+ size_t i;
+ for (i = 0; i < pglob->gl_pathc; ++i)
+ if (pglob->gl_pathv[pglob->gl_offs + i] != NULL)
+ free (pglob->gl_pathv[pglob->gl_offs + i]);
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
}
}
-#ifdef __GLOB64
+#ifdef COMPILE_GLOB64
libc_hidden_def(globfree64)
#else
libc_hidden_def(globfree)