2005-12-23 Dick Porter <dick@ximian.com>
[mono.git] / mono / metadata / file-io.c
index 220d81b7bcbc49ebc2c7427f74b5048a34f91c53..8556e9f5f3f018ddbfc8948f7a485cb1deb3051d 100644 (file)
@@ -3,18 +3,32 @@
  *
  * Author:
  *     Dick Porter (dick@ximian.com)
+ *     Gonzalo Paniagua Javier (gonzalo@ximian.com)
  *
- * (C) 2001 Ximian, Inc.
+ * (C) 2001,2002,2003 Ximian, Inc.
+ * Copyright (c) 2004,2005 Novell, Inc. (http://www.novell.com)
  */
 
 #include <config.h>
 #include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 
 #include <mono/metadata/object.h>
 #include <mono/io-layer/io-layer.h>
 #include <mono/metadata/file-io.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
+#include <mono/utils/strenc.h>
 
 #undef DEBUG
 
@@ -154,10 +168,10 @@ static guint32 convert_seekorigin(MonoSeekOrigin origin)
 
 static gint64 convert_filetime (const FILETIME *filetime)
 {
-       gint64 *ticks;
-
-       ticks = (gint64 *)filetime;
-       return *ticks;
+       guint64 ticks = filetime->dwHighDateTime;
+       ticks <<= 32;
+       ticks += filetime->dwLowDateTime;
+       return (gint64)ticks;
 }
 
 static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
@@ -177,15 +191,27 @@ static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *
        stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
 }
 
+/* Managed file attributes have nearly but not quite the same values
+ * as the w32 equivalents.
+ */
+static guint32 convert_attrs(MonoFileAttributes attrs)
+{
+       if(attrs & FileAttributes_Encrypted) {
+               attrs |= FILE_ATTRIBUTE_ENCRYPTED;
+       }
+       
+       return(attrs);
+}
+
 /* System.IO.MonoIO internal calls */
 
 MonoBoolean
 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=CreateDirectory (mono_string_chars (path), NULL);
@@ -199,10 +225,10 @@ ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
 MonoBoolean
 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=RemoveDirectory (mono_string_chars (path));
@@ -213,79 +239,276 @@ ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
        return(ret);
 }
 
-HANDLE 
-ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat,
-                                         gint32 *error)
+static gint
+get_error_from_g_file_error (gint error)
 {
-       MONO_ARCH_SAVE_REGS;
+       switch (error) {
+       case G_FILE_ERROR_ACCES:
+               error = ERROR_ACCESS_DENIED;
+               break;
+       case G_FILE_ERROR_NAMETOOLONG:
+               error = ERROR_FILENAME_EXCED_RANGE;
+               break;
+       case G_FILE_ERROR_NOENT:
+               error = ERROR_FILE_NOT_FOUND;
+               break;
+       case G_FILE_ERROR_NOTDIR:
+               error = ERROR_FILE_NOT_FOUND;
+               break;
+       case G_FILE_ERROR_ROFS:
+               error = ERROR_ACCESS_DENIED;
+               break;
+       case G_FILE_ERROR_TXTBSY:
+               error = ERROR_SHARING_VIOLATION;
+               break;
+       case G_FILE_ERROR_NOSPC:
+               error = ERROR_HANDLE_DISK_FULL;
+               break;
+       case G_FILE_ERROR_NFILE:
+       case G_FILE_ERROR_MFILE:
+               error = ERROR_TOO_MANY_OPEN_FILES;
+               break;
+       case G_FILE_ERROR_BADF:
+               error = ERROR_INVALID_HANDLE;
+               break;
+       case G_FILE_ERROR_INVAL:
+               error = ERROR_INVALID_PARAMETER;
+               break;
+       case G_FILE_ERROR_AGAIN:
+               error = ERROR_SHARING_VIOLATION;
+               break;
+       case G_FILE_ERROR_INTR:
+               error = ERROR_IO_PENDING;
+               break;
+       case G_FILE_ERROR_PERM:
+               error = ERROR_ACCESS_DENIED;
+               break;
+       case G_FILE_ERROR_FAILED:
+               error = ERROR_INVALID_PARAMETER;
+               break;
+       case G_FILE_ERROR_NXIO:
+       case G_FILE_ERROR_NOMEM:
+       case G_FILE_ERROR_NODEV:
+       case G_FILE_ERROR_FAULT:
+       case G_FILE_ERROR_LOOP:
+       case G_FILE_ERROR_PIPE:
+       case G_FILE_ERROR_IO:
+       default:
+               error = ERROR_GEN_FAILURE;
+               break;
 
-       WIN32_FIND_DATA data;
-       HANDLE result;
+       }
 
-       *error=ERROR_SUCCESS;
-       
-       result = FindFirstFile (mono_string_chars (path), &data);
+       return error;
+}
 
-       /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
+static gint
+file_compare (gconstpointer a, gconstpointer b)
+{
+       gchar *astr = *(gchar **) a;
+       gchar *bstr = *(gchar **) b;
 
-       if (result != INVALID_HANDLE_VALUE) {
-               convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
-                                                  &data.cFileName [0], stat);
-       } else {
-               *error=GetLastError ();
+       return strcmp (astr, bstr);
+}
+
+static gint
+get_file_attributes (const char *filename)
+{
+#ifdef PLATFORM_WIN32
+       gunichar2 *full16;
+       gint result;
+
+       full16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+       if (full16 == NULL) {
+               g_message ("Bad encoding for '%s'\n", filename);
+               return FALSE;
        }
 
+       result = GetFileAttributes (full16);
+       g_free (full16);
        return result;
+#else
+       struct stat buf;
+       struct stat linkbuf;
+       int result;
+       int file_attrs;
+
+       result = lstat (filename, &buf);
+       if (result == -1)
+               return FALSE;
+
+       if ((buf.st_mode & S_IFLNK) != 0) {
+               result = stat (filename, &linkbuf);
+               if (result != -1) {
+                       buf = linkbuf;
+               } else {
+                       buf.st_mode |= ~S_IFDIR; /* force it to be returned as regular file */
+               }
+       }
+
+       file_attrs = 0;
+       if ((buf.st_mode & S_IFDIR) != 0)
+               file_attrs |= FILE_ATTRIBUTE_DIRECTORY;
+       else
+               file_attrs |= FILE_ATTRIBUTE_ARCHIVE;
+
+       if ((buf.st_mode & S_IWUSR) == 0)
+               file_attrs |= FILE_ATTRIBUTE_READONLY;
+
+       if (*filename == '.')
+               file_attrs |= FILE_ATTRIBUTE_HIDDEN;
+
+       return file_attrs;
+#endif
 }
 
-MonoBoolean
-ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat,
-                                        gint32 *error)
+static gboolean
+test_file (const char *filename, int attrs, int mask)
 {
-       MONO_ARCH_SAVE_REGS;
+       int file_attr;
 
-       WIN32_FIND_DATA data;
-       gboolean result;
+       file_attr = get_file_attributes (filename);
+       if (file_attr == FALSE)
+               return FALSE;
 
-       *error=ERROR_SUCCESS;
+       return ((file_attr & mask) == attrs);
+}
+
+/* scandir using glib */
+static gint
+mono_io_scandir (const gchar *dirname, const gchar *pattern, int attrs,
+               int mask, gchar ***namelist)
+{
+       GError *error = NULL;
+       GDir *dir;
+       GPtrArray *names;
+       const gchar *name;
+       gint result;
+       GPatternSpec *patspec;
+       gchar *full_name;
+
+       mask = convert_attrs (mask);
+       *namelist = NULL;
+       dir = g_dir_open (dirname, 0, &error);
+       if (dir == NULL) {
+               /* g_dir_open returns ENOENT on directories on which we don't
+                * have read/x permission */
+               gint errnum = get_error_from_g_file_error (error->code);
+               g_error_free (error);
+               if (errnum == ERROR_FILE_NOT_FOUND && g_file_test (dirname, G_FILE_TEST_IS_DIR))
+                       errnum = ERROR_ACCESS_DENIED;
+
+               SetLastError (errnum);
+               return -1;
+       }
+
+       patspec = g_pattern_spec_new (pattern);
+       names = g_ptr_array_new ();
+       while ((name = g_dir_read_name (dir)) != NULL) {
+               if (!g_pattern_match_string (patspec, name))
+                       continue;
+
+               full_name = g_build_filename (dirname, name, NULL);
+               if (FALSE == test_file (full_name, attrs, mask)) {
+                       g_free (full_name);
+                       continue;
+               }
+
+               g_ptr_array_add (names, full_name);
+       }
        
-       result = FindNextFile (find, &data);
-       if (result) {
-               convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
-                                                  &data.cFileName [0], stat);
+       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 {
-               *error=GetLastError ();
+               g_ptr_array_free (names, TRUE);
        }
 
        return result;
 }
 
-MonoBoolean
-ves_icall_System_IO_MonoIO_FindClose (HANDLE find, gint32 *error)
+MonoArray *
+ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *_path, MonoString *_pattern,
+                                       gint attrs, gint mask, gint32 *error)
 {
+       MonoDomain *domain;
+       MonoArray *result;
+       gchar **namelist;
+       gchar *path;
+       gchar *pattern;
+       int i, nnames;
+       int removed;
+       MonoString *str_name;
+#ifndef PLATFORM_WIN32
+       gunichar2 *utf16;
+       gsize nbytes;
+#endif
+
        MONO_ARCH_SAVE_REGS;
 
-       gboolean ret;
-       
-       *error=ERROR_SUCCESS;
-       
-       ret=FindClose (find);
-       if(ret==FALSE) {
-               *error=GetLastError ();
+       *error = ERROR_SUCCESS;
+
+       path = mono_string_to_utf8 (_path);
+       pattern = mono_string_to_utf8 (_pattern);
+       nnames = mono_io_scandir (path, pattern, attrs, mask, &namelist);
+       if (nnames < 0) {
+               *error = GetLastError ();
+               g_free (pattern);
+               g_free (path);
+               return NULL;
        }
-       
-       return(ret);
+
+       domain = mono_domain_get ();
+       result = mono_array_new (domain, mono_defaults.string_class, nnames);
+       removed = 0;
+       for (i = 0; i < nnames; i++) {
+#if PLATFORM_WIN32
+               str_name = mono_string_new (domain, namelist [i]);
+#else
+               utf16 = mono_unicode_from_external (namelist [i], &nbytes);
+               if (utf16 == NULL) {
+                       g_message ("Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODING\n",
+                               namelist [i]);
+                       removed++;
+                       continue;
+               }
+               str_name = mono_string_from_utf16 (utf16);
+               g_free (utf16);
+#endif
+               mono_array_set (result, MonoString *, i - removed, str_name);
+       }
+
+       if (removed > 0) {
+               MonoArray *shrinked;
+               shrinked = mono_array_new (domain, mono_defaults.string_class, nnames - removed);
+               for (i = 0; i < (nnames - removed); i++) {
+                       MonoString *str;
+                       str = mono_array_get (result, MonoString *, i);
+                       mono_array_set (shrinked, MonoString *,i, str);
+               }
+               result = shrinked;
+       }
+
+       g_strfreev (namelist);
+       g_free (pattern);
+       g_free (path);
+       return result;
 }
 
 MonoString *
 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        MonoString *result;
        gunichar2 *buf;
        int len;
 
+       MONO_ARCH_SAVE_REGS;
+
        len = MAX_PATH + 1;
        buf = g_new (gunichar2, len);
        
@@ -310,10 +533,10 @@ MonoBoolean
 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
                                                gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=SetCurrentDirectory (mono_string_chars (path));
@@ -328,10 +551,10 @@ MonoBoolean
 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
                                     gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
@@ -346,10 +569,10 @@ MonoBoolean
 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
                                     MonoBoolean overwrite, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
@@ -363,10 +586,10 @@ ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
 MonoBoolean
 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=DeleteFile (mono_string_chars (path));
@@ -380,14 +603,22 @@ ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
 gint32 
 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gint32 ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=GetFileAttributes (mono_string_chars (path));
-       if(ret==INVALID_FILE_ATTRIBUTES) {
+
+       /* 
+        * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
+        * headers is wrong, hence this temporary workaround.
+        * See
+        * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
+        */
+       if (ret==-1) {
+         /* if(ret==INVALID_FILE_ATTRIBUTES) { */
                *error=GetLastError ();
        }
        
@@ -398,13 +629,14 @@ MonoBoolean
 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
                                              gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
-       ret=SetFileAttributes (mono_string_chars (path), attrs);
+       ret=SetFileAttributes (mono_string_chars (path),
+                              convert_attrs (attrs));
        if(ret==FALSE) {
                *error=GetLastError ();
        }
@@ -415,10 +647,10 @@ ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
 gint32
 ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=GetFileType (handle);
@@ -436,11 +668,11 @@ MonoBoolean
 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
                                        gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean result;
        WIN32_FILE_ATTRIBUTE_DATA data;
 
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
@@ -459,17 +691,18 @@ ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
 HANDLE 
 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
                                 gint32 access_mode, gint32 share,
-                                gint32 *error)
+                                MonoBoolean async, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        HANDLE ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=CreateFile (mono_string_chars (filename),
                        convert_access (access_mode), convert_share (share),
-                       NULL, convert_mode (mode), FILE_ATTRIBUTE_NORMAL,
+                       NULL, convert_mode (mode),
+                       FILE_ATTRIBUTE_NORMAL | ((async) ? FILE_FLAG_OVERLAPPED : 0),
                        NULL);
        if(ret==INVALID_HANDLE_VALUE) {
                *error=GetLastError ();
@@ -481,10 +714,10 @@ ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
 MonoBoolean
 ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=CloseHandle (handle);
@@ -500,12 +733,12 @@ ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
                                 gint32 dest_offset, gint32 count,
                                 gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        guchar *buffer;
        gboolean result;
        guint32 n;
 
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        if (dest_offset + count > mono_array_length (dest))
@@ -527,12 +760,12 @@ ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
                                  gint32 src_offset, gint32 count,
                                  gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        guchar *buffer;
        gboolean result;
        guint32 n;
 
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        if (src_offset + count > mono_array_length (src))
@@ -553,10 +786,10 @@ gint64
 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
                                 gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        guint32 offset_hi;
 
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        offset_hi = offset >> 32;
@@ -573,10 +806,10 @@ ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
 MonoBoolean
 ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        ret=FlushFileBuffers (handle);
@@ -590,11 +823,11 @@ ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
 gint64 
 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gint64 length;
        guint32 length_hi;
 
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        length = GetFileSize (handle, &length_hi);
@@ -609,13 +842,13 @@ MonoBoolean
 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
                                      gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gint64 offset, offset_set;
        gint32 offset_hi;
        gint32 length_hi;
        gboolean result;
 
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        /* save file pointer */
@@ -660,13 +893,13 @@ ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
                                        gint64 last_access_time,
                                        gint64 last_write_time, gint32 *error)
 {
-       MONO_ARCH_SAVE_REGS;
-
        gboolean ret;
        const FILETIME *creation_filetime;
        const FILETIME *last_access_filetime;
        const FILETIME *last_write_filetime;
 
+       MONO_ARCH_SAVE_REGS;
+
        *error=ERROR_SUCCESS;
        
        if (creation_time < 0)
@@ -720,11 +953,11 @@ MonoBoolean
 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
                                       HANDLE *write_handle)
 {
-       MONO_ARCH_SAVE_REGS;
-
        SECURITY_ATTRIBUTES attr;
        gboolean ret;
        
+       MONO_ARCH_SAVE_REGS;
+
        attr.nLength=sizeof(SECURITY_ATTRIBUTES);
        attr.bInheritHandle=TRUE;
        attr.lpSecurityDescriptor=NULL;
@@ -741,57 +974,60 @@ ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
 gunichar2 
 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
 {
-       MONO_ARCH_SAVE_REGS;
-
 #if defined (PLATFORM_WIN32)
-       return (gunichar2) 0x003a;      /* colon */
+       return (gunichar2) ':'; /* colon */
 #else
-       return (gunichar2) 0x002f;      /* forward slash */
+       return (gunichar2) '/'; /* forward slash */
 #endif
 }
 
 gunichar2 
 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
 {
-       MONO_ARCH_SAVE_REGS;
-
 #if defined (PLATFORM_WIN32)
-       return (gunichar2) 0x005c;      /* backslash */
+       return (gunichar2) '\\';        /* backslash */
 #else
-       return (gunichar2) 0x002f;      /* forward slash */
+       return (gunichar2) '/'; /* forward slash */
 #endif
 }
 
 gunichar2 
 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
 {
-       MONO_ARCH_SAVE_REGS;
-
 #if defined (PLATFORM_WIN32)
-       return (gunichar2) 0x002f;      /* forward slash */
+       return (gunichar2) '/'; /* forward slash */
 #else
-       return (gunichar2) 0x005c;      /* backslash */
+       return (gunichar2) '/'; /* slash, same as DirectorySeparatorChar */
 #endif
 }
 
 gunichar2 
 ves_icall_System_IO_MonoIO_get_PathSeparator ()
 {
-       MONO_ARCH_SAVE_REGS;
-
 #if defined (PLATFORM_WIN32)
-       return (gunichar2) 0x003b;      /* semicolon */
+       return (gunichar2) ';'; /* semicolon */
 #else
-       return (gunichar2) 0x003a;      /* colon */
+       return (gunichar2) ':'; /* colon */
 #endif
 }
 
-static gunichar2 invalid_path_chars [] = {
+static const gunichar2
+invalid_path_chars [] = {
 #if defined (PLATFORM_WIN32)
-       0x0022,                         /* double quote */
+       0x0022,                         /* double quote, which seems allowed in MS.NET but should be rejected */
        0x003c,                         /* less than */
        0x003e,                         /* greater than */
        0x007c,                         /* pipe */
+       0x0008,
+       0x0010,
+       0x0011,
+       0x0012,
+       0x0014,
+       0x0015,
+       0x0016,
+       0x0017,
+       0x0018,
+       0x0019,
 #endif
        0x0000                          /* null */
 };
@@ -799,19 +1035,78 @@ static gunichar2 invalid_path_chars [] = {
 MonoArray *
 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
 {
-       MONO_ARCH_SAVE_REGS;
-
        MonoArray *chars;
        MonoDomain *domain;
        int i, n;
 
-       domain = mono_domain_get ();
-       chars = mono_array_new (domain, mono_defaults.char_class, 5);
+       MONO_ARCH_SAVE_REGS;
 
+       domain = mono_domain_get ();
        n = sizeof (invalid_path_chars) / sizeof (gunichar2);
+       chars = mono_array_new (domain, mono_defaults.char_class, n);
 
        for (i = 0; i < n; ++ i)
                mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
        
        return chars;
 }
+
+gint32
+ves_icall_System_IO_MonoIO_GetTempPath (MonoString **mono_name)
+{
+       gunichar2 *name;
+       int ret;
+
+       name=g_new0 (gunichar2, 256);
+       
+       ret=GetTempPath (256, name);
+       if(ret>255) {
+               /* Buffer was too short. Try again... */
+               g_free (name);
+               name=g_new0 (gunichar2, ret+2); /* include the terminator */
+               ret=GetTempPath (ret, name);
+       }
+       
+       if(ret>0) {
+#ifdef DEBUG
+               g_message (G_GNUC_PRETTY_FUNCTION
+                          ": Temp path is [%s] (len %d)", name, ret);
+#endif
+
+               *mono_name=mono_string_new_utf16 (mono_domain_get (), name,
+                                                 ret);
+       }
+
+       g_free (name);
+       
+       return(ret);
+}
+
+void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
+                                     gint64 length, gint32 *error)
+{
+       gboolean ret;
+       
+       *error=ERROR_SUCCESS;
+       
+       ret=LockFile (handle, position & 0xFFFFFFFF, position >> 32,
+                     length & 0xFFFFFFFF, length >> 32);
+       if (ret == FALSE) {
+               *error = GetLastError ();
+       }
+}
+
+void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
+                                       gint64 length, gint32 *error)
+{
+       gboolean ret;
+       
+       *error=ERROR_SUCCESS;
+       
+       ret=UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
+                       length & 0xFFFFFFFF, length >> 32);
+       if (ret == FALSE) {
+               *error = GetLastError ();
+       }
+}
+