[reflection] Use coop handles for MonoMethod icalls (#4272)
[mono.git] / mono / io-layer / io-portability.c
index 13b54ce2d0c333b49a84cbaead5440ecc204f757..282cbe93a29b8e6f60923db0fafba329529ac924 100644 (file)
@@ -6,6 +6,7 @@
  *     Dick Porter (dick@ximian.com)
  *
  * Copyright (c) 2006 Novell, Inc.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include <config.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/types.h>
-#include <dirent.h>
+#include <sys/time.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif
 #include <utime.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
 
-/* Returns newly allocated string, or NULL on failure */
-static gchar *find_in_dir (DIR *current, const gchar *name)
-{
-       struct dirent *entry;
-
-#ifdef DEBUG
-       g_message ("%s: looking for [%s]\n", __func__, name);
-#endif
-       
-       while((entry = readdir (current)) != NULL) {
-#ifdef DEBUGX
-               g_message ("%s: found [%s]\n", __func__, entry->d_name);
-#endif
-               
-               if (!g_ascii_strcasecmp (name, entry->d_name)) {
-                       char *ret;
-                       
-#ifdef DEBUG
-                       g_message ("%s: matched [%s] to [%s]\n", __func__,
-                                  entry->d_name, name);
-#endif
-
-                       ret = g_strdup (entry->d_name);
-                       closedir (current);
-                       return ret;
-               }
-       }
-       
-#ifdef DEBUG
-       g_message ("%s: returning NULL\n", __func__);
-#endif
-       
-       closedir (current);
-       
-       return(NULL);
-}
-
-/* Returns newly-allocated string or NULL on failure */
-static gchar *find_file (const gchar *pathname, gboolean last_exists)
-{
-       gchar *new_pathname, **components, **new_components;
-       int num_components = 0, component = 0;
-       DIR *scanning = NULL;
-
-       mono_portability_helpers_init ();
-
-       if (IS_PORTABILITY_NONE) {
-               return(NULL);
-       }
-
-       new_pathname = g_strdup (pathname);
-       
-#ifdef DEBUG
-       g_message ("%s: Finding [%s] last_exists: %s\n", __func__, pathname,
-                  last_exists?"TRUE":"FALSE");
-#endif
-       
-       if (last_exists &&
-           access (new_pathname, F_OK) == 0) {
-#ifdef DEBUG
-               g_message ("%s: Found it without doing anything\n", __func__);
-#endif
-               return(new_pathname);
-       }
-       
-       /* First turn '\' into '/' and strip any drive letters */
-       g_strdelimit (new_pathname, "\\", '/');
-
-#ifdef DEBUG
-       g_message ("%s: Fixed slashes, now have [%s]\n", __func__,
-                  new_pathname);
-#endif
-       
-       if (IS_PORTABILITY_DRIVE &&
-           g_ascii_isalpha (new_pathname[0]) &&
-           (new_pathname[1] == ':')) {
-               int len = strlen (new_pathname);
-               
-               g_memmove (new_pathname, new_pathname+2, len - 2);
-               new_pathname[len - 2] = '\0';
-               
-#ifdef DEBUG
-               g_message ("%s: Stripped drive letter, now looking for [%s]\n",
-                          __func__, new_pathname);
-#endif
-       }
-       
-       if (last_exists &&
-           access (new_pathname, F_OK) == 0) {
-#ifdef DEBUG
-               g_message ("%s: Found it\n", __func__);
-#endif
-               
-               return(new_pathname);
-       }
-
-       /* OK, have to work harder.  Take each path component in turn
-        * and do a case-insensitive directory scan for it
-        */
-
-       if (!(IS_PORTABILITY_CASE)) {
-               g_free (new_pathname);
-               return(NULL);
-       }
-
-       components = g_strsplit (new_pathname, "/", 0);
-       if (components == NULL) {
-               /* This shouldn't happen */
-               g_free (new_pathname);
-               return(NULL);
-       }
-       
-       while(components[num_components] != NULL) {
-               num_components++;
-       }
-       g_free (new_pathname);
-       
-       if (num_components == 0){
-               return NULL;
-       }
-       
-
-       new_components = (gchar **)g_new0 (gchar **, num_components + 1);
-
-       if (num_components > 1) {
-               if (strcmp (components[0], "") == 0) {
-                       /* first component blank, so start at / */
-                       scanning = opendir ("/");
-                       if (scanning == NULL) {
-#ifdef DEBUG
-                               g_message ("%s: opendir 1 error: %s", __func__,
-                                          g_strerror (errno));
-#endif
-                               g_strfreev (new_components);
-                               g_strfreev (components);
-                               return(NULL);
-                       }
-               
-                       new_components[component++] = g_strdup ("");
-               } else {
-                       DIR *current;
-                       gchar *entry;
-               
-                       current = opendir (".");
-                       if (current == NULL) {
-#ifdef DEBUG
-                               g_message ("%s: opendir 2 error: %s", __func__,
-                                          g_strerror (errno));
-#endif
-                               g_strfreev (new_components);
-                               g_strfreev (components);
-                               return(NULL);
-                       }
-               
-                       entry = find_in_dir (current, components[0]);
-                       if (entry == NULL) {
-                               g_strfreev (new_components);
-                               g_strfreev (components);
-                               return(NULL);
-                       }
-               
-                       scanning = opendir (entry);
-                       if (scanning == NULL) {
-#ifdef DEBUG
-                               g_message ("%s: opendir 3 error: %s", __func__,
-                                          g_strerror (errno));
-#endif
-                               g_free (entry);
-                               g_strfreev (new_components);
-                               g_strfreev (components);
-                               return(NULL);
-                       }
-               
-                       new_components[component++] = entry;
-               }
-       } else {
-               if (last_exists) {
-                       if (strcmp (components[0], "") == 0) {
-                               /* First and only component blank */
-                               new_components[component++] = g_strdup ("");
-                       } else {
-                               DIR *current;
-                               gchar *entry;
-                               
-                               current = opendir (".");
-                               if (current == NULL) {
-#ifdef DEBUG
-                                       g_message ("%s: opendir 4 error: %s",
-                                                  __func__,
-                                                  g_strerror (errno));
-#endif
-                                       g_strfreev (new_components);
-                                       g_strfreev (components);
-                                       return(NULL);
-                               }
-                               
-                               entry = find_in_dir (current, components[0]);
-                               if (entry == NULL) {
-                                       g_strfreev (new_components);
-                                       g_strfreev (components);
-                                       return(NULL);
-                               }
-                               
-                               new_components[component++] = entry;
-                       }
-               } else {
-                               new_components[component++] = g_strdup (components[0]);
-               }
-       }
-
-#ifdef DEBUG
-       g_message ("%s: Got first entry: [%s]\n", __func__, new_components[0]);
-#endif
-
-       g_assert (component == 1);
-       
-       for(; component < num_components; component++) {
-               gchar *entry;
-               gchar *path_so_far;
-               
-               if (!last_exists &&
-                   component == num_components -1) {
-                       entry = g_strdup (components[component]);
-                       closedir (scanning);
-               } else {
-                       entry = find_in_dir (scanning, components[component]);
-                       if (entry == NULL) {
-                               g_strfreev (new_components);
-                               g_strfreev (components);
-                               return(NULL);
-                       }
-               }
-               
-               new_components[component] = entry;
-               
-               if (component < num_components -1) {
-                       path_so_far = g_strjoinv ("/", new_components);
-
-                       scanning = opendir (path_so_far);
-                       g_free (path_so_far);
-                       if (scanning == NULL) {
-                               g_strfreev (new_components);
-                               g_strfreev (components);
-                               return(NULL);
-                       }
-               }
-       }
-       
-       g_strfreev (components);
-
-       new_pathname = g_strjoinv ("/", new_components);
-
-#ifdef DEBUG
-       g_message ("%s: pathname [%s] became [%s]\n", __func__, pathname,
-                  new_pathname);
-#endif
-       
-       g_strfreev (new_components);
-
-       if ((last_exists &&
-            access (new_pathname, F_OK) == 0) ||
-           (!last_exists)) {
-               return(new_pathname);
-       }
-       
-       g_free (new_pathname);
-       return(NULL);
-}
-
 int _wapi_open (const char *pathname, int flags, mode_t mode)
 {
        int fd;
        gchar *located_filename;
        
        if (flags & O_CREAT) {
-               located_filename = find_file (pathname, FALSE);
+               located_filename = mono_portability_find_file (pathname, FALSE);
                if (located_filename == NULL) {
                        fd = open (pathname, flags, mode);
                } else {
@@ -318,7 +52,7 @@ int _wapi_open (const char *pathname, int flags, mode_t mode)
                    (errno == ENOENT || errno == ENOTDIR) &&
                    IS_PORTABILITY_SET) {
                        int saved_errno = errno;
-                       located_filename = find_file (pathname, TRUE);
+                       located_filename = mono_portability_find_file (pathname, TRUE);
                        
                        if (located_filename == NULL) {
                                errno = saved_errno;
@@ -343,7 +77,7 @@ int _wapi_access (const char *pathname, int mode)
            (errno == ENOENT || errno == ENOTDIR) &&
            IS_PORTABILITY_SET) {
                int saved_errno = errno;
-               gchar *located_filename = find_file (pathname, TRUE);
+               gchar *located_filename = mono_portability_find_file (pathname, TRUE);
                
                if (located_filename == NULL) {
                        errno = saved_errno;
@@ -366,7 +100,7 @@ int _wapi_chmod (const char *pathname, mode_t mode)
            (errno == ENOENT || errno == ENOTDIR) &&
            IS_PORTABILITY_SET) {
                int saved_errno = errno;
-               gchar *located_filename = find_file (pathname, TRUE);
+               gchar *located_filename = mono_portability_find_file (pathname, TRUE);
                
                if (located_filename == NULL) {
                        errno = saved_errno;
@@ -389,7 +123,7 @@ int _wapi_utime (const char *filename, const struct utimbuf *buf)
            errno == ENOENT &&
            IS_PORTABILITY_SET) {
                int saved_errno = errno;
-               gchar *located_filename = find_file (filename, TRUE);
+               gchar *located_filename = mono_portability_find_file (filename, TRUE);
                
                if (located_filename == NULL) {
                        errno = saved_errno;
@@ -412,7 +146,7 @@ int _wapi_unlink (const char *pathname)
            (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) &&
            IS_PORTABILITY_SET) {
                int saved_errno = errno;
-               gchar *located_filename = find_file (pathname, TRUE);
+               gchar *located_filename = mono_portability_find_file (pathname, TRUE);
                
                if (located_filename == NULL) {
                        errno = saved_errno;
@@ -429,7 +163,7 @@ int _wapi_unlink (const char *pathname)
 int _wapi_rename (const char *oldpath, const char *newpath)
 {
        int ret;
-       gchar *located_newpath = find_file (newpath, FALSE);
+       gchar *located_newpath = mono_portability_find_file (newpath, FALSE);
        
        if (located_newpath == NULL) {
                ret = rename (oldpath, newpath);
@@ -441,7 +175,7 @@ int _wapi_rename (const char *oldpath, const char *newpath)
                     errno == ENOENT || errno == ENOTDIR || errno == EXDEV) &&
                    IS_PORTABILITY_SET) {
                        int saved_errno = errno;
-                       gchar *located_oldpath = find_file (oldpath, TRUE);
+                       gchar *located_oldpath = mono_portability_find_file (oldpath, TRUE);
                        
                        if (located_oldpath == NULL) {
                                g_free (located_oldpath);
@@ -469,7 +203,7 @@ int _wapi_stat (const char *path, struct stat *buf)
            (errno == ENOENT || errno == ENOTDIR) &&
            IS_PORTABILITY_SET) {
                int saved_errno = errno;
-               gchar *located_filename = find_file (path, TRUE);
+               gchar *located_filename = mono_portability_find_file (path, TRUE);
                
                if (located_filename == NULL) {
                        errno = saved_errno;
@@ -492,7 +226,7 @@ int _wapi_lstat (const char *path, struct stat *buf)
            (errno == ENOENT || errno == ENOTDIR) &&
            IS_PORTABILITY_SET) {
                int saved_errno = errno;
-               gchar *located_filename = find_file (path, TRUE);
+               gchar *located_filename = mono_portability_find_file (path, TRUE);
                
                if (located_filename == NULL) {
                        errno = saved_errno;
@@ -509,7 +243,7 @@ int _wapi_lstat (const char *path, struct stat *buf)
 int _wapi_mkdir (const char *pathname, mode_t mode)
 {
        int ret;
-       gchar *located_filename = find_file (pathname, FALSE);
+       gchar *located_filename = mono_portability_find_file (pathname, FALSE);
        
        if (located_filename == NULL) {
                ret = mkdir (pathname, mode);
@@ -530,7 +264,7 @@ int _wapi_rmdir (const char *pathname)
            (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) &&
            IS_PORTABILITY_SET) {
                int saved_errno = errno;
-               gchar *located_filename = find_file (pathname, TRUE);
+               gchar *located_filename = mono_portability_find_file (pathname, TRUE);
                
                if (located_filename == NULL) {
                        errno = saved_errno;
@@ -553,7 +287,7 @@ int _wapi_chdir (const char *path)
            (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) &&
            IS_PORTABILITY_SET) {
                int saved_errno = errno;
-               gchar *located_filename = find_file (path, TRUE);
+               gchar *located_filename = mono_portability_find_file (path, TRUE);
                
                if (located_filename == NULL) {
                        errno = saved_errno;
@@ -571,9 +305,9 @@ gchar *_wapi_basename (const gchar *filename)
 {
        gchar *new_filename = g_strdup (filename), *ret;
 
-       mono_portability_helpers_init ();
-       
-       g_strdelimit (new_filename, "\\", '/');
+       if (IS_PORTABILITY_SET) {
+               g_strdelimit (new_filename, "\\", '/');
+       }
 
        if (IS_PORTABILITY_DRIVE &&
            g_ascii_isalpha (new_filename[0]) &&
@@ -594,9 +328,9 @@ gchar *_wapi_dirname (const gchar *filename)
 {
        gchar *new_filename = g_strdup (filename), *ret;
 
-       mono_portability_helpers_init ();
-       
-       g_strdelimit (new_filename, "\\", '/');
+       if (IS_PORTABILITY_SET) {
+               g_strdelimit (new_filename, "\\", '/');
+       }
 
        if (IS_PORTABILITY_DRIVE &&
            g_ascii_isalpha (new_filename[0]) &&
@@ -623,7 +357,7 @@ GDir *_wapi_g_dir_open (const gchar *path, guint flags, GError **error)
             (*error)->code == G_FILE_ERROR_NOTDIR ||
             (*error)->code == G_FILE_ERROR_NAMETOOLONG) &&
            IS_PORTABILITY_SET) {
-               gchar *located_filename = find_file (path, TRUE);
+               gchar *located_filename = mono_portability_find_file (path, TRUE);
                GError *tmp_error = NULL;
                
                if (located_filename == NULL) {
@@ -807,11 +541,16 @@ gint _wapi_io_scandir (const gchar *dirname, const gchar *pattern,
                 * TODO: should this be a MONO_IOMAP option?
                 */
                gchar *pattern2 = g_strndup (pattern, strlen (pattern) - 2);
+               gint result2;
                
                g_dir_rewind (dir);
-               result = _wapi_glob (dir, pattern2, flags | WAPI_GLOB_APPEND | WAPI_GLOB_UNIQUE, &glob_buf);
+               result2 = _wapi_glob (dir, pattern2, flags | WAPI_GLOB_APPEND | WAPI_GLOB_UNIQUE, &glob_buf);
 
                g_free (pattern2);
+
+               if (result != 0) {
+                       result = result2;
+               }
        }
        
        g_dir_close (dir);