2007-04-05 Dick Porter <dick@ximian.com>
authorDick Porter <dick@acm.org>
Thu, 5 Apr 2007 12:42:34 +0000 (12:42 -0000)
committerDick Porter <dick@acm.org>
Thu, 5 Apr 2007 12:42:34 +0000 (12:42 -0000)
* 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-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.

svn path=/trunk/mono/; revision=75431

mono/io-layer/ChangeLog
mono/io-layer/Makefile.am
mono/io-layer/io-portability.c
mono/io-layer/io-portability.h
mono/io-layer/io.c
mono/io-layer/wapi_glob.c [new file with mode: 0644]
mono/io-layer/wapi_glob.h [new file with mode: 0644]
mono/metadata/ChangeLog
mono/metadata/appdomain.c
mono/metadata/file-io.c
mono/metadata/file-io.h

index 99f74ed441d35a437189086199d679112ab00eab..ae821320acbbaafd364a5ddc5dad81dbc955716c 100644 (file)
@@ -1,3 +1,14 @@
+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)
index a824ba8bea0f0601bfa02c10619ce24922286a55..a65e8b81f51bb6be0a7d65204ccf4e11d34edc3d 100644 (file)
@@ -98,6 +98,8 @@ OTHER_SRC = \
        versioninfo.h           \
        wait.c                  \
        wait.h                  \
+       wapi_glob.h             \
+       wapi_glob.c             \
        wapi.h                  \
        wapi-private.h
 
index 17b5a60013b2ebfdfbaff429c334873e5f6b1cd1..c44a29b09e4f4b5b9e63f93c6b46f229e87c787f 100644 (file)
@@ -23,6 +23,8 @@
 #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
@@ -682,3 +684,187 @@ GDir *_wapi_g_dir_open (const gchar *path, guint flags, GError **error)
        
        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;
+}
index dfbe7771d8b49b25b0ec6b606ab3cc9220ba19c1..8beb367f2e638097cd9f3c6d1c5817b49f1fadc7 100644 (file)
@@ -33,6 +33,8 @@ extern int _wapi_chdir (const char *path);
 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
 
index 7af0d0de06ee40e2b06e41421ce7928868e34556..6a4fefbb4d2b14120a8cbafd103151bfe110c9d6 100644 (file)
@@ -2610,181 +2610,6 @@ gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
        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};
@@ -2854,7 +2679,8 @@ gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
         */
 
        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
@@ -2965,6 +2791,8 @@ retry:
                 * 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;
        }
diff --git a/mono/io-layer/wapi_glob.c b/mono/io-layer/wapi_glob.c
new file mode 100644 (file)
index 0000000..761d7fc
--- /dev/null
@@ -0,0 +1,367 @@
+/*     $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
diff --git a/mono/io-layer/wapi_glob.h b/mono/io-layer/wapi_glob.h
new file mode 100644 (file)
index 0000000..3d77426
--- /dev/null
@@ -0,0 +1,68 @@
+/*     $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_ */
index a848fef2a6e94e4610c4702b89f59d25f641e9fa..ceba6dd1859ebb13dc260e33d98c32adbf1afa0a 100644 (file)
@@ -1,3 +1,14 @@
+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
index d887b6bc1c8a1435fdc9b3dac198e6d958c64353..a0bec7e76dbfae3490c356064431474ee5311b5c 100644 (file)
@@ -41,7 +41,7 @@
 #include <direct.h>
 #endif
 
-#define MONO_CORLIB_VERSION 55
+#define MONO_CORLIB_VERSION 56
 
 CRITICAL_SECTION mono_delegate_section;
 
index 6538e72a69bdceeaaf653855d064729562b7143c..311739a3554eadacb201f4eff61bd1a93b4db213 100644 (file)
@@ -239,272 +239,81 @@ ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
        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;
 }
 
index 43d829b3769837de83577b82b34f5d8be4f0d119..d5e9c6f13597c0a50aa6fc866187c3eb86fbf8da 100644 (file)
@@ -119,8 +119,10 @@ extern MonoBoolean
 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;