2002-04-23 Patrik Torstensson <patrik.torstensson@labs2.com>
[mono.git] / mono / metadata / file-io.c
index f8118083a3065e665a653654e05f253c7e672fb7..56a3d7ab3e1b2608648a320e87418d1b544fa6df 100644 (file)
 #include <mono/io-layer/io-layer.h>
 #include <mono/metadata/file-io.h>
 #include <mono/metadata/exception.h>
+#include <mono/metadata/appdomain.h>
 
 #define DEBUG
 
+/* conversion functions */
+
 static guint32 convert_mode(MonoFileMode mono_mode)
 {
        guint32 mode;
@@ -101,6 +104,7 @@ static guint32 convert_share(MonoFileShare mono_share)
        return(share);
 }
 
+#if 0
 static guint32 convert_stdhandle(guint32 fd)
 {
        guint32 stdhandle;
@@ -122,6 +126,7 @@ static guint32 convert_stdhandle(guint32 fd)
        
        return(stdhandle);
 }
+#endif
 
 static guint32 convert_seekorigin(MonoSeekOrigin origin)
 {
@@ -147,224 +152,446 @@ static guint32 convert_seekorigin(MonoSeekOrigin origin)
        return(w32origin);
 }
 
-static MonoException *get_io_exception(const guchar *msg)
+static gint64 convert_filetime (const FILETIME *filetime)
 {
-       static MonoException *ex = NULL;
+       gint64 *ticks;
 
-       if(ex==NULL) {
-               ex=(MonoException *)mono_exception_from_name(
-                       mono_defaults.corlib, "System.IO", "IOException");
-       }
+       ticks = (gint64 *)filetime;
+       return *ticks;
+}
 
-       ex->message=mono_string_new(msg);
+static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
+{
+       int len;
        
-       return(ex);
+       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;
+
+       stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
 }
 
-/* fd must be one of stdin (value 0), stdout (1) or stderr (2).  These
- * values must be hardcoded in corlib.
- */
-HANDLE ves_icall_System_PAL_OpSys_GetStdHandle(MonoObject *this,
-                                              gint32 fd)
+/* System.IO.MonoIO internal calls */
+
+gint32 
+ves_icall_System_IO_MonoIO_GetLastError ()
 {
-       HANDLE handle;
+       return GetLastError ();
+}
 
-       if(fd!=0 && fd!=1 && fd!=2) {
-               mono_raise_exception(
-                       get_io_exception("Invalid file descriptor"));
-       }
-       
-       handle=GetStdHandle(convert_stdhandle(fd));
-       
-       return(handle);
+gboolean 
+ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path)
+{
+       gunichar2 *utf16_path;
+       gboolean result;
+
+       utf16_path = mono_string_to_utf16 (path);
+       result = CreateDirectory (utf16_path, NULL);
+       g_free (utf16_path);
+
+       return result;
 }
 
-gint32 ves_icall_System_PAL_OpSys_ReadFile(MonoObject *this, HANDLE handle, MonoArray *buffer, gint32 offset, gint32 count)
+gboolean 
+ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path)
 {
-       gboolean ret;
-       guint32 bytesread;
-       guchar *buf;
-       gint32 alen;
+       gunichar2 *utf16_path;
+       gboolean result;
 
-       if(handle == INVALID_HANDLE_VALUE) {
-               mono_raise_exception(get_io_exception("Invalid handle"));
-       }
+       utf16_path = mono_string_to_utf16 (path);
+       result = RemoveDirectory (utf16_path);
+       g_free (utf16_path);
 
-       alen=mono_array_length(buffer);
-       if(offset+count>alen) {
-               return(0);
-       }
-       
-       buf=mono_array_addr(buffer, guchar, offset);
-       
-       ret=ReadFile(handle, buf, count, &bytesread, NULL);
-       
-       return(bytesread);
+       return result;
 }
 
-gint32 ves_icall_System_PAL_OpSys_WriteFile(MonoObject *this, HANDLE handle,  MonoArray *buffer, gint32 offset, gint32 count)
+HANDLE 
+ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat)
 {
-       gboolean ret;
-       guint32 byteswritten;
-       guchar *buf;
-       gint32 alen;
-       
-       if(handle == INVALID_HANDLE_VALUE) {
-               mono_raise_exception(get_io_exception("Invalid handle"));
-       }
+       gunichar2 *utf16_path;
+       WIN32_FIND_DATA data;
+       HANDLE result;
 
-       alen=mono_array_length(buffer);
-       if(offset+count>alen) {
-               return(0);
-       }
-       
-       buf=mono_array_addr(buffer, guchar, offset);
-       
-       ret=WriteFile(handle, buf, count, &byteswritten, NULL);
-       
-       return(byteswritten);
+       utf16_path = mono_string_to_utf16 (path);
+       result = FindFirstFile (utf16_path, &data);
+       g_free (utf16_path);
+
+       /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
+
+       if (result != INVALID_HANDLE_VALUE)
+               convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
+                                                  &data.cFileName [0], stat);
+
+       return result;
 }
 
-gint32 ves_icall_System_PAL_OpSys_SetLengthFile(MonoObject *this, HANDLE handle, gint64 length)
+gboolean 
+ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat)
 {
-       /* FIXME: Should this put the file pointer back to where it
-        * was before we started setting the length? The spec doesnt
-        * say, as usual
-        */
+       WIN32_FIND_DATA data;
+       gboolean result;
 
-       gboolean ret;
-       gint32 lenlo, lenhi, retlo;
-       
-       if(handle == INVALID_HANDLE_VALUE) {
-               mono_raise_exception(get_io_exception("Invalid handle"));
-       }
+       result = FindNextFile (find, &data);
+       if (result)
+               convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
+                                                  &data.cFileName [0], stat);
 
-       lenlo=length & 0xFFFFFFFF;
-       lenhi=length >> 32;
+       return result;
+}
 
-       retlo=SetFilePointer(handle, lenlo, &lenhi, FILE_BEGIN);
-       ret=SetEndOfFile(handle);
+gboolean 
+ves_icall_System_IO_MonoIO_FindClose (HANDLE find)
+{
+       return FindClose (find);
+}
+
+MonoString *
+ves_icall_System_IO_MonoIO_GetCurrentDirectory ()
+{
+       MonoString *result;
+       gunichar2 *buf;
+       int len;
+
+       len = MAX_PATH + 1;
+       buf = g_new (gunichar2, len);
        
-       if(ret==FALSE) {
-               mono_raise_exception(get_io_exception("IO Exception"));
+       result = NULL;
+       if (GetCurrentDirectory (len, buf) > 0) {
+               len = 0;
+               while (buf [len])
+                       ++ len;
+
+               result = mono_string_new_utf16 (mono_domain_get (), buf, len);
        }
-       
-       return(0);
+
+       g_free (buf);
+       return result;
 }
 
-HANDLE ves_icall_System_PAL_OpSys_OpenFile(MonoObject *this, MonoString *path, gint32 mode, gint32 access, gint32 share)
+gboolean 
+ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path)
 {
-       HANDLE handle;
-       char *filename;
-       
-       filename=mono_string_to_utf16(path);
+       gunichar2 *utf16_path;
+       gboolean result;
        
-       handle=CreateFile(filename, convert_access(access),
-                         convert_share(share), NULL, convert_mode(mode),
-                         FILE_ATTRIBUTE_NORMAL, NULL);
+       utf16_path = mono_string_to_utf16 (path);
+       result = SetCurrentDirectory (utf16_path);
+       g_free (utf16_path);
 
-       g_free(filename);
-       
-       /* fixme: raise mor appropriate exceptions (errno) */
-       if(handle == INVALID_HANDLE_VALUE) {
-               mono_raise_exception(get_io_exception("Invalid handle"));
-       }
+       return result;
+}
+
+gboolean 
+ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest)
+{
+       gunichar2 *utf16_path, *utf16_dest;
+       gboolean result;
+
+       utf16_path = mono_string_to_utf16 (path);
+       utf16_dest = mono_string_to_utf16 (dest);
+       result = MoveFile (utf16_path, utf16_dest);
+       g_free (utf16_path);
+       g_free (utf16_dest);
 
-       return(handle);
+       return result;
 }
 
-void ves_icall_System_PAL_OpSys_CloseFile(MonoObject *this, HANDLE handle)
+gboolean 
+ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest, gboolean overwrite)
 {
-       if(handle == INVALID_HANDLE_VALUE) {
-               mono_raise_exception(get_io_exception("Invalid handle"));
-       }
+       gunichar2 *utf16_path, *utf16_dest;
+       gboolean result;
+
+       utf16_path = mono_string_to_utf16 (path);
+       utf16_dest = mono_string_to_utf16 (dest);
+       result = CopyFile (utf16_path, utf16_dest, !overwrite);
+       g_free (utf16_path);
+       g_free (utf16_dest);
 
-       CloseHandle(handle);
+       return result;
 }
 
-gint64 ves_icall_System_PAL_OpSys_SeekFile(MonoObject *this, HANDLE handle,
-                                          gint64 offset, gint32 origin)
+gboolean 
+ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path)
 {
-       gint64 ret;
-       gint32 offsetlo, offsethi, retlo;
-       
-       if(handle == INVALID_HANDLE_VALUE) {
-               mono_raise_exception(get_io_exception("Invalid handle"));
-       }
+       gunichar2 *utf16_path;
+       gboolean result;
 
-       offsetlo=offset & 0xFFFFFFFF;
-       offsethi=offset >> 32;
+       utf16_path = mono_string_to_utf16 (path);
+       result = DeleteFile (utf16_path);
+       g_free (utf16_path);
 
-       retlo=SetFilePointer(handle, offset, &offsethi,
-                            convert_seekorigin(origin));
-       
-       ret=((gint64)offsethi << 32) + offsetlo;
+       return result;
+}
+
+gint32 
+ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path)
+{
+       gunichar2 *utf16_path;
+       gint32 result;
 
-       return(ret);
+       utf16_path = mono_string_to_utf16 (path);
+       result = GetFileAttributes (utf16_path);
+       g_free (utf16_path);
+
+       return result;
 }
 
-void ves_icall_System_PAL_OpSys_DeleteFile(MonoObject *this, MonoString *path)
+gboolean
+ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs)
 {
-       char *filename;
-       
-       filename=mono_string_to_utf16(path);
-       
-       DeleteFile(filename);
+       gunichar2 *utf16_path;
+       gboolean result;
+
+       utf16_path = mono_string_to_utf16 (path);
+       result = SetFileAttributes (utf16_path, attrs);
+       g_free (utf16_path);
 
-       g_free(filename);
+       return result;
 }
 
-gboolean ves_icall_System_PAL_OpSys_ExistsFile(MonoObject *this, MonoString *path)
+gboolean 
+ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat)
 {
-       return(FALSE);
+       gunichar2 *utf16_path;
+       gboolean result;
+       WIN32_FILE_ATTRIBUTE_DATA data;
+
+       utf16_path = mono_string_to_utf16 (path);
+       result = GetFileAttributesEx (utf16_path, GetFileExInfoStandard, &data);
+       g_free (utf16_path);
+
+       if (result)
+               convert_win32_file_attribute_data (&data, utf16_path, stat);
+
+       return result;
 }
 
-gboolean ves_icall_System_PAL_OpSys_GetFileTime(HANDLE handle, gint64 *createtime, gint64 *lastaccess, gint64 *lastwrite)
+HANDLE 
+ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode, gint32 access_mode, gint32 share)
 {
-       gboolean ret;
-       FILETIME cr, ac, wr;
-       
-       if(handle == INVALID_HANDLE_VALUE) {
-               mono_raise_exception(get_io_exception("Invalid handle"));
-       }
+       gunichar2 *utf16_filename;
+       HANDLE result;
 
-       ret=GetFileTime(handle, &cr, &ac, &wr);
-       if(ret==TRUE) {
-               /* The FILETIME struct holds two unsigned 32 bit
-                * values for the low and high bytes, but the .net
-                * file time insists on being signed :(
-                */
-               *createtime=((gint64)cr.dwHighDateTime << 32) +
-                       cr.dwLowDateTime;
-               *lastaccess=((gint64)ac.dwHighDateTime << 32) +
-                       ac.dwLowDateTime;
-               *lastwrite=((gint64)wr.dwHighDateTime << 32) +
-                       wr.dwLowDateTime;
-       }
-       
-       return(ret);
+       utf16_filename = mono_string_to_utf16 (filename);
+       result = CreateFile (utf16_filename, convert_access (access_mode), convert_share (share),
+                            NULL, convert_mode (mode), FILE_ATTRIBUTE_NORMAL, NULL);
+       g_free (utf16_filename);
+
+       return result;
 }
 
-gboolean ves_icall_System_PAL_OpSys_SetFileTime(HANDLE handle, gint64 createtime, gint64 lastaccess, gint64 lastwrite)
+gboolean 
+ves_icall_System_IO_MonoIO_Close (HANDLE handle)
 {
-       gboolean ret;
-       FILETIME cr, ac, wr;
-       
-       if(handle == INVALID_HANDLE_VALUE) {
-               mono_raise_exception(get_io_exception("Invalid handle"));
-       }
+       return CloseHandle (handle);
+}
 
-       cr.dwLowDateTime= createtime & 0xFFFFFFFF;
-       cr.dwHighDateTime= createtime >> 32;
-       
-       ac.dwLowDateTime= lastaccess & 0xFFFFFFFF;
-       ac.dwHighDateTime= lastaccess >> 32;
-       
-       wr.dwLowDateTime= lastwrite & 0xFFFFFFFF;
-       wr.dwHighDateTime= lastwrite >> 32;
+gint32 
+ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest, gint32 dest_offset, gint32 count)
+{
+       guchar *buffer;
+       gboolean result;
+       guint32 n;
+
+       if (dest_offset + count > mono_array_length (dest))
+               return 0;
+
+       buffer = mono_array_addr (dest, guchar, dest_offset);
+       result = ReadFile (handle, buffer, count, &n, NULL);
+
+       if (!result)
+               return -1;
 
-       ret=SetFileTime(handle, &cr, &ac, &wr);
+       return (gint32)n;
+}
+
+gint32 
+ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src, gint32 src_offset, gint32 count)
+{
+       guchar *buffer;
+       gboolean result;
+       guint32 n;
+
+       if (src_offset + count > mono_array_length (src))
+               return 0;
        
-       return(ret);
+       buffer = mono_array_addr (src, guchar, src_offset);
+       result = WriteFile (handle, buffer, count, &n, NULL);
+
+       if (!result)
+               return -1;
+
+       return (gint32)n;
+}
+
+gint64 
+ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin)
+{
+       guint32 offset_hi;
+
+       offset_hi = offset >> 32;
+       offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
+                                convert_seekorigin (origin));
+
+       return offset | ((gint64)offset_hi << 32);
 }
 
+gboolean 
+ves_icall_System_IO_MonoIO_Flush (HANDLE handle)
+{
+       return FlushFileBuffers (handle);
+}
+
+gint64 
+ves_icall_System_IO_MonoIO_GetLength (HANDLE handle)
+{
+       gint64 length;
+       guint32 length_hi;
+
+       length = GetFileSize (handle, &length_hi);
+       return length | ((gint64)length_hi << 32);
+}
+
+gboolean 
+ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length)
+{
+       gint64 offset;
+       gint32 offset_hi;
+       gint32 length_hi;
+       gboolean result;
+
+       /* save file pointer */
+
+       offset_hi = 0;
+       offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
+
+       /* extend or truncate */
+
+       length_hi = length >> 32;
+       SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi, FILE_BEGIN);
+       result = SetEndOfFile (handle);
+
+       /* restore file pointer */
+
+       SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi, FILE_BEGIN);
+
+       return result;
+}
+
+gboolean
+ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time, gint64 last_access_time, gint64 last_write_time)
+{
+       const FILETIME *creation_filetime;
+       const FILETIME *last_access_filetime;
+       const FILETIME *last_write_filetime;
+
+       if (creation_time < 0)
+               creation_filetime = NULL;
+       else
+               creation_filetime = (FILETIME *)&creation_time;
+
+       if (last_access_time < 0)
+               last_access_filetime = NULL;
+       else
+               last_access_filetime = (FILETIME *)&last_access_time;
+
+       if (last_write_time < 0)
+               last_write_filetime = NULL;
+       else
+               last_write_filetime = (FILETIME *)&last_write_time;
+
+       return SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
+}
+
+HANDLE 
+ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
+{
+       return GetStdHandle (STD_OUTPUT_HANDLE);
+}
+
+HANDLE 
+ves_icall_System_IO_MonoIO_get_ConsoleInput ()
+{
+       return GetStdHandle (STD_INPUT_HANDLE);
+}
+
+HANDLE 
+ves_icall_System_IO_MonoIO_get_ConsoleError ()
+{
+       return GetStdHandle (STD_ERROR_HANDLE);
+}
+
+gunichar2 
+ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
+{
+#if defined (PLATFORM_WIN32)
+       return (gunichar2) 0x003a;      /* colon */
+#else
+       return (gunichar2) 0x002f;      /* forward slash */
+#endif
+}
+
+gunichar2 
+ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
+{
+#if defined (PLATFORM_WIN32)
+       return (gunichar2) 0x005c;      /* backslash */
+#else
+       return (gunichar2) 0x002f;      /* forward slash */
+#endif
+}
+
+gunichar2 
+ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
+{
+#if defined (PLATFORM_WIN32)
+       return (gunichar2) 0x002f;      /* forward slash */
+#else
+       return (gunichar2) 0x005c;      /* backslash */
+#endif
+}
+
+gunichar2 
+ves_icall_System_IO_MonoIO_get_PathSeparator ()
+{
+#if defined (PLATFORM_WIN32)
+       return (gunichar2) 0x003b;      /* semicolon */
+#else
+       return (gunichar2) 0x003a;      /* colon */
+#endif
+}
+
+static gunichar2 invalid_path_chars [] = {
+#if defined (PLATFORM_WIN32)
+       0x0022,                         /* double quote */
+       0x003c,                         /* less than */
+       0x003e,                         /* greater than */
+       0x007c,                         /* pipe */
+#endif
+       0x0000                          /* null */
+};
+
+MonoArray *
+ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
+{
+       MonoArray *chars;
+       MonoDomain *domain;
+       int i, n;
+
+       domain = mono_domain_get ();
+       chars = mono_array_new (domain, mono_defaults.char_class, 5);
+
+       n = sizeof (invalid_path_chars) / sizeof (gunichar2);
+
+       for (i = 0; i < n; ++ i)
+               mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
+       
+       return chars;
+}