+2007-04-05 Dick Porter <dick@ximian.com>
+
+ * io.c:
+ * io-portability.c (_wapi_io_scandir): Moved from io.c, and
+ changed to use a cut-down version of glob(3) that has been
+ extended to match with case-insensitivity if needed.
+
+ * wapi_glob.h:
+ * wapi_glob.c: Cut down implementation of glob(3), based on
+ OpenBSD.
+
2007-03-22 Dick Porter <dick@ximian.com>
* sockets.c (_wapi_connect): Do additional checks when connect(2)
versioninfo.h \
wait.c \
wait.h \
+ wapi_glob.h \
+ wapi_glob.c \
wapi.h \
wapi-private.h
#include <sys/stat.h>
#include <mono/io-layer/mono-mutex.h>
+#include <mono/io-layer/error.h>
+#include <mono/io-layer/wapi_glob.h>
#include <mono/io-layer/io-portability.h>
#undef DEBUG
return(ret);
}
+
+
+static gint
+file_compare (gconstpointer a, gconstpointer b)
+{
+ gchar *astr = *(gchar **) a;
+ gchar *bstr = *(gchar **) b;
+
+ return strcmp (astr, bstr);
+}
+
+static gint
+get_errno_from_g_file_error (gint error)
+{
+ switch (error) {
+#ifdef EACCESS
+ case G_FILE_ERROR_ACCES:
+ error = EACCES;
+ break;
+#endif
+#ifdef ENAMETOOLONG
+ case G_FILE_ERROR_NAMETOOLONG:
+ error = ENAMETOOLONG;
+ break;
+#endif
+#ifdef ENOENT
+ case G_FILE_ERROR_NOENT:
+ error = ENOENT;
+ break;
+#endif
+#ifdef ENOTDIR
+ case G_FILE_ERROR_NOTDIR:
+ error = ENOTDIR;
+ break;
+#endif
+#ifdef ENXIO
+ case G_FILE_ERROR_NXIO:
+ error = ENXIO;
+ break;
+#endif
+#ifdef ENODEV
+ case G_FILE_ERROR_NODEV:
+ error = ENODEV;
+ break;
+#endif
+#ifdef EROFS
+ case G_FILE_ERROR_ROFS:
+ error = EROFS;
+ break;
+#endif
+#ifdef ETXTBSY
+ case G_FILE_ERROR_TXTBSY:
+ error = ETXTBSY;
+ break;
+#endif
+#ifdef EFAULT
+ case G_FILE_ERROR_FAULT:
+ error = EFAULT;
+ break;
+#endif
+#ifdef ELOOP
+ case G_FILE_ERROR_LOOP:
+ error = ELOOP;
+ break;
+#endif
+#ifdef ENOSPC
+ case G_FILE_ERROR_NOSPC:
+ error = ENOSPC;
+ break;
+#endif
+#ifdef ENOMEM
+ case G_FILE_ERROR_NOMEM:
+ error = ENOMEM;
+ break;
+#endif
+#ifdef EMFILE
+ case G_FILE_ERROR_MFILE:
+ error = EMFILE;
+ break;
+#endif
+#ifdef ENFILE
+ case G_FILE_ERROR_NFILE:
+ error = ENFILE;
+ break;
+#endif
+#ifdef EBADF
+ case G_FILE_ERROR_BADF:
+ error = EBADF;
+ break;
+#endif
+#ifdef EINVAL
+ case G_FILE_ERROR_INVAL:
+ error = EINVAL;
+ break;
+#endif
+#ifdef EPIPE
+ case G_FILE_ERROR_PIPE:
+ error = EPIPE;
+ break;
+#endif
+#ifdef EAGAIN
+ case G_FILE_ERROR_AGAIN:
+ error = EAGAIN;
+ break;
+#endif
+#ifdef EINTR
+ case G_FILE_ERROR_INTR:
+ error = EINTR;
+ break;
+#endif
+#ifdef EWIO
+ case G_FILE_ERROR_IO:
+ error = EIO;
+ break;
+#endif
+#ifdef EPERM
+ case G_FILE_ERROR_PERM:
+ error = EPERM;
+ break;
+#endif
+ case G_FILE_ERROR_FAILED:
+ error = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ return error;
+}
+
+/* scandir using glib */
+gint _wapi_io_scandir (const gchar *dirname, const gchar *pattern,
+ gchar ***namelist)
+{
+ GError *error = NULL;
+ GDir *dir;
+ GPtrArray *names;
+ gint result;
+ wapi_glob_t glob_buf;
+ int flags = 0, i;
+
+ dir = _wapi_g_dir_open (dirname, 0, &error);
+ if (dir == NULL) {
+ /* g_dir_open returns ENOENT on directories on which we don't
+ * have read/x permission */
+ gint errnum = get_errno_from_g_file_error (error->code);
+ g_error_free (error);
+ if (errnum == ENOENT &&
+ !_wapi_access (dirname, F_OK) &&
+ _wapi_access (dirname, R_OK|X_OK)) {
+ errnum = EACCES;
+ }
+
+ errno = errnum;
+ return -1;
+ }
+
+ if (portability_helpers & PORTABILITY_CASE) {
+ flags = WAPI_GLOB_IGNORECASE;
+ }
+
+ result = _wapi_glob (dir, pattern, flags, &glob_buf);
+ g_dir_close (dir);
+ if (result == WAPI_GLOB_NOMATCH) {
+ return(0);
+ } else if (result != 0) {
+ return(-1);
+ }
+
+ names = g_ptr_array_new ();
+ for (i = 0; i < glob_buf.gl_pathc; i++) {
+ g_ptr_array_add (names, g_strdup (glob_buf.gl_pathv[i]));
+ }
+
+ result = names->len;
+ if (result > 0) {
+ g_ptr_array_sort (names, file_compare);
+ g_ptr_array_set_size (names, result + 1);
+
+ *namelist = (gchar **) g_ptr_array_free (names, FALSE);
+ } else {
+ g_ptr_array_free (names, TRUE);
+ }
+
+ return result;
+}
extern gchar *_wapi_basename (const gchar *filename);
extern gchar *_wapi_dirname (const gchar *filename);
extern GDir *_wapi_g_dir_open (const gchar *path, guint flags, GError **error);
+extern gint _wapi_io_scandir (const gchar *dirname, const gchar *pattern,
+ gchar ***namelist);
G_END_DECLS
return(TRUE);
}
-static gint
-file_compare (gconstpointer a, gconstpointer b)
-{
- gchar *astr = *(gchar **) a;
- gchar *bstr = *(gchar **) b;
-
- return strcmp (astr, bstr);
-}
-
-static gint
-get_errno_from_g_file_error (gint error)
-{
- switch (error) {
-#ifdef EACCESS
- case G_FILE_ERROR_ACCES:
- error = EACCES;
- break;
-#endif
-#ifdef ENAMETOOLONG
- case G_FILE_ERROR_NAMETOOLONG:
- error = ENAMETOOLONG;
- break;
-#endif
-#ifdef ENOENT
- case G_FILE_ERROR_NOENT:
- error = ENOENT;
- break;
-#endif
-#ifdef ENOTDIR
- case G_FILE_ERROR_NOTDIR:
- error = ENOTDIR;
- break;
-#endif
-#ifdef ENXIO
- case G_FILE_ERROR_NXIO:
- error = ENXIO;
- break;
-#endif
-#ifdef ENODEV
- case G_FILE_ERROR_NODEV:
- error = ENODEV;
- break;
-#endif
-#ifdef EROFS
- case G_FILE_ERROR_ROFS:
- error = EROFS;
- break;
-#endif
-#ifdef ETXTBSY
- case G_FILE_ERROR_TXTBSY:
- error = ETXTBSY;
- break;
-#endif
-#ifdef EFAULT
- case G_FILE_ERROR_FAULT:
- error = EFAULT;
- break;
-#endif
-#ifdef ELOOP
- case G_FILE_ERROR_LOOP:
- error = ELOOP;
- break;
-#endif
-#ifdef ENOSPC
- case G_FILE_ERROR_NOSPC:
- error = ENOSPC;
- break;
-#endif
-#ifdef ENOMEM
- case G_FILE_ERROR_NOMEM:
- error = ENOMEM;
- break;
-#endif
-#ifdef EMFILE
- case G_FILE_ERROR_MFILE:
- error = EMFILE;
- break;
-#endif
-#ifdef ENFILE
- case G_FILE_ERROR_NFILE:
- error = ENFILE;
- break;
-#endif
-#ifdef EBADF
- case G_FILE_ERROR_BADF:
- error = EBADF;
- break;
-#endif
-#ifdef EINVAL
- case G_FILE_ERROR_INVAL:
- error = EINVAL;
- break;
-#endif
-#ifdef EPIPE
- case G_FILE_ERROR_PIPE:
- error = EPIPE;
- break;
-#endif
-#ifdef EAGAIN
- case G_FILE_ERROR_AGAIN:
- error = EAGAIN;
- break;
-#endif
-#ifdef EINTR
- case G_FILE_ERROR_INTR:
- error = EINTR;
- break;
-#endif
-#ifdef EWIO
- case G_FILE_ERROR_IO:
- error = EIO;
- break;
-#endif
-#ifdef EPERM
- case G_FILE_ERROR_PERM:
- error = EPERM;
- break;
-#endif
- case G_FILE_ERROR_FAILED:
- error = ERROR_INVALID_PARAMETER;
- break;
- }
-
- return error;
-}
-
-/* scandir using glib */
-static gint
-mono_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist)
-{
- GError *error = NULL;
- GDir *dir;
- GPtrArray *names;
- const gchar *name;
- gint result;
- GPatternSpec *patspec;
-
- dir = _wapi_g_dir_open (dirname, 0, &error);
- if (dir == NULL) {
- /* g_dir_open returns ENOENT on directories on which we don't
- * have read/x permission */
- gint errnum = get_errno_from_g_file_error (error->code);
- g_error_free (error);
- if (errnum == ENOENT &&
- !_wapi_access (dirname, F_OK) &&
- _wapi_access (dirname, R_OK|X_OK)) {
- errnum = EACCES;
- }
-
- errno = errnum;
- return -1;
- }
-
- patspec = g_pattern_spec_new (pattern);
- names = g_ptr_array_new ();
- while ((name = g_dir_read_name (dir)) != NULL) {
- if (g_pattern_match_string (patspec, name))
- g_ptr_array_add (names, g_strdup (name));
- }
-
- g_pattern_spec_free (patspec);
- g_dir_close (dir);
- result = names->len;
- if (result > 0) {
- g_ptr_array_sort (names, file_compare);
- g_ptr_array_set_size (names, result + 1);
-
- *namelist = (gchar **) g_ptr_array_free (names, FALSE);
- } else {
- g_ptr_array_free (names, TRUE);
- }
-
- return result;
-}
-
gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
{
struct _WapiHandle_find find_handle = {0};
*/
find_handle.namelist = NULL;
- result = mono_io_scandir (dir_part, entry_part, &find_handle.namelist);
+ result = _wapi_io_scandir (dir_part, entry_part,
+ &find_handle.namelist);
if (result == 0) {
/* No files, which windows seems to call
* encoding of the name wasn't convertible), so just
* ignore it.
*/
+ g_warning ("%s: Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODINGS\n", __func__, filename);
+
g_free (filename);
goto retry;
}
--- /dev/null
+/* $OpenBSD: glob.c,v 1.26 2005/11/28 17:50:12 deraadt Exp $ */
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * _wapi_glob(3) -- a subset of the one defined in POSIX 1003.2.
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_MAGCHAR:
+ * Set in gl_flags if pattern contained a globbing character.
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/cdefs.h>
+
+#include "wapi_glob.h"
+
+#define EOS '\0'
+#define NOT '!'
+#define QUESTION '?'
+#define QUOTE '\\'
+#define STAR '*'
+
+#ifndef DEBUG
+
+#define M_QUOTE 0x8000
+#define M_PROTECT 0x4000
+#define M_MASK 0xffff
+#define M_ASCII 0x00ff
+
+typedef u_short Char;
+
+#else
+
+#define M_QUOTE 0x80
+#define M_PROTECT 0x40
+#define M_MASK 0xff
+#define M_ASCII 0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define CHAR(c) ((gchar)((c)&M_ASCII))
+#define META(c) ((gchar)((c)|M_QUOTE))
+#define M_ALL META('*')
+#define M_ONE META('?')
+#define ismeta(c) (((c)&M_QUOTE) != 0)
+
+
+static int g_Ctoc(const gchar *, char *, u_int);
+static int glob0(GDir *dir, const gchar *, wapi_glob_t *, gboolean);
+static int glob1(GDir *dir, gchar *, gchar *, wapi_glob_t *, size_t *, gboolean);
+static int glob3(GDir *dir, gchar *, gchar *, wapi_glob_t *, size_t *, gboolean);
+static int globextend(const gchar *, wapi_glob_t *, size_t *);
+static int match(const gchar *, gchar *, gchar *, gboolean);
+#ifdef DEBUG
+static void qprintf(const char *, Char *);
+#endif
+
+int
+_wapi_glob(GDir *dir, const char *pattern, int flags, wapi_glob_t *pglob)
+{
+ const u_char *patnext;
+ int c;
+ gchar *bufnext, *bufend, patbuf[MAXPATHLEN];
+
+ patnext = (u_char *) pattern;
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ pglob->gl_offs = 0;
+ pglob->gl_flags = flags & ~WAPI_GLOB_MAGCHAR;
+
+ bufnext = patbuf;
+ bufend = bufnext + MAXPATHLEN - 1;
+
+ /* Protect the quoted characters. */
+ while (bufnext < bufend && (c = *patnext++) != EOS)
+ if (c == QUOTE) {
+ if ((c = *patnext++) == EOS) {
+ c = QUOTE;
+ --patnext;
+ }
+ *bufnext++ = c | M_PROTECT;
+ } else
+ *bufnext++ = c;
+
+ *bufnext = EOS;
+
+ return glob0(dir, patbuf, pglob, flags & WAPI_GLOB_IGNORECASE);
+}
+
+/*
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested). Returns 0
+ * if things went well, nonzero if errors occurred. It is not an error
+ * to find no matches.
+ */
+static int
+glob0(GDir *dir, const gchar *pattern, wapi_glob_t *pglob, gboolean ignorecase)
+{
+ const gchar *qpatnext;
+ int c, err, oldpathc;
+ gchar *bufnext, patbuf[MAXPATHLEN];
+ size_t limit = 0;
+
+ qpatnext = pattern;
+ oldpathc = pglob->gl_pathc;
+ bufnext = patbuf;
+
+ /* We don't need to check for buffer overflow any more. */
+ while ((c = *qpatnext++) != EOS) {
+ switch (c) {
+ case QUESTION:
+ pglob->gl_flags |= WAPI_GLOB_MAGCHAR;
+ *bufnext++ = M_ONE;
+ break;
+ case STAR:
+ pglob->gl_flags |= WAPI_GLOB_MAGCHAR;
+ /* collapse adjacent stars to one,
+ * to avoid exponential behavior
+ */
+ if (bufnext == patbuf || bufnext[-1] != M_ALL)
+ *bufnext++ = M_ALL;
+ break;
+ default:
+ *bufnext++ = CHAR(c);
+ break;
+ }
+ }
+ *bufnext = EOS;
+#ifdef DEBUG
+ qprintf("glob0:", patbuf);
+#endif
+
+ if ((err = glob1(dir, patbuf, patbuf+MAXPATHLEN-1, pglob, &limit,
+ ignorecase)) != 0)
+ return(err);
+
+ if (pglob->gl_pathc == oldpathc) {
+ return(WAPI_GLOB_NOMATCH);
+ }
+
+ return(0);
+}
+
+static int
+glob1(GDir *dir, gchar *pattern, gchar *pattern_last, wapi_glob_t *pglob,
+ size_t *limitp, gboolean ignorecase)
+{
+ /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+ if (*pattern == EOS)
+ return(0);
+ return(glob3(dir, pattern, pattern_last, pglob, limitp, ignorecase));
+}
+
+static int
+glob3(GDir *dir, gchar *pattern, gchar *pattern_last, wapi_glob_t *pglob,
+ size_t *limitp, gboolean ignorecase)
+{
+ const gchar *name;
+
+ /* Search directory for matching names. */
+ while ((name = g_dir_read_name(dir))) {
+ if (!match(name, pattern, pattern + strlen (pattern),
+ ignorecase)) {
+ continue;
+ }
+ globextend (name, pglob, limitp);
+ }
+
+ return(0);
+}
+
+
+/*
+ * Extend the gl_pathv member of a wapi_glob_t structure to accommodate a new item,
+ * add the new item, and update gl_pathc.
+ *
+ * This assumes the BSD realloc, which only copies the block when its size
+ * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
+ * behavior.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the wapi_glob_t structure:
+ * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ * gl_pathv points to (gl_offs + gl_pathc + 1) items.
+ */
+static int
+globextend(const gchar *path, wapi_glob_t *pglob, size_t *limitp)
+{
+ char **pathv;
+ int i;
+ u_int newsize, len;
+ char *copy;
+ const gchar *p;
+
+ newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+ pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
+ malloc(newsize);
+ if (pathv == NULL) {
+ if (pglob->gl_pathv) {
+ free(pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+ return(WAPI_GLOB_NOSPACE);
+ }
+
+ if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+ /* first time around -- clear initial gl_offs items */
+ pathv += pglob->gl_offs;
+ for (i = pglob->gl_offs; --i >= 0; )
+ *--pathv = NULL;
+ }
+ pglob->gl_pathv = pathv;
+
+ for (p = path; *p++;)
+ ;
+ len = (size_t)(p - path);
+ *limitp += len;
+ if ((copy = malloc(len)) != NULL) {
+ if (g_Ctoc(path, copy, len)) {
+ free(copy);
+ return(WAPI_GLOB_NOSPACE);
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+ if ((pglob->gl_flags & WAPI_GLOB_LIMIT) &&
+ newsize + *limitp >= ARG_MAX) {
+ errno = 0;
+ return(WAPI_GLOB_NOSPACE);
+ }
+
+ return(copy == NULL ? WAPI_GLOB_NOSPACE : 0);
+}
+
+
+/*
+ * pattern matching function for filenames. Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(const gchar *name, gchar *pat, gchar *patend, gboolean ignorecase)
+{
+ gchar c;
+
+ while (pat < patend) {
+ c = *pat++;
+ switch (c & M_MASK) {
+ case M_ALL:
+ if (pat == patend)
+ return(1);
+ do {
+ if (match(name, pat, patend, ignorecase))
+ return(1);
+ } while (*name++ != EOS);
+ return(0);
+ case M_ONE:
+ if (*name++ == EOS)
+ return(0);
+ break;
+ default:
+ if (ignorecase) {
+ if (g_ascii_tolower (*name++) != g_ascii_tolower (c))
+ return(0);
+ } else {
+ if (*name++ != c)
+ return(0);
+ }
+
+ break;
+ }
+ }
+ return(*name == EOS);
+}
+
+/* Free allocated data belonging to a wapi_glob_t structure. */
+void
+_wapi_globfree(wapi_glob_t *pglob)
+{
+ int i;
+ char **pp;
+
+ if (pglob->gl_pathv != NULL) {
+ pp = pglob->gl_pathv + pglob->gl_offs;
+ for (i = pglob->gl_pathc; i--; ++pp)
+ if (*pp)
+ free(*pp);
+ free(pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+}
+
+static int
+g_Ctoc(const gchar *str, char *buf, u_int len)
+{
+
+ while (len--) {
+ if ((*buf++ = *str++) == EOS)
+ return (0);
+ }
+ return (1);
+}
+
+#ifdef DEBUG
+static void
+qprintf(const char *str, Char *s)
+{
+ Char *p;
+
+ (void)printf("%s:\n", str);
+ for (p = s; *p; p++)
+ (void)printf("%c", CHAR(*p));
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", ismeta(*p) ? '_' : ' ');
+ (void)printf("\n");
+}
+#endif
--- /dev/null
+/* $OpenBSD: glob.h,v 1.10 2005/12/13 00:35:22 millert Exp $ */
+/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)glob.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _WAPI_GLOB_H_
+#define _WAPI_GLOB_H_
+
+#include <glib.h>
+#include <sys/cdefs.h>
+
+struct stat;
+typedef struct {
+ int gl_pathc; /* Count of total paths so far. */
+ int gl_offs; /* Reserved at beginning of gl_pathv. */
+ int gl_flags; /* Copy of flags parameter to glob. */
+ char **gl_pathv; /* List of paths matching pattern. */
+} wapi_glob_t;
+
+
+#define WAPI_GLOB_NOSPACE (-1) /* Malloc call failed. */
+#define WAPI_GLOB_ABORTED (-2) /* Unignored error. */
+#define WAPI_GLOB_NOMATCH (-3) /* No match and WAPI_GLOB_NOCHECK not set. */
+#define WAPI_GLOB_NOSYS (-4) /* Function not supported. */
+
+#define WAPI_GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
+#define WAPI_GLOB_LIMIT 0x2000 /* Limit pattern match output to ARG_MAX */
+#define WAPI_GLOB_IGNORECASE 0x4000 /* Ignore case when matching */
+#define WAPI_GLOB_ABEND WAPI_GLOB_ABORTED /* backward compatibility */
+
+__BEGIN_DECLS
+int _wapi_glob(GDir *dir, const char *, int, wapi_glob_t *);
+void _wapi_globfree(wapi_glob_t *);
+__END_DECLS
+
+#endif /* !_WAPI_GLOB_H_ */
+2007-04-05 Dick Porter <dick@ximian.com>
+
+ * file-io.c (ves_icall_System_IO_MonoIO_GetFileSystemEntries): use
+ FindFirstFile()/FindNextFile() to find entries. This lets the
+ io-layer versions use MONO_IOMAP compatibility helpers. Fixes bug
+ 81038.
+
+ * appdomain.c (MONO_CORLIB_VERSION): Increment, as the usage of
+ the parameters of
+ ves_icall_System_IO_MonoIO_GetFileSystemEntries() has changed.
+
2007-04-04 Martin Baulig <martin@ximian.com>
* debug-helpers.c
#include <direct.h>
#endif
-#define MONO_CORLIB_VERSION 55
+#define MONO_CORLIB_VERSION 56
CRITICAL_SECTION mono_delegate_section;
return(ret);
}
-static gint
-get_error_from_g_file_error (gint error)
-{
- switch (error) {
- case G_FILE_ERROR_ACCES:
- error = ERROR_ACCESS_DENIED;
- break;
- case G_FILE_ERROR_NAMETOOLONG:
- error = ERROR_FILENAME_EXCED_RANGE;
- break;
- case G_FILE_ERROR_NOENT:
- error = ERROR_FILE_NOT_FOUND;
- break;
- case G_FILE_ERROR_NOTDIR:
- error = ERROR_FILE_NOT_FOUND;
- break;
- case G_FILE_ERROR_ROFS:
- error = ERROR_ACCESS_DENIED;
- break;
- case G_FILE_ERROR_TXTBSY:
- error = ERROR_SHARING_VIOLATION;
- break;
- case G_FILE_ERROR_NOSPC:
- error = ERROR_HANDLE_DISK_FULL;
- break;
- case G_FILE_ERROR_NFILE:
- case G_FILE_ERROR_MFILE:
- error = ERROR_TOO_MANY_OPEN_FILES;
- break;
- case G_FILE_ERROR_BADF:
- error = ERROR_INVALID_HANDLE;
- break;
- case G_FILE_ERROR_INVAL:
- error = ERROR_INVALID_PARAMETER;
- break;
- case G_FILE_ERROR_AGAIN:
- error = ERROR_SHARING_VIOLATION;
- break;
- case G_FILE_ERROR_INTR:
- error = ERROR_IO_PENDING;
- break;
- case G_FILE_ERROR_PERM:
- error = ERROR_ACCESS_DENIED;
- break;
- case G_FILE_ERROR_FAILED:
- error = ERROR_INVALID_PARAMETER;
- break;
- case G_FILE_ERROR_NXIO:
- case G_FILE_ERROR_NOMEM:
- case G_FILE_ERROR_NODEV:
- case G_FILE_ERROR_FAULT:
- case G_FILE_ERROR_LOOP:
- case G_FILE_ERROR_PIPE:
- case G_FILE_ERROR_IO:
- default:
- error = ERROR_GEN_FAILURE;
- break;
-
- }
-
- return error;
-}
-
-static gint
-file_compare (gconstpointer a, gconstpointer b)
-{
- gchar *astr = *(gchar **) a;
- gchar *bstr = *(gchar **) b;
-
- return strcmp (astr, bstr);
-}
-
-static gint
-get_file_attributes (const char *filename)
+MonoArray *
+ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
+ MonoString *path_with_pattern,
+ gint attrs, gint mask,
+ gint32 *error)
{
-#ifdef PLATFORM_WIN32
- gunichar2 *full16;
- gint result;
-
- full16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
- if (full16 == NULL) {
- g_message ("Bad encoding for '%s'\n", filename);
- return FALSE;
- }
-
- result = GetFileAttributes (full16);
- g_free (full16);
- return result;
-#else
- struct stat buf;
- struct stat linkbuf;
- int result;
- int file_attrs;
- gboolean issymlink = FALSE;
-
- result = lstat (filename, &buf);
- if (result == -1)
- return FALSE;
-
- if (S_ISLNK (buf.st_mode)) {
- issymlink = TRUE;
- result = stat (filename, &linkbuf);
- if (result != -1) {
- buf = linkbuf;
- }
- }
-
- /* Sockets (0140000) != Directory (040000) + Regular file (0100000) */
- if (S_ISSOCK (buf.st_mode))
- buf.st_mode &= ~S_IFSOCK; /* don't consider socket protection */
-
- file_attrs = 0;
- if (S_ISDIR (buf.st_mode))
- file_attrs |= FILE_ATTRIBUTE_DIRECTORY;
- else
- file_attrs |= FILE_ATTRIBUTE_ARCHIVE;
-
- if ((buf.st_mode & S_IWUSR) == 0)
- file_attrs |= FILE_ATTRIBUTE_READONLY;
-
- if (*filename == '.')
- file_attrs |= FILE_ATTRIBUTE_HIDDEN;
-
- if (issymlink) {
- file_attrs |= FILE_ATTRIBUTE_REPARSE_POINT;
- }
+ MonoDomain *domain;
+ MonoArray *result;
+ int i;
+ WIN32_FIND_DATA data;
+ HANDLE find_handle;
+ GPtrArray *names;
+ gchar *utf8_path, *utf8_result, *full_name;
- return file_attrs;
-#endif
-}
-
-static gboolean
-test_file (const char *filename, int attrs, int mask)
-{
- int file_attr;
-
- file_attr = get_file_attributes (filename);
- if (file_attr == FALSE)
- return FALSE;
-
- return ((file_attr & mask) == attrs);
-}
+ MONO_ARCH_SAVE_REGS;
-/* scandir using glib */
-static gint
-mono_io_scandir (const gchar *dirname, const gchar *pattern, int attrs,
- int mask, gchar ***namelist)
-{
- GError *error = NULL;
- GDir *dir;
- GPtrArray *names;
- const gchar *name;
- gint result;
- GPatternSpec *patspec;
- gchar *full_name;
+ *error = ERROR_SUCCESS;
+ domain = mono_domain_get ();
mask = convert_attrs (mask);
- *namelist = NULL;
- dir = g_dir_open (dirname, 0, &error);
- if (dir == NULL) {
- /* g_dir_open returns ENOENT on directories on which we don't
- * have read/x permission */
- gint errnum = get_error_from_g_file_error (error->code);
- g_error_free (error);
- if (errnum == ERROR_FILE_NOT_FOUND && g_file_test (dirname, G_FILE_TEST_IS_DIR))
- errnum = ERROR_ACCESS_DENIED;
-
- SetLastError (errnum);
- return -1;
+
+ find_handle = FindFirstFile (mono_string_chars (path_with_pattern),
+ &data);
+ if (find_handle == INVALID_HANDLE_VALUE) {
+ gint32 find_error = GetLastError ();
+
+ if (find_error == ERROR_FILE_NOT_FOUND) {
+ /* No files, so just return an empty array */
+ result = mono_array_new (domain,
+ mono_defaults.string_class,
+ 0);
+
+ return(result);
+ }
+
+ *error = find_error;
+ return(NULL);
}
- patspec = g_pattern_spec_new (pattern);
names = g_ptr_array_new ();
- while ((name = g_dir_read_name (dir)) != NULL) {
- if (!g_pattern_match_string (patspec, name))
- continue;
+ utf8_path = mono_string_to_utf8 (path);
- full_name = g_build_filename (dirname, name, NULL);
- if (FALSE == test_file (full_name, attrs, mask)) {
- g_free (full_name);
+ do {
+ if ((data.cFileName[0] == '.' && data.cFileName[1] == 0) ||
+ (data.cFileName[0] == '.' && data.cFileName[1] == '.' && data.cFileName[2] == 0)) {
continue;
}
+
+ if ((data.dwFileAttributes & mask) == attrs) {
+ utf8_result = g_utf16_to_utf8 (data.cFileName, -1, NULL, NULL, NULL);
+ full_name = g_build_filename (utf8_path, utf8_result, NULL);
+
+ g_ptr_array_add (names, mono_string_new (domain,
+ full_name));
+ g_free (full_name);
+ g_free (utf8_result);
+ }
+ } while(FindNextFile (find_handle, &data));
- g_ptr_array_add (names, full_name);
- }
-
- g_pattern_spec_free (patspec);
- g_dir_close (dir);
- result = names->len;
- if (result > 0) {
- g_ptr_array_sort (names, file_compare);
- g_ptr_array_set_size (names, result + 1);
-
- *namelist = (gchar **) g_ptr_array_free (names, FALSE);
- } else {
- g_ptr_array_free (names, TRUE);
- }
-
- return result;
-}
-
-MonoArray *
-ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *_path, MonoString *_pattern,
- gint attrs, gint mask, gint32 *error)
-{
- MonoDomain *domain;
- MonoArray *result;
- gchar **namelist;
- gchar *path;
- gchar *pattern;
- int i, nnames;
- int removed;
- MonoString *str_name;
-#ifndef PLATFORM_WIN32
- gunichar2 *utf16;
- gsize nbytes;
-#endif
-
- MONO_ARCH_SAVE_REGS;
-
- *error = ERROR_SUCCESS;
-
- path = mono_string_to_utf8 (_path);
- pattern = mono_string_to_utf8 (_pattern);
- nnames = mono_io_scandir (path, pattern, attrs, mask, &namelist);
- if (nnames < 0) {
+ if (FindClose (find_handle) == FALSE) {
*error = GetLastError ();
- g_free (pattern);
- g_free (path);
- return NULL;
- }
-
- domain = mono_domain_get ();
- result = mono_array_new (domain, mono_defaults.string_class, nnames);
- removed = 0;
- for (i = 0; i < nnames; i++) {
-#if PLATFORM_WIN32
- str_name = mono_string_new (domain, namelist [i]);
-#else
- utf16 = mono_unicode_from_external (namelist [i], &nbytes);
- if (utf16 == NULL) {
- g_message ("Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODINGS\n",
- namelist [i]);
- removed++;
- continue;
- }
- str_name = mono_string_from_utf16 (utf16);
- g_free (utf16);
-#endif
- mono_array_setref (result, i - removed, str_name);
+ g_ptr_array_free (names, TRUE);
+ g_free (utf8_path);
+ return(NULL);
}
- if (removed > 0) {
- MonoArray *shrinked;
- shrinked = mono_array_new (domain, mono_defaults.string_class, nnames - removed);
- for (i = 0; i < (nnames - removed); i++) {
- MonoString *str;
- str = mono_array_get (result, MonoString *, i);
- mono_array_setref (shrinked, i, str);
- }
- result = shrinked;
+ result = mono_array_new (domain, mono_defaults.string_class,
+ names->len);
+ for (i = 0; i < names->len; i++) {
+ mono_array_setref (result, i, g_ptr_array_index (names, i));
}
- g_strfreev (namelist);
- g_free (pattern);
- g_free (path);
+ g_ptr_array_free (names, TRUE);
+ g_free (utf8_path);
+
return result;
}
ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error) MONO_INTERNAL;
MonoArray *
-ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *_path, MonoString *_pattern,
- gint mask, gint attrs, gint32 *error) MONO_INTERNAL;
+ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
+ MonoString *path_with_pattern,
+ gint mask, gint attrs,
+ gint32 *error) MONO_INTERNAL;
extern MonoString *
ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error) MONO_INTERNAL;