[runtime] Update comment with link to Linux Kernel fix.
[mono.git] / mono / metadata / w32file-unix.c
index ecca05ec6aa9bfecb911522876e2ae1b6f751a0d..8c97b06cc8c9aaa91add0272f64f3ec381417f60 100644 (file)
@@ -1,3 +1,6 @@
+/**
+ * \file
+ */
 
 #include <config.h>
 #include <glib.h>
@@ -36,6 +39,7 @@
 
 #include "w32file-unix-glob.h"
 #include "w32handle.h"
+#include "w32error.h"
 #include "utils/mono-io-portability.h"
 #include "utils/mono-logger-internals.h"
 #include "utils/mono-os-mutex.h"
@@ -46,7 +50,6 @@
 typedef struct {
        guint64 device;
        guint64 inode;
-       pid_t opened_by_pid;
        guint32 sharemode;
        guint32 access;
        guint32 handle_refs;
@@ -78,7 +81,7 @@ typedef struct {
  * 4MB array.
  */
 static GHashTable *file_share_table;
-static mono_mutex_t file_share_mutex;
+static MonoCoopMutex file_share_mutex;
 
 static void
 time_t_to_filetime (time_t timeval, FILETIME *filetime)
@@ -94,7 +97,7 @@ static void
 file_share_release (FileShare *share_info)
 {
        /* Prevent new entries racing with us */
-       mono_os_mutex_lock (&file_share_mutex);
+       mono_coop_mutex_lock (&file_share_mutex);
 
        g_assert (share_info->handle_refs > 0);
        share_info->handle_refs -= 1;
@@ -102,7 +105,7 @@ file_share_release (FileShare *share_info)
        if (share_info->handle_refs == 0)
                g_hash_table_remove (file_share_table, share_info);
 
-       mono_os_mutex_unlock (&file_share_mutex);
+       mono_coop_mutex_unlock (&file_share_mutex);
 }
 
 static gint
@@ -130,7 +133,7 @@ file_share_get (guint64 device, guint64 inode, guint32 new_sharemode, guint32 ne
        gboolean exists = FALSE;
 
        /* Prevent new entries racing with us */
-       mono_os_mutex_lock (&file_share_mutex);
+       mono_coop_mutex_lock (&file_share_mutex);
 
        FileShare tmp;
 
@@ -160,7 +163,6 @@ file_share_get (guint64 device, guint64 inode, guint32 new_sharemode, guint32 ne
 
                file_share->device = device;
                file_share->inode = inode;
-               file_share->opened_by_pid = wapi_getpid ();
                file_share->sharemode = new_sharemode;
                file_share->access = new_access;
                file_share->handle_refs = 1;
@@ -169,7 +171,7 @@ file_share_get (guint64 device, guint64 inode, guint32 new_sharemode, guint32 ne
                g_hash_table_insert (file_share_table, file_share, file_share);
        }
 
-       mono_os_mutex_unlock (&file_share_mutex);
+       mono_coop_mutex_unlock (&file_share_mutex);
 
        return(exists);
 }
@@ -183,13 +185,19 @@ _wapi_open (const gchar *pathname, gint flags, mode_t mode)
        if (flags & O_CREAT) {
                located_filename = mono_portability_find_file (pathname, FALSE);
                if (located_filename == NULL) {
+                       MONO_ENTER_GC_SAFE;
                        fd = open (pathname, flags, mode);
+                       MONO_EXIT_GC_SAFE;
                } else {
+                       MONO_ENTER_GC_SAFE;
                        fd = open (located_filename, flags, mode);
+                       MONO_EXIT_GC_SAFE;
                        g_free (located_filename);
                }
        } else {
+               MONO_ENTER_GC_SAFE;
                fd = open (pathname, flags, mode);
+               MONO_EXIT_GC_SAFE;
                if (fd == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
                        gint saved_errno = errno;
                        located_filename = mono_portability_find_file (pathname, TRUE);
@@ -199,7 +207,9 @@ _wapi_open (const gchar *pathname, gint flags, mode_t mode)
                                return -1;
                        }
 
+                       MONO_ENTER_GC_SAFE;
                        fd = open (located_filename, flags, mode);
+                       MONO_EXIT_GC_SAFE;
                        g_free (located_filename);
                }
        }
@@ -212,7 +222,9 @@ _wapi_access (const gchar *pathname, gint mode)
 {
        gint ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = access (pathname, mode);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
                gint saved_errno = errno;
                gchar *located_filename = mono_portability_find_file (pathname, TRUE);
@@ -222,7 +234,9 @@ _wapi_access (const gchar *pathname, gint mode)
                        return -1;
                }
 
+               MONO_ENTER_GC_SAFE;
                ret = access (located_filename, mode);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
        }
 
@@ -234,7 +248,9 @@ _wapi_chmod (const gchar *pathname, mode_t mode)
 {
        gint ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = chmod (pathname, mode);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
                gint saved_errno = errno;
                gchar *located_filename = mono_portability_find_file (pathname, TRUE);
@@ -244,7 +260,9 @@ _wapi_chmod (const gchar *pathname, mode_t mode)
                        return -1;
                }
 
+               MONO_ENTER_GC_SAFE;
                ret = chmod (located_filename, mode);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
        }
 
@@ -256,7 +274,9 @@ _wapi_utime (const gchar *filename, const struct utimbuf *buf)
 {
        gint ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = utime (filename, buf);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1 && errno == ENOENT && IS_PORTABILITY_SET) {
                gint saved_errno = errno;
                gchar *located_filename = mono_portability_find_file (filename, TRUE);
@@ -266,7 +286,9 @@ _wapi_utime (const gchar *filename, const struct utimbuf *buf)
                        return -1;
                }
 
+               MONO_ENTER_GC_SAFE;
                ret = utime (located_filename, buf);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
        }
 
@@ -278,7 +300,9 @@ _wapi_unlink (const gchar *pathname)
 {
        gint ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = unlink (pathname);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) && IS_PORTABILITY_SET) {
                gint saved_errno = errno;
                gchar *located_filename = mono_portability_find_file (pathname, TRUE);
@@ -288,7 +312,9 @@ _wapi_unlink (const gchar *pathname)
                        return -1;
                }
 
+               MONO_ENTER_GC_SAFE;
                ret = unlink (located_filename);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
        }
 
@@ -302,9 +328,13 @@ _wapi_rename (const gchar *oldpath, const gchar *newpath)
        gchar *located_newpath = mono_portability_find_file (newpath, FALSE);
 
        if (located_newpath == NULL) {
+               MONO_ENTER_GC_SAFE;
                ret = rename (oldpath, newpath);
+               MONO_EXIT_GC_SAFE;
        } else {
+               MONO_ENTER_GC_SAFE;
                ret = rename (oldpath, located_newpath);
+               MONO_EXIT_GC_SAFE;
 
                if (ret == -1 && (errno == EISDIR || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EXDEV) && IS_PORTABILITY_SET) {
                        gint saved_errno = errno;
@@ -318,7 +348,9 @@ _wapi_rename (const gchar *oldpath, const gchar *newpath)
                                return -1;
                        }
 
+                       MONO_ENTER_GC_SAFE;
                        ret = rename (located_oldpath, located_newpath);
+                       MONO_EXIT_GC_SAFE;
                        g_free (located_oldpath);
                }
                g_free (located_newpath);
@@ -332,7 +364,9 @@ _wapi_stat (const gchar *path, struct stat *buf)
 {
        gint ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = stat (path, buf);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
                gint saved_errno = errno;
                gchar *located_filename = mono_portability_find_file (path, TRUE);
@@ -342,7 +376,9 @@ _wapi_stat (const gchar *path, struct stat *buf)
                        return -1;
                }
 
+               MONO_ENTER_GC_SAFE;
                ret = stat (located_filename, buf);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
        }
 
@@ -354,7 +390,9 @@ _wapi_lstat (const gchar *path, struct stat *buf)
 {
        gint ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = lstat (path, buf);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
                gint saved_errno = errno;
                gchar *located_filename = mono_portability_find_file (path, TRUE);
@@ -378,9 +416,13 @@ _wapi_mkdir (const gchar *pathname, mode_t mode)
        gchar *located_filename = mono_portability_find_file (pathname, FALSE);
 
        if (located_filename == NULL) {
+               MONO_ENTER_GC_SAFE;
                ret = mkdir (pathname, mode);
+               MONO_EXIT_GC_SAFE;
        } else {
+               MONO_ENTER_GC_SAFE;
                ret = mkdir (located_filename, mode);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
        }
 
@@ -392,7 +434,9 @@ _wapi_rmdir (const gchar *pathname)
 {
        gint ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = rmdir (pathname);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) && IS_PORTABILITY_SET) {
                gint saved_errno = errno;
                gchar *located_filename = mono_portability_find_file (pathname, TRUE);
@@ -402,7 +446,9 @@ _wapi_rmdir (const gchar *pathname)
                        return -1;
                }
 
+               MONO_ENTER_GC_SAFE;
                ret = rmdir (located_filename);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
        }
 
@@ -414,7 +460,9 @@ _wapi_chdir (const gchar *path)
 {
        gint ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = chdir (path);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) && IS_PORTABILITY_SET) {
                gint saved_errno = errno;
                gchar *located_filename = mono_portability_find_file (path, TRUE);
@@ -424,7 +472,9 @@ _wapi_chdir (const gchar *path)
                        return -1;
                }
 
+               MONO_ENTER_GC_SAFE;
                ret = chdir (located_filename);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
        }
 
@@ -480,7 +530,9 @@ _wapi_g_dir_open (const gchar *path, guint flags, GError **error)
 {
        GDir *ret;
 
+       MONO_ENTER_GC_SAFE;
        ret = g_dir_open (path, flags, error);
+       MONO_EXIT_GC_SAFE;
        if (ret == NULL && ((*error)->code == G_FILE_ERROR_NOENT || (*error)->code == G_FILE_ERROR_NOTDIR || (*error)->code == G_FILE_ERROR_NAMETOOLONG) && IS_PORTABILITY_SET) {
                gchar *located_filename = mono_portability_find_file (path, TRUE);
                GError *tmp_error = NULL;
@@ -489,7 +541,9 @@ _wapi_g_dir_open (const gchar *path, guint flags, GError **error)
                        return(NULL);
                }
 
+               MONO_ENTER_GC_SAFE;
                ret = g_dir_open (located_filename, flags, &tmp_error);
+               MONO_EXIT_GC_SAFE;
                g_free (located_filename);
                if (tmp_error == NULL) {
                        g_clear_error (error);
@@ -503,7 +557,7 @@ static gint
 get_errno_from_g_file_error (gint error)
 {
        switch (error) {
-#ifdef EACCESS
+#ifdef EACCES
        case G_FILE_ERROR_ACCES: return EACCES;
 #endif
 #ifdef ENAMETOOLONG
@@ -560,7 +614,7 @@ get_errno_from_g_file_error (gint error)
 #ifdef EINTR
        case G_FILE_ERROR_INTR: return EINTR;
 #endif
-#ifdef EWIO
+#ifdef EIO
        case G_FILE_ERROR_IO: return EIO;
 #endif
 #ifdef EPERM
@@ -623,7 +677,9 @@ _wapi_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist)
                gchar *pattern2 = g_strndup (pattern, strlen (pattern) - 2);
                gint result2;
 
+               MONO_ENTER_GC_SAFE;
                g_dir_rewind (dir);
+               MONO_EXIT_GC_SAFE;
                result2 = mono_w32file_unix_glob (dir, pattern2, flags | W32FILE_UNIX_GLOB_APPEND | W32FILE_UNIX_GLOB_UNIQUE, &glob_buf);
 
                g_free (pattern2);
@@ -633,7 +689,9 @@ _wapi_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist)
                }
        }
 
+       MONO_ENTER_GC_SAFE;
        g_dir_close (dir);
+       MONO_EXIT_GC_SAFE;
        if (glob_buf.gl_pathc == 0) {
                return(0);
        } else if (result != 0) {
@@ -663,16 +721,11 @@ _wapi_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist)
 static gboolean
 _wapi_lock_file_region (gint fd, off_t offset, off_t length)
 {
-#if defined(__native_client__)
-       printf("WARNING: %s: fcntl() not available on Native Client!\n", __func__);
-       // behave as below -- locks are not available
-       return TRUE;
-#else
        struct flock lock_data;
        gint ret;
 
        if (offset < 0 || length < 0) {
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return FALSE;
        }
 
@@ -703,21 +756,16 @@ _wapi_lock_file_region (gint fd, off_t offset, off_t length)
                        return TRUE;
                }
 
-               SetLastError (ERROR_LOCK_VIOLATION);
+               mono_w32error_set_last (ERROR_LOCK_VIOLATION);
                return FALSE;
        }
 
        return TRUE;
-#endif /* __native_client__ */
 }
 
 static gboolean
 _wapi_unlock_file_region (gint fd, off_t offset, off_t length)
 {
-#if defined(__native_client__)
-       printf("WARNING: %s: fcntl() not available on Native Client!\n", __func__);
-       return TRUE;
-#else
        struct flock lock_data;
        gint ret;
 
@@ -748,12 +796,11 @@ _wapi_unlock_file_region (gint fd, off_t offset, off_t length)
                        return TRUE;
                }
 
-               SetLastError (ERROR_LOCK_VIOLATION);
+               mono_w32error_set_last (ERROR_LOCK_VIOLATION);
                return FALSE;
        }
 
        return TRUE;
-#endif /* __native_client__ */
 }
 
 static void file_close (gpointer handle, gpointer data);
@@ -1009,7 +1056,7 @@ static guint32 _wapi_stat_to_file_attributes (const gchar *pathname,
 static void
 _wapi_set_last_error_from_errno (void)
 {
-       SetLastError (_wapi_get_win32_file_error (errno));
+       mono_w32error_set_last (mono_w32error_unix_to_win32 (errno));
 }
 
 static void _wapi_set_last_path_error_from_errno (const gchar *dir,
@@ -1029,9 +1076,9 @@ static void _wapi_set_last_path_error_from_errno (const gchar *dir,
                }
                
                if (_wapi_access (dirname, F_OK) == 0) {
-                       SetLastError (ERROR_FILE_NOT_FOUND);
+                       mono_w32error_set_last (ERROR_FILE_NOT_FOUND);
                } else {
-                       SetLastError (ERROR_PATH_NOT_FOUND);
+                       mono_w32error_set_last (ERROR_PATH_NOT_FOUND);
                }
 
                g_free (dirname);
@@ -1044,6 +1091,8 @@ static void _wapi_set_last_path_error_from_errno (const gchar *dir,
  */
 static void file_close (gpointer handle, gpointer data)
 {
+       /* FIXME: after mono_w32handle_close is coop-aware, change this to MONO_REQ_GC_UNSAFE_MODE and leave just the switch to SAFE around close() below */
+       MONO_ENTER_GC_UNSAFE;
        MonoW32HandleFile *file_handle = (MonoW32HandleFile *)data;
        gint fd = file_handle->fd;
        
@@ -1058,7 +1107,10 @@ static void file_close (gpointer handle, gpointer data)
        if (file_handle->share_info)
                file_share_release (file_handle->share_info);
        
+       MONO_ENTER_GC_SAFE;
        close (fd);
+       MONO_EXIT_GC_SAFE;
+       MONO_EXIT_GC_UNSAFE;
 }
 
 static void file_details (gpointer data)
@@ -1104,7 +1156,7 @@ file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread
        if(ok==FALSE) {
                g_warning ("%s: error looking up file handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
 
@@ -1118,12 +1170,14 @@ file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
                          __func__, handle, file_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
 
        do {
+               MONO_ENTER_GC_SAFE;
                ret = read (fd, buffer, numbytes);
+               MONO_EXIT_GC_SAFE;
        } while (ret == -1 && errno == EINTR &&
                 !mono_thread_info_is_interrupt_state (info));
                        
@@ -1132,7 +1186,7 @@ file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread
 
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: read of handle %p error: %s", __func__,
                          handle, strerror(err));
-               SetLastError (_wapi_get_win32_file_error (err));
+               mono_w32error_set_last (mono_w32error_unix_to_win32 (err));
                return(FALSE);
        }
                
@@ -1157,7 +1211,7 @@ file_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byt
        if(ok==FALSE) {
                g_warning ("%s: error looking up file handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
 
@@ -1171,7 +1225,7 @@ file_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byt
           !(file_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
@@ -1180,7 +1234,9 @@ file_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byt
                 * because we only do advisory locking on POSIX
                 * systems
                 */
+               MONO_ENTER_GC_SAFE;
                current_pos = lseek (fd, (off_t)0, SEEK_CUR);
+               MONO_EXIT_GC_SAFE;
                if (current_pos == -1) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p lseek failed: %s", __func__,
                                   handle, strerror (errno));
@@ -1196,7 +1252,9 @@ file_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byt
        }
                
        do {
+               MONO_ENTER_GC_SAFE;
                ret = write (fd, buffer, numbytes);
+               MONO_EXIT_GC_SAFE;
        } while (ret == -1 && errno == EINTR &&
                 !mono_thread_info_is_interrupt_state (info));
        
@@ -1233,7 +1291,7 @@ static gboolean file_flush(gpointer handle)
        if(ok==FALSE) {
                g_warning ("%s: error looking up file handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
 
@@ -1243,11 +1301,13 @@ static gboolean file_flush(gpointer handle)
           !(file_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
 
+       MONO_ENTER_GC_SAFE;
        ret=fsync(fd);
+       MONO_EXIT_GC_SAFE;
        if (ret==-1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fsync of handle %p error: %s", __func__, handle,
                          strerror(errno));
@@ -1273,7 +1333,7 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
        if(ok==FALSE) {
                g_warning ("%s: error looking up file handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(INVALID_SET_FILE_POINTER);
        }
        
@@ -1284,7 +1344,7 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
           !(file_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(INVALID_SET_FILE_POINTER);
        }
 
@@ -1301,7 +1361,7 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
        default:
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: invalid seek type %d", __func__, method);
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return(INVALID_SET_FILE_POINTER);
        }
 
@@ -1324,9 +1384,13 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
 
 #ifdef PLATFORM_ANDROID
        /* bionic doesn't support -D_FILE_OFFSET_BITS=64 */
+       MONO_ENTER_GC_SAFE;
        newpos=lseek64(fd, offset, whence);
+       MONO_EXIT_GC_SAFE;
 #else
+       MONO_ENTER_GC_SAFE;
        newpos=lseek(fd, offset, whence);
+       MONO_EXIT_GC_SAFE;
 #endif
        if(newpos==-1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lseek on handle %p returned error %s",
@@ -1371,7 +1435,7 @@ static gboolean file_setendoffile(gpointer handle)
        if(ok==FALSE) {
                g_warning ("%s: error looking up file handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        fd = file_handle->fd;
@@ -1380,7 +1444,7 @@ static gboolean file_setendoffile(gpointer handle)
           !(file_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
 
@@ -1390,7 +1454,9 @@ static gboolean file_setendoffile(gpointer handle)
         * than the length, truncate the file.
         */
        
+       MONO_ENTER_GC_SAFE;
        ret=fstat(fd, &statbuf);
+       MONO_EXIT_GC_SAFE;
        if(ret==-1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__,
                           handle, strerror(errno));
@@ -1399,7 +1465,9 @@ static gboolean file_setendoffile(gpointer handle)
                return(FALSE);
        }
 
+       MONO_ENTER_GC_SAFE;
        pos=lseek(fd, (off_t)0, SEEK_CUR);
+       MONO_EXIT_GC_SAFE;
        if(pos==-1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p lseek failed: %s", __func__,
                          handle, strerror(errno));
@@ -1423,7 +1491,9 @@ static gboolean file_setendoffile(gpointer handle)
                 * drop this write.
                 */
                do {
+                       MONO_ENTER_GC_SAFE;
                        ret = write (fd, "", 1);
+                       MONO_EXIT_GC_SAFE;
                } while (ret == -1 && errno == EINTR &&
                         !mono_thread_info_is_interrupt_state (info));
 
@@ -1435,7 +1505,9 @@ static gboolean file_setendoffile(gpointer handle)
                }
 
                /* And put the file position back after the write */
+               MONO_ENTER_GC_SAFE;
                ret = lseek (fd, pos, SEEK_SET);
+               MONO_EXIT_GC_SAFE;
                if (ret == -1) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p second lseek failed: %s",
                                   __func__, handle, strerror(errno));
@@ -1446,13 +1518,13 @@ static gboolean file_setendoffile(gpointer handle)
        }
 #endif
 
-/* Native Client has no ftruncate function, even in standalone sel_ldr. */
-#ifndef __native_client__
        /* always truncate, because the extend write() adds an extra
         * byte to the end of the file
         */
        do {
+               MONO_ENTER_GC_SAFE;
                ret=ftruncate(fd, pos);
+               MONO_EXIT_GC_SAFE;
        }
        while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); 
        if(ret==-1) {
@@ -1462,7 +1534,6 @@ static gboolean file_setendoffile(gpointer handle)
                _wapi_set_last_error_from_errno ();
                return(FALSE);
        }
-#endif
                
        return(TRUE);
 }
@@ -1481,7 +1552,7 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
        if(ok==FALSE) {
                g_warning ("%s: error looking up file handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(INVALID_FILE_SIZE);
        }
        fd = file_handle->fd;
@@ -1491,7 +1562,7 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
           !(file_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(INVALID_FILE_SIZE);
        }
 
@@ -1499,9 +1570,11 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
         * caller can't tell if this is an error, so clear the error
         * value
         */
-       SetLastError (ERROR_SUCCESS);
+       mono_w32error_set_last (ERROR_SUCCESS);
        
+       MONO_ENTER_GC_SAFE;
        ret = fstat(fd, &statbuf);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__,
                           handle, strerror(errno));
@@ -1514,7 +1587,11 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
 #ifdef BLKGETSIZE64
        if (S_ISBLK(statbuf.st_mode)) {
                guint64 bigsize;
-               if (ioctl(fd, BLKGETSIZE64, &bigsize) < 0) {
+               gint res;
+               MONO_ENTER_GC_SAFE;
+               res = ioctl (fd, BLKGETSIZE64, &bigsize);
+               MONO_EXIT_GC_SAFE;
+               if (res < 0) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p ioctl BLKGETSIZE64 failed: %s",
                                   __func__, handle, strerror(errno));
 
@@ -1567,7 +1644,7 @@ static gboolean file_getfiletime(gpointer handle, FILETIME *create_time,
        if(ok==FALSE) {
                g_warning ("%s: error looking up file handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        fd = file_handle->fd;
@@ -1577,11 +1654,13 @@ static gboolean file_getfiletime(gpointer handle, FILETIME *create_time,
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
                          __func__, handle, file_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
+       MONO_ENTER_GC_SAFE;
        ret=fstat(fd, &statbuf);
+       MONO_EXIT_GC_SAFE;
        if(ret==-1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__, handle,
                          strerror(errno));
@@ -1649,7 +1728,7 @@ static gboolean file_setfiletime(gpointer handle,
        if(ok==FALSE) {
                g_warning ("%s: error looking up file handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        fd = file_handle->fd;
@@ -1658,26 +1737,28 @@ static gboolean file_setfiletime(gpointer handle,
           !(file_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
 
        if(file_handle->filename == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p unknown filename", __func__, handle);
 
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        
        /* Get the current times, so we can put the same times back in
         * the event that one of the FileTime structs is NULL
         */
+       MONO_ENTER_GC_SAFE;
        ret=fstat (fd, &statbuf);
+       MONO_EXIT_GC_SAFE;
        if(ret==-1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p fstat failed: %s", __func__, handle,
                          strerror(errno));
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return(FALSE);
        }
 
@@ -1690,14 +1771,14 @@ static gboolean file_setfiletime(gpointer handle,
                if (access_ticks < 116444736000000000ULL) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set access time too early",
                                   __func__);
-                       SetLastError (ERROR_INVALID_PARAMETER);
+                       mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                        return(FALSE);
                }
 
                if (sizeof (utbuf.actime) == 4 && ((access_ticks - 116444736000000000ULL) / 10000000) > INT_MAX) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time that is too big for a 32bits time_t",
                                   __func__);
-                       SetLastError (ERROR_INVALID_PARAMETER);
+                       mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                        return(FALSE);
                }
 
@@ -1715,13 +1796,13 @@ static gboolean file_setfiletime(gpointer handle,
                if (write_ticks < 116444736000000000ULL) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time too early",
                                   __func__);
-                       SetLastError (ERROR_INVALID_PARAMETER);
+                       mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                        return(FALSE);
                }
                if (sizeof (utbuf.modtime) == 4 && ((write_ticks - 116444736000000000ULL) / 10000000) > INT_MAX) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt to set write time that is too big for a 32bits time_t",
                                   __func__);
-                       SetLastError (ERROR_INVALID_PARAMETER);
+                       mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                        return(FALSE);
                }
                
@@ -1738,7 +1819,7 @@ static gboolean file_setfiletime(gpointer handle,
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p [%s] utime failed: %s", __func__,
                           handle, file_handle->filename, strerror(errno));
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return(FALSE);
        }
        
@@ -1747,6 +1828,8 @@ static gboolean file_setfiletime(gpointer handle,
 
 static void console_close (gpointer handle, gpointer data)
 {
+       /* FIXME: after mono_w32handle_close is coop-aware, change this to MONO_REQ_GC_UNSAFE_MODE and leave just the switch to SAFE around close() below */
+       MONO_ENTER_GC_UNSAFE;
        MonoW32HandleFile *console_handle = (MonoW32HandleFile *)data;
        gint fd = console_handle->fd;
        
@@ -1757,8 +1840,11 @@ static void console_close (gpointer handle, gpointer data)
        if (fd > 2) {
                if (console_handle->share_info)
                        file_share_release (console_handle->share_info);
+               MONO_ENTER_GC_SAFE;
                close (fd);
+               MONO_EXIT_GC_SAFE;
        }
+       MONO_EXIT_GC_UNSAFE;
 }
 
 static void console_details (gpointer data)
@@ -1794,7 +1880,7 @@ console_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesr
        if(ok==FALSE) {
                g_warning ("%s: error looking up console handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        fd = console_handle->fd;
@@ -1808,12 +1894,14 @@ console_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesr
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
                           __func__, handle, console_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
        do {
+               MONO_ENTER_GC_SAFE;
                ret=read(fd, buffer, numbytes);
+               MONO_EXIT_GC_SAFE;
        } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
 
        if(ret==-1) {
@@ -1844,7 +1932,7 @@ console_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *
        if(ok==FALSE) {
                g_warning ("%s: error looking up console handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        fd = console_handle->fd;
@@ -1857,12 +1945,14 @@ console_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *
           !(console_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, console_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
        do {
+               MONO_ENTER_GC_SAFE;
                ret = write(fd, buffer, numbytes);
+               MONO_EXIT_GC_SAFE;
        } while (ret == -1 && errno == EINTR &&
                 !mono_thread_info_is_interrupt_state (info));
 
@@ -1897,6 +1987,8 @@ static gsize find_typesize (void)
 
 static void pipe_close (gpointer handle, gpointer data)
 {
+       /* FIXME: after mono_w32handle_close is coop-aware, change this to MONO_REQ_GC_UNSAFE_MODE and leave just the switch to SAFE around close() below */
+       MONO_ENTER_GC_UNSAFE;
        MonoW32HandleFile *pipe_handle = (MonoW32HandleFile*)data;
        gint fd = pipe_handle->fd;
 
@@ -1907,7 +1999,10 @@ static void pipe_close (gpointer handle, gpointer data)
        if (pipe_handle->share_info)
                file_share_release (pipe_handle->share_info);
 
+       MONO_ENTER_GC_SAFE;
        close (fd);
+       MONO_EXIT_GC_SAFE;
+       MONO_EXIT_GC_UNSAFE;
 }
 
 static void pipe_details (gpointer data)
@@ -1943,7 +2038,7 @@ pipe_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesrea
        if(ok==FALSE) {
                g_warning ("%s: error looking up pipe handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        fd = pipe_handle->fd;
@@ -1957,7 +2052,7 @@ pipe_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesrea
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ access: %u",
                          __func__, handle, pipe_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
@@ -1965,7 +2060,9 @@ pipe_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesrea
                   numbytes, handle);
 
        do {
+               MONO_ENTER_GC_SAFE;
                ret=read(fd, buffer, numbytes);
+               MONO_EXIT_GC_SAFE;
        } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info));
                
        if (ret == -1) {
@@ -2003,7 +2100,7 @@ pipe_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byt
        if(ok==FALSE) {
                g_warning ("%s: error looking up pipe handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        fd = pipe_handle->fd;
@@ -2016,7 +2113,7 @@ pipe_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byt
           !(pipe_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, pipe_handle->fileaccess);
 
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
@@ -2024,7 +2121,9 @@ pipe_write(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byt
                   handle);
 
        do {
+               MONO_ENTER_GC_SAFE;
                ret = write (fd, buffer, numbytes);
+               MONO_EXIT_GC_SAFE;
        } while (ret == -1 && errno == EINTR &&
                 !mono_thread_info_is_interrupt_state (info));
 
@@ -2220,14 +2319,14 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode
                perms = 0600;
        
        if (attrs & FILE_ATTRIBUTE_ENCRYPTED){
-               SetLastError (ERROR_ENCRYPTION_FAILED);
+               mono_w32error_set_last (ERROR_ENCRYPTION_FAILED);
                return INVALID_HANDLE_VALUE;
        }
        
        if (name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(INVALID_HANDLE_VALUE);
        }
 
@@ -2235,7 +2334,7 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode
        if (filename == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(INVALID_HANDLE_VALUE);
        }
        
@@ -2270,37 +2369,38 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode
        if (fd >= mono_w32handle_fd_reserve) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
 
-               SetLastError (ERROR_TOO_MANY_OPEN_FILES);
+               mono_w32error_set_last (ERROR_TOO_MANY_OPEN_FILES);
                
+               MONO_ENTER_GC_SAFE;
                close (fd);
+               MONO_EXIT_GC_SAFE;
                g_free (filename);
                
                return(INVALID_HANDLE_VALUE);
        }
 
+       MONO_ENTER_GC_SAFE;
        ret = fstat (fd, &statbuf);
+       MONO_EXIT_GC_SAFE;
        if (ret == -1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fstat error of file %s: %s", __func__,
                           filename, strerror (errno));
                _wapi_set_last_error_from_errno ();
                g_free (filename);
+               MONO_ENTER_GC_SAFE;
                close (fd);
+               MONO_EXIT_GC_SAFE;
                
                return(INVALID_HANDLE_VALUE);
        }
-#ifdef __native_client__
-       /* Workaround: Native Client currently returns the same fake inode
-        * for all files, so do a simple hash on the filename so we don't
-        * use the same share info for each file.
-        */
-       statbuf.st_ino = g_str_hash(filename);
-#endif
 
        if (share_allows_open (&statbuf, sharemode, fileaccess,
                         &file_handle.share_info) == FALSE) {
-               SetLastError (ERROR_SHARING_VIOLATION);
+               mono_w32error_set_last (ERROR_SHARING_VIOLATION);
                g_free (filename);
+               MONO_ENTER_GC_SAFE;
                close (fd);
+               MONO_EXIT_GC_SAFE;
                
                return (INVALID_HANDLE_VALUE);
        }
@@ -2308,8 +2408,10 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode
                /* No space, so no more files can be opened */
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No space in the share table", __func__);
 
-               SetLastError (ERROR_TOO_MANY_OPEN_FILES);
+               mono_w32error_set_last (ERROR_TOO_MANY_OPEN_FILES);
+               MONO_ENTER_GC_SAFE;
                close (fd);
+               MONO_EXIT_GC_SAFE;
                g_free (filename);
                
                return(INVALID_HANDLE_VALUE);
@@ -2323,15 +2425,24 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode
        file_handle.attrs=attrs;
 
 #ifdef HAVE_POSIX_FADVISE
-       if (attrs & FILE_FLAG_SEQUENTIAL_SCAN)
+       if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) {
+               MONO_ENTER_GC_SAFE;
                posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);
-       if (attrs & FILE_FLAG_RANDOM_ACCESS)
+               MONO_EXIT_GC_SAFE;
+       }
+       if (attrs & FILE_FLAG_RANDOM_ACCESS) {
+               MONO_ENTER_GC_SAFE;
                posix_fadvise (fd, 0, 0, POSIX_FADV_RANDOM);
+               MONO_EXIT_GC_SAFE;
+       }
 #endif
 
 #ifdef F_RDAHEAD
-       if (attrs & FILE_FLAG_SEQUENTIAL_SCAN)
+       if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) {
+               MONO_ENTER_GC_SAFE;
                fcntl(fd, F_RDAHEAD, 1);
+               MONO_EXIT_GC_SAFE;
+       }
 #endif
 
 #ifndef S_ISFIFO
@@ -2349,13 +2460,17 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode
                handle_type = MONO_W32HANDLE_FILE;
        }
 
+       MONO_ENTER_GC_SAFE; /* FIXME: mono_w32handle_new_fd should be updated with coop transitions */
        handle = mono_w32handle_new_fd (handle_type, fd, &file_handle);
+       MONO_EXIT_GC_SAFE;
        if (handle == INVALID_HANDLE_VALUE) {
                g_warning ("%s: error creating file handle", __func__);
                g_free (filename);
+               MONO_ENTER_GC_SAFE;
                close (fd);
+               MONO_EXIT_GC_SAFE;
                
-               SetLastError (ERROR_GEN_FAILURE);
+               mono_w32error_set_last (ERROR_GEN_FAILURE);
                return(INVALID_HANDLE_VALUE);
        }
        
@@ -2364,12 +2479,24 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode
        return(handle);
 }
 
+gboolean
+mono_w32file_close (gpointer handle)
+{
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       /* FIXME: we transition here and not in file_close, pipe_close,
+        * console_close because w32handle_close is not coop aware yet, but it
+        * calls back into w32file. */
+       res = mono_w32handle_close (handle);
+       MONO_EXIT_GC_SAFE;
+       return res;
+}
+
 gboolean mono_w32file_delete(const gunichar2 *name)
 {
        gchar *filename;
        gint retval;
        gboolean ret = FALSE;
-       guint32 attrs;
 #if 0
        struct stat statbuf;
        FileShare *shareinfo;
@@ -2378,7 +2505,7 @@ gboolean mono_w32file_delete(const gunichar2 *name)
        if(name==NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
 
@@ -2386,15 +2513,7 @@ gboolean mono_w32file_delete(const gunichar2 *name)
        if(filename==NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
-               return(FALSE);
-       }
-
-       attrs = mono_w32file_get_attributes (name);
-       if (attrs == INVALID_FILE_ATTRIBUTES) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file attributes error", __func__);
-               /* Error set by mono_w32file_get_attributes() */
-               g_free (filename);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
 
@@ -2414,7 +2533,7 @@ gboolean mono_w32file_delete(const gunichar2 *name)
        
        if (share_allows_open (&statbuf, 0, GENERIC_WRITE,
                               &shareinfo) == FALSE) {
-               SetLastError (ERROR_SHARING_VIOLATION);
+               mono_w32error_set_last (ERROR_SHARING_VIOLATION);
                g_free (filename);
                return FALSE;
        }
@@ -2425,6 +2544,19 @@ gboolean mono_w32file_delete(const gunichar2 *name)
        retval = _wapi_unlink (filename);
        
        if (retval == -1) {
+               /* On linux, calling unlink on an non-existing file in a read-only mount will fail with EROFS.
+                * The expected behavior is for this function to return FALSE and not trigger an exception.
+                * To work around this behavior, we stat the file on failure.
+                *
+                * This was supposedly fixed on kernel 3.0 [1] but we could reproduce it with Ubuntu 16.04 which has kernel 4.4.
+                * We can't remove this workaround until the early 2020's when most Android deviced will have a fix.
+                * [1] https://github.com/torvalds/linux/commit/50338b889dc504c69e0cb316ac92d1b9e51f3c8a
+                */
+               if (errno == EROFS) {
+                       MonoIOStat stat;
+                       if (mono_w32file_get_attributes_ex (name, &stat)) //The file exists, so must be due the RO file system
+                               errno = EROFS;
+               }
                _wapi_set_last_path_error_from_errno (NULL, filename);
        } else {
                ret = TRUE;
@@ -2447,7 +2579,7 @@ MoveFile (gunichar2 *name, gunichar2 *dest_name)
        if(name==NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
 
@@ -2455,7 +2587,7 @@ MoveFile (gunichar2 *name, gunichar2 *dest_name)
        if (utf8_name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
                
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return FALSE;
        }
        
@@ -2463,7 +2595,7 @@ MoveFile (gunichar2 *name, gunichar2 *dest_name)
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
                g_free (utf8_name);
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
 
@@ -2472,7 +2604,7 @@ MoveFile (gunichar2 *name, gunichar2 *dest_name)
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
                g_free (utf8_name);
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return FALSE;
        }
 
@@ -2495,7 +2627,7 @@ MoveFile (gunichar2 *name, gunichar2 *dest_name)
                    stat_dest.st_ino != stat_src.st_ino) {
                        g_free (utf8_name);
                        g_free (utf8_dest_name);
-                       SetLastError (ERROR_ALREADY_EXISTS);
+                       mono_w32error_set_last (ERROR_ALREADY_EXISTS);
                        return FALSE;
                }
        }
@@ -2508,7 +2640,7 @@ MoveFile (gunichar2 *name, gunichar2 *dest_name)
         * then we can implement that later.
         */
        if (share_allows_delete (&stat_src, &shareinfo) == FALSE) {
-               SetLastError (ERROR_SHARING_VIOLATION);
+               mono_w32error_set_last (ERROR_SHARING_VIOLATION);
                return FALSE;
        }
        if (shareinfo)
@@ -2520,7 +2652,7 @@ MoveFile (gunichar2 *name, gunichar2 *dest_name)
        if (result == -1) {
                switch(errno_copy) {
                case EEXIST:
-                       SetLastError (ERROR_ALREADY_EXISTS);
+                       mono_w32error_set_last (ERROR_ALREADY_EXISTS);
                        break;
 
                case EXDEV:
@@ -2544,7 +2676,7 @@ MoveFile (gunichar2 *name, gunichar2 *dest_name)
                gint32 copy_error;
 
                if (S_ISDIR (stat_src.st_mode)) {
-                       SetLastError (ERROR_NOT_SAME_DEVICE);
+                       mono_w32error_set_last (ERROR_NOT_SAME_DEVICE);
                        return FALSE;
                }
                /* Try a copy to the new location, and delete the source */
@@ -2575,7 +2707,9 @@ write_file (gint src_fd, gint dest_fd, struct stat *st_src, gboolean report_erro
        buf = (gchar *) g_malloc (buf_size);
 
        for (;;) {
+               MONO_ENTER_GC_SAFE;
                remain = read (src_fd, buf, buf_size);
+               MONO_EXIT_GC_SAFE;
                if (remain < 0) {
                        if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
                                continue;
@@ -2592,7 +2726,10 @@ write_file (gint src_fd, gint dest_fd, struct stat *st_src, gboolean report_erro
 
                wbuf = buf;
                while (remain > 0) {
-                       if ((n = write (dest_fd, wbuf, remain)) < 0) {
+                       MONO_ENTER_GC_SAFE;
+                       n = write (dest_fd, wbuf, remain);
+                       MONO_EXIT_GC_SAFE;
+                       if (n < 0) {
                                if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
                                        continue;
 
@@ -2621,11 +2758,12 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
        struct utimbuf dest_time;
        gboolean ret = TRUE;
        gint ret_utime;
+       gint syscall_res;
        
        if(name==NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
        
@@ -2634,7 +2772,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of source returned NULL",
                           __func__);
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return(FALSE);
        }
        
@@ -2642,7 +2780,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dest is NULL", __func__);
 
                g_free (utf8_src);
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
        
@@ -2651,7 +2789,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of dest returned NULL",
                           __func__);
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
 
                g_free (utf8_src);
                
@@ -2668,12 +2806,17 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
                return(FALSE);
        }
 
-       if (fstat (src_fd, &st) < 0) {
+       MONO_ENTER_GC_SAFE;
+       syscall_res = fstat (src_fd, &st);
+       MONO_EXIT_GC_SAFE;
+       if (syscall_res < 0) {
                _wapi_set_last_error_from_errno ();
 
                g_free (utf8_src);
                g_free (utf8_dest);
+               MONO_ENTER_GC_SAFE;
                close (src_fd);
+               MONO_EXIT_GC_SAFE;
                
                return(FALSE);
        }
@@ -2686,9 +2829,11 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
 
                g_free (utf8_src);
                g_free (utf8_dest);
+               MONO_ENTER_GC_SAFE;
                close (src_fd);
+               MONO_EXIT_GC_SAFE;
 
-               SetLastError (ERROR_SHARING_VIOLATION);
+               mono_w32error_set_last (ERROR_SHARING_VIOLATION);
                return (FALSE);
        }
        
@@ -2696,7 +2841,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
                dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL, st.st_mode);
        } else {
                /* FIXME: it kinda sucks that this code path potentially scans
-                * the directory twice due to the weird SetLastError()
+                * the directory twice due to the weird mono_w32error_set_last()
                 * behavior. */
                dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode);
                if (dest_fd < 0) {
@@ -2706,7 +2851,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
                        /* Apparently this error is set if we
                         * overwrite the dest file
                         */
-                       SetLastError (ERROR_ALREADY_EXISTS);
+                       mono_w32error_set_last (ERROR_ALREADY_EXISTS);
                }
        }
        if (dest_fd < 0) {
@@ -2714,7 +2859,9 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
 
                g_free (utf8_src);
                g_free (utf8_dest);
+               MONO_ENTER_GC_SAFE;
                close (src_fd);
+               MONO_EXIT_GC_SAFE;
 
                return(FALSE);
        }
@@ -2727,7 +2874,9 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex
        
        dest_time.modtime = st.st_mtime;
        dest_time.actime = st.st_atime;
+       MONO_ENTER_GC_SAFE;
        ret_utime = utime (utf8_dest, &dest_time);
+       MONO_EXIT_GC_SAFE;
        if (ret_utime == -1)
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file [%s] utime failed: %s", __func__, utf8_dest, strerror(errno));
        
@@ -2744,7 +2893,7 @@ convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name)
 
        if (arg == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s is NULL", __func__, arg_name);
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return NULL;
        }
 
@@ -2752,7 +2901,7 @@ convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name)
        if (utf8_ret == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion of %s returned NULL",
                           __func__, arg_name);
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return NULL;
        }
 
@@ -2807,14 +2956,20 @@ replace_cleanup:
        g_free (utf8_replacedFileName);
        g_free (utf8_replacementFileName);
        g_free (utf8_backupFileName);
-       if (backup_fd != -1)
+       if (backup_fd != -1) {
+               MONO_ENTER_GC_SAFE;
                close (backup_fd);
-       if (replaced_fd != -1)
+               MONO_EXIT_GC_SAFE;
+       }
+       if (replaced_fd != -1) {
+               MONO_ENTER_GC_SAFE;
                close (replaced_fd);
+               MONO_EXIT_GC_SAFE;
+       }
        return ret;
 }
 
-static mono_mutex_t stdhandle_mutex;
+static MonoCoopMutex stdhandle_mutex;
 
 static gpointer
 _wapi_stdhandle_create (gint fd, const gchar *name)
@@ -2825,7 +2980,6 @@ _wapi_stdhandle_create (gint fd, const gchar *name)
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating standard handle type %s, fd %d", __func__, name, fd);
 
-#if !defined(__native_client__)
        /* Check if fd is valid */
        do {
                flags = fcntl(fd, F_GETFL);
@@ -2837,7 +2991,7 @@ _wapi_stdhandle_create (gint fd, const gchar *name)
                 */
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl error on fd %d: %s", __func__, fd, strerror(errno));
 
-               SetLastError (_wapi_get_win32_file_error (errno));
+               mono_w32error_set_last (mono_w32error_unix_to_win32 (errno));
                return INVALID_HANDLE_VALUE;
        }
 
@@ -2856,13 +3010,6 @@ _wapi_stdhandle_create (gint fd, const gchar *name)
                file_handle.fileaccess = 0;
                break;
        }
-#else
-       /*
-        * fcntl will return -1 in nacl, as there is no real file system API.
-        * Yet, standard streams are available.
-        */
-       file_handle.fileaccess = (fd == STDIN_FILENO) ? GENERIC_READ : GENERIC_WRITE;
-#endif
 
        file_handle.fd = fd;
        file_handle.filename = g_strdup(name);
@@ -2881,7 +3028,7 @@ _wapi_stdhandle_create (gint fd, const gchar *name)
        handle = mono_w32handle_new_fd (MONO_W32HANDLE_CONSOLE, fd, &file_handle);
        if (handle == INVALID_HANDLE_VALUE) {
                g_warning ("%s: error creating file handle", __func__);
-               SetLastError (ERROR_GEN_FAILURE);
+               mono_w32error_set_last (ERROR_GEN_FAILURE);
                return INVALID_HANDLE_VALUE;
        }
 
@@ -2927,7 +3074,7 @@ mono_w32file_get_std_handle (gint stdhandle)
 
        handle = GINT_TO_POINTER (fd);
 
-       mono_os_mutex_lock (&stdhandle_mutex);
+       mono_coop_mutex_lock (&stdhandle_mutex);
 
        ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_CONSOLE,
                                  (gpointer *)&file_handle);
@@ -2936,17 +3083,14 @@ mono_w32file_get_std_handle (gint stdhandle)
                handle = _wapi_stdhandle_create (fd, name);
                
                if (handle == INVALID_HANDLE_VALUE) {
-                       SetLastError (ERROR_NO_MORE_FILES);
+                       mono_w32error_set_last (ERROR_NO_MORE_FILES);
                        goto done;
                }
-       } else {
-               /* Add a reference to this handle */
-               mono_w32handle_ref (handle);
        }
        
   done:
-       mono_os_mutex_unlock (&stdhandle_mutex);
-       
+       mono_coop_mutex_unlock (&stdhandle_mutex);
+
        return(handle);
 }
 
@@ -2958,7 +3102,7 @@ mono_w32file_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *
        type = mono_w32handle_get_type (handle);
        
        if(io_ops[type].readfile==NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        
@@ -2973,7 +3117,7 @@ mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, gui
        type = mono_w32handle_get_type (handle);
        
        if(io_ops[type].writefile==NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        
@@ -2988,7 +3132,7 @@ mono_w32file_flush (gpointer handle)
        type = mono_w32handle_get_type (handle);
        
        if(io_ops[type].flushfile==NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        
@@ -3003,7 +3147,7 @@ mono_w32file_truncate (gpointer handle)
        type = mono_w32handle_get_type (handle);
        
        if (io_ops[type].setendoffile == NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        
@@ -3018,7 +3162,7 @@ mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistanc
        type = mono_w32handle_get_type (handle);
        
        if (io_ops[type].seek == NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(INVALID_SET_FILE_POINTER);
        }
        
@@ -3034,7 +3178,7 @@ mono_w32file_get_type(gpointer handle)
        type = mono_w32handle_get_type (handle);
        
        if (io_ops[type].getfiletype == NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FILE_TYPE_UNKNOWN);
        }
        
@@ -3049,7 +3193,7 @@ GetFileSize(gpointer handle, guint32 *highsize)
        type = mono_w32handle_get_type (handle);
        
        if (io_ops[type].getfilesize == NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(INVALID_FILE_SIZE);
        }
        
@@ -3064,7 +3208,7 @@ mono_w32file_get_times(gpointer handle, FILETIME *create_time, FILETIME *access_
        type = mono_w32handle_get_type (handle);
        
        if (io_ops[type].getfiletime == NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        
@@ -3080,7 +3224,7 @@ mono_w32file_set_times(gpointer handle, const FILETIME *create_time, const FILET
        type = mono_w32handle_get_type (handle);
        
        if (io_ops[type].setfiletime == NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        
@@ -3114,7 +3258,7 @@ mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *syste
        if(system_time==NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: system_time NULL", __func__);
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return(FALSE);
        }
        
@@ -3128,7 +3272,7 @@ mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *syste
        if(file_ticks<0) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file_time too big", __func__);
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return(FALSE);
        }
 
@@ -3215,7 +3359,7 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
        if (pattern == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pattern is NULL", __func__);
 
-               SetLastError (ERROR_PATH_NOT_FOUND);
+               mono_w32error_set_last (ERROR_PATH_NOT_FOUND);
                return(INVALID_HANDLE_VALUE);
        }
 
@@ -3223,7 +3367,7 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
        if (utf8_pattern == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
                
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(INVALID_HANDLE_VALUE);
        }
 
@@ -3239,7 +3383,7 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
         * FIXME: Figure out a better solution to keep some checks...
         */
        if (strchr (dir_part, '*') || strchr (dir_part, '?')) {
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                g_free (dir_part);
                g_free (entry_part);
                g_free (utf8_pattern);
@@ -3275,7 +3419,7 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
                /* No files, which windows seems to call
                 * FILE_NOT_FOUND
                 */
-               SetLastError (ERROR_FILE_NOT_FOUND);
+               mono_w32error_set_last (ERROR_FILE_NOT_FOUND);
                g_free (utf8_pattern);
                g_free (entry_part);
                g_free (dir_part);
@@ -3306,7 +3450,7 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
                g_free (dir_part);
                g_free (entry_part);
                g_free (utf8_pattern);
-               SetLastError (ERROR_GEN_FAILURE);
+               mono_w32error_set_last (ERROR_GEN_FAILURE);
                
                return(INVALID_HANDLE_VALUE);
        }
@@ -3314,7 +3458,7 @@ mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
        if (handle != INVALID_HANDLE_VALUE &&
            !mono_w32file_find_next (handle, find_data)) {
                mono_w32file_find_close (handle);
-               SetLastError (ERROR_NO_MORE_FILES);
+               mono_w32error_set_last (ERROR_NO_MORE_FILES);
                handle = INVALID_HANDLE_VALUE;
        }
 
@@ -3340,7 +3484,7 @@ mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data)
        if(ok==FALSE) {
                g_warning ("%s: error looking up find handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
 
@@ -3348,7 +3492,7 @@ mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data)
        
 retry:
        if (find_handle->count >= find_handle->num) {
-               SetLastError (ERROR_NO_MORE_FILES);
+               mono_w32error_set_last (ERROR_NO_MORE_FILES);
                goto cleanup;
        }
 
@@ -3369,7 +3513,6 @@ retry:
                goto retry;
        }
 
-#ifndef __native_client__
        result = _wapi_lstat (filename, &linkbuf);
        if (result != 0) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: lstat failed: %s", __func__, filename);
@@ -3377,7 +3520,6 @@ retry:
                g_free (filename);
                goto retry;
        }
-#endif
 
        utf8_filename = mono_utf8_from_external (filename);
        if (utf8_filename == NULL) {
@@ -3401,11 +3543,7 @@ retry:
        else
                create_time = buf.st_ctime;
        
-#ifdef __native_client__
-       find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, NULL);
-#else
        find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, &linkbuf);
-#endif
 
        time_t_to_filetime (create_time, &find_data->ftCreationTime);
        time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
@@ -3462,7 +3600,7 @@ mono_w32file_find_close (gpointer handle)
        gboolean ok;
 
        if (handle == NULL) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
        
@@ -3471,7 +3609,7 @@ mono_w32file_find_close (gpointer handle)
        if(ok==FALSE) {
                g_warning ("%s: error looking up find handle %p", __func__,
                           handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
 
@@ -3482,7 +3620,9 @@ mono_w32file_find_close (gpointer handle)
 
        mono_w32handle_unlock_handle (handle);
        
+       MONO_ENTER_GC_SAFE;
        mono_w32handle_unref (handle);
+       MONO_EXIT_GC_SAFE;
        
        return(TRUE);
 }
@@ -3496,7 +3636,7 @@ mono_w32file_create_directory (const gunichar2 *name)
        if (name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
        
@@ -3504,7 +3644,7 @@ mono_w32file_create_directory (const gunichar2 *name)
        if (utf8_name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
        
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return FALSE;
        }
 
@@ -3529,7 +3669,7 @@ mono_w32file_remove_directory (const gunichar2 *name)
        if (name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
 
@@ -3537,7 +3677,7 @@ mono_w32file_remove_directory (const gunichar2 *name)
        if (utf8_name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
                
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return FALSE;
        }
 
@@ -3564,7 +3704,7 @@ mono_w32file_get_attributes (const gunichar2 *name)
        if (name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
        
@@ -3572,12 +3712,12 @@ mono_w32file_get_attributes (const gunichar2 *name)
        if (utf8_name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return (INVALID_FILE_ATTRIBUTES);
        }
 
        result = _wapi_stat (utf8_name, &buf);
-       if (result == -1 && errno == ENOENT) {
+       if (result == -1 && (errno == ENOENT || errno == ELOOP)) {
                /* Might be a dangling symlink... */
                result = _wapi_lstat (utf8_name, &buf);
        }
@@ -3588,20 +3728,14 @@ mono_w32file_get_attributes (const gunichar2 *name)
                return (INVALID_FILE_ATTRIBUTES);
        }
 
-#ifndef __native_client__
        result = _wapi_lstat (utf8_name, &linkbuf);
        if (result != 0) {
                _wapi_set_last_path_error_from_errno (NULL, utf8_name);
                g_free (utf8_name);
                return (INVALID_FILE_ATTRIBUTES);
        }
-#endif
        
-#ifdef __native_client__
-       ret = _wapi_stat_to_file_attributes (utf8_name, &buf, NULL);
-#else
        ret = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf);
-#endif
        
        g_free (utf8_name);
 
@@ -3619,7 +3753,7 @@ mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat)
        if (name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
 
@@ -3627,7 +3761,7 @@ mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat)
        if (utf8_name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return FALSE;
        }
 
@@ -3678,7 +3812,7 @@ mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
        if (name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(FALSE);
        }
 
@@ -3686,7 +3820,7 @@ mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
        if (utf8_name == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return FALSE;
        }
 
@@ -3726,7 +3860,9 @@ mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
                if ((buf.st_mode & S_IROTH) != 0)
                        exec_mask |= S_IXOTH;
 
+               MONO_ENTER_GC_SAFE;
                result = chmod (utf8_name, buf.st_mode | exec_mask);
+               MONO_EXIT_GC_SAFE;
        }
        /* Don't bother to reset executable (might need to change this
         * policy)
@@ -3744,12 +3880,6 @@ mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
        glong count;
        gsize bytes;
 
-#ifdef __native_client__
-       gchar *path = g_get_current_dir ();
-       if (length < strlen(path) + 1 || path == NULL)
-               return 0;
-       memcpy (buffer, path, strlen(path) + 1);
-#else
        if (getcwd ((gchar*)buffer, length) == NULL) {
                if (errno == ERANGE) { /*buffer length is not big enough */ 
                        gchar *path = g_get_current_dir (); /*FIXME g_get_current_dir doesn't work with broken paths and calling it just to know the path length is silly*/
@@ -3763,7 +3893,6 @@ mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
                _wapi_set_last_error_from_errno ();
                return 0;
        }
-#endif
 
        utf16_path = mono_unicode_from_external ((gchar*)buffer, &bytes);
        count = (bytes/2)+1;
@@ -3785,7 +3914,7 @@ mono_w32file_set_cwd (const gunichar2 *path)
        gboolean result;
 
        if (path == NULL) {
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return(FALSE);
        }
        
@@ -3813,7 +3942,9 @@ mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
        
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating pipe", __func__);
 
+       MONO_ENTER_GC_SAFE;
        ret=pipe (filedes);
+       MONO_EXIT_GC_SAFE;
        if(ret==-1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error creating pipe: %s", __func__,
                           strerror (errno));
@@ -3826,10 +3957,12 @@ mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
            filedes[1] >= mono_w32handle_fd_reserve) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
 
-               SetLastError (ERROR_TOO_MANY_OPEN_FILES);
+               mono_w32error_set_last (ERROR_TOO_MANY_OPEN_FILES);
                
+               MONO_ENTER_GC_SAFE;
                close (filedes[0]);
                close (filedes[1]);
+               MONO_EXIT_GC_SAFE;
                
                return(FALSE);
        }
@@ -3842,9 +3975,11 @@ mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
                                           &pipe_read_handle);
        if (read_handle == INVALID_HANDLE_VALUE) {
                g_warning ("%s: error creating pipe read handle", __func__);
+               MONO_ENTER_GC_SAFE;
                close (filedes[0]);
                close (filedes[1]);
-               SetLastError (ERROR_GEN_FAILURE);
+               MONO_EXIT_GC_SAFE;
+               mono_w32error_set_last (ERROR_GEN_FAILURE);
                
                return(FALSE);
        }
@@ -3855,11 +3990,14 @@ mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
                                            &pipe_write_handle);
        if (write_handle == INVALID_HANDLE_VALUE) {
                g_warning ("%s: error creating pipe write handle", __func__);
+
+               MONO_ENTER_GC_SAFE;
                mono_w32handle_unref (read_handle);
                
                close (filedes[0]);
                close (filedes[1]);
-               SetLastError (ERROR_GEN_FAILURE);
+               MONO_EXIT_GC_SAFE;
+               mono_w32error_set_last (ERROR_GEN_FAILURE);
                
                return(FALSE);
        }
@@ -3882,15 +4020,21 @@ mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
        gint size, n, i;
        gunichar2 *dir;
        glong length, total = 0;
-       
+       gint syscall_res;
+
+       MONO_ENTER_GC_SAFE;
        n = getfsstat (NULL, 0, MNT_NOWAIT);
+       MONO_EXIT_GC_SAFE;
        if (n == -1)
                return 0;
        size = n * sizeof (struct statfs);
        stats = (struct statfs *) g_malloc (size);
        if (stats == NULL)
                return 0;
-       if (getfsstat (stats, size, MNT_NOWAIT) == -1){
+       MONO_ENTER_GC_SAFE;
+       syscall_res = getfsstat (stats, size, MNT_NOWAIT);
+       MONO_EXIT_GC_SAFE;
+       if (syscall_res == -1){
                g_free (stats);
                return 0;
        }
@@ -3977,11 +4121,15 @@ mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
        gboolean (*parser)(guint32, gunichar2*, LinuxMountInfoParseState*) = NULL;
 
        memset (buf, 0, len * sizeof (gunichar2));
+       MONO_ENTER_GC_SAFE;
        fd = open ("/proc/self/mountinfo", O_RDONLY);
+       MONO_EXIT_GC_SAFE;
        if (fd != -1)
                parser = GetLogicalDriveStrings_MountInfo;
        else {
+               MONO_ENTER_GC_SAFE;
                fd = open ("/proc/mounts", O_RDONLY);
+               MONO_EXIT_GC_SAFE;
                if (fd != -1)
                        parser = GetLogicalDriveStrings_Mounts;
        }
@@ -3995,7 +4143,12 @@ mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
        state.field_number = 1;
        state.delimiter = ' ';
 
-       while ((state.nbytes = read (fd, state.buffer, GET_LOGICAL_DRIVE_STRINGS_BUFFER)) > 0) {
+       while (1) {
+               MONO_ENTER_GC_SAFE;
+               state.nbytes = read (fd, state.buffer, GET_LOGICAL_DRIVE_STRINGS_BUFFER);
+               MONO_EXIT_GC_SAFE;
+               if (!(state.nbytes > 0))
+                       break;
                state.buffer_index = 0;
 
                while ((*parser)(len, buf, &state)) {
@@ -4017,8 +4170,11 @@ mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
        ret = state.total;
 
   done_and_out:
-       if (fd != -1)
+       if (fd != -1) {
+               MONO_ENTER_GC_SAFE;
                close (fd);
+               MONO_EXIT_GC_SAFE;
+       }
        return ret;
 }
 
@@ -4251,15 +4407,25 @@ GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
        /* Sigh, mntent and friends don't work well.
         * It stops on the first line that doesn't begin with a '/'.
         * (linux 2.6.5, libc 2.3.2.ds1-12) - Gonz */
+       MONO_ENTER_GC_SAFE;
        fp = fopen ("/etc/mtab", "rt");
+       MONO_EXIT_GC_SAFE;
        if (fp == NULL) {
+               MONO_ENTER_GC_SAFE;
                fp = fopen ("/etc/mnttab", "rt");
+               MONO_EXIT_GC_SAFE;
                if (fp == NULL)
                        return 1;
        }
 
        ptr = buf;
-       while (fgets (buffer, 512, fp) != NULL) {
+       while (1) {
+               gchar *fgets_res;
+               MONO_ENTER_GC_SAFE;
+               fgets_res = fgets (buffer, 512, fp);
+               MONO_EXIT_GC_SAFE;
+               if (!fgets_res)
+                       break;
                if (*buffer != '/')
                        continue;
 
@@ -4273,7 +4439,9 @@ GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
                dir = g_utf8_to_utf16 (*(splitted + 1), -1, NULL, &length, NULL);
                g_strfreev (splitted);
                if (total + length + 1 > len) {
+                       MONO_ENTER_GC_SAFE;
                        fclose (fp);
+                       MONO_EXIT_GC_SAFE;
                        g_free (dir);
                        return len * 2; /* guess */
                }
@@ -4283,7 +4451,9 @@ GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
                total += length + 1;
        }
 
+       MONO_ENTER_GC_SAFE;
        fclose (fp);
+       MONO_EXIT_GC_SAFE;
        return total;
 /* Commented out, does not work with my mtab!!! - Gonz */
 #ifdef NOTENABLED /* HAVE_MNTENT_H */
@@ -4294,18 +4464,30 @@ GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
        glong len, total = 0;
        
 
+       MONO_ENTER_GC_SAFE;
        fp = setmntent ("/etc/mtab", "rt");
+       MONO_EXIT_GC_SAFE;
        if (fp == NULL) {
+               MONO_ENTER_GC_SAFE;
                fp = setmntent ("/etc/mnttab", "rt");
+               MONO_EXIT_GC_SAFE;
                if (fp == NULL)
                        return;
        }
 
        ptr = buf;
-       while ((mnt = getmntent (fp)) != NULL) {
+       while (1) {
+               MONO_ENTER_GC_SAFE;
+               mnt = getmntent (fp);
+               MONO_EXIT_GC_SAFE;
+               if (mnt == NULL)
+                       break;
                g_print ("GOT %s\n", mnt->mnt_dir);
                dir = g_utf8_to_utf16 (mnt->mnt_dir, &len, NULL, NULL, NULL);
                if (total + len + 1 > len) {
+                       MONO_ENTER_GC_SAFE;
+                       endmntent (fp);
+                       MONO_EXIT_GC_SAFE;
                        return len * 2; /* guess */
                }
 
@@ -4314,7 +4496,9 @@ GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
                total += len + 1;
        }
 
+       MONO_ENTER_GC_SAFE;
        endmntent (fp);
+       MONO_EXIT_GC_SAFE;
        return total;
 }
 #endif
@@ -4338,7 +4522,7 @@ mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_byte
        if (path_name == NULL) {
                utf8_path_name = g_strdup (g_get_current_dir());
                if (utf8_path_name == NULL) {
-                       SetLastError (ERROR_DIRECTORY);
+                       mono_w32error_set_last (ERROR_DIRECTORY);
                        return(FALSE);
                }
        }
@@ -4347,18 +4531,22 @@ mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_byte
                if (utf8_path_name == NULL) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-                       SetLastError (ERROR_INVALID_NAME);
+                       mono_w32error_set_last (ERROR_INVALID_NAME);
                        return(FALSE);
                }
        }
 
        do {
 #ifdef HAVE_STATVFS
+               MONO_ENTER_GC_SAFE;
                ret = statvfs (utf8_path_name, &fsstat);
+               MONO_EXIT_GC_SAFE;
                isreadonly = ((fsstat.f_flag & ST_RDONLY) == ST_RDONLY);
                block_size = fsstat.f_frsize;
 #elif defined(HAVE_STATFS)
+               MONO_ENTER_GC_SAFE;
                ret = statfs (utf8_path_name, &fsstat);
+               MONO_EXIT_GC_SAFE;
 #if defined (MNT_RDONLY)
                isreadonly = ((fsstat.f_flags & MNT_RDONLY) == MNT_RDONLY);
 #elif defined (MS_RDONLY)
@@ -4596,8 +4784,12 @@ static guint32
 GetDriveTypeFromPath (const gchar *utf8_root_path_name)
 {
        struct statfs buf;
-       
-       if (statfs (utf8_root_path_name, &buf) == -1)
+       gint res;
+
+       MONO_ENTER_GC_SAFE;
+       res = statfs (utf8_root_path_name, &buf);
+       MONO_EXIT_GC_SAFE;
+       if (res == -1)
                return DRIVE_UNKNOWN;
 #if PLATFORM_MACOSX
        return _wapi_get_drive_type (buf.f_fstypename);
@@ -4614,15 +4806,25 @@ GetDriveTypeFromPath (const gchar *utf8_root_path_name)
        gchar buffer [512];
        gchar **splitted;
 
+       MONO_ENTER_GC_SAFE;
        fp = fopen ("/etc/mtab", "rt");
+       MONO_EXIT_GC_SAFE;
        if (fp == NULL) {
+               MONO_ENTER_GC_SAFE;
                fp = fopen ("/etc/mnttab", "rt");
+               MONO_EXIT_GC_SAFE;
                if (fp == NULL) 
                        return(DRIVE_UNKNOWN);
        }
 
        drive_type = DRIVE_NO_ROOT_DIR;
-       while (fgets (buffer, 512, fp) != NULL) {
+       while (1) {
+               gchar *fgets_res;
+               MONO_ENTER_GC_SAFE;
+               fgets_res = fgets (buffer, 512, fp);
+               MONO_EXIT_GC_SAFE;
+               if (fgets_res == NULL)
+                       break;
                splitted = g_strsplit (buffer, " ", 0);
                if (!*splitted || !*(splitted + 1) || !*(splitted + 2)) {
                        g_strfreev (splitted);
@@ -4645,7 +4847,9 @@ GetDriveTypeFromPath (const gchar *utf8_root_path_name)
                g_strfreev (splitted);
        }
 
+       MONO_ENTER_GC_SAFE;
        fclose (fp);
+       MONO_EXIT_GC_SAFE;
        return drive_type;
 }
 #endif
@@ -4680,7 +4884,7 @@ mono_w32file_get_drive_type(const gunichar2 *root_path_name)
        return (drive_type);
 }
 
-#if defined (PLATFORM_MACOSX) || defined (__linux__) || defined(PLATFORM_BSD) || defined(__native_client__) || defined(__FreeBSD_kernel__)
+#if defined (PLATFORM_MACOSX) || defined (__linux__) || defined(PLATFORM_BSD) || defined(__FreeBSD_kernel__) || defined(__HAIKU__)
 static gchar*
 get_fstypename (gchar *utfpath)
 {
@@ -4689,7 +4893,11 @@ get_fstypename (gchar *utfpath)
 #if __linux__
        _wapi_drive_type *current;
 #endif
-       if (statfs (utfpath, &stat) == -1)
+       gint statfs_res;
+       MONO_ENTER_GC_SAFE;
+       statfs_res = statfs (utfpath, &stat);
+       MONO_EXIT_GC_SAFE;
+       if (statfs_res == -1)
                return NULL;
 #if PLATFORM_MACOSX
        return g_strdup (stat.f_fstypename);
@@ -4745,13 +4953,13 @@ LockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 leng
 
        if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE, (gpointer *)&file_handle)) {
                g_warning ("%s: error looking up file handle %p", __func__, handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return FALSE;
        }
 
        if (!(file_handle->fileaccess & GENERIC_READ) && !(file_handle->fileaccess & GENERIC_WRITE) && !(file_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return FALSE;
        }
 
@@ -4762,7 +4970,7 @@ LockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 leng
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locking handle %p, offset %lld, length %lld", __func__, handle, offset, length);
 #else
        if (offset_high > 0 || length_high > 0) {
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return FALSE;
        }
        offset = offset_low;
@@ -4782,13 +4990,13 @@ UnlockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 le
 
        if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_FILE, (gpointer *)&file_handle)) {
                g_warning ("%s: error looking up file handle %p", __func__, handle);
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return FALSE;
        }
 
        if (!(file_handle->fileaccess & GENERIC_READ) && !(file_handle->fileaccess & GENERIC_WRITE) && !(file_handle->fileaccess & GENERIC_ALL)) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-               SetLastError (ERROR_ACCESS_DENIED);
+               mono_w32error_set_last (ERROR_ACCESS_DENIED);
                return FALSE;
        }
 
@@ -4810,8 +5018,8 @@ UnlockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 le
 void
 mono_w32file_init (void)
 {
-       mono_os_mutex_init (&stdhandle_mutex);
-       mono_os_mutex_init (&file_share_mutex);
+       mono_coop_mutex_init (&stdhandle_mutex);
+       mono_coop_mutex_init (&file_share_mutex);
 
        mono_w32handle_register_ops (MONO_W32HANDLE_FILE,    &_wapi_file_ops);
        mono_w32handle_register_ops (MONO_W32HANDLE_CONSOLE, &_wapi_console_ops);
@@ -4823,14 +5031,14 @@ mono_w32file_init (void)
 /*     mono_w32handle_register_capabilities (MONO_W32HANDLE_CONSOLE, */
 /*                                         MONO_W32HANDLE_CAP_WAIT); */
 
-       if (g_getenv ("MONO_STRICT_IO_EMULATION"))
+       if (g_hasenv ("MONO_STRICT_IO_EMULATION"))
                lock_while_writing = TRUE;
 }
 
 void
 mono_w32file_cleanup (void)
 {
-       mono_os_mutex_destroy (&file_share_mutex);
+       mono_coop_mutex_destroy (&file_share_mutex);
 
        if (file_share_table)
                g_hash_table_destroy (file_share_table);
@@ -4841,14 +5049,9 @@ mono_w32file_move (gunichar2 *path, gunichar2 *dest, gint32 *error)
 {
        gboolean result;
 
-       MONO_ENTER_GC_SAFE;
-
        result = MoveFile (path, dest);
        if (!result)
-               *error = GetLastError ();
-
-       MONO_EXIT_GC_SAFE;
-
+               *error = mono_w32error_get_last ();
        return result;
 }
 
@@ -4857,13 +5060,9 @@ mono_w32file_copy (gunichar2 *path, gunichar2 *dest, gboolean overwrite, gint32
 {
        gboolean result;
 
-       MONO_ENTER_GC_SAFE;
-
        result = CopyFile (path, dest, !overwrite);
        if (!result)
-               *error = GetLastError ();
-
-       MONO_EXIT_GC_SAFE;
+               *error = mono_w32error_get_last ();
 
        return result;
 }
@@ -4873,14 +5072,9 @@ mono_w32file_replace (gunichar2 *destinationFileName, gunichar2 *sourceFileName,
 {
        gboolean result;
 
-       MONO_ENTER_GC_SAFE;
-
        result = ReplaceFile (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
        if (!result)
-               *error = GetLastError ();
-
-       MONO_EXIT_GC_SAFE;
-
+               *error = mono_w32error_get_last ();
        return result;
 }
 
@@ -4890,15 +5084,11 @@ mono_w32file_get_file_size (gpointer handle, gint32 *error)
        gint64 length;
        guint32 length_hi;
 
-       MONO_ENTER_GC_SAFE;
-
        length = GetFileSize (handle, &length_hi);
        if(length==INVALID_FILE_SIZE) {
-               *error=GetLastError ();
+               *error=mono_w32error_get_last ();
        }
 
-       MONO_EXIT_GC_SAFE;
-
        return length | ((gint64)length_hi << 32);
 }
 
@@ -4907,14 +5097,9 @@ mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *erro
 {
        gboolean result;
 
-       MONO_ENTER_GC_SAFE;
-
        result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
        if (!result)
-               *error = GetLastError ();
-
-       MONO_EXIT_GC_SAFE;
-
+               *error = mono_w32error_get_last ();
        return result;
 }
 
@@ -4923,49 +5108,26 @@ mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *er
 {
        gboolean result;
 
-       MONO_ENTER_GC_SAFE;
-
        result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
        if (!result)
-               *error = GetLastError ();
-
-       MONO_EXIT_GC_SAFE;
-
+               *error = mono_w32error_get_last ();
        return result;
 }
 
 gpointer
 mono_w32file_get_console_input (void)
 {
-       gpointer handle;
-
-       MONO_ENTER_GC_SAFE;
-       handle = mono_w32file_get_std_handle (STD_INPUT_HANDLE);
-       MONO_EXIT_GC_SAFE;
-
-       return handle;
+       return mono_w32file_get_std_handle (STD_INPUT_HANDLE);
 }
 
 gpointer
 mono_w32file_get_console_output (void)
 {
-       gpointer handle;
-
-       MONO_ENTER_GC_SAFE;
-       handle = mono_w32file_get_std_handle (STD_OUTPUT_HANDLE);
-       MONO_EXIT_GC_SAFE;
-
-       return handle;
+       return mono_w32file_get_std_handle (STD_OUTPUT_HANDLE);
 }
 
 gpointer
 mono_w32file_get_console_error (void)
 {
-       gpointer handle;
-
-       MONO_ENTER_GC_SAFE;
-       handle = mono_w32file_get_std_handle (STD_ERROR_HANDLE);
-       MONO_EXIT_GC_SAFE;
-
-       return handle;
+       return mono_w32file_get_std_handle (STD_ERROR_HANDLE);
 }