New tests.
[mono.git] / mono / metadata / file-io.c
index 5730d476416a903beb08d67f17d89dbee9622e07..1ee2d20efc1f58808db5f1acbd6b5df3cd81357b 100644 (file)
@@ -5,8 +5,8 @@
  *     Dick Porter (dick@ximian.com)
  *     Gonzalo Paniagua Javier (gonzalo@ximian.com)
  *
- * (C) 2001,2002,2003 Ximian, Inc.
- * Copyright (c) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  */
 
 #include <config.h>
@@ -14,7 +14,6 @@
 #include <glib.h>
 #include <string.h>
 #include <errno.h>
-#include <signal.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -188,7 +187,7 @@ static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *
        while (name [len])
                ++ len;
 
-       stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
+       MONO_STRUCT_SETREF (stat, name, mono_string_new_utf16 (mono_domain_get (), name, len));
 }
 
 /* Managed file attributes have nearly but not quite the same values
@@ -345,8 +344,8 @@ ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
                return(NULL);
        }
 
+       utf8_path = mono_string_to_utf8 (path); /*If this raises there is not memory to release*/
        names = g_ptr_array_new ();
-       utf8_path = mono_string_to_utf8 (path);
 
        do {
                if ((data.cFileName[0] == '.' && data.cFileName[1] == 0) ||
@@ -386,22 +385,139 @@ ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
        return result;
 }
 
+typedef struct {
+       MonoDomain *domain;
+       gchar *utf8_path;
+       HANDLE find_handle;
+} IncrementalFind;
+       
+static gboolean
+incremental_find_check_match (IncrementalFind *handle, WIN32_FIND_DATA *data, MonoString **result)
+{
+       gchar *utf8_result;
+       gchar *full_name;
+       
+       if ((data->cFileName[0] == '.' && data->cFileName[1] == 0) || (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0))
+               return FALSE;
+
+       utf8_result = g_utf16_to_utf8 (data->cFileName, -1, NULL, NULL, NULL);
+       if (utf8_result == NULL) 
+               return FALSE;
+       
+       full_name = g_build_filename (handle->utf8_path, utf8_result, NULL);
+       g_free (utf8_result);
+       *result = mono_string_new (mono_domain_get (), full_name);
+       g_free (full_name);
+       
+       return TRUE;
+}
+
+MonoString *
+ves_icall_System_IO_MonoIO_FindFirst (MonoString *path,
+                                     MonoString *path_with_pattern,
+                                     gint32 *result_attr, gint32 *error,
+                                     gpointer *handle)
+{
+       WIN32_FIND_DATA data;
+       HANDLE find_handle;
+       IncrementalFind *ifh;
+       MonoString *result;
+       
+       *error = ERROR_SUCCESS;
+       
+       find_handle = FindFirstFile (mono_string_chars (path_with_pattern), &data);
+       
+       if (find_handle == INVALID_HANDLE_VALUE) {
+               gint32 find_error = GetLastError ();
+               *handle = NULL;
+               
+               if (find_error == ERROR_FILE_NOT_FOUND) 
+                       return NULL;
+               
+               *error = find_error;
+               return NULL;
+       }
+
+       ifh = g_new (IncrementalFind, 1);
+       ifh->find_handle = find_handle;
+       ifh->utf8_path = mono_string_to_utf8 (path);
+       ifh->domain = mono_domain_get ();
+       *handle = ifh;
+
+       while (incremental_find_check_match (ifh, &data, &result) == 0){
+               if (FindNextFile (find_handle, &data) == FALSE){
+                       int e = GetLastError ();
+                       if (e != ERROR_NO_MORE_FILES)
+                               *error = e;
+                       return NULL;
+               }
+       }
+       *result_attr = data.dwFileAttributes;
+       
+       return result;
+}
+
+MonoString *
+ves_icall_System_IO_MonoIO_FindNext (gpointer handle, gint32 *result_attr, gint32 *error)
+{
+       IncrementalFind *ifh = handle;
+       WIN32_FIND_DATA data;
+       MonoString *result;
+
+       error = ERROR_SUCCESS;
+       do {
+               if (FindNextFile (ifh->find_handle, &data) == FALSE){
+                       int e = GetLastError ();
+                       if (e != ERROR_NO_MORE_FILES)
+                               *error = e;
+                       return NULL;
+               }
+       } while (incremental_find_check_match (ifh, &data, &result) == 0);
+
+       *result_attr = data.dwFileAttributes;
+       return result;
+}
+
+int
+ves_icall_System_IO_MonoIO_FindClose (gpointer handle)
+{
+       IncrementalFind *ifh = handle;
+       gint32 error;
+       
+       if (FindClose (ifh->find_handle) == FALSE){
+               error = GetLastError ();
+       } else
+               error = ERROR_SUCCESS;
+       g_free (ifh->utf8_path);
+       g_free (ifh);
+
+       return error;
+}
+
 MonoString *
 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
 {
        MonoString *result;
        gunichar2 *buf;
-       int len;
+       int len, res_len;
 
        MONO_ARCH_SAVE_REGS;
 
-       len = MAX_PATH + 1;
+       len = MAX_PATH + 1; /*FIXME this is too smal under most unix systems.*/
        buf = g_new (gunichar2, len);
        
        *error=ERROR_SUCCESS;
        result = NULL;
 
-       if (GetCurrentDirectory (len, buf) > 0) {
+       res_len = GetCurrentDirectory (len, buf);
+       if (res_len > len) { /*buf is too small.*/
+               int old_res_len = res_len;
+               g_free (buf);
+               buf = g_new (gunichar2, res_len);
+               res_len = GetCurrentDirectory (res_len, buf) == old_res_len;
+       }
+       
+       if (res_len) {
                len = 0;
                while (buf [len])
                        ++ len;
@@ -599,6 +715,7 @@ ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
                                                   stat);
        } else {
                *error=GetLastError ();
+               memset (stat, 0, sizeof (MonoIOStat));
        }
 
        return result;
@@ -742,7 +859,7 @@ ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
        *error=ERROR_SUCCESS;
        
        offset_hi = offset >> 32;
-       offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
+       offset = SetFilePointer (handle, (gint32) (offset & 0xFFFFFFFF), &offset_hi,
                                 convert_seekorigin (origin));
 
        if(offset==INVALID_SET_FILE_POINTER) {
@@ -941,7 +1058,7 @@ MonoBoolean ves_icall_System_IO_MonoIO_DuplicateHandle (HANDLE source_process_ha
 gunichar2 
 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
 {
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
        return (gunichar2) ':'; /* colon */
 #else
        return (gunichar2) '/'; /* forward slash */
@@ -951,7 +1068,7 @@ ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
 gunichar2 
 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
 {
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
        return (gunichar2) '\\';        /* backslash */
 #else
        return (gunichar2) '/'; /* forward slash */
@@ -961,7 +1078,7 @@ ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
 gunichar2 
 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
 {
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
        return (gunichar2) '/'; /* forward slash */
 #else
        return (gunichar2) '/'; /* slash, same as DirectorySeparatorChar */
@@ -971,7 +1088,7 @@ ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
 gunichar2 
 ves_icall_System_IO_MonoIO_get_PathSeparator ()
 {
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
        return (gunichar2) ';'; /* semicolon */
 #else
        return (gunichar2) ':'; /* colon */
@@ -980,7 +1097,7 @@ ves_icall_System_IO_MonoIO_get_PathSeparator ()
 
 static const gunichar2
 invalid_path_chars [] = {
-#if defined (PLATFORM_WIN32)
+#if defined (TARGET_WIN32)
        0x0022,                         /* double quote, which seems allowed in MS.NET but should be rejected */
        0x003c,                         /* less than */
        0x003e,                         /* greater than */
@@ -1036,12 +1153,11 @@ ves_icall_System_IO_MonoIO_GetTempPath (MonoString **mono_name)
        
        if(ret>0) {
 #ifdef DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION
-                          ": Temp path is [%s] (len %d)", name, ret);
+               g_message ("%s: Temp path is [%s] (len %d)", __func__, name, ret);
 #endif
 
-               *mono_name=mono_string_new_utf16 (mono_domain_get (), name,
-                                                 ret);
+               mono_gc_wbarrier_generic_store ((gpointer) mono_name,
+                               (MonoObject*) mono_string_new_utf16 (mono_domain_get (), name, ret));
        }
 
        g_free (name);