Merge pull request #487 from mayerwin/patch-1
[mono.git] / mono / metadata / file-io.c
index 0aa7ad244f66a4b15b845f0d1badc6b8f919ba52..ac7b0c41cc3f4bac4f2aa4e50c6bf68ef12d9c7b 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
  */
 
 #include <config.h>
@@ -31,6 +32,7 @@
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/marshal.h>
 #include <mono/utils/strenc.h>
+#include <utils/mono-io-portability.h>
 
 #undef DEBUG
 
@@ -173,21 +175,13 @@ static gint64 convert_filetime (const FILETIME *filetime)
        return (gint64)ticks;
 }
 
-static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
+static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, MonoIOStat *stat)
 {
-       int len;
-       
        stat->attributes = data->dwFileAttributes;
        stat->creation_time = convert_filetime (&data->ftCreationTime);
        stat->last_access_time = convert_filetime (&data->ftLastAccessTime);
        stat->last_write_time = convert_filetime (&data->ftLastWriteTime);
        stat->length = ((gint64)data->nFileSizeHigh << 32) | data->nFileSizeLow;
-
-       len = 0;
-       while (name [len])
-               ++ 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
@@ -305,6 +299,18 @@ ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
        return(ret);
 }
 
+static gchar *
+get_search_dir (MonoString *pattern)
+{
+       gchar *p;
+       gchar *result;
+
+       p = mono_string_to_utf8 (pattern);
+       result = g_path_get_dirname (p);
+       g_free (p);
+       return result;
+}
+
 MonoArray *
 ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
                                                 MonoString *path_with_pattern,
@@ -317,33 +323,41 @@ ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
        WIN32_FIND_DATA data;
        HANDLE find_handle;
        GPtrArray *names;
-       gchar *utf8_result;
+       gchar *utf8_path, *utf8_result, *full_name;
+       gint32 attributes;
        
        MONO_ARCH_SAVE_REGS;
 
+       result = NULL;
        *error = ERROR_SUCCESS;
 
        domain = mono_domain_get ();
        mask = convert_attrs (mask);
+       attributes = get_file_attributes (mono_string_chars (path));
+       if (attributes != -1) {
+               if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+                       *error = ERROR_INVALID_NAME;
+                       goto leave;
+               }
+       } else {
+               *error = GetLastError ();
+               goto leave;
+       }
        
-       find_handle = FindFirstFile (mono_string_chars (path_with_pattern),
-                                    &data);
+       find_handle = FindFirstFile (mono_string_chars (path_with_pattern), &data);
        if (find_handle == INVALID_HANDLE_VALUE) {
                gint32 find_error = GetLastError ();
                
-               if (find_error == ERROR_FILE_NOT_FOUND) {
+               if (find_error == ERROR_FILE_NOT_FOUND || find_error == ERROR_NO_MORE_FILES) {
                        /* No files, so just return an empty array */
-                       result = mono_array_new (domain,
-                                                mono_defaults.string_class,
-                                                0);
-
-                       return(result);
+                       goto leave;
                }
                
                *error = find_error;
-               return(NULL);
+               goto leave;
        }
 
+       utf8_path = get_search_dir (path_with_pattern);
        names = g_ptr_array_new ();
 
        do {
@@ -358,7 +372,10 @@ ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
                                continue;
                        }
                        
-                       g_ptr_array_add (names, utf8_result);
+                       full_name = g_build_filename (utf8_path, utf8_result, NULL);
+                       g_ptr_array_add (names, full_name);
+
+                       g_free (utf8_result);
                }
        } while(FindNextFile (find_handle, &data));
 
@@ -376,7 +393,13 @@ ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
                g_free (g_ptr_array_index (names, i));
        }
        g_ptr_array_free (names, TRUE);
-       
+       g_free (utf8_path);
+
+leave:
+       // If there's no array and no error, then return an empty array.
+       if (result == NULL && *error == ERROR_SUCCESS)
+               result = mono_array_new (domain, mono_defaults.string_class, 0);
+
        return result;
 }
 
@@ -705,9 +728,7 @@ ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
        result = get_file_attributes_ex (mono_string_chars (path), &data);
 
        if (result) {
-               convert_win32_file_attribute_data (&data,
-                                                  mono_string_chars (path),
-                                                  stat);
+               convert_win32_file_attribute_data (&data, stat);
        } else {
                *error=GetLastError ();
                memset (stat, 0, sizeof (MonoIOStat));
@@ -801,6 +822,8 @@ ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
        MONO_ARCH_SAVE_REGS;
 
        *error=ERROR_SUCCESS;
+
+       MONO_CHECK_ARG_NULL (dest);
        
        if (dest_offset + count > mono_array_length (dest))
                return 0;
@@ -828,6 +851,8 @@ ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
        MONO_ARCH_SAVE_REGS;
 
        *error=ERROR_SUCCESS;
+
+       MONO_CHECK_ARG_NULL (src);
        
        if (src_offset + count > mono_array_length (src))
                return 0;
@@ -1076,7 +1101,10 @@ ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
 #if defined (TARGET_WIN32)
        return (gunichar2) '/'; /* forward slash */
 #else
-       return (gunichar2) '/'; /* slash, same as DirectorySeparatorChar */
+       if (IS_PORTABILITY_SET)
+               return (gunichar2) '\\';        /* backslash */
+       else
+               return (gunichar2) '/'; /* forward slash */
 #endif
 }
 
@@ -1188,3 +1216,35 @@ void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
        }
 }
 
+//Support for io-layer free mmap'd files.
+
+#if defined (TARGET_IOS) || defined (TARGET_ANDROID)
+
+gint64
+mono_filesize_from_path (MonoString *string)
+{
+       struct stat buf;
+       gint64 res;
+       char *path = mono_string_to_utf8 (string);
+       
+       if (stat (path, &buf) == -1)
+               res = -1;
+       else
+               res = (gint64)buf.st_size;
+
+       g_free (path);
+       return res;
+}
+
+gint64
+mono_filesize_from_fd (int fd)
+{
+       struct stat buf;
+
+       if (fstat (fd, &buf) == -1)
+               return (gint64)-1;
+
+       return (gint64)buf.st_size;
+}
+
+#endif