Merge pull request #819 from brendanzagaeski/patch-1
[mono.git] / mono / io-layer / io.c
old mode 100644 (file)
new mode 100755 (executable)
index 4037f72..b67a9ca
@@ -5,6 +5,8 @@
  *     Dick Porter (dick@ximian.com)
  *
  * (C) 2002 Ximian, Inc.
+ * Copyright (c) 2002-2006 Novell, Inc.
+ * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
  */
 
 #include <config.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/stat.h>
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+#if defined(HAVE_SYS_STATFS_H)
+#include <sys/statfs.h>
+#endif
+#if defined(HAVE_SYS_PARAM_H) && defined(HAVE_SYS_MOUNT_H)
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
 #include <sys/types.h>
 #include <dirent.h>
 #include <fnmatch.h>
 #include <stdio.h>
 #include <utime.h>
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <mono/utils/linux_magic.h>
+#endif
 
 #include <mono/io-layer/wapi.h>
 #include <mono/io-layer/wapi-private.h>
 #include <mono/io-layer/io-private.h>
 #include <mono/io-layer/timefuncs-private.h>
 #include <mono/io-layer/thread-private.h>
+#include <mono/io-layer/io-portability.h>
 #include <mono/utils/strenc.h>
 
-#undef DEBUG
-
-static gboolean _wapi_lock_file_region (int fd, off_t offset, off_t length);
-static gboolean _wapi_unlock_file_region (int fd, off_t offset, off_t length);
+#if 0
+#define DEBUG(...) g_message(__VA_ARGS__)
+#define DEBUG_ENABLED 1
+#else
+#define DEBUG(...)
+#endif
 
 static void file_close (gpointer handle, gpointer data);
 static WapiFileType file_getfiletype(void);
@@ -53,6 +73,7 @@ static gboolean file_setfiletime(gpointer handle,
                                 const WapiFileTime *create_time,
                                 const WapiFileTime *last_access,
                                 const WapiFileTime *last_write);
+static guint32 GetDriveTypeFromPath (const gchar *utf8_root_path_name);
 
 /* File handle is only signalled for overlapped IO */
 struct _WapiHandleOps _wapi_file_ops = {
@@ -60,6 +81,8 @@ struct _WapiHandleOps _wapi_file_ops = {
        NULL,                   /* signal */
        NULL,                   /* own */
        NULL,                   /* is_owned */
+       NULL,                   /* special_wait */
+       NULL                    /* prewait */
 };
 
 void _wapi_file_details (gpointer handle_info)
@@ -94,6 +117,8 @@ struct _WapiHandleOps _wapi_console_ops = {
        NULL,                   /* signal */
        NULL,                   /* own */
        NULL,                   /* is_owned */
+       NULL,                   /* special_wait */
+       NULL                    /* prewait */
 };
 
 void _wapi_console_details (gpointer handle_info)
@@ -108,6 +133,8 @@ struct _WapiHandleOps _wapi_find_ops = {
        NULL,                   /* signal */
        NULL,                   /* own */
        NULL,                   /* is_owned */
+       NULL,                   /* special_wait */
+       NULL                    /* prewait */
 };
 
 static void pipe_close (gpointer handle, gpointer data);
@@ -125,6 +152,8 @@ struct _WapiHandleOps _wapi_pipe_ops = {
        NULL,                   /* signal */
        NULL,                   /* own */
        NULL,                   /* is_owned */
+       NULL,                   /* special_wait */
+       NULL                    /* prewait */
 };
 
 void _wapi_pipe_details (gpointer handle_info)
@@ -193,13 +222,8 @@ static const struct {
         NULL, NULL, NULL, NULL, NULL, NULL},
 };
 
-#define NO_SIGPIPE(x) do {                     \
-               void (*old_sigpipe)(int) = signal (SIGPIPE, SIG_IGN);   \
-               x;                                                      \
-               signal (SIGPIPE, old_sigpipe);                          \
-       }  while (0)
-
 static mono_once_t io_ops_once=MONO_ONCE_INIT;
+static gboolean lock_while_writing = FALSE;
 
 static void io_ops_init (void)
 {
@@ -207,24 +231,98 @@ static void io_ops_init (void)
 /*                                         WAPI_HANDLE_CAP_WAIT); */
 /*     _wapi_handle_register_capabilities (WAPI_HANDLE_CONSOLE, */
 /*                                         WAPI_HANDLE_CAP_WAIT); */
+
+       if (g_getenv ("MONO_STRICT_IO_EMULATION") != NULL) {
+               lock_while_writing = TRUE;
+       }
 }
 
 /* Some utility functions.
  */
 
-static guint32 _wapi_stat_to_file_attributes (struct stat *buf)
+/*
+ * Check if a file is writable by the current user.
+ *
+ * This is is a best effort kind of thing. It assumes a reasonable sane set
+ * of permissions by the underlying OS.
+ *
+ * We assume that basic unix permission bits are authoritative. Which might not
+ * be the case under systems with extended permissions systems (posix ACLs, SELinux, OSX/iOS sandboxing, etc)
+ *
+ * The choice of access as the fallback is due to the expected lower overhead compared to trying to open the file.
+ *
+ * The only expected problem with using access are for root, setuid or setgid programs as access is not consistent
+ * under those situations. It's to be expected that this should not happen in practice as those bits are very dangerous
+ * and should not be used with a dynamic runtime.
+ */
+static gboolean
+is_file_writable (struct stat *st, const char *path)
+{
+       /* Is it globally writable? */
+       if (st->st_mode & S_IWOTH)
+               return 1;
+
+       /* Am I the owner? */
+       if ((st->st_uid == geteuid ()) && (st->st_mode & S_IWUSR))
+               return 1;
+
+       /* Am I in the same group? */
+       if ((st->st_gid == getegid ()) && (st->st_mode & S_IWGRP))
+               return 1;
+
+       /* Fallback to using access(2). It's not ideal as it might not take into consideration euid/egid
+        * but it's the only sane option we have on unix.
+        */
+       return access (path, W_OK) == 0;
+}
+
+
+static guint32 _wapi_stat_to_file_attributes (const gchar *pathname,
+                                             struct stat *buf,
+                                             struct stat *lbuf)
 {
        guint32 attrs = 0;
+       gchar *filename;
+       
+       /* FIXME: this could definitely be better, but there seems to
+        * be no pattern to the attributes that are set
+        */
 
-       /* FIXME: this could definitely be better */
+       /* Sockets (0140000) != Directory (040000) + Regular file (0100000) */
+       if (S_ISSOCK (buf->st_mode))
+               buf->st_mode &= ~S_IFSOCK; /* don't consider socket protection */
 
-       if (S_ISDIR (buf->st_mode))
-               attrs |= FILE_ATTRIBUTE_DIRECTORY;
-       else
-               attrs |= FILE_ATTRIBUTE_ARCHIVE;
+       filename = _wapi_basename (pathname);
+
+       if (S_ISDIR (buf->st_mode)) {
+               attrs = FILE_ATTRIBUTE_DIRECTORY;
+               if (!is_file_writable (buf, pathname)) {
+                       attrs |= FILE_ATTRIBUTE_READONLY;
+               }
+               if (filename[0] == '.') {
+                       attrs |= FILE_ATTRIBUTE_HIDDEN;
+               }
+       } else {
+               if (!is_file_writable (buf, pathname)) {
+                       attrs = FILE_ATTRIBUTE_READONLY;
+
+                       if (filename[0] == '.') {
+                               attrs |= FILE_ATTRIBUTE_HIDDEN;
+                       }
+               } else if (filename[0] == '.') {
+                       attrs = FILE_ATTRIBUTE_HIDDEN;
+               } else {
+                       attrs = FILE_ATTRIBUTE_NORMAL;
+               }
+       }
+
+       if (lbuf != NULL) {
+               if (S_ISLNK (lbuf->st_mode)) {
+                       attrs |= FILE_ATTRIBUTE_REPARSE_POINT;
+               }
+       }
        
-       if (!(buf->st_mode & S_IWUSR))
-               attrs |= FILE_ATTRIBUTE_READONLY;
+       g_free (filename);
        
        return attrs;
 }
@@ -235,22 +333,53 @@ _wapi_set_last_error_from_errno (void)
        SetLastError (_wapi_get_win32_file_error (errno));
 }
 
+static void _wapi_set_last_path_error_from_errno (const gchar *dir,
+                                                 const gchar *path)
+{
+       if (errno == ENOENT) {
+               /* Check the path - if it's a missing directory then
+                * we need to set PATH_NOT_FOUND not FILE_NOT_FOUND
+                */
+               gchar *dirname;
+
+
+               if (dir == NULL) {
+                       dirname = _wapi_dirname (path);
+               } else {
+                       dirname = g_strdup (dir);
+               }
+               
+               if (_wapi_access (dirname, F_OK) == 0) {
+                       SetLastError (ERROR_FILE_NOT_FOUND);
+               } else {
+                       SetLastError (ERROR_PATH_NOT_FOUND);
+               }
+
+               g_free (dirname);
+       } else {
+               _wapi_set_last_error_from_errno ();
+       }
+}
+
 /* Handle ops.
  */
 static void file_close (gpointer handle, gpointer data)
 {
        struct _WapiHandle_file *file_handle = (struct _WapiHandle_file *)data;
+       int fd = file_handle->fd;
        
-#ifdef DEBUG
-       g_message("%s: closing file handle %p [%s]", __func__, handle,
+       DEBUG("%s: closing file handle %p [%s]", __func__, handle,
                  file_handle->filename);
-#endif
 
+       if (file_handle->attrs & FILE_FLAG_DELETE_ON_CLOSE)
+               _wapi_unlink (file_handle->filename);
+       
        g_free (file_handle->filename);
        
-       _wapi_handle_share_release (file_handle->share_info);
+       if (file_handle->share_info)
+               _wapi_handle_share_release (file_handle->share_info);
        
-       close (GPOINTER_TO_UINT(handle));
+       close (fd);
 }
 
 static WapiFileType file_getfiletype(void)
@@ -264,8 +393,7 @@ static gboolean file_read(gpointer handle, gpointer buffer,
 {
        struct _WapiHandle_file *file_handle;
        gboolean ok;
-       int fd = GPOINTER_TO_UINT(handle);
-       int ret;
+       int fd, ret;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -276,16 +404,15 @@ static gboolean file_read(gpointer handle, gpointer buffer,
                return(FALSE);
        }
 
+       fd = file_handle->fd;
        if(bytesread!=NULL) {
                *bytesread=0;
        }
        
        if(!(file_handle->fileaccess & GENERIC_READ) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_READ access: %u",
+               DEBUG("%s: handle %p doesn't have GENERIC_READ access: %u",
                          __func__, handle, file_handle->fileaccess);
-#endif
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
@@ -299,10 +426,8 @@ static gboolean file_read(gpointer handle, gpointer buffer,
        if(ret==-1) {
                gint err = errno;
 
-#ifdef DEBUG
-               g_message("%s: read of handle %p error: %s", __func__,
+               DEBUG("%s: read of handle %p error: %s", __func__,
                          handle, strerror(err));
-#endif
                SetLastError (_wapi_get_win32_file_error (err));
                return(FALSE);
        }
@@ -320,9 +445,8 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
 {
        struct _WapiHandle_file *file_handle;
        gboolean ok;
-       int ret;
-       off_t current_pos;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
+       off_t current_pos = 0;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -332,6 +456,8 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+
+       fd = file_handle->fd;
        
        if(byteswritten!=NULL) {
                *byteswritten=0;
@@ -339,40 +465,40 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
        
        if(!(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-#endif
+               DEBUG("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
-       /* Need to lock the region we're about to write to, because we
-        * only do advisory locking on POSIX systems
-        */
-       current_pos = lseek (fd, (off_t)0, SEEK_CUR);
-       if (current_pos == -1) {
-#ifdef DEBUG
-               g_message ("%s: handle %p lseek failed: %s", __func__, handle,
-                          strerror (errno));
-#endif
-               _wapi_set_last_error_from_errno ();
-               return(FALSE);
-       }
+       if (lock_while_writing) {
+               /* Need to lock the region we're about to write to,
+                * because we only do advisory locking on POSIX
+                * systems
+                */
+               current_pos = lseek (fd, (off_t)0, SEEK_CUR);
+               if (current_pos == -1) {
+                       DEBUG ("%s: handle %p lseek failed: %s", __func__,
+                                  handle, strerror (errno));
+                       _wapi_set_last_error_from_errno ();
+                       return(FALSE);
+               }
                
-       if (_wapi_lock_file_region (fd, current_pos, numbytes) == FALSE) {
-               /* The error has already been set */
-               return(FALSE);
+               if (_wapi_lock_file_region (fd, current_pos,
+                                           numbytes) == FALSE) {
+                       /* The error has already been set */
+                       return(FALSE);
+               }
        }
                
-       NO_SIGPIPE(
-               do {
-                       ret = write (fd, buffer, numbytes);
-               } while (ret == -1 && errno == EINTR &&
-                        !_wapi_thread_cur_apc_pending());
-               );
+       do {
+               ret = write (fd, buffer, numbytes);
+       } while (ret == -1 && errno == EINTR &&
+                !_wapi_thread_cur_apc_pending());
        
-       _wapi_unlock_file_region (fd, current_pos, numbytes);
+       if (lock_while_writing) {
+               _wapi_unlock_file_region (fd, current_pos, numbytes);
+       }
 
        if (ret == -1) {
                if (errno == EINTR) {
@@ -380,10 +506,8 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
                } else {
                        _wapi_set_last_error_from_errno ();
                                
-#ifdef DEBUG
-                       g_message("%s: write of handle %p error: %s",
+                       DEBUG("%s: write of handle %p error: %s",
                                  __func__, handle, strerror(errno));
-#endif
 
                        return(FALSE);
                }
@@ -398,8 +522,7 @@ static gboolean file_flush(gpointer handle)
 {
        struct _WapiHandle_file *file_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -410,11 +533,11 @@ static gboolean file_flush(gpointer handle)
                return(FALSE);
        }
 
+       fd = file_handle->fd;
+
        if(!(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-#endif
+               DEBUG("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
@@ -422,10 +545,8 @@ static gboolean file_flush(gpointer handle)
 
        ret=fsync(fd);
        if (ret==-1) {
-#ifdef DEBUG
-               g_message("%s: fsync of handle %p error: %s", __func__, handle,
+               DEBUG("%s: fsync of handle %p error: %s", __func__, handle,
                          strerror(errno));
-#endif
 
                _wapi_set_last_error_from_errno ();
                return(FALSE);
@@ -439,10 +560,9 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
 {
        struct _WapiHandle_file *file_handle;
        gboolean ok;
-       off_t offset, newpos;
-       int whence;
+       gint64 offset, newpos;
+       int whence, fd;
        guint32 ret;
-       int fd = GPOINTER_TO_UINT(handle);
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -453,12 +573,12 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
                return(INVALID_SET_FILE_POINTER);
        }
        
+       fd = file_handle->fd;
+
        if(!(file_handle->fileaccess & GENERIC_READ) &&
           !(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message ("%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-#endif
+               DEBUG ("%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(INVALID_SET_FILE_POINTER);
@@ -475,9 +595,7 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
                whence=SEEK_END;
                break;
        default:
-#ifdef DEBUG
-               g_message("%s: invalid seek type %d", __func__, method);
-#endif
+               DEBUG("%s: invalid seek type %d", __func__, method);
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return(INVALID_SET_FILE_POINTER);
@@ -486,49 +604,35 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
 #ifdef HAVE_LARGE_FILE_SUPPORT
        if(highmovedistance==NULL) {
                offset=movedistance;
-#ifdef DEBUG
-               g_message("%s: setting offset to %lld (low %d)", __func__,
+               DEBUG("%s: setting offset to %lld (low %d)", __func__,
                          offset, movedistance);
-#endif
        } else {
                offset=((gint64) *highmovedistance << 32) | (guint32)movedistance;
                
-#ifdef DEBUG
-               g_message("%s: setting offset to %lld 0x%llx (high %d 0x%x, low %d 0x%x)", __func__, offset, offset, *highmovedistance, *highmovedistance, movedistance, movedistance);
-#endif
+               DEBUG("%s: setting offset to %lld 0x%llx (high %d 0x%x, low %d 0x%x)", __func__, offset, offset, *highmovedistance, *highmovedistance, movedistance, movedistance);
        }
 #else
        offset=movedistance;
 #endif
 
-#ifdef DEBUG
-#ifdef HAVE_LARGE_FILE_SUPPORT
-       g_message("%s: moving handle %p by %lld bytes from %d", __func__,
-                 handle, offset, whence);
-#else
-       g_message("%s: moving handle %p fd %d by %ld bytes from %d", __func__,
-                 handle, offset, whence);
-#endif
-#endif
+       DEBUG ("%s: moving handle %p by %lld bytes from %d", __func__,
+                  handle, (long long)offset, whence);
 
+#ifdef PLATFORM_ANDROID
+       /* bionic doesn't support -D_FILE_OFFSET_BITS=64 */
+       newpos=lseek64(fd, offset, whence);
+#else
        newpos=lseek(fd, offset, whence);
+#endif
        if(newpos==-1) {
-#ifdef DEBUG
-               g_message("%s: lseek on handle %p returned error %s",
+               DEBUG("%s: lseek on handle %p returned error %s",
                          __func__, handle, strerror(errno));
-#endif
 
                _wapi_set_last_error_from_errno ();
                return(INVALID_SET_FILE_POINTER);
        }
 
-#ifdef DEBUG
-#ifdef HAVE_LARGE_FILE_SUPPORT
-       g_message("%s: lseek returns %lld", __func__, newpos);
-#else
-       g_message ("%s: lseek returns %ld", __func__, newpos);
-#endif
-#endif
+       DEBUG ("%s: lseek returns %lld", __func__, newpos);
 
 #ifdef HAVE_LARGE_FILE_SUPPORT
        ret=newpos & 0xFFFFFFFF;
@@ -543,10 +647,8 @@ static guint32 file_seek(gpointer handle, gint32 movedistance,
        }
 #endif
 
-#ifdef DEBUG
-       g_message ("%s: move of handle %p returning %d/%d", __func__,
+       DEBUG ("%s: move of handle %p returning %d/%d", __func__,
                   handle, ret, highmovedistance==NULL?0:*highmovedistance);
-#endif
 
        return(ret);
 }
@@ -557,8 +659,7 @@ static gboolean file_setendoffile(gpointer handle)
        gboolean ok;
        struct stat statbuf;
        off_t size, pos;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -568,12 +669,11 @@ static gboolean file_setendoffile(gpointer handle)
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = file_handle->fd;
        
        if(!(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-#endif
+               DEBUG("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
@@ -587,10 +687,8 @@ static gboolean file_setendoffile(gpointer handle)
        
        ret=fstat(fd, &statbuf);
        if(ret==-1) {
-#ifdef DEBUG
-               g_message ("%s: handle %p fstat failed: %s", __func__,
+               DEBUG ("%s: handle %p fstat failed: %s", __func__,
                           handle, strerror(errno));
-#endif
 
                _wapi_set_last_error_from_errno ();
                return(FALSE);
@@ -599,15 +697,18 @@ static gboolean file_setendoffile(gpointer handle)
 
        pos=lseek(fd, (off_t)0, SEEK_CUR);
        if(pos==-1) {
-#ifdef DEBUG
-               g_message("%s: handle %p lseek failed: %s", __func__,
+               DEBUG("%s: handle %p lseek failed: %s", __func__,
                          handle, strerror(errno));
-#endif
 
                _wapi_set_last_error_from_errno ();
                return(FALSE);
        }
        
+#ifdef FTRUNCATE_DOESNT_EXTEND
+       /* I haven't bothered to write the configure.in stuff for this
+        * because I don't know if any platform needs it.  I'm leaving
+        * this code just in case though
+        */
        if(pos>size) {
                /* Extend the file.  Use write() here, because some
                 * manuals say that ftruncate() behaviour is undefined
@@ -616,23 +717,32 @@ static gboolean file_setendoffile(gpointer handle)
                 * every system we care about conforms, then we can
                 * drop this write.
                 */
-               NO_SIGPIPE(
-                       do {
-                               ret = write (fd, "", 1);
-                       } while (ret == -1 && errno == EINTR &&
-                                !_wapi_thread_cur_apc_pending());
-                       );
+               do {
+                       ret = write (fd, "", 1);
+               } while (ret == -1 && errno == EINTR &&
+                        !_wapi_thread_cur_apc_pending());
 
                if(ret==-1) {
-#ifdef DEBUG
-                       g_message("%s: handle %p extend write failed: %s", __func__, handle, strerror(errno));
-#endif
+                       DEBUG("%s: handle %p extend write failed: %s", __func__, handle, strerror(errno));
+
+                       _wapi_set_last_error_from_errno ();
+                       return(FALSE);
+               }
+
+               /* And put the file position back after the write */
+               ret = lseek (fd, pos, SEEK_SET);
+               if (ret == -1) {
+                       DEBUG ("%s: handle %p second lseek failed: %s",
+                                  __func__, handle, strerror(errno));
 
                        _wapi_set_last_error_from_errno ();
                        return(FALSE);
                }
        }
+#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
         */
@@ -641,14 +751,13 @@ static gboolean file_setendoffile(gpointer handle)
        }
        while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending()); 
        if(ret==-1) {
-#ifdef DEBUG
-               g_message("%s: handle %p ftruncate failed: %s", __func__,
+               DEBUG("%s: handle %p ftruncate failed: %s", __func__,
                          handle, strerror(errno));
-#endif
                
                _wapi_set_last_error_from_errno ();
                return(FALSE);
        }
+#endif
                
        return(TRUE);
 }
@@ -660,7 +769,7 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
        struct stat statbuf;
        guint32 size;
        int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -670,13 +779,12 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
                SetLastError (ERROR_INVALID_HANDLE);
                return(INVALID_FILE_SIZE);
        }
+       fd = file_handle->fd;
        
        if(!(file_handle->fileaccess & GENERIC_READ) &&
           !(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-#endif
+               DEBUG("%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(INVALID_FILE_SIZE);
@@ -690,15 +798,37 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
        
        ret = fstat(fd, &statbuf);
        if (ret == -1) {
-#ifdef DEBUG
-               g_message ("%s: handle %p fstat failed: %s", __func__,
+               DEBUG ("%s: handle %p fstat failed: %s", __func__,
                           handle, strerror(errno));
-#endif
 
                _wapi_set_last_error_from_errno ();
                return(INVALID_FILE_SIZE);
        }
        
+       /* fstat indicates block devices as zero-length, so go a different path */
+#ifdef BLKGETSIZE64
+       if (S_ISBLK(statbuf.st_mode)) {
+               guint64 bigsize;
+               if (ioctl(fd, BLKGETSIZE64, &bigsize) < 0) {
+                       DEBUG ("%s: handle %p ioctl BLKGETSIZE64 failed: %s",
+                                  __func__, handle, strerror(errno));
+
+                       _wapi_set_last_error_from_errno ();
+                       return(INVALID_FILE_SIZE);
+               }
+               
+               size = bigsize & 0xFFFFFFFF;
+               if (highsize != NULL) {
+                       *highsize = bigsize>>32;
+               }
+
+               DEBUG ("%s: Returning block device size %d/%d",
+                          __func__, size, *highsize);
+       
+               return(size);
+       }
+#endif
+       
 #ifdef HAVE_LARGE_FILE_SUPPORT
        size = statbuf.st_size & 0xFFFFFFFF;
        if (highsize != NULL) {
@@ -712,9 +842,7 @@ static guint32 file_getfilesize(gpointer handle, guint32 *highsize)
        size = statbuf.st_size;
 #endif
 
-#ifdef DEBUG
-       g_message ("%s: Returning size %d/%d", __func__, size, *highsize);
-#endif
+       DEBUG ("%s: Returning size %d/%d", __func__, size, *highsize);
        
        return(size);
 }
@@ -727,8 +855,7 @@ static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
        gboolean ok;
        struct stat statbuf;
        guint64 create_ticks, access_ticks, write_ticks;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -738,13 +865,12 @@ static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = file_handle->fd;
 
        if(!(file_handle->fileaccess & GENERIC_READ) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_READ access: %u",
+               DEBUG("%s: handle %p doesn't have GENERIC_READ access: %u",
                          __func__, handle, file_handle->fileaccess);
-#endif
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
@@ -752,20 +878,16 @@ static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
        
        ret=fstat(fd, &statbuf);
        if(ret==-1) {
-#ifdef DEBUG
-               g_message("%s: handle %p fstat failed: %s", __func__, handle,
+               DEBUG("%s: handle %p fstat failed: %s", __func__, handle,
                          strerror(errno));
-#endif
 
                _wapi_set_last_error_from_errno ();
                return(FALSE);
        }
 
-#ifdef DEBUG
-       g_message("%s: atime: %ld ctime: %ld mtime: %ld", __func__,
+       DEBUG("%s: atime: %ld ctime: %ld mtime: %ld", __func__,
                  statbuf.st_atime, statbuf.st_ctime,
                  statbuf.st_mtime);
-#endif
 
        /* Try and guess a meaningful create time by using the older
         * of atime or ctime
@@ -784,10 +906,8 @@ static gboolean file_getfiletime(gpointer handle, WapiFileTime *create_time,
        access_ticks=((guint64)statbuf.st_atime*10000000)+116444736000000000ULL;
        write_ticks=((guint64)statbuf.st_mtime*10000000)+116444736000000000ULL;
        
-#ifdef DEBUG
-       g_message("%s: aticks: %llu cticks: %llu wticks: %llu", __func__,
+       DEBUG("%s: aticks: %llu cticks: %llu wticks: %llu", __func__,
                  access_ticks, create_ticks, write_ticks);
-#endif
 
        if(create_time!=NULL) {
                create_time->dwLowDateTime = create_ticks & 0xFFFFFFFF;
@@ -817,8 +937,7 @@ static gboolean file_setfiletime(gpointer handle,
        struct utimbuf utbuf;
        struct stat statbuf;
        guint64 access_ticks, write_ticks;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
                                (gpointer *)&file_handle);
@@ -828,21 +947,18 @@ static gboolean file_setfiletime(gpointer handle,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = file_handle->fd;
        
        if(!(file_handle->fileaccess & GENERIC_WRITE) &&
           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-#endif
+               DEBUG("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
 
        if(file_handle->filename == NULL) {
-#ifdef DEBUG
-               g_message("%s: handle %p unknown filename", __func__, handle);
-#endif
+               DEBUG("%s: handle %p unknown filename", __func__, handle);
 
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
@@ -853,10 +969,8 @@ static gboolean file_setfiletime(gpointer handle,
         */
        ret=fstat (fd, &statbuf);
        if(ret==-1) {
-#ifdef DEBUG
-               g_message("%s: handle %p fstat failed: %s", __func__, handle,
+               DEBUG("%s: handle %p fstat failed: %s", __func__, handle,
                          strerror(errno));
-#endif
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return(FALSE);
@@ -869,10 +983,8 @@ static gboolean file_setfiletime(gpointer handle,
                 * but this will do for now.
                 */
                if (access_ticks < 116444736000000000ULL) {
-#ifdef DEBUG
-                       g_message ("%s: attempt to set access time too early",
+                       DEBUG ("%s: attempt to set access time too early",
                                   __func__);
-#endif
                        SetLastError (ERROR_INVALID_PARAMETER);
                        return(FALSE);
                }
@@ -889,10 +1001,8 @@ static gboolean file_setfiletime(gpointer handle,
                 * but this will do for now.
                 */
                if (write_ticks < 116444736000000000ULL) {
-#ifdef DEBUG
-                       g_message ("%s: attempt to set write time too early",
+                       DEBUG ("%s: attempt to set write time too early",
                                   __func__);
-#endif
                        SetLastError (ERROR_INVALID_PARAMETER);
                        return(FALSE);
                }
@@ -902,18 +1012,14 @@ static gboolean file_setfiletime(gpointer handle,
                utbuf.modtime=statbuf.st_mtime;
        }
 
-#ifdef DEBUG
-       g_message("%s: setting handle %p access %ld write %ld", __func__,
-                 handle, utbuf.actime, utbuf.modtime);
-#endif
+       DEBUG ("%s: setting handle %p access %ld write %ld", __func__,
+                  handle, utbuf.actime, utbuf.modtime);
 
-       ret=utime(file_handle->filename, &utbuf);
-       if(ret==-1) {
-#ifdef DEBUG
-               g_message("%s: handle %p [%s] utime failed: %s", __func__,
-                         handle, file_handle->filename, strerror(errno));
+       ret = _wapi_utime (file_handle->filename, &utbuf);
+       if (ret == -1) {
+               DEBUG ("%s: handle %p [%s] utime failed: %s", __func__,
+                          handle, file_handle->filename, strerror(errno));
 
-#endif
                SetLastError (ERROR_INVALID_PARAMETER);
                return(FALSE);
        }
@@ -924,14 +1030,13 @@ static gboolean file_setfiletime(gpointer handle,
 static void console_close (gpointer handle, gpointer data)
 {
        struct _WapiHandle_file *console_handle = (struct _WapiHandle_file *)data;
+       int fd = console_handle->fd;
        
-#ifdef DEBUG
-       g_message("%s: closing console handle %p", __func__, handle);
-#endif
+       DEBUG("%s: closing console handle %p", __func__, handle);
 
        g_free (console_handle->filename);
        
-       close (GPOINTER_TO_UINT(handle));
+       close (fd);
 }
 
 static WapiFileType console_getfiletype(void)
@@ -945,9 +1050,8 @@ static gboolean console_read(gpointer handle, gpointer buffer,
 {
        struct _WapiHandle_file *console_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
-       
+       int ret, fd;
+
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
                                (gpointer *)&console_handle);
        if(ok==FALSE) {
@@ -956,6 +1060,7 @@ static gboolean console_read(gpointer handle, gpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = console_handle->fd;
        
        if(bytesread!=NULL) {
                *bytesread=0;
@@ -963,10 +1068,8 @@ static gboolean console_read(gpointer handle, gpointer buffer,
        
        if(!(console_handle->fileaccess & GENERIC_READ) &&
           !(console_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message ("%s: handle %p doesn't have GENERIC_READ access: %u",
+               DEBUG ("%s: handle %p doesn't have GENERIC_READ access: %u",
                           __func__, handle, console_handle->fileaccess);
-#endif
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
@@ -977,10 +1080,8 @@ static gboolean console_read(gpointer handle, gpointer buffer,
        } while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
 
        if(ret==-1) {
-#ifdef DEBUG
-               g_message("%s: read of handle %p error: %s", __func__, handle,
+               DEBUG("%s: read of handle %p error: %s", __func__, handle,
                          strerror(errno));
-#endif
 
                _wapi_set_last_error_from_errno ();
                return(FALSE);
@@ -999,8 +1100,7 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
 {
        struct _WapiHandle_file *console_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
                                (gpointer *)&console_handle);
@@ -1010,6 +1110,7 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = console_handle->fd;
        
        if(byteswritten!=NULL) {
                *byteswritten=0;
@@ -1017,20 +1118,16 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
        
        if(!(console_handle->fileaccess & GENERIC_WRITE) &&
           !(console_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, console_handle->fileaccess);
-#endif
+               DEBUG("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, console_handle->fileaccess);
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
-       NO_SIGPIPE(
-               do {
-                       ret = write(fd, buffer, numbytes);
-               } while (ret == -1 && errno == EINTR &&
-                        !_wapi_thread_cur_apc_pending());
-               );
+       do {
+               ret = write(fd, buffer, numbytes);
+       } while (ret == -1 && errno == EINTR &&
+                !_wapi_thread_cur_apc_pending());
 
        if (ret == -1) {
                if (errno == EINTR) {
@@ -1038,10 +1135,8 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
                } else {
                        _wapi_set_last_error_from_errno ();
                        
-#ifdef DEBUG
-                       g_message ("%s: write of handle %p error: %s",
+                       DEBUG ("%s: write of handle %p error: %s",
                                   __func__, handle, strerror(errno));
-#endif
 
                        return(FALSE);
                }
@@ -1053,15 +1148,16 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
        return(TRUE);
 }
 
-static void pipe_close (gpointer handle, gpointer data G_GNUC_UNUSED)
+static void pipe_close (gpointer handle, gpointer data)
 {
-#ifdef DEBUG
-       g_message("%s: closing pipe handle %p", __func__, handle);
-#endif
+       struct _WapiHandle_file *pipe_handle = (struct _WapiHandle_file*)data;
+       int fd = pipe_handle->fd;
+
+       DEBUG("%s: closing pipe handle %p", __func__, handle);
 
        /* No filename with pipe handles */
 
-       close(GPOINTER_TO_UINT(handle));
+       close (fd);
 }
 
 static WapiFileType pipe_getfiletype(void)
@@ -1075,9 +1171,8 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
 {
        struct _WapiHandle_file *pipe_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
-       
+       int ret, fd;
+
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
                                (gpointer *)&pipe_handle);
        if(ok==FALSE) {
@@ -1086,6 +1181,7 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = pipe_handle->fd;
 
        if(bytesread!=NULL) {
                *bytesread=0;
@@ -1093,19 +1189,15 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
        
        if(!(pipe_handle->fileaccess & GENERIC_READ) &&
           !(pipe_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_READ access: %u",
+               DEBUG("%s: handle %p doesn't have GENERIC_READ access: %u",
                          __func__, handle, pipe_handle->fileaccess);
-#endif
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
-#ifdef DEBUG
-       g_message ("%s: reading up to %d bytes from pipe %p", __func__,
+       DEBUG ("%s: reading up to %d bytes from pipe %p", __func__,
                   numbytes, handle);
-#endif
 
        do {
                ret=read(fd, buffer, numbytes);
@@ -1117,18 +1209,14 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
                } else {
                        _wapi_set_last_error_from_errno ();
                        
-#ifdef DEBUG
-                       g_message("%s: read of handle %p error: %s", __func__,
+                       DEBUG("%s: read of handle %p error: %s", __func__,
                                  handle, strerror(errno));
-#endif
 
                        return(FALSE);
                }
        }
        
-#ifdef DEBUG
-       g_message ("%s: read %d bytes from pipe", __func__, ret);
-#endif
+       DEBUG ("%s: read %d bytes from pipe", __func__, ret);
 
        if(bytesread!=NULL) {
                *bytesread=ret;
@@ -1143,8 +1231,7 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
 {
        struct _WapiHandle_file *pipe_handle;
        gboolean ok;
-       int ret;
-       int fd = GPOINTER_TO_UINT(handle);
+       int ret, fd;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PIPE,
                                (gpointer *)&pipe_handle);
@@ -1154,6 +1241,7 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
                SetLastError (ERROR_INVALID_HANDLE);
                return(FALSE);
        }
+       fd = pipe_handle->fd;
        
        if(byteswritten!=NULL) {
                *byteswritten=0;
@@ -1161,25 +1249,19 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
        
        if(!(pipe_handle->fileaccess & GENERIC_WRITE) &&
           !(pipe_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, pipe_handle->fileaccess);
-#endif
+               DEBUG("%s: handle %p doesn't have GENERIC_WRITE access: %u", __func__, handle, pipe_handle->fileaccess);
 
                SetLastError (ERROR_ACCESS_DENIED);
                return(FALSE);
        }
        
-#ifdef DEBUG
-       g_message ("%s: writing up to %d bytes to pipe %p", __func__, numbytes,
+       DEBUG ("%s: writing up to %d bytes to pipe %p", __func__, numbytes,
                   handle);
-#endif
 
-       NO_SIGPIPE(
-               do {
-                       ret = write (fd, buffer, numbytes);
-               } while (ret == -1 && errno == EINTR &&
-                        !_wapi_thread_cur_apc_pending());
-               );
+       do {
+               ret = write (fd, buffer, numbytes);
+       } while (ret == -1 && errno == EINTR &&
+                !_wapi_thread_cur_apc_pending());
 
        if (ret == -1) {
                if (errno == EINTR) {
@@ -1187,10 +1269,8 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
                } else {
                        _wapi_set_last_error_from_errno ();
                        
-#ifdef DEBUG
-                       g_message("%s: write of handle %p error: %s", __func__,
+                       DEBUG("%s: write of handle %p error: %s", __func__,
                                  handle, strerror(errno));
-#endif
 
                        return(FALSE);
                }
@@ -1217,10 +1297,8 @@ static int convert_flags(guint32 fileaccess, guint32 createmode)
                flags=O_RDWR;
                break;
        default:
-#ifdef DEBUG
-               g_message("%s: Unknown access type 0x%x", __func__,
+               DEBUG("%s: Unknown access type 0x%x", __func__,
                          fileaccess);
-#endif
                break;
        }
 
@@ -1240,41 +1318,14 @@ static int convert_flags(guint32 fileaccess, guint32 createmode)
                flags|=O_TRUNC;
                break;
        default:
-#ifdef DEBUG
-               g_message("%s: Unknown create mode 0x%x", __func__,
+               DEBUG("%s: Unknown create mode 0x%x", __func__,
                          createmode);
-#endif
                break;
        }
        
        return(flags);
 }
 
-static guint32 convert_from_flags(int flags)
-{
-       guint32 fileaccess=0;
-       
-#ifndef O_ACCMODE
-#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
-#endif
-
-       if((flags & O_ACCMODE) == O_RDONLY) {
-               fileaccess=GENERIC_READ;
-       } else if ((flags & O_ACCMODE) == O_WRONLY) {
-               fileaccess=GENERIC_WRITE;
-       } else if ((flags & O_ACCMODE) == O_RDWR) {
-               fileaccess=GENERIC_READ|GENERIC_WRITE;
-       } else {
-#ifdef DEBUG
-               g_message("%s: Can't figure out flags 0x%x", __func__, flags);
-#endif
-       }
-
-       /* Maybe sort out create mode too */
-
-       return(fileaccess);
-}
-
 #if 0 /* unused */
 static mode_t convert_perms(guint32 sharemode)
 {
@@ -1307,9 +1358,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode,
                 */
                if (file_existing_share == 0) {
                        /* Quick and easy, no possibility to share */
-#ifdef DEBUG
-                       g_message ("%s: Share mode prevents open: requested access: 0x%x, file has sharing = NONE", __func__, fileaccess);
-#endif
+                       DEBUG ("%s: Share mode prevents open: requested access: 0x%x, file has sharing = NONE", __func__, fileaccess);
 
                        _wapi_handle_share_release (*share_info);
                        
@@ -1321,9 +1370,7 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode,
                    ((file_existing_share == FILE_SHARE_WRITE) &&
                     (fileaccess != GENERIC_WRITE))) {
                        /* New access mode doesn't match up */
-#ifdef DEBUG
-                       g_message ("%s: Share mode prevents open: requested access: 0x%x, file has sharing: 0x%x", __func__, fileaccess, file_existing_share);
-#endif
+                       DEBUG ("%s: Share mode prevents open: requested access: 0x%x, file has sharing: 0x%x", __func__, fileaccess, file_existing_share);
 
                        _wapi_handle_share_release (*share_info);
                
@@ -1335,23 +1382,56 @@ static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode,
                    ((file_existing_access & GENERIC_WRITE) &&
                     !(sharemode & FILE_SHARE_WRITE))) {
                        /* New share mode doesn't match up */
-#ifdef DEBUG
-                       g_message ("%s: Access mode prevents open: requested share: 0x%x, file has access: 0x%x", __func__, sharemode, file_existing_access);
-#endif
+                       DEBUG ("%s: Access mode prevents open: requested share: 0x%x, file has access: 0x%x", __func__, sharemode, file_existing_access);
 
                        _wapi_handle_share_release (*share_info);
                
                        return(FALSE);
                }
        } else {
-#ifdef DEBUG
-               g_message ("%s: New file!", __func__);
-#endif
+               DEBUG ("%s: New file!", __func__);
        }
 
        return(TRUE);
 }
 
+
+static gboolean
+share_allows_delete (struct stat *statbuf, struct _WapiFileShare **share_info)
+{
+       gboolean file_already_shared;
+       guint32 file_existing_share, file_existing_access;
+
+       file_already_shared = _wapi_handle_get_or_set_share (statbuf->st_dev, statbuf->st_ino, FILE_SHARE_DELETE, GENERIC_READ, &file_existing_share, &file_existing_access, share_info);
+
+       if (file_already_shared) {
+               /* The reference to this share info was incremented
+                * when we looked it up, so be careful to put it back
+                * if we conclude we can't use this file.
+                */
+               if (file_existing_share == 0) {
+                       /* Quick and easy, no possibility to share */
+                       DEBUG ("%s: Share mode prevents open: requested access: 0x%x, file has sharing = NONE", __func__, fileaccess);
+
+                       _wapi_handle_share_release (*share_info);
+
+                       return(FALSE);
+               }
+
+               if (!(file_existing_share & FILE_SHARE_DELETE)) {
+                       /* New access mode doesn't match up */
+                       DEBUG ("%s: Share mode prevents open: requested access: 0x%x, file has sharing: 0x%x", __func__, fileaccess, file_existing_share);
+
+                       _wapi_handle_share_release (*share_info);
+
+                       return(FALSE);
+               }
+       } else {
+               DEBUG ("%s: New file!", __func__);
+       }
+
+       return(TRUE);
+}
 static gboolean share_check (struct stat *statbuf, guint32 sharemode,
                             guint32 fileaccess,
                             struct _WapiFileShare **share_info, int fd)
@@ -1425,7 +1505,7 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
         * other code, perms instead are the on-disk permissions and
         * this is a sane default.
         */
-       mode_t perms=0644;
+       mode_t perms=0666;
        gchar *filename;
        int fd, ret;
        int handle_type;
@@ -1433,10 +1513,16 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
        
        mono_once (&io_ops_once, io_ops_init);
 
+       if (attrs & FILE_ATTRIBUTE_TEMPORARY)
+               perms = 0600;
+       
+       if (attrs & FILE_ATTRIBUTE_ENCRYPTED){
+               SetLastError (ERROR_ENCRYPTION_FAILED);
+               return INVALID_HANDLE_VALUE;
+       }
+       
        if (name == NULL) {
-#ifdef DEBUG
-               g_message ("%s: name is NULL", __func__);
-#endif
+               DEBUG ("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(INVALID_HANDLE_VALUE);
@@ -1444,20 +1530,16 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
 
        filename = mono_unicode_to_external (name);
        if (filename == NULL) {
-#ifdef DEBUG
-               g_message("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG("%s: unicode conversion returned NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(INVALID_HANDLE_VALUE);
        }
        
-#ifdef DEBUG
-       g_message ("%s: Opening %s with share 0x%x and access 0x%x", __func__,
+       DEBUG ("%s: Opening %s with share 0x%x and access 0x%x", __func__,
                   filename, sharemode, fileaccess);
-#endif
        
-       fd = open(filename, flags, perms);
+       fd = _wapi_open (filename, flags, perms);
     
        /* If we were trying to open a directory with write permissions
         * (e.g. O_WRONLY or O_RDWR), this call will fail with
@@ -1470,24 +1552,20 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
        if (fd == -1 && errno == EISDIR)
        {
                /* Try again but don't try to make it writable */
-               fd = open(filename, flags  & ~(O_RDWR|O_WRONLY), perms);
+               fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms);
        }
        
        if (fd == -1) {
-#ifdef DEBUG
-               g_message("%s: Error opening file %s: %s", __func__, filename,
+               DEBUG("%s: Error opening file %s: %s", __func__, filename,
                          strerror(errno));
-#endif
-               _wapi_set_last_error_from_errno ();
+               _wapi_set_last_path_error_from_errno (NULL, filename);
                g_free (filename);
 
                return(INVALID_HANDLE_VALUE);
        }
 
        if (fd >= _wapi_fd_reserve) {
-#ifdef DEBUG
-               g_message ("%s: File descriptor is too big", __func__);
-#endif
+               DEBUG ("%s: File descriptor is too big", __func__);
 
                SetLastError (ERROR_TOO_MANY_OPEN_FILES);
                
@@ -1499,16 +1577,21 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
 
        ret = fstat (fd, &statbuf);
        if (ret == -1) {
-#ifdef DEBUG
-               g_message ("%s: fstat error of file %s: %s", __func__,
+               DEBUG ("%s: fstat error of file %s: %s", __func__,
                           filename, strerror (errno));
-#endif
                _wapi_set_last_error_from_errno ();
                g_free (filename);
                close (fd);
                
                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_check (&statbuf, sharemode, fileaccess,
                         &file_handle.share_info, fd) == FALSE) {
@@ -1520,9 +1603,7 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
        }
        if (file_handle.share_info == NULL) {
                /* No space, so no more files can be opened */
-#ifdef DEBUG
-               g_message ("%s: No space in the share table", __func__);
-#endif
+               DEBUG ("%s: No space in the share table", __func__);
 
                SetLastError (ERROR_TOO_MANY_OPEN_FILES);
                close (fd);
@@ -1538,14 +1619,29 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
                //security, sizeof(WapiSecurityAttributes));
        }
        
+       file_handle.fd = fd;
        file_handle.fileaccess=fileaccess;
        file_handle.sharemode=sharemode;
        file_handle.attrs=attrs;
 
+#ifdef HAVE_POSIX_FADVISE
+       if (attrs & FILE_FLAG_SEQUENTIAL_SCAN)
+               posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+       if (attrs & FILE_FLAG_RANDOM_ACCESS)
+               posix_fadvise (fd, 0, 0, POSIX_FADV_RANDOM);
+#endif
+       
 #ifndef S_ISFIFO
 #define S_ISFIFO(m) ((m & S_IFIFO) != 0)
 #endif
-       handle_type = (S_ISFIFO (statbuf.st_mode)) ? WAPI_HANDLE_PIPE : WAPI_HANDLE_FILE;
+       if (S_ISFIFO (statbuf.st_mode)) {
+               handle_type = WAPI_HANDLE_PIPE;
+       } else if (S_ISCHR (statbuf.st_mode)) {
+               handle_type = WAPI_HANDLE_CONSOLE;
+       } else {
+               handle_type = WAPI_HANDLE_FILE;
+       }
+
        handle = _wapi_handle_new_fd (handle_type, fd, &file_handle);
        if (handle == _WAPI_HANDLE_INVALID) {
                g_warning ("%s: error creating file handle", __func__);
@@ -1556,9 +1652,7 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
                return(INVALID_HANDLE_VALUE);
        }
        
-#ifdef DEBUG
-       g_message("%s: returning handle %p", __func__, handle);
-#endif
+       DEBUG("%s: returning handle %p", __func__, handle);
        
        return(handle);
 }
@@ -1575,12 +1669,16 @@ gpointer CreateFile(const gunichar2 *name, guint32 fileaccess,
 gboolean DeleteFile(const gunichar2 *name)
 {
        gchar *filename;
-       int ret;
+       int retval;
+       gboolean ret = FALSE;
+       guint32 attrs;
+#if 0
+       struct stat statbuf;
+       struct _WapiFileShare *shareinfo;
+#endif
        
        if(name==NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
@@ -1588,24 +1686,55 @@ gboolean DeleteFile(const gunichar2 *name)
 
        filename=mono_unicode_to_external(name);
        if(filename==NULL) {
-#ifdef DEBUG
-               g_message("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG("%s: unicode conversion returned NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
        }
+
+       attrs = GetFileAttributes (name);
+       if (attrs == INVALID_FILE_ATTRIBUTES) {
+               DEBUG ("%s: file attributes error", __func__);
+               /* Error set by GetFileAttributes() */
+               g_free (filename);
+               return(FALSE);
+       }
+
+#if 0
+       /* Check to make sure sharing allows us to open the file for
+        * writing.  See bug 323389.
+        *
+        * Do the checks that don't need an open file descriptor, for
+        * simplicity's sake.  If we really have to do the full checks
+        * then we can implement that later.
+        */
+       if (_wapi_stat (filename, &statbuf) < 0) {
+               _wapi_set_last_path_error_from_errno (NULL, filename);
+               g_free (filename);
+               return(FALSE);
+       }
        
-       ret=unlink(filename);
-       
-       g_free(filename);
+       if (share_allows_open (&statbuf, 0, GENERIC_WRITE,
+                              &shareinfo) == FALSE) {
+               SetLastError (ERROR_SHARING_VIOLATION);
+               g_free (filename);
+               return FALSE;
+       }
+       if (shareinfo)
+               _wapi_handle_share_release (shareinfo);
+#endif
 
-       if(ret==0) {
-               return(TRUE);
+       retval = _wapi_unlink (filename);
+       
+       if (retval == -1) {
+               _wapi_set_last_path_error_from_errno (NULL, filename);
+       } else {
+               ret = TRUE;
        }
 
-       _wapi_set_last_error_from_errno ();
-       return(FALSE);
+       g_free(filename);
+
+       return(ret);
 }
 
 /**
@@ -1624,13 +1753,13 @@ gboolean DeleteFile(const gunichar2 *name)
 gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
 {
        gchar *utf8_name, *utf8_dest_name;
-       int result;
+       int result, errno_copy;
        struct stat stat_src, stat_dest;
+       gboolean ret = FALSE;
+       struct _WapiFileShare *shareinfo;
        
        if(name==NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
@@ -1638,18 +1767,14 @@ gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
 
        utf8_name = mono_unicode_to_external (name);
        if (utf8_name == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG ("%s: unicode conversion returned NULL", __func__);
                
                SetLastError (ERROR_INVALID_NAME);
                return FALSE;
        }
        
        if(dest_name==NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                g_free (utf8_name);
                SetLastError (ERROR_INVALID_NAME);
@@ -1658,9 +1783,7 @@ gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
 
        utf8_dest_name = mono_unicode_to_external (dest_name);
        if (utf8_dest_name == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG ("%s: unicode conversion returned NULL", __func__);
 
                g_free (utf8_name);
                SetLastError (ERROR_INVALID_NAME);
@@ -1672,18 +1795,65 @@ gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
         * We check it here and return the failure if dest exists and is not
         * the same file as src.
         */
-       if (!stat (utf8_dest_name, &stat_dest) && !stat (utf8_name, &stat_src)) {
-               if (stat_dest.st_dev != stat_src.st_dev || stat_dest.st_ino != stat_src.st_ino) {
+       if (_wapi_stat (utf8_name, &stat_src) < 0) {
+               if (errno != ENOENT || _wapi_lstat (utf8_name, &stat_src) < 0) {
+                       _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+                       g_free (utf8_name);
+                       g_free (utf8_dest_name);
+                       return FALSE;
+               }
+       }
+       
+       if (!_wapi_stat (utf8_dest_name, &stat_dest)) {
+               if (stat_dest.st_dev != stat_src.st_dev ||
+                   stat_dest.st_ino != stat_src.st_ino) {
+                       g_free (utf8_name);
+                       g_free (utf8_dest_name);
                        SetLastError (ERROR_ALREADY_EXISTS);
                        return FALSE;
-               }       
+               }
+       }
+
+       /* Check to make that we have delete sharing permission.
+        * See https://bugzilla.xamarin.com/show_bug.cgi?id=17009
+        *
+        * Do the checks that don't need an open file descriptor, for
+        * simplicity's sake.  If we really have to do the full checks
+        * then we can implement that later.
+        */
+       if (share_allows_delete (&stat_src, &shareinfo) == FALSE) {
+               SetLastError (ERROR_SHARING_VIOLATION);
+               return FALSE;
        }
+       if (shareinfo)
+               _wapi_handle_share_release (shareinfo);
+
+       result = _wapi_rename (utf8_name, utf8_dest_name);
+       errno_copy = errno;
+       
+       if (result == -1) {
+               switch(errno_copy) {
+               case EEXIST:
+                       SetLastError (ERROR_ALREADY_EXISTS);
+                       break;
 
-       result = rename (utf8_name, utf8_dest_name);
+               case EXDEV:
+                       /* Ignore here, it is dealt with below */
+                       break;
+                       
+               default:
+                       _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+               }
+       }
+       
        g_free (utf8_name);
        g_free (utf8_dest_name);
 
-       if (result != 0 && errno == EXDEV) {
+       if (result != 0 && errno_copy == EXDEV) {
+               if (S_ISDIR (stat_src.st_mode)) {
+                       SetLastError (ERROR_NOT_SAME_DEVICE);
+                       return FALSE;
+               }
                /* Try a copy to the new location, and delete the source */
                if (CopyFile (name, dest_name, TRUE)==FALSE) {
                        /* CopyFile will set the error */
@@ -1694,20 +1864,58 @@ gboolean MoveFile (const gunichar2 *name, const gunichar2 *dest_name)
        }
 
        if (result == 0) {
-               return TRUE;
+               ret = TRUE;
        }
-       
-       switch (errno) {
-       case EEXIST:
-               SetLastError (ERROR_ALREADY_EXISTS);
-               break;
-       
-       default:
-               _wapi_set_last_error_from_errno ();
-               break;
+
+       return(ret);
+}
+
+static gboolean
+write_file (int src_fd, int dest_fd, struct stat *st_src, gboolean report_errors)
+{
+       int remain, n;
+       char *buf, *wbuf;
+       int buf_size = st_src->st_blksize;
+
+       buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : buf_size);
+       buf = (char *) malloc (buf_size);
+
+       for (;;) {
+               remain = read (src_fd, buf, buf_size);
+               if (remain < 0) {
+                       if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
+                               continue;
+
+                       if (report_errors)
+                               _wapi_set_last_error_from_errno ();
+
+                       free (buf);
+                       return FALSE;
+               }
+               if (remain == 0) {
+                       break;
+               }
+
+               wbuf = buf;
+               while (remain > 0) {
+                       if ((n = write (dest_fd, wbuf, remain)) < 0) {
+                               if (errno == EINTR && !_wapi_thread_cur_apc_pending ())
+                                       continue;
+
+                               if (report_errors)
+                                       _wapi_set_last_error_from_errno ();
+                               DEBUG ("%s: write failed.", __func__);
+                               free (buf);
+                               return FALSE;
+                       }
+
+                       remain -= n;
+                       wbuf += n;
+               }
        }
 
-       return FALSE;
+       free (buf);
+       return TRUE ;
 }
 
 /**
@@ -1727,15 +1935,13 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
 {
        gchar *utf8_src, *utf8_dest;
        int src_fd, dest_fd;
-       int buf_size;
-       char *buf;
-       int remain, n;
-       struct stat st;
+       struct stat st, dest_st;
+       struct utimbuf dest_time;
+       gboolean ret = TRUE;
+       int ret_utime;
        
        if(name==NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
@@ -1743,19 +1949,15 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
        
        utf8_src = mono_unicode_to_external (name);
        if (utf8_src == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion of source returned NULL",
+               DEBUG ("%s: unicode conversion of source returned NULL",
                           __func__);
-#endif
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return(FALSE);
        }
        
        if(dest_name==NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: dest is NULL", __func__);
 
                g_free (utf8_src);
                SetLastError (ERROR_INVALID_NAME);
@@ -1764,10 +1966,8 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
        
        utf8_dest = mono_unicode_to_external (dest_name);
        if (utf8_dest == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion of dest returned NULL",
+               DEBUG ("%s: unicode conversion of dest returned NULL",
                           __func__);
-#endif
 
                SetLastError (ERROR_INVALID_PARAMETER);
 
@@ -1776,10 +1976,10 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
                return(FALSE);
        }
        
-       src_fd = open (utf8_src, O_RDONLY);
+       src_fd = _wapi_open (utf8_src, O_RDONLY, 0);
        if (src_fd < 0) {
-               _wapi_set_last_error_from_errno ();
-
+               _wapi_set_last_path_error_from_errno (NULL, utf8_src);
+               
                g_free (utf8_src);
                g_free (utf8_dest);
                
@@ -1795,17 +1995,36 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
                
                return(FALSE);
        }
+
+       /* Before trying to open/create the dest, we need to report a 'file busy'
+        * error if src and dest are actually the same file. We do the check here to take
+        * advantage of the IOMAP capability */
+       if (!_wapi_stat (utf8_dest, &dest_st) && st.st_dev == dest_st.st_dev && 
+                       st.st_ino == dest_st.st_ino) {
+
+               g_free (utf8_src);
+               g_free (utf8_dest);
+               close (src_fd);
+
+               SetLastError (ERROR_SHARING_VIOLATION);
+               return (FALSE);
+       }
        
        if (fail_if_exists) {
-               dest_fd = open (utf8_dest, O_WRONLY | O_CREAT, st.st_mode);
+               dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL, st.st_mode);
        } else {
-               dest_fd = open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode);
+               /* FIXME: it kinda sucks that this code path potentially scans
+                * the directory twice due to the weird SetLastError()
+                * behavior. */
+               dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode);
                if (dest_fd < 0) {
-                       /* O_TRUNC might cause a fail if the file
-                        * doesn't exist
+                       /* The file does not exist, try creating it */
+                       dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode);
+               } else {
+                       /* Apparently this error is set if we
+                        * overwrite the dest file
                         */
-                       dest_fd = open (utf8_dest, O_WRONLY | O_CREAT,
-                                       st.st_mode);
+                       SetLastError (ERROR_ALREADY_EXISTS);
                }
        }
        if (dest_fd < 0) {
@@ -1814,125 +2033,105 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
                g_free (utf8_src);
                g_free (utf8_dest);
                close (src_fd);
-               
+
                return(FALSE);
        }
-       
-       buf_size = st.st_blksize;
-       buf = (char *) alloca (buf_size);
-       
-       for (;;) {
-               remain = read (src_fd, buf, buf_size);
-               
-               if (remain < 0) {
-                       if (errno == EINTR && !_wapi_thread_cur_apc_pending()) {
-                               continue;
-                       }
-                       
-                       _wapi_set_last_error_from_errno ();
-
-                       g_free (utf8_src);
-                       g_free (utf8_dest);
-                       close (src_fd);
-                       close (dest_fd);
-                       
-                       return(FALSE);
-               }
-               
-               if (remain == 0) {
-                       break;
-               }
 
-               while (remain > 0) {
-                       if ((n = write (dest_fd, buf, remain)) < 0) {
-                               if (errno == EINTR && !_wapi_thread_cur_apc_pending())
-                                       continue;
+       if (!write_file (src_fd, dest_fd, &st, TRUE))
+               ret = FALSE;
 
-                               _wapi_set_last_error_from_errno ();
-#ifdef DEBUG
-                               g_message ("%s: write failed.", __func__);
-#endif
+       close (src_fd);
+       close (dest_fd);
+       
+       dest_time.modtime = st.st_mtime;
+       dest_time.actime = st.st_atime;
+       ret_utime = utime (utf8_dest, &dest_time);
+       if (ret_utime == -1)
+               DEBUG ("%s: file [%s] utime failed: %s", __func__, utf8_dest, strerror(errno));
+       
+       g_free (utf8_src);
+       g_free (utf8_dest);
 
-                               g_free (utf8_src);
-                               g_free (utf8_dest);
-                               close (src_fd);
-                               close (dest_fd);
+       return ret;
+}
 
-                               return (FALSE);
-                       }
+static gchar*
+convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name)
+{
+       gchar *utf8_ret;
 
-                       remain -= n;
-               }
+       if (arg == NULL) {
+               DEBUG ("%s: %s is NULL", __func__, arg_name);
+               SetLastError (ERROR_INVALID_NAME);
+               return NULL;
        }
 
-       g_free (utf8_src);
-       g_free (utf8_dest);
-       close (src_fd);
-       close (dest_fd);
+       utf8_ret = mono_unicode_to_external (arg);
+       if (utf8_ret == NULL) {
+               DEBUG ("%s: unicode conversion of %s returned NULL",
+                          __func__, arg_name);
+               SetLastError (ERROR_INVALID_PARAMETER);
+               return NULL;
+       }
 
-       return(TRUE);
+       return utf8_ret;
 }
 
-static mono_once_t stdhandle_once=MONO_ONCE_INIT;
-static gpointer stdin_handle=INVALID_HANDLE_VALUE;
-static gpointer stdout_handle=INVALID_HANDLE_VALUE;
-static gpointer stderr_handle=INVALID_HANDLE_VALUE;
-
-static gpointer stdhandle_create (int fd, const guchar *name)
+gboolean
+ReplaceFile (const gunichar2 *replacedFileName, const gunichar2 *replacementFileName,
+                     const gunichar2 *backupFileName, guint32 replaceFlags, 
+                     gpointer exclude, gpointer reserved)
 {
-       struct _WapiHandle_file file_handle = {0};
-       gpointer handle;
-       int flags;
-       
-#ifdef DEBUG
-       g_message("%s: creating standard handle type %s, fd %d", __func__,
-                 name, fd);
-#endif
-       
-       /* Check if fd is valid */
-       do {
-               flags=fcntl(fd, F_GETFL);
-       } while (flags == -1 && errno == EINTR);
-
-       if(flags==-1) {
-               /* Invalid fd.  Not really much point checking for EBADF
-                * specifically
-                */
-#ifdef DEBUG
-               g_message("%s: fcntl error on fd %d: %s", __func__, fd,
-                         strerror(errno));
-#endif
+       int result, backup_fd = -1,replaced_fd = -1;
+       gchar *utf8_replacedFileName, *utf8_replacementFileName = NULL, *utf8_backupFileName = NULL;
+       struct stat stBackup;
+       gboolean ret = FALSE;
 
-               _wapi_set_last_error_from_errno ();
-               return(INVALID_HANDLE_VALUE);
-       }
+       if (!(utf8_replacedFileName = convert_arg_to_utf8 (replacedFileName, "replacedFileName")))
+               return FALSE;
+       if (!(utf8_replacementFileName = convert_arg_to_utf8 (replacementFileName, "replacementFileName")))
+               goto replace_cleanup;
+       if (backupFileName != NULL) {
+               if (!(utf8_backupFileName = convert_arg_to_utf8 (backupFileName, "backupFileName")))
+                       goto replace_cleanup;
+       }
+
+       if (utf8_backupFileName) {
+               // Open the backup file for read so we can restore the file if an error occurs.
+               backup_fd = _wapi_open (utf8_backupFileName, O_RDONLY, 0);
+               result = _wapi_rename (utf8_replacedFileName, utf8_backupFileName);
+               if (result == -1)
+                       goto replace_cleanup;
+       }
+
+       result = _wapi_rename (utf8_replacementFileName, utf8_replacedFileName);
+       if (result == -1) {
+               _wapi_set_last_path_error_from_errno (NULL, utf8_replacementFileName);
+               _wapi_rename (utf8_backupFileName, utf8_replacedFileName);
+               if (backup_fd != -1 && !fstat (backup_fd, &stBackup)) {
+                       replaced_fd = _wapi_open (utf8_backupFileName, O_WRONLY | O_CREAT | O_TRUNC,
+                                                 stBackup.st_mode);
+                       
+                       if (replaced_fd == -1)
+                               goto replace_cleanup;
 
-       file_handle.filename = g_strdup(name);
-       /* some default security attributes might be needed */
-       file_handle.security_attributes=0;
-       file_handle.fileaccess=convert_from_flags(flags);
-       file_handle.sharemode=0;
-       file_handle.attrs=0;
+                       write_file (backup_fd, replaced_fd, &stBackup, FALSE);
+               }
 
-       handle = _wapi_handle_new_fd (WAPI_HANDLE_CONSOLE, fd, &file_handle);
-       if (handle == _WAPI_HANDLE_INVALID) {
-               g_warning ("%s: error creating file handle", __func__);
-               SetLastError (ERROR_GEN_FAILURE);
-               return(INVALID_HANDLE_VALUE);
+               goto replace_cleanup;
        }
-       
-#ifdef DEBUG
-       g_message("%s: returning handle %p", __func__, handle);
-#endif
 
-       return(handle);
-}
+       ret = TRUE;
 
-static void stdhandle_init (void)
-{
-       stdin_handle=stdhandle_create (0, "<stdin>");
-       stdout_handle=stdhandle_create (1, "<stdout>");
-       stderr_handle=stdhandle_create (2, "<stderr>");
+replace_cleanup:
+       g_free (utf8_replacedFileName);
+       g_free (utf8_replacementFileName);
+       g_free (utf8_backupFileName);
+       if (backup_fd != -1)
+               close (backup_fd);
+       if (replaced_fd != -1)
+               close (replaced_fd);
+       return ret;
 }
 
 /**
@@ -1945,42 +2144,65 @@ static void stdhandle_init (void)
  * Return value: the handle, or %INVALID_HANDLE_VALUE on error
  */
 
+static mono_mutex_t stdhandle_mutex;
+
 gpointer GetStdHandle(WapiStdHandle stdhandle)
 {
+       struct _WapiHandle_file *file_handle;
        gpointer handle;
-       
-       mono_once (&io_ops_once, io_ops_init);
-       mono_once (&stdhandle_once, stdhandle_init);
+       int thr_ret, fd;
+       const gchar *name;
+       gboolean ok;
        
        switch(stdhandle) {
        case STD_INPUT_HANDLE:
-               handle=stdin_handle;
+               fd = 0;
+               name = "<stdin>";
                break;
 
        case STD_OUTPUT_HANDLE:
-               handle=stdout_handle;
+               fd = 1;
+               name = "<stdout>";
                break;
 
        case STD_ERROR_HANDLE:
-               handle=stderr_handle;
+               fd = 2;
+               name = "<stderr>";
                break;
 
        default:
-#ifdef DEBUG
-               g_message("%s: unknown standard handle type", __func__);
-#endif
+               DEBUG("%s: unknown standard handle type", __func__);
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return(INVALID_HANDLE_VALUE);
        }
 
-       if (handle == INVALID_HANDLE_VALUE) {
-               SetLastError (ERROR_NO_MORE_FILES);
-               return(INVALID_HANDLE_VALUE);
+       handle = GINT_TO_POINTER (fd);
+
+       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+                             (void *)&stdhandle_mutex);
+       thr_ret = mono_mutex_lock (&stdhandle_mutex);
+       g_assert (thr_ret == 0);
+
+       ok = _wapi_lookup_handle (handle, WAPI_HANDLE_CONSOLE,
+                                 (gpointer *)&file_handle);
+       if (ok == FALSE) {
+               /* Need to create this console handle */
+               handle = _wapi_stdhandle_create (fd, name);
+               
+               if (handle == INVALID_HANDLE_VALUE) {
+                       SetLastError (ERROR_NO_MORE_FILES);
+                       goto done;
+               }
+       } else {
+               /* Add a reference to this handle */
+               _wapi_handle_ref (handle);
        }
        
-       /* Add a reference to this handle */
-       _wapi_handle_ref (handle);
+  done:
+       thr_ret = mono_mutex_unlock (&stdhandle_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
        
        return(handle);
 }
@@ -2338,9 +2560,7 @@ gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
        const guint16 *ip;
        
        if(system_time==NULL) {
-#ifdef DEBUG
-               g_message("%s: system_time NULL", __func__);
-#endif
+               DEBUG("%s: system_time NULL", __func__);
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return(FALSE);
@@ -2354,9 +2574,7 @@ gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
         * year and day calculation to work later
         */
        if(file_ticks<0) {
-#ifdef DEBUG
-               g_message("%s: file_time too big", __func__);
-#endif
+               DEBUG("%s: file_time too big", __func__);
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return(FALSE);
@@ -2364,41 +2582,29 @@ gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
 
        totaldays=(file_ticks / TICKS_PER_DAY);
        rem = file_ticks % TICKS_PER_DAY;
-#ifdef DEBUG
-       g_message("%s: totaldays: %lld rem: %lld", __func__, totaldays, rem);
-#endif
+       DEBUG("%s: totaldays: %lld rem: %lld", __func__, totaldays, rem);
 
        system_time->wHour=rem/TICKS_PER_HOUR;
        rem %= TICKS_PER_HOUR;
-#ifdef DEBUG
-       g_message("%s: Hour: %d rem: %lld", __func__, system_time->wHour, rem);
-#endif
+       DEBUG("%s: Hour: %d rem: %lld", __func__, system_time->wHour, rem);
        
        system_time->wMinute = rem / TICKS_PER_MINUTE;
        rem %= TICKS_PER_MINUTE;
-#ifdef DEBUG
-       g_message("%s: Minute: %d rem: %lld", __func__, system_time->wMinute,
+       DEBUG("%s: Minute: %d rem: %lld", __func__, system_time->wMinute,
                  rem);
-#endif
        
        system_time->wSecond = rem / TICKS_PER_SECOND;
        rem %= TICKS_PER_SECOND;
-#ifdef DEBUG
-       g_message("%s: Second: %d rem: %lld", __func__, system_time->wSecond,
+       DEBUG("%s: Second: %d rem: %lld", __func__, system_time->wSecond,
                  rem);
-#endif
        
        system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND;
-#ifdef DEBUG
-       g_message("%s: Milliseconds: %d", __func__,
+       DEBUG("%s: Milliseconds: %d", __func__,
                  system_time->wMilliseconds);
-#endif
 
        /* January 1, 1601 was a Monday, according to Emacs calendar */
        system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1;
-#ifdef DEBUG
-       g_message("%s: Day of week: %d", __func__, system_time->wDayOfWeek);
-#endif
+       DEBUG("%s: Day of week: %d", __func__, system_time->wDayOfWeek);
        
        /* This algorithm to find year and month given days from epoch
         * from glibc
@@ -2411,31 +2617,23 @@ gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
        while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) {
                /* Guess a corrected year, assuming 365 days per year */
                gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0);
-#ifdef DEBUG
-               g_message("%s: totaldays: %lld yg: %lld y: %lld", __func__,
+               DEBUG("%s: totaldays: %lld yg: %lld y: %lld", __func__,
                          totaldays, yg,
                          y);
                g_message("%s: LEAPS(yg): %lld LEAPS(y): %lld", __func__,
                          LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1));
-#endif
                
                /* Adjust days and y to match the guessed year. */
                totaldays -= ((yg - y) * 365
                              + LEAPS_THRU_END_OF (yg - 1)
                              - LEAPS_THRU_END_OF (y - 1));
-#ifdef DEBUG
-               g_message("%s: totaldays: %lld", __func__, totaldays);
-#endif
+               DEBUG("%s: totaldays: %lld", __func__, totaldays);
                y = yg;
-#ifdef DEBUG
-               g_message("%s: y: %lld", __func__, y);
-#endif
+               DEBUG("%s: y: %lld", __func__, y);
        }
        
        system_time->wYear = y;
-#ifdef DEBUG
-       g_message("%s: Year: %d", __func__, system_time->wYear);
-#endif
+       DEBUG("%s: Year: %d", __func__, system_time->wYear);
 
        ip = mon_yday[isleap(y)];
        
@@ -2443,241 +2641,57 @@ gboolean FileTimeToSystemTime(const WapiFileTime *file_time,
                continue;
        }
        totaldays-=ip[y];
-#ifdef DEBUG
-       g_message("%s: totaldays: %lld", __func__, totaldays);
-#endif
+       DEBUG("%s: totaldays: %lld", __func__, totaldays);
        
        system_time->wMonth = y + 1;
-#ifdef DEBUG
-       g_message("%s: Month: %d", __func__, system_time->wMonth);
-#endif
+       DEBUG("%s: Month: %d", __func__, system_time->wMonth);
 
        system_time->wDay = totaldays + 1;
-#ifdef DEBUG
-       g_message("%s: Day: %d", __func__, system_time->wDay);
-#endif
+       DEBUG("%s: Day: %d", __func__, system_time->wDay);
        
        return(TRUE);
 }
 
-static gint
-file_compare (gconstpointer a, gconstpointer b)
+gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
 {
-       gchar *astr = *(gchar **) a;
-       gchar *bstr = *(gchar **) b;
+       struct _WapiHandle_find find_handle = {0};
+       gpointer handle;
+       gchar *utf8_pattern = NULL, *dir_part, *entry_part;
+       int result;
+       
+       if (pattern == NULL) {
+               DEBUG ("%s: pattern is NULL", __func__);
 
-       return strcmp (astr, bstr);
-}
+               SetLastError (ERROR_PATH_NOT_FOUND);
+               return(INVALID_HANDLE_VALUE);
+       }
 
-static gint
-get_errno_from_g_file_error (gint error)
-{
-       switch (error) {
-#ifdef EACCESS
-       case G_FILE_ERROR_ACCES:
-               error = EACCES;
-               break;
-#endif
-#ifdef ENAMETOOLONG
-       case G_FILE_ERROR_NAMETOOLONG:
-               error = ENAMETOOLONG;
-               break;
-#endif
-#ifdef ENOENT
-       case G_FILE_ERROR_NOENT:
-               error = ENOENT;
-               break;
-#endif
-#ifdef ENOTDIR
-       case G_FILE_ERROR_NOTDIR:
-               error = ENOTDIR;
-               break;
-#endif
-#ifdef ENXIO
-       case G_FILE_ERROR_NXIO:
-               error = ENXIO;
-               break;
-#endif
-#ifdef ENODEV
-       case G_FILE_ERROR_NODEV:
-               error = ENODEV;
-               break;
-#endif
-#ifdef EROFS
-       case G_FILE_ERROR_ROFS:
-               error = EROFS;
-               break;
-#endif
-#ifdef ETXTBSY
-       case G_FILE_ERROR_TXTBSY:
-               error = ETXTBSY;
-               break;
-#endif
-#ifdef EFAULT
-       case G_FILE_ERROR_FAULT:
-               error = EFAULT;
-               break;
-#endif
-#ifdef ELOOP
-       case G_FILE_ERROR_LOOP:
-               error = ELOOP;
-               break;
-#endif
-#ifdef ENOSPC
-       case G_FILE_ERROR_NOSPC:
-               error = ENOSPC;
-               break;
-#endif
-#ifdef ENOMEM
-       case G_FILE_ERROR_NOMEM:
-               error = ENOMEM;
-               break;
-#endif
-#ifdef EMFILE
-       case G_FILE_ERROR_MFILE:
-               error = EMFILE;
-               break;
-#endif
-#ifdef ENFILE
-       case G_FILE_ERROR_NFILE:
-               error = ENFILE;
-               break;
-#endif
-#ifdef EBADF
-       case G_FILE_ERROR_BADF:
-               error = EBADF;
-               break;
-#endif
-#ifdef EINVAL
-       case G_FILE_ERROR_INVAL:
-               error = EINVAL;
-               break;
-#endif
-#ifdef EPIPE
-       case G_FILE_ERROR_PIPE:
-               error = EPIPE;
-               break;
-#endif
-#ifdef EAGAIN
-       case G_FILE_ERROR_AGAIN:
-               error = EAGAIN;
-               break;
-#endif
-#ifdef EINTR
-       case G_FILE_ERROR_INTR:
-               error = EINTR;
-               break;
-#endif
-#ifdef EWIO
-       case G_FILE_ERROR_IO:
-               error = EIO;
-               break;
-#endif
-#ifdef EPERM
-       case G_FILE_ERROR_PERM:
-               error = EPERM;
-               break;
-#endif
-       case G_FILE_ERROR_FAILED:
-               error = ERROR_INVALID_PARAMETER;
-               break;
-       }
-
-       return error;
-}
-
-/* scandir using glib */
-static gint
-mono_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist)
-{
-       GError *error = NULL;
-       GDir *dir;
-       GPtrArray *names;
-       const gchar *name;
-       gint result;
-       GPatternSpec *patspec;
-
-       dir = g_dir_open (dirname, 0, &error);
-       if (dir == NULL) {
-               /* g_dir_open returns ENOENT on directories on which we don't
-                * have read/x permission */
-               gint errnum = get_errno_from_g_file_error (error->code);
-               g_error_free (error);
-               if (errnum == ENOENT && g_file_test (dirname, G_FILE_TEST_IS_DIR))
-                       errnum = EACCES;
-
-               errno = errnum;
-               return -1;
-       }
-
-       patspec = g_pattern_spec_new (pattern);
-       names = g_ptr_array_new ();
-       while ((name = g_dir_read_name (dir)) != NULL) {
-               if (g_pattern_match_string (patspec, name))
-                       g_ptr_array_add (names, g_strdup (name));
-       }
-       
-       g_pattern_spec_free (patspec);
-       g_dir_close (dir);
-       result = names->len;
-       if (result > 0) {
-               g_ptr_array_sort (names, file_compare);
-               g_ptr_array_set_size (names, result + 1);
-
-               *namelist = (gchar **) g_ptr_array_free (names, FALSE);
-       } else {
-               g_ptr_array_free (names, TRUE);
-       }
-
-       return result;
-}
-
-gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
-{
-       struct _WapiHandle_find find_handle = {0};
-       gpointer handle;
-       gchar *utf8_pattern = NULL, *dir_part, *entry_part;
-       int result;
-       
-       if (pattern == NULL) {
-#ifdef DEBUG
-               g_message ("%s: pattern is NULL", __func__);
-#endif
-
-               SetLastError (ERROR_PATH_NOT_FOUND);
-               return(INVALID_HANDLE_VALUE);
-       }
-
-       utf8_pattern = mono_unicode_to_external (pattern);
-       if (utf8_pattern == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion returned NULL", __func__);
-#endif
-               
-               SetLastError (ERROR_INVALID_NAME);
-               return(INVALID_HANDLE_VALUE);
-       }
-
-#ifdef DEBUG
-       g_message ("%s: looking for [%s]", __func__, utf8_pattern);
-#endif
-       
-       /* Figure out which bit of the pattern is the directory */
-       dir_part = g_path_get_dirname (utf8_pattern);
-       entry_part = g_path_get_basename (utf8_pattern);
-
-#if 0
-       /* Don't do this check for now, it breaks if directories
-        * really do have metachars in their names (see bug 58116).
-        * FIXME: Figure out a better solution to keep some checks...
-        */
-       if (strchr (dir_part, '*') || strchr (dir_part, '?')) {
-               SetLastError (ERROR_INVALID_NAME);
-               g_free (dir_part);
-               g_free (entry_part);
-               g_free (utf8_pattern);
-               return(INVALID_HANDLE_VALUE);
-       }
+       utf8_pattern = mono_unicode_to_external (pattern);
+       if (utf8_pattern == NULL) {
+               DEBUG ("%s: unicode conversion returned NULL", __func__);
+               
+               SetLastError (ERROR_INVALID_NAME);
+               return(INVALID_HANDLE_VALUE);
+       }
+
+       DEBUG ("%s: looking for [%s]", __func__, utf8_pattern);
+       
+       /* Figure out which bit of the pattern is the directory */
+       dir_part = _wapi_dirname (utf8_pattern);
+       entry_part = _wapi_basename (utf8_pattern);
+
+#if 0
+       /* Don't do this check for now, it breaks if directories
+        * really do have metachars in their names (see bug 58116).
+        * FIXME: Figure out a better solution to keep some checks...
+        */
+       if (strchr (dir_part, '*') || strchr (dir_part, '?')) {
+               SetLastError (ERROR_INVALID_NAME);
+               g_free (dir_part);
+               g_free (entry_part);
+               g_free (utf8_pattern);
+               return(INVALID_HANDLE_VALUE);
+       }
 #endif
 
        /* The pattern can specify a directory or a set of files.
@@ -2701,17 +2715,27 @@ gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
         */
 
        find_handle.namelist = NULL;
-       result = mono_io_scandir (dir_part, entry_part, &find_handle.namelist);
+       result = _wapi_io_scandir (dir_part, entry_part,
+                                  &find_handle.namelist);
+       
+       if (result == 0) {
+               /* No files, which windows seems to call
+                * FILE_NOT_FOUND
+                */
+               SetLastError (ERROR_FILE_NOT_FOUND);
+               g_free (utf8_pattern);
+               g_free (entry_part);
+               g_free (dir_part);
+               return (INVALID_HANDLE_VALUE);
+       }
        
        if (result < 0) {
-#ifdef DEBUG
+#ifdef DEBUG_ENABLED
                gint errnum = errno;
 #endif
-               _wapi_set_last_error_from_errno ();
-#ifdef DEBUG
-               g_message ("%s: scandir error: %s", __func__,
+               _wapi_set_last_path_error_from_errno (dir_part, NULL);
+               DEBUG ("%s: scandir error: %s", __func__,
                           g_strerror (errnum));
-#endif
                g_free (utf8_pattern);
                g_free (entry_part);
                g_free (dir_part);
@@ -2721,9 +2745,7 @@ gpointer FindFirstFile (const gunichar2 *pattern, WapiFindData *find_data)
        g_free (utf8_pattern);
        g_free (entry_part);
        
-#ifdef DEBUG
-       g_message ("%s: Got %d matches", __func__, result);
-#endif
+       DEBUG ("%s: Got %d matches", __func__, result);
 
        find_handle.dir_part = dir_part;
        find_handle.num = result;
@@ -2754,7 +2776,8 @@ gboolean FindNextFile (gpointer handle, WapiFindData *find_data)
 {
        struct _WapiHandle_find *find_handle;
        gboolean ok;
-       struct stat buf;
+       struct stat buf, linkbuf;
+       int result;
        gchar *filename;
        gchar *utf8_filename, *utf8_basename;
        gunichar2 *utf16_basename;
@@ -2786,41 +2809,44 @@ retry:
        /* stat next match */
 
        filename = g_build_filename (find_handle->dir_part, find_handle->namelist[find_handle->count ++], NULL);
-       if (lstat (filename, &buf) != 0) {
-#ifdef DEBUG
-               g_message ("%s: stat failed: %s", __func__, filename);
-#endif
+
+       result = _wapi_stat (filename, &buf);
+       if (result == -1 && errno == ENOENT) {
+               /* Might be a dangling symlink */
+               result = _wapi_lstat (filename, &buf);
+       }
+       
+       if (result != 0) {
+               DEBUG ("%s: stat failed: %s", __func__, filename);
 
                g_free (filename);
                goto retry;
        }
 
-       /* Check for dangling symlinks, and ignore them (principle of
-        * least surprise, avoiding confusion where we report the file
-        * exists, but when someone tries to open it we would report
-        * it isn't there.)
-        */
-       if(S_ISLNK (buf.st_mode)) {
-               if(stat (filename, &buf) != 0) {
-                       g_free (filename);
-                       goto retry;
-               }
+#ifndef __native_client__
+       result = _wapi_lstat (filename, &linkbuf);
+       if (result != 0) {
+               DEBUG ("%s: lstat failed: %s", __func__, filename);
+
+               g_free (filename);
+               goto retry;
        }
-       
+#endif
+
        utf8_filename = mono_utf8_from_external (filename);
        if (utf8_filename == NULL) {
                /* We couldn't turn this filename into utf8 (eg the
                 * encoding of the name wasn't convertible), so just
                 * ignore it.
                 */
+               g_warning ("%s: Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODINGS\n", __func__, filename);
+               
                g_free (filename);
                goto retry;
        }
        g_free (filename);
        
-#ifdef DEBUG
-       g_message ("%s: Found [%s]", __func__, utf8_filename);
-#endif
+       DEBUG ("%s: Found [%s]", __func__, utf8_filename);
        
        /* fill data block */
 
@@ -2829,7 +2855,11 @@ retry:
        else
                create_time = buf.st_ctime;
        
-       find_data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
+#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
 
        _wapi_time_t_to_filetime (create_time, &find_data->ftCreationTime);
        _wapi_time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime);
@@ -2846,7 +2876,7 @@ retry:
        find_data->dwReserved0 = 0;
        find_data->dwReserved1 = 0;
 
-       utf8_basename = g_path_get_basename (utf8_filename);
+       utf8_basename = _wapi_basename (utf8_filename);
        utf16_basename = g_utf8_to_utf16 (utf8_basename, -1, NULL, &bytes,
                                          NULL);
        if(utf16_basename==NULL) {
@@ -2895,6 +2925,11 @@ gboolean FindClose (gpointer handle)
        gboolean ok;
        int thr_ret;
 
+       if (handle == NULL) {
+               SetLastError (ERROR_INVALID_HANDLE);
+               return(FALSE);
+       }
+       
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_FIND,
                                (gpointer *)&find_handle);
        if(ok==FALSE) {
@@ -2936,13 +2971,9 @@ gboolean CreateDirectory (const gunichar2 *name,
 {
        gchar *utf8_name;
        int result;
-       struct stat buf;
-       guint32 attrs;
        
        if (name == NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
@@ -2950,40 +2981,20 @@ gboolean CreateDirectory (const gunichar2 *name,
        
        utf8_name = mono_unicode_to_external (name);
        if (utf8_name == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG ("%s: unicode conversion returned NULL", __func__);
        
                SetLastError (ERROR_INVALID_NAME);
                return FALSE;
        }
 
-       result = mkdir (utf8_name, 0777);
+       result = _wapi_mkdir (utf8_name, 0777);
 
        if (result == 0) {
                g_free (utf8_name);
                return TRUE;
        }
 
-       if (errno == EEXIST) {
-               result = stat (utf8_name, &buf);
-               if (result == -1) {
-                       _wapi_set_last_error_from_errno ();
-                       g_free (utf8_name);
-                       return FALSE;
-               }
-
-               g_free (utf8_name);
-               attrs = _wapi_stat_to_file_attributes (&buf);
-               if ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
-                       return TRUE;
-
-               errno = EEXIST;
-               _wapi_set_last_error_from_errno ();
-               return FALSE;
-       }
-
-       _wapi_set_last_error_from_errno ();
+       _wapi_set_last_path_error_from_errno (NULL, utf8_name);
        g_free (utf8_name);
        return FALSE;
 }
@@ -3003,9 +3014,7 @@ gboolean RemoveDirectory (const gunichar2 *name)
        int result;
        
        if (name == NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
@@ -3013,22 +3022,22 @@ gboolean RemoveDirectory (const gunichar2 *name)
 
        utf8_name = mono_unicode_to_external (name);
        if (utf8_name == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG ("%s: unicode conversion returned NULL", __func__);
                
                SetLastError (ERROR_INVALID_NAME);
                return FALSE;
        }
 
-       result = rmdir (utf8_name);
+       result = _wapi_rmdir (utf8_name);
+       if (result == -1) {
+               _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+               g_free (utf8_name);
+               
+               return(FALSE);
+       }
        g_free (utf8_name);
 
-       if (result == 0)
-               return TRUE;
-       
-       _wapi_set_last_error_from_errno ();
-       return FALSE;
+       return(TRUE);
 }
 
 /**
@@ -3042,13 +3051,12 @@ gboolean RemoveDirectory (const gunichar2 *name)
 guint32 GetFileAttributes (const gunichar2 *name)
 {
        gchar *utf8_name;
-       struct stat buf;
+       struct stat buf, linkbuf;
        int result;
+       guint32 ret;
        
        if (name == NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
@@ -3056,24 +3064,42 @@ guint32 GetFileAttributes (const gunichar2 *name)
        
        utf8_name = mono_unicode_to_external (name);
        if (utf8_name == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG ("%s: unicode conversion returned NULL", __func__);
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return (INVALID_FILE_ATTRIBUTES);
        }
 
-       result = stat (utf8_name, &buf);
+       result = _wapi_stat (utf8_name, &buf);
+       if (result == -1 && errno == ENOENT) {
+               /* Might be a dangling symlink... */
+               result = _wapi_lstat (utf8_name, &buf);
+       }
 
        if (result != 0) {
-               _wapi_set_last_error_from_errno ();
+               _wapi_set_last_path_error_from_errno (NULL, utf8_name);
                g_free (utf8_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);
-       return _wapi_stat_to_file_attributes (&buf);
+
+       return(ret);
 }
 
 /**
@@ -3091,24 +3117,20 @@ gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels lev
        gchar *utf8_name;
        WapiFileAttributesData *data;
 
-       struct stat buf;
+       struct stat buf, linkbuf;
        time_t create_time;
        int result;
        
        if (level != GetFileExInfoStandard) {
-#ifdef DEBUG
-               g_message ("%s: info level %d not supported.", __func__,
+               DEBUG ("%s: info level %d not supported.", __func__,
                           level);
-#endif
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return FALSE;
        }
        
        if (name == NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
@@ -3116,22 +3138,31 @@ gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels lev
 
        utf8_name = mono_unicode_to_external (name);
        if (utf8_name == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG ("%s: unicode conversion returned NULL", __func__);
 
                SetLastError (ERROR_INVALID_PARAMETER);
                return FALSE;
        }
 
-       result = stat (utf8_name, &buf);
-       g_free (utf8_name);
-
+       result = _wapi_stat (utf8_name, &buf);
+       if (result == -1 && errno == ENOENT) {
+               /* Might be a dangling symlink... */
+               result = _wapi_lstat (utf8_name, &buf);
+       }
+       
        if (result != 0) {
-               SetLastError (ERROR_FILE_NOT_FOUND);
+               _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+               g_free (utf8_name);
                return FALSE;
        }
 
+       result = _wapi_lstat (utf8_name, &linkbuf);
+       if (result != 0) {
+               _wapi_set_last_path_error_from_errno (NULL, utf8_name);
+               g_free (utf8_name);
+               return(FALSE);
+       }
+
        /* fill data block */
 
        data = (WapiFileAttributesData *)info;
@@ -3141,7 +3172,11 @@ gboolean GetFileAttributesEx (const gunichar2 *name, WapiGetFileExInfoLevels lev
        else
                create_time = buf.st_ctime;
        
-       data->dwFileAttributes = _wapi_stat_to_file_attributes (&buf);
+       data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_name,
+                                                               &buf,
+                                                               &linkbuf);
+
+       g_free (utf8_name);
 
        _wapi_time_t_to_filetime (create_time, &data->ftCreationTime);
        _wapi_time_t_to_filetime (buf.st_atime, &data->ftLastAccessTime);
@@ -3181,9 +3216,7 @@ extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
         */
        
        if (name == NULL) {
-#ifdef DEBUG
-               g_message("%s: name is NULL", __func__);
-#endif
+               DEBUG("%s: name is NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return(FALSE);
@@ -3191,18 +3224,21 @@ extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
 
        utf8_name = mono_unicode_to_external (name);
        if (utf8_name == NULL) {
-#ifdef DEBUG
-               g_message ("%s: unicode conversion returned NULL", __func__);
-#endif
+               DEBUG ("%s: unicode conversion returned NULL", __func__);
 
                SetLastError (ERROR_INVALID_NAME);
                return FALSE;
        }
 
-       result = stat (utf8_name, &buf);
+       result = _wapi_stat (utf8_name, &buf);
+       if (result == -1 && errno == ENOENT) {
+               /* Might be a dangling symlink... */
+               result = _wapi_lstat (utf8_name, &buf);
+       }
+
        if (result != 0) {
+               _wapi_set_last_path_error_from_errno (NULL, utf8_name);
                g_free (utf8_name);
-               SetLastError (ERROR_FILE_NOT_FOUND);
                return FALSE;
        }
 
@@ -3211,9 +3247,9 @@ extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
         * catch that case here.
         */
        if (attrs & FILE_ATTRIBUTE_READONLY) {
-               result = chmod (utf8_name, buf.st_mode & ~(S_IWRITE | S_IWOTH | S_IWGRP));
+               result = _wapi_chmod (utf8_name, buf.st_mode & ~(S_IWRITE | S_IWOTH | S_IWGRP));
        } else {
-               result = chmod (utf8_name, buf.st_mode | S_IWRITE);
+               result = _wapi_chmod (utf8_name, buf.st_mode | S_IWRITE);
        }
 
        /* Ignore the other attributes for now */
@@ -3252,35 +3288,40 @@ extern gboolean SetFileAttributes (const gunichar2 *name, guint32 attrs)
  */
 extern guint32 GetCurrentDirectory (guint32 length, gunichar2 *buffer)
 {
-       gchar *path;
        gunichar2 *utf16_path;
        glong count;
        gsize bytes;
-       
-       path = g_get_current_dir ();
-       if (path == NULL)
+
+#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 ((char*)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*/
+                       if (path == NULL)
+                               return 0;
+                       utf16_path = mono_unicode_from_external (path, &bytes);
+                       g_free (utf16_path);
+                       g_free (path);
+                       return (bytes/2)+1;
+               }
+               _wapi_set_last_error_from_errno ();
+               return 0;
+       }
+#endif
 
-       utf16_path=mono_unicode_from_external (path, &bytes);
-       
-       /* if buffer too small, return number of characters required.
-        * this is plain dumb.
-        */
-       
+       utf16_path = mono_unicode_from_external ((gchar*)buffer, &bytes);
        count = (bytes/2)+1;
-       if (count > length) {
-               g_free(path);
-               g_free (utf16_path);
-               
-               return (count);
-       }
+       g_assert (count <= length); /*getcwd must have failed before with ERANGE*/
 
        /* Add the terminator */
        memset (buffer, '\0', bytes+2);
        memcpy (buffer, utf16_path, bytes);
        
        g_free (utf16_path);
-       g_free (path);
 
        return count;
 }
@@ -3298,8 +3339,13 @@ extern gboolean SetCurrentDirectory (const gunichar2 *path)
        gchar *utf8_path;
        gboolean result;
 
+       if (path == NULL) {
+               SetLastError (ERROR_INVALID_PARAMETER);
+               return(FALSE);
+       }
+       
        utf8_path = mono_unicode_to_external (path);
-       if (chdir (utf8_path) != 0) {
+       if (_wapi_chdir (utf8_path) != 0) {
                _wapi_set_last_error_from_errno ();
                result = FALSE;
        }
@@ -3322,16 +3368,12 @@ gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
        
        mono_once (&io_ops_once, io_ops_init);
        
-#ifdef DEBUG
-       g_message ("%s: Creating pipe", __func__);
-#endif
+       DEBUG ("%s: Creating pipe", __func__);
 
        ret=pipe (filedes);
        if(ret==-1) {
-#ifdef DEBUG
-               g_message ("%s: Error creating pipe: %s", __func__,
+               DEBUG ("%s: Error creating pipe: %s", __func__,
                           strerror (errno));
-#endif
                
                _wapi_set_last_error_from_errno ();
                return(FALSE);
@@ -3339,9 +3381,7 @@ gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
 
        if (filedes[0] >= _wapi_fd_reserve ||
            filedes[1] >= _wapi_fd_reserve) {
-#ifdef DEBUG
-               g_message ("%s: File descriptor is too big", __func__);
-#endif
+               DEBUG ("%s: File descriptor is too big", __func__);
 
                SetLastError (ERROR_TOO_MANY_OPEN_FILES);
                
@@ -3353,6 +3393,7 @@ gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
        
        /* filedes[0] is open for reading, filedes[1] for writing */
 
+       pipe_read_handle.fd = filedes [0];
        pipe_read_handle.fileaccess = GENERIC_READ;
        read_handle = _wapi_handle_new_fd (WAPI_HANDLE_PIPE, filedes[0],
                                           &pipe_read_handle);
@@ -3365,6 +3406,7 @@ gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
                return(FALSE);
        }
        
+       pipe_write_handle.fd = filedes [1];
        pipe_write_handle.fileaccess = GENERIC_WRITE;
        write_handle = _wapi_handle_new_fd (WAPI_HANDLE_PIPE, filedes[1],
                                            &pipe_write_handle);
@@ -3382,10 +3424,8 @@ gboolean CreatePipe (gpointer *readpipe, gpointer *writepipe,
        *readpipe = read_handle;
        *writepipe = write_handle;
 
-#ifdef DEBUG
-       g_message ("%s: Returning pipe: read handle %p, write handle %p",
+       DEBUG ("%s: Returning pipe: read handle %p, write handle %p",
                   __func__, read_handle, write_handle);
-#endif
 
        return(TRUE);
 }
@@ -3411,10 +3451,8 @@ guint32 GetTempPath (guint32 len, gunichar2 *buf)
                dirlen=(bytes/2);
                
                if(dirlen+1>len) {
-#ifdef DEBUG
-                       g_message ("%s: Size %d smaller than needed (%ld)",
+                       DEBUG ("%s: Size %d smaller than needed (%ld)",
                                   __func__, len, dirlen+1);
-#endif
                
                        ret=dirlen+1;
                } else {
@@ -3434,8 +3472,360 @@ guint32 GetTempPath (guint32 len, gunichar2 *buf)
        return(ret);
 }
 
+#ifdef HAVE_GETFSSTAT
+/* Darwin has getfsstat */
+gint32 GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
+{
+       struct statfs *stats;
+       int size, n, i;
+       gunichar2 *dir;
+       glong length, total = 0;
+       
+       n = getfsstat (NULL, 0, MNT_NOWAIT);
+       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){
+               g_free (stats);
+               return 0;
+       }
+       for (i = 0; i < n; i++){
+               dir = g_utf8_to_utf16 (stats [i].f_mntonname, -1, NULL, &length, NULL);
+               if (total + length < len){
+                       memcpy (buf + total, dir, sizeof (gunichar2) * length);
+                       buf [total+length] = 0;
+               } 
+               g_free (dir);
+               total += length + 1;
+       }
+       if (total < len)
+               buf [total] = 0;
+       total++;
+       g_free (stats);
+       return total;
+}
+#else
+/* In-place octal sequence replacement */
+static void
+unescape_octal (gchar *str)
+{
+       gchar *rptr;
+       gchar *wptr;
+
+       if (str == NULL)
+               return;
+
+       rptr = wptr = str;
+       while (*rptr != '\0') {
+               if (*rptr == '\\') {
+                       char c;
+                       rptr++;
+                       c = (*(rptr++) - '0') << 6;
+                       c += (*(rptr++) - '0') << 3;
+                       c += *(rptr++) - '0';
+                       *wptr++ = c;
+               } else if (wptr != rptr) {
+                       *wptr++ = *rptr++;
+               } else {
+                       rptr++; wptr++;
+               }
+       }
+       *wptr = '\0';
+}
+static gint32 GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf);
+
+#if __linux__
+#define GET_LOGICAL_DRIVE_STRINGS_BUFFER 512
+#define GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER 512
+#define GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER 64
+
+typedef struct 
+{
+       glong total;
+       guint32 buffer_index;
+       guint32 mountpoint_index;
+       guint32 field_number;
+       guint32 allocated_size;
+       guint32 fsname_index;
+       guint32 fstype_index;
+       gchar mountpoint [GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER + 1];
+       gchar *mountpoint_allocated;
+       gchar buffer [GET_LOGICAL_DRIVE_STRINGS_BUFFER];
+       gchar fsname [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1];
+       gchar fstype [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1];
+       ssize_t nbytes;
+       gchar delimiter;
+       gboolean check_mount_source;
+} LinuxMountInfoParseState;
+
+static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+static void append_to_mountpoint (LinuxMountInfoParseState *state);
+static gboolean add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+
+gint32 GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
+{
+       int fd;
+       gint32 ret = 0;
+       LinuxMountInfoParseState state;
+       gboolean (*parser)(guint32, gunichar2*, LinuxMountInfoParseState*) = NULL;
+
+       memset (buf, 0, len * sizeof (gunichar2));
+       fd = open ("/proc/self/mountinfo", O_RDONLY);
+       if (fd != -1)
+               parser = GetLogicalDriveStrings_MountInfo;
+       else {
+               fd = open ("/proc/mounts", O_RDONLY);
+               if (fd != -1)
+                       parser = GetLogicalDriveStrings_Mounts;
+       }
+
+       if (!parser) {
+               ret = GetLogicalDriveStrings_Mtab (len, buf);
+               goto done_and_out;
+       }
+
+       memset (&state, 0, sizeof (LinuxMountInfoParseState));
+       state.field_number = 1;
+       state.delimiter = ' ';
+
+       while ((state.nbytes = read (fd, state.buffer, GET_LOGICAL_DRIVE_STRINGS_BUFFER)) > 0) {
+               state.buffer_index = 0;
+
+               while ((*parser)(len, buf, &state)) {
+                       if (state.buffer [state.buffer_index] == '\n') {
+                               gboolean quit = add_drive_string (len, buf, &state);
+                               state.field_number = 1;
+                               state.buffer_index++;
+                               if (state.mountpoint_allocated) {
+                                       g_free (state.mountpoint_allocated);
+                                       state.mountpoint_allocated = NULL;
+                               }
+                               if (quit) {
+                                       ret = state.total;
+                                       goto done_and_out;
+                               }
+                       }
+               }
+       };
+       ret = state.total;
+
+  done_and_out:
+       if (fd != -1)
+               close (fd);
+       return ret;
+}
+
+static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+       gchar *ptr;
+
+       if (state->field_number == 1)
+               state->check_mount_source = TRUE;
+
+       while (state->buffer_index < (guint32)state->nbytes) {
+               if (state->buffer [state->buffer_index] == state->delimiter) {
+                       state->field_number++;
+                       switch (state->field_number) {
+                               case 2:
+                                       state->mountpoint_index = 0;
+                                       break;
+
+                               case 3:
+                                       if (state->mountpoint_allocated)
+                                               state->mountpoint_allocated [state->mountpoint_index] = 0;
+                                       else
+                                               state->mountpoint [state->mountpoint_index] = 0;
+                                       break;
+
+                               default:
+                                       ptr = (gchar*)memchr (state->buffer + state->buffer_index, '\n', GET_LOGICAL_DRIVE_STRINGS_BUFFER - state->buffer_index);
+                                       if (ptr)
+                                               state->buffer_index = (ptr - (gchar*)state->buffer) - 1;
+                                       else
+                                               state->buffer_index = state->nbytes;
+                                       return TRUE;
+                       }
+                       state->buffer_index++;
+                       continue;
+               } else if (state->buffer [state->buffer_index] == '\n')
+                       return TRUE;
+
+               switch (state->field_number) {
+                       case 1:
+                               if (state->check_mount_source) {
+                                       if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') {
+                                               /* We can ignore the rest, it's a device
+                                                * path */
+                                               state->check_mount_source = FALSE;
+                                               state->fsname [state->fsname_index++] = '/';
+                                               break;
+                                       }
+                                       if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+                                               state->fsname [state->fsname_index++] = state->buffer [state->buffer_index];
+                               }
+                               break;
+
+                       case 2:
+                               append_to_mountpoint (state);
+                               break;
+
+                       case 3:
+                               if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+                                       state->fstype [state->fstype_index++] = state->buffer [state->buffer_index];
+                               break;
+               }
+
+               state->buffer_index++;
+       }
+
+       return FALSE;
+}
+
+static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+       while (state->buffer_index < (guint32)state->nbytes) {
+               if (state->buffer [state->buffer_index] == state->delimiter) {
+                       state->field_number++;
+                       switch (state->field_number) {
+                               case 5:
+                                       state->mountpoint_index = 0;
+                                       break;
+
+                               case 6:
+                                       if (state->mountpoint_allocated)
+                                               state->mountpoint_allocated [state->mountpoint_index] = 0;
+                                       else
+                                               state->mountpoint [state->mountpoint_index] = 0;
+                                       break;
+
+                               case 7:
+                                       state->delimiter = '-';
+                                       break;
+
+                               case 8:
+                                       state->delimiter = ' ';
+                                       break;
+
+                               case 10:
+                                       state->check_mount_source = TRUE;
+                                       break;
+                       }
+                       state->buffer_index++;
+                       continue;
+               } else if (state->buffer [state->buffer_index] == '\n')
+                       return TRUE;
+
+               switch (state->field_number) {
+                       case 5:
+                               append_to_mountpoint (state);
+                               break;
+
+                       case 9:
+                               if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+                                       state->fstype [state->fstype_index++] = state->buffer [state->buffer_index];
+                               break;
+
+                       case 10:
+                               if (state->check_mount_source) {
+                                       if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') {
+                                               /* We can ignore the rest, it's a device
+                                                * path */
+                                               state->check_mount_source = FALSE;
+                                               state->fsname [state->fsname_index++] = '/';
+                                               break;
+                                       }
+                                       if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+                                               state->fsname [state->fsname_index++] = state->buffer [state->buffer_index];
+                               }
+                               break;
+               }
+
+               state->buffer_index++;
+       }
+
+       return FALSE;
+}
+
+static void
+append_to_mountpoint (LinuxMountInfoParseState *state)
+{
+       gchar ch = state->buffer [state->buffer_index];
+       if (state->mountpoint_allocated) {
+               if (state->mountpoint_index >= state->allocated_size) {
+                       guint32 newsize = (state->allocated_size << 1) + 1;
+                       gchar *newbuf = g_malloc0 (newsize * sizeof (gchar));
+
+                       memcpy (newbuf, state->mountpoint_allocated, state->mountpoint_index);
+                       g_free (state->mountpoint_allocated);
+                       state->mountpoint_allocated = newbuf;
+                       state->allocated_size = newsize;
+               }
+               state->mountpoint_allocated [state->mountpoint_index++] = ch;
+       } else {
+               if (state->mountpoint_index >= GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER) {
+                       state->allocated_size = (state->mountpoint_index << 1) + 1;
+                       state->mountpoint_allocated = g_malloc0 (state->allocated_size * sizeof (gchar));
+                       memcpy (state->mountpoint_allocated, state->mountpoint, state->mountpoint_index);
+                       state->mountpoint_allocated [state->mountpoint_index++] = ch;
+               } else
+                       state->mountpoint [state->mountpoint_index++] = ch;
+       }
+}
+
+static gboolean
+add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+       gboolean quit = FALSE;
+       gboolean ignore_entry;
+
+       if (state->fsname_index == 1 && state->fsname [0] == '/')
+               ignore_entry = FALSE;
+       else if (state->fsname_index == 0 || memcmp ("none", state->fsname, state->fsname_index) == 0)
+               ignore_entry = TRUE;
+       else if (state->fstype_index >= 5 && memcmp ("fuse.", state->fstype, 5) == 0) {
+               /* Ignore GNOME's gvfs */
+               if (state->fstype_index == 21 && memcmp ("fuse.gvfs-fuse-daemon", state->fstype, state->fstype_index) == 0)
+                       ignore_entry = TRUE;
+               else
+                       ignore_entry = FALSE;
+       } else
+               ignore_entry = TRUE;
+
+       if (!ignore_entry) {
+               gunichar2 *dir;
+               glong length;
+               gchar *mountpoint = state->mountpoint_allocated ? state->mountpoint_allocated : state->mountpoint;
+
+               unescape_octal (mountpoint);
+               dir = g_utf8_to_utf16 (mountpoint, -1, NULL, &length, NULL);
+               if (state->total + length + 1 > len) {
+                       quit = TRUE;
+                       state->total = len * 2;
+               } else {
+                       length++;
+                       memcpy (buf + state->total, dir, sizeof (gunichar2) * length);
+                       state->total += length;
+               }
+               g_free (dir);
+       }
+       state->fsname_index = 0;
+       state->fstype_index = 0;
+
+       return quit;
+}
+#else
 gint32
 GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
+{
+       return GetLogicalDriveStrings_Mtab (len, buf);
+}
+#endif
+static gint32
+GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
 {
        FILE *fp;
        gunichar2 *ptr, *dir;
@@ -3469,10 +3859,12 @@ GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
                        continue;
                }
 
-               dir = g_utf8_to_utf16 (*(splitted + 1), -1, &length, NULL, NULL);
+               unescape_octal (*(splitted + 1));
+               dir = g_utf8_to_utf16 (*(splitted + 1), -1, NULL, &length, NULL);
                g_strfreev (splitted);
                if (total + length + 1 > len) {
                        fclose (fp);
+                       g_free (dir);
                        return len * 2; /* guess */
                }
 
@@ -3517,182 +3909,424 @@ GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
 }
 #endif
 }
+#endif
 
-static gboolean _wapi_lock_file_region (int fd, off_t offset, off_t length)
+#if (defined(HAVE_STATVFS) || defined(HAVE_STATFS)) && !defined(PLATFORM_ANDROID)
+gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_bytes_avail,
+                           WapiULargeInteger *total_number_of_bytes,
+                           WapiULargeInteger *total_number_of_free_bytes)
 {
-       struct flock lock_data;
+#ifdef HAVE_STATVFS
+       struct statvfs fsstat;
+#elif defined(HAVE_STATFS)
+       struct statfs fsstat;
+#endif
+       gboolean isreadonly;
+       gchar *utf8_path_name;
        int ret;
+       unsigned long block_size;
+
+       if (path_name == NULL) {
+               utf8_path_name = g_strdup (g_get_current_dir());
+               if (utf8_path_name == NULL) {
+                       SetLastError (ERROR_DIRECTORY);
+                       return(FALSE);
+               }
+       }
+       else {
+               utf8_path_name = mono_unicode_to_external (path_name);
+               if (utf8_path_name == NULL) {
+                       DEBUG("%s: unicode conversion returned NULL", __func__);
+
+                       SetLastError (ERROR_INVALID_NAME);
+                       return(FALSE);
+               }
+       }
 
-       lock_data.l_type = F_WRLCK;
-       lock_data.l_whence = SEEK_SET;
-       lock_data.l_start = offset;
-       lock_data.l_len = length;
-       
        do {
-               ret = fcntl (fd, F_SETLK, &lock_data);
-       } while(ret == -1 && errno == EINTR);
-       
-#ifdef DEBUG
-       g_message ("%s: fcntl returns %d", __func__, ret);
+#ifdef HAVE_STATVFS
+               ret = statvfs (utf8_path_name, &fsstat);
+               isreadonly = ((fsstat.f_flag & ST_RDONLY) == ST_RDONLY);
+               block_size = fsstat.f_frsize;
+#elif defined(HAVE_STATFS)
+               ret = statfs (utf8_path_name, &fsstat);
+               isreadonly = ((fsstat.f_flags & MNT_RDONLY) == MNT_RDONLY);
+               block_size = fsstat.f_bsize;
 #endif
+       } while(ret == -1 && errno == EINTR);
+
+       g_free(utf8_path_name);
 
        if (ret == -1) {
-               /*
-                * if locks are not available (NFS for example),
-                * ignore the error
-                */
-               if (errno == ENOLCK
-#ifdef EOPNOTSUPP
-                   || errno == EOPNOTSUPP
-#endif
-#ifdef ENOTSUP
-                   || errno == ENOTSUP
-#endif
-                  ) {
-                       return (TRUE);
-               }
-               
-               SetLastError (ERROR_LOCK_VIOLATION);
+               _wapi_set_last_error_from_errno ();
+               DEBUG ("%s: statvfs failed: %s", __func__, strerror (errno));
                return(FALSE);
        }
 
+       /* total number of free bytes for non-root */
+       if (free_bytes_avail != NULL) {
+               if (isreadonly) {
+                       free_bytes_avail->QuadPart = 0;
+               }
+               else {
+                       free_bytes_avail->QuadPart = block_size * (guint64)fsstat.f_bavail;
+               }
+       }
+
+       /* total number of bytes available for non-root */
+       if (total_number_of_bytes != NULL) {
+               total_number_of_bytes->QuadPart = block_size * (guint64)fsstat.f_blocks;
+       }
+
+       /* total number of bytes available for root */
+       if (total_number_of_free_bytes != NULL) {
+               if (isreadonly) {
+                       total_number_of_free_bytes->QuadPart = 0;
+               }
+               else {
+                       total_number_of_free_bytes->QuadPart = block_size * (guint64)fsstat.f_bfree;
+               }
+       }
+       
+       return(TRUE);
+}
+#else
+gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_bytes_avail,
+                           WapiULargeInteger *total_number_of_bytes,
+                           WapiULargeInteger *total_number_of_free_bytes)
+{
+       if (free_bytes_avail != NULL) {
+               free_bytes_avail->QuadPart = (guint64) -1;
+       }
+
+       if (total_number_of_bytes != NULL) {
+               total_number_of_bytes->QuadPart = (guint64) -1;
+       }
+
+       if (total_number_of_free_bytes != NULL) {
+               total_number_of_free_bytes->QuadPart = (guint64) -1;
+       }
+
        return(TRUE);
 }
+#endif
+
+/*
+ * General Unix support
+ */
+typedef struct {
+       guint32 drive_type;
+#if __linux__
+       const long fstypeid;
+#endif
+       const gchar* fstype;
+} _wapi_drive_type;
+
+static _wapi_drive_type _wapi_drive_types[] = {
+#if PLATFORM_MACOSX
+       { DRIVE_REMOTE, "afp" },
+       { DRIVE_REMOTE, "autofs" },
+       { DRIVE_CDROM, "cddafs" },
+       { DRIVE_CDROM, "cd9660" },
+       { DRIVE_RAMDISK, "devfs" },
+       { DRIVE_FIXED, "exfat" },
+       { DRIVE_RAMDISK, "fdesc" },
+       { DRIVE_REMOTE, "ftp" },
+       { DRIVE_FIXED, "hfs" },
+       { DRIVE_FIXED, "msdos" },
+       { DRIVE_REMOTE, "nfs" },
+       { DRIVE_FIXED, "ntfs" },
+       { DRIVE_REMOTE, "smbfs" },
+       { DRIVE_FIXED, "udf" },
+       { DRIVE_REMOTE, "webdav" },
+       { DRIVE_UNKNOWN, NULL }
+#elif __linux__
+       { DRIVE_FIXED, ADFS_SUPER_MAGIC, "adfs"},
+       { DRIVE_FIXED, AFFS_SUPER_MAGIC, "affs"},
+       { DRIVE_REMOTE, AFS_SUPER_MAGIC, "afs"},
+       { DRIVE_RAMDISK, AUTOFS_SUPER_MAGIC, "autofs"},
+       { DRIVE_RAMDISK, AUTOFS_SBI_MAGIC, "autofs4"},
+       { DRIVE_REMOTE, CODA_SUPER_MAGIC, "coda" },
+       { DRIVE_RAMDISK, CRAMFS_MAGIC, "cramfs"},
+       { DRIVE_RAMDISK, CRAMFS_MAGIC_WEND, "cramfs"},
+       { DRIVE_REMOTE, CIFS_MAGIC_NUMBER, "cifs"},
+       { DRIVE_RAMDISK, DEBUGFS_MAGIC, "debugfs"},
+       { DRIVE_RAMDISK, SYSFS_MAGIC, "sysfs"},
+       { DRIVE_RAMDISK, SECURITYFS_MAGIC, "securityfs"},
+       { DRIVE_RAMDISK, SELINUX_MAGIC, "selinuxfs"},
+       { DRIVE_RAMDISK, RAMFS_MAGIC, "ramfs"},
+       { DRIVE_FIXED, SQUASHFS_MAGIC, "squashfs"},
+       { DRIVE_FIXED, EFS_SUPER_MAGIC, "efs"},
+       { DRIVE_FIXED, EXT2_SUPER_MAGIC, "ext"},
+       { DRIVE_FIXED, EXT3_SUPER_MAGIC, "ext"},
+       { DRIVE_FIXED, EXT4_SUPER_MAGIC, "ext"},
+       { DRIVE_REMOTE, XENFS_SUPER_MAGIC, "xenfs"},
+       { DRIVE_FIXED, BTRFS_SUPER_MAGIC, "btrfs"},
+       { DRIVE_FIXED, HFS_SUPER_MAGIC, "hfs"},
+       { DRIVE_FIXED, HFSPLUS_SUPER_MAGIC, "hfsplus"},
+       { DRIVE_FIXED, HPFS_SUPER_MAGIC, "hpfs"},
+       { DRIVE_RAMDISK, HUGETLBFS_MAGIC, "hugetlbfs"},
+       { DRIVE_CDROM, ISOFS_SUPER_MAGIC, "iso"},
+       { DRIVE_FIXED, JFFS2_SUPER_MAGIC, "jffs2"},
+       { DRIVE_RAMDISK, ANON_INODE_FS_MAGIC, "anon_inode"},
+       { DRIVE_FIXED, JFS_SUPER_MAGIC, "jfs"},
+       { DRIVE_FIXED, MINIX_SUPER_MAGIC, "minix"},
+       { DRIVE_FIXED, MINIX_SUPER_MAGIC2, "minix v2"},
+       { DRIVE_FIXED, MINIX2_SUPER_MAGIC, "minix2"},
+       { DRIVE_FIXED, MINIX2_SUPER_MAGIC2, "minix2 v2"},
+       { DRIVE_FIXED, MINIX3_SUPER_MAGIC, "minix3"},
+       { DRIVE_FIXED, MSDOS_SUPER_MAGIC, "msdos"},
+       { DRIVE_REMOTE, NCP_SUPER_MAGIC, "ncp"},
+       { DRIVE_REMOTE, NFS_SUPER_MAGIC, "nfs"},
+       { DRIVE_FIXED, NTFS_SB_MAGIC, "ntfs"},
+       { DRIVE_RAMDISK, OPENPROM_SUPER_MAGIC, "openpromfs"},
+       { DRIVE_RAMDISK, PROC_SUPER_MAGIC, "proc"},
+       { DRIVE_FIXED, QNX4_SUPER_MAGIC, "qnx4"},
+       { DRIVE_FIXED, REISERFS_SUPER_MAGIC, "reiserfs"},
+       { DRIVE_RAMDISK, ROMFS_MAGIC, "romfs"},
+       { DRIVE_REMOTE, SMB_SUPER_MAGIC, "samba"},
+       { DRIVE_RAMDISK, CGROUP_SUPER_MAGIC, "cgroupfs"},
+       { DRIVE_RAMDISK, FUTEXFS_SUPER_MAGIC, "futexfs"},
+       { DRIVE_FIXED, SYSV2_SUPER_MAGIC, "sysv2"},
+       { DRIVE_FIXED, SYSV4_SUPER_MAGIC, "sysv4"},
+       { DRIVE_RAMDISK, TMPFS_MAGIC, "tmpfs"},
+       { DRIVE_RAMDISK, DEVPTS_SUPER_MAGIC, "devpts"},
+       { DRIVE_CDROM, UDF_SUPER_MAGIC, "udf"},
+       { DRIVE_FIXED, UFS_MAGIC, "ufs"},
+       { DRIVE_FIXED, UFS_MAGIC_BW, "ufs"},
+       { DRIVE_FIXED, UFS2_MAGIC, "ufs2"},
+       { DRIVE_FIXED, UFS_CIGAM, "ufs"},
+       { DRIVE_RAMDISK, USBDEVICE_SUPER_MAGIC, "usbdev"},
+       { DRIVE_FIXED, XENIX_SUPER_MAGIC, "xenix"},
+       { DRIVE_FIXED, XFS_SB_MAGIC, "xfs"},
+       { DRIVE_RAMDISK, FUSE_SUPER_MAGIC, "fuse"},
+       { DRIVE_FIXED, V9FS_MAGIC, "9p"},
+       { DRIVE_REMOTE, CEPH_SUPER_MAGIC, "ceph"},
+       { DRIVE_RAMDISK, CONFIGFS_MAGIC, "configfs"},
+       { DRIVE_RAMDISK, ECRYPTFS_SUPER_MAGIC, "eCryptfs"},
+       { DRIVE_FIXED, EXOFS_SUPER_MAGIC, "exofs"},
+       { DRIVE_FIXED, VXFS_SUPER_MAGIC, "vxfs"},
+       { DRIVE_FIXED, VXFS_OLT_MAGIC, "vxfs_olt"},
+       { DRIVE_REMOTE, GFS2_MAGIC, "gfs2"},
+       { DRIVE_FIXED, LOGFS_MAGIC_U32, "logfs"},
+       { DRIVE_FIXED, OCFS2_SUPER_MAGIC, "ocfs2"},
+       { DRIVE_FIXED, OMFS_MAGIC, "omfs"},
+       { DRIVE_FIXED, UBIFS_SUPER_MAGIC, "ubifs"},
+       { DRIVE_UNKNOWN, 0, NULL}
+#else
+       { DRIVE_RAMDISK, "ramfs"      },
+       { DRIVE_RAMDISK, "tmpfs"      },
+       { DRIVE_RAMDISK, "proc"       },
+       { DRIVE_RAMDISK, "sysfs"      },
+       { DRIVE_RAMDISK, "debugfs"    },
+       { DRIVE_RAMDISK, "devpts"     },
+       { DRIVE_RAMDISK, "securityfs" },
+       { DRIVE_CDROM,   "iso9660"    },
+       { DRIVE_FIXED,   "ext2"       },
+       { DRIVE_FIXED,   "ext3"       },
+       { DRIVE_FIXED,   "ext4"       },
+       { DRIVE_FIXED,   "sysv"       },
+       { DRIVE_FIXED,   "reiserfs"   },
+       { DRIVE_FIXED,   "ufs"        },
+       { DRIVE_FIXED,   "vfat"       },
+       { DRIVE_FIXED,   "msdos"      },
+       { DRIVE_FIXED,   "udf"        },
+       { DRIVE_FIXED,   "hfs"        },
+       { DRIVE_FIXED,   "hpfs"       },
+       { DRIVE_FIXED,   "qnx4"       },
+       { DRIVE_FIXED,   "ntfs"       },
+       { DRIVE_FIXED,   "ntfs-3g"    },
+       { DRIVE_REMOTE,  "smbfs"      },
+       { DRIVE_REMOTE,  "fuse"       },
+       { DRIVE_REMOTE,  "nfs"        },
+       { DRIVE_REMOTE,  "nfs4"       },
+       { DRIVE_REMOTE,  "cifs"       },
+       { DRIVE_REMOTE,  "ncpfs"      },
+       { DRIVE_REMOTE,  "coda"       },
+       { DRIVE_REMOTE,  "afs"        },
+       { DRIVE_UNKNOWN, NULL         }
+#endif
+};
 
-static gboolean _wapi_unlock_file_region (int fd, off_t offset, off_t length)
+#if __linux__
+static guint32 _wapi_get_drive_type(long f_type)
 {
-       struct flock lock_data;
-       int ret;
+       _wapi_drive_type *current;
 
-       lock_data.l_type = F_UNLCK;
-       lock_data.l_whence = SEEK_SET;
-       lock_data.l_start = offset;
-       lock_data.l_len = length;
-       
-       do {
-               ret = fcntl (fd, F_SETLK, &lock_data);
-       } while(ret == -1 && errno == EINTR);
+       current = &_wapi_drive_types[0];
+       while (current->drive_type != DRIVE_UNKNOWN) {
+               if (current->fstypeid == f_type)
+                       return current->drive_type;
+               current++;
+       }
+
+       return DRIVE_UNKNOWN;
+}
+#else
+static guint32 _wapi_get_drive_type(const gchar* fstype)
+{
+       _wapi_drive_type *current;
+
+       current = &_wapi_drive_types[0];
+       while (current->drive_type != DRIVE_UNKNOWN) {
+               if (strcmp (current->fstype, fstype) == 0)
+                       break;
+
+               current++;
+       }
        
-#ifdef DEBUG
-       g_message ("%s: fcntl returns %d", __func__, ret);
+       return current->drive_type;
+}
 #endif
+
+#if defined (PLATFORM_MACOSX) || defined (__linux__)
+static guint32
+GetDriveTypeFromPath (const char *utf8_root_path_name)
+{
+       struct statfs buf;
        
-       if (ret == -1) {
-               /*
-                * if locks are not available (NFS for example),
-                * ignore the error
-                */
-               if (errno == ENOLCK
-#ifdef EOPNOTSUPP
-                   || errno == EOPNOTSUPP
-#endif
-#ifdef ENOTSUP
-                   || errno == ENOTSUP
+       if (statfs (utf8_root_path_name, &buf) == -1)
+               return DRIVE_UNKNOWN;
+#if PLATFORM_MACOSX
+       return _wapi_get_drive_type (buf.f_fstypename);
+#else
+       return _wapi_get_drive_type (buf.f_type);
 #endif
-                  ) {
-                       return (TRUE);
+}
+#else
+static guint32
+GetDriveTypeFromPath (const gchar *utf8_root_path_name)
+{
+       guint32 drive_type;
+       FILE *fp;
+       gchar buffer [512];
+       gchar **splitted;
+
+       fp = fopen ("/etc/mtab", "rt");
+       if (fp == NULL) {
+               fp = fopen ("/etc/mnttab", "rt");
+               if (fp == NULL) 
+                       return(DRIVE_UNKNOWN);
+       }
+
+       drive_type = DRIVE_NO_ROOT_DIR;
+       while (fgets (buffer, 512, fp) != NULL) {
+               splitted = g_strsplit (buffer, " ", 0);
+               if (!*splitted || !*(splitted + 1) || !*(splitted + 2)) {
+                       g_strfreev (splitted);
+                       continue;
                }
-               
-               SetLastError (ERROR_LOCK_VIOLATION);
-               return(FALSE);
+
+               /* compare given root_path_name with the one from mtab, 
+                 if length of utf8_root_path_name is zero it must be the root dir */
+               if (strcmp (*(splitted + 1), utf8_root_path_name) == 0 ||
+                   (strcmp (*(splitted + 1), "/") == 0 && strlen (utf8_root_path_name) == 0)) {
+                       drive_type = _wapi_get_drive_type (*(splitted + 2));
+                       /* it is possible this path might be mounted again with
+                          a known type...keep looking */
+                       if (drive_type != DRIVE_UNKNOWN) {
+                               g_strfreev (splitted);
+                               break;
+                       }
+               }
+
+               g_strfreev (splitted);
        }
 
-       return(TRUE);
+       fclose (fp);
+       return drive_type;
 }
+#endif
 
-gboolean LockFile (gpointer handle, guint32 offset_low, guint32 offset_high,
-                  guint32 length_low, guint32 length_high)
+guint32 GetDriveType(const gunichar2 *root_path_name)
 {
-       struct _WapiHandle_file *file_handle;
-       gboolean ok;
-       off_t offset, length;
-       int fd = GPOINTER_TO_UINT(handle);
-       
-       ok = _wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
-                                 (gpointer *)&file_handle);
-       if (ok == FALSE) {
-               g_warning ("%s: error looking up file handle %p", __func__,
-                          handle);
-               SetLastError (ERROR_INVALID_HANDLE);
-               return(FALSE);
-       }
+       gchar *utf8_root_path_name;
+       guint32 drive_type;
 
-       if (!(file_handle->fileaccess & GENERIC_READ) &&
-           !(file_handle->fileaccess & GENERIC_WRITE) &&
-           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message ("%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-#endif
-               SetLastError (ERROR_ACCESS_DENIED);
-               return(FALSE);
+       if (root_path_name == NULL) {
+               utf8_root_path_name = g_strdup (g_get_current_dir());
+               if (utf8_root_path_name == NULL) {
+                       return(DRIVE_NO_ROOT_DIR);
+               }
        }
+       else {
+               utf8_root_path_name = mono_unicode_to_external (root_path_name);
+               if (utf8_root_path_name == NULL) {
+                       DEBUG("%s: unicode conversion returned NULL", __func__);
+                       return(DRIVE_NO_ROOT_DIR);
+               }
+               
+               /* strip trailing slash for compare below */
+               if (g_str_has_suffix(utf8_root_path_name, "/") && utf8_root_path_name [1] != 0) {
+                       utf8_root_path_name[strlen(utf8_root_path_name) - 1] = 0;
+               }
+       }
+       drive_type = GetDriveTypeFromPath (utf8_root_path_name);
+       g_free (utf8_root_path_name);
 
-#ifdef HAVE_LARGE_FILE_SUPPORT
-       offset = ((gint64)offset_high << 32) | offset_low;
-       length = ((gint64)length_high << 32) | length_low;
+       return (drive_type);
+}
 
-#ifdef DEBUG
-       g_message ("%s: Locking handle %p, offset %lld, length %lld", __func__,
-                  handle, offset, length);
-#endif
+static gchar*
+get_fstypename (gchar *utfpath)
+{
+#if defined (PLATFORM_MACOSX) || defined (__linux__)
+       struct statfs stat;
+#if __linux__
+       _wapi_drive_type *current;
+#endif
+       if (statfs (utfpath, &stat) == -1)
+               return NULL;
+#if PLATFORM_MACOSX
+       return g_strdup (stat.f_fstypename);
 #else
-       offset = offset_low;
-       length = length_low;
-
-#ifdef DEBUG
-       g_message ("%s: Locking handle %p, offset %ld, length %ld", __func__,
-                  handle, offset, length);
+       current = &_wapi_drive_types[0];
+       while (current->drive_type != DRIVE_UNKNOWN) {
+               if (stat.f_type == current->fstypeid)
+                       return g_strdup (current->fstype);
+               current++;
+       }
+       return NULL;
 #endif
+#else
+       return NULL;
 #endif
-
-       return(_wapi_lock_file_region (fd, offset, length));
 }
 
-gboolean UnlockFile (gpointer handle, guint32 offset_low,
-                    guint32 offset_high, guint32 length_low,
-                    guint32 length_high)
+/* Linux has struct statfs which has a different layout */
+#if defined (PLATFORM_MACOSX) || defined (__linux__) || defined(PLATFORM_BSD) || defined(__native_client__)
+gboolean
+GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesize, int *outserial, int *maxcomp, int *fsflags, gunichar2 *fsbuffer, int fsbuffersize)
 {
-       struct _WapiHandle_file *file_handle;
-       gboolean ok;
-       off_t offset, length;
-       int fd = GPOINTER_TO_UINT(handle);
+       gchar *utfpath;
+       gchar *fstypename;
+       gboolean status = FALSE;
+       glong len;
        
-       ok = _wapi_lookup_handle (handle, WAPI_HANDLE_FILE,
-                                 (gpointer *)&file_handle);
-       if (ok == FALSE) {
-               g_warning ("%s: error looking up file handle %p", __func__,
-                          handle);
-               SetLastError (ERROR_INVALID_HANDLE);
-               return(FALSE);
-       }
+       // We only support getting the file system type
+       if (fsbuffer == NULL)
+               return 0;
        
-       if (!(file_handle->fileaccess & GENERIC_READ) &&
-           !(file_handle->fileaccess & GENERIC_WRITE) &&
-           !(file_handle->fileaccess & GENERIC_ALL)) {
-#ifdef DEBUG
-               g_message ("%s: handle %p doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, handle, file_handle->fileaccess);
-#endif
-               SetLastError (ERROR_ACCESS_DENIED);
-               return(FALSE);
+       utfpath = mono_unicode_to_external (path);
+       if ((fstypename = get_fstypename (utfpath)) != NULL){
+               gunichar2 *ret = g_utf8_to_utf16 (fstypename, -1, NULL, &len, NULL);
+               if (ret != NULL && len < fsbuffersize){
+                       memcpy (fsbuffer, ret, len * sizeof (gunichar2));
+                       fsbuffer [len] = 0;
+                       status = TRUE;
+               }
+               if (ret != NULL)
+                       g_free (ret);
+               g_free (fstypename);
        }
-
-#ifdef HAVE_LARGE_FILE_SUPPORT
-       offset = ((gint64)offset_high << 32) | offset_low;
-       length = ((gint64)length_high << 32) | length_low;
-
-#ifdef DEBUG
-       g_message ("%s: Unlocking handle %p, offset %lld, length %lld",
-                  __func__, handle, offset, length);
+       g_free (utfpath);
+       return status;
+}
 #endif
-#else
-       offset = offset_low;
-       length = length_low;
 
-#ifdef DEBUG
-       g_message ("%s: Unlocking handle %p, offset %ld, length %ld", __func__,
-                  handle, offset, length);
-#endif
-#endif
 
-       return(_wapi_unlock_file_region (fd, offset, length));
+void
+_wapi_io_init (void)
+{
+       mono_mutex_init (&stdhandle_mutex);
 }