2 * file-io.c: File IO internal calls
5 * Dick Porter (dick@ximian.com)
7 * (C) 2001 Ximian, Inc.
13 #include <mono/metadata/object.h>
14 #include <mono/io-layer/io-layer.h>
15 #include <mono/metadata/file-io.h>
16 #include <mono/metadata/exception.h>
17 #include <mono/metadata/appdomain.h>
21 /* conversion functions */
23 static guint32 convert_mode(MonoFileMode mono_mode)
28 case FileMode_CreateNew:
37 case FileMode_OpenOrCreate:
40 case FileMode_Truncate:
41 mode=TRUNCATE_EXISTING;
47 g_warning("System.IO.FileMode has unknown value 0x%x",
56 static guint32 convert_access(MonoFileAccess mono_access)
64 case FileAccess_Write:
67 case FileAccess_ReadWrite:
68 access=GENERIC_READ|GENERIC_WRITE;
71 g_warning("System.IO.FileAccess has unknown value 0x%x",
80 static guint32 convert_share(MonoFileShare mono_share)
89 share=FILE_SHARE_READ;
92 share=FILE_SHARE_WRITE;
94 case FileShare_ReadWrite:
95 share=FILE_SHARE_READ|FILE_SHARE_WRITE;
98 g_warning("System.IO.FileShare has unknown value 0x%x",
108 static guint32 convert_stdhandle(guint32 fd)
114 stdhandle=STD_INPUT_HANDLE;
117 stdhandle=STD_OUTPUT_HANDLE;
120 stdhandle=STD_ERROR_HANDLE;
123 g_warning("unknown standard file descriptor %d", fd);
124 stdhandle=STD_INPUT_HANDLE;
131 static guint32 convert_seekorigin(MonoSeekOrigin origin)
136 case SeekOrigin_Begin:
137 w32origin=FILE_BEGIN;
139 case SeekOrigin_Current:
140 w32origin=FILE_CURRENT;
146 g_warning("System.IO.SeekOrigin has unknown value 0x%x",
149 w32origin=FILE_CURRENT;
155 static gint64 convert_filetime (const FILETIME *filetime)
159 ticks = (gint64 *)filetime;
163 static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, const gunichar2 *name, MonoIOStat *stat)
167 stat->attributes = data->dwFileAttributes;
168 stat->creation_time = convert_filetime (&data->ftCreationTime);
169 stat->last_access_time = convert_filetime (&data->ftLastAccessTime);
170 stat->last_write_time = convert_filetime (&data->ftLastWriteTime);
171 stat->length = ((gint64)data->nFileSizeHigh << 32) | data->nFileSizeLow;
177 stat->name = mono_string_new_utf16 (mono_domain_get (), name, len);
180 /* System.IO.MonoIO internal calls */
183 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
189 *error=ERROR_SUCCESS;
191 ret=CreateDirectory (mono_string_chars (path), NULL);
193 *error=GetLastError ();
200 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
206 *error=ERROR_SUCCESS;
208 ret=RemoveDirectory (mono_string_chars (path));
210 *error=GetLastError ();
217 ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat,
220 WIN32_FIND_DATA data;
225 *error=ERROR_SUCCESS;
227 result = FindFirstFile (mono_string_chars (path), &data);
229 /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
231 if (result != INVALID_HANDLE_VALUE) {
232 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
233 &data.cFileName [0], stat);
235 *error=GetLastError ();
242 ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat,
245 WIN32_FIND_DATA data;
250 *error=ERROR_SUCCESS;
252 result = FindNextFile (find, &data);
254 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
255 &data.cFileName [0], stat);
257 *error=GetLastError ();
264 ves_icall_System_IO_MonoIO_FindClose (HANDLE find, gint32 *error)
270 *error=ERROR_SUCCESS;
272 ret=FindClose (find);
274 *error=GetLastError ();
281 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
290 buf = g_new (gunichar2, len);
292 *error=ERROR_SUCCESS;
295 if (GetCurrentDirectory (len, buf) > 0) {
300 result = mono_string_new_utf16 (mono_domain_get (), buf, len);
302 *error=GetLastError ();
310 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
317 *error=ERROR_SUCCESS;
319 ret=SetCurrentDirectory (mono_string_chars (path));
321 *error=GetLastError ();
328 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
335 *error=ERROR_SUCCESS;
337 ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
339 *error=GetLastError ();
346 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
347 MonoBoolean overwrite, gint32 *error)
353 *error=ERROR_SUCCESS;
355 ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
357 *error=GetLastError ();
364 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
370 *error=ERROR_SUCCESS;
372 ret=DeleteFile (mono_string_chars (path));
374 *error=GetLastError ();
381 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
387 *error=ERROR_SUCCESS;
389 ret=GetFileAttributes (mono_string_chars (path));
390 if(ret==INVALID_FILE_ATTRIBUTES) {
391 *error=GetLastError ();
398 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
405 *error=ERROR_SUCCESS;
407 ret=SetFileAttributes (mono_string_chars (path), attrs);
409 *error=GetLastError ();
416 ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
422 *error=ERROR_SUCCESS;
424 ret=GetFileType (handle);
425 if(ret==FILE_TYPE_UNKNOWN) {
426 /* Not necessarily an error, but the caller will have
427 * to decide based on the error value.
429 *error=GetLastError ();
436 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
440 WIN32_FILE_ATTRIBUTE_DATA data;
444 *error=ERROR_SUCCESS;
446 result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
449 convert_win32_file_attribute_data (&data,
450 mono_string_chars (path),
453 *error=GetLastError ();
460 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
461 gint32 access_mode, gint32 share,
468 *error=ERROR_SUCCESS;
470 ret=CreateFile (mono_string_chars (filename),
471 convert_access (access_mode), convert_share (share),
472 NULL, convert_mode (mode), FILE_ATTRIBUTE_NORMAL,
474 if(ret==INVALID_HANDLE_VALUE) {
475 *error=GetLastError ();
482 ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
488 *error=ERROR_SUCCESS;
490 ret=CloseHandle (handle);
492 *error=GetLastError ();
499 ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
500 gint32 dest_offset, gint32 count,
509 *error=ERROR_SUCCESS;
511 if (dest_offset + count > mono_array_length (dest))
514 buffer = mono_array_addr (dest, guchar, dest_offset);
515 result = ReadFile (handle, buffer, count, &n, NULL);
518 *error=GetLastError ();
526 ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
527 gint32 src_offset, gint32 count,
536 *error=ERROR_SUCCESS;
538 if (src_offset + count > mono_array_length (src))
541 buffer = mono_array_addr (src, guchar, src_offset);
542 result = WriteFile (handle, buffer, count, &n, NULL);
545 *error=GetLastError ();
553 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
560 *error=ERROR_SUCCESS;
562 offset_hi = offset >> 32;
563 offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
564 convert_seekorigin (origin));
566 if(offset==INVALID_SET_FILE_POINTER) {
567 *error=GetLastError ();
570 return offset | ((gint64)offset_hi << 32);
574 ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
580 *error=ERROR_SUCCESS;
582 ret=FlushFileBuffers (handle);
584 *error=GetLastError ();
591 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
598 *error=ERROR_SUCCESS;
600 length = GetFileSize (handle, &length_hi);
601 if(length==INVALID_FILE_SIZE) {
602 *error=GetLastError ();
605 return length | ((gint64)length_hi << 32);
609 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
612 gint64 offset, offset_set;
619 *error=ERROR_SUCCESS;
621 /* save file pointer */
624 offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
625 if(offset==INVALID_SET_FILE_POINTER) {
626 *error=GetLastError ();
630 /* extend or truncate */
632 length_hi = length >> 32;
633 offset_set=SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi,
635 if(offset_set==INVALID_SET_FILE_POINTER) {
636 *error=GetLastError ();
640 result = SetEndOfFile (handle);
642 *error=GetLastError ();
646 /* restore file pointer */
648 offset_set=SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
650 if(offset_set==INVALID_SET_FILE_POINTER) {
651 *error=GetLastError ();
659 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
660 gint64 last_access_time,
661 gint64 last_write_time, gint32 *error)
664 const FILETIME *creation_filetime;
665 const FILETIME *last_access_filetime;
666 const FILETIME *last_write_filetime;
670 *error=ERROR_SUCCESS;
672 if (creation_time < 0)
673 creation_filetime = NULL;
675 creation_filetime = (FILETIME *)&creation_time;
677 if (last_access_time < 0)
678 last_access_filetime = NULL;
680 last_access_filetime = (FILETIME *)&last_access_time;
682 if (last_write_time < 0)
683 last_write_filetime = NULL;
685 last_write_filetime = (FILETIME *)&last_write_time;
687 ret=SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
689 *error=GetLastError ();
696 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
700 return GetStdHandle (STD_OUTPUT_HANDLE);
704 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
708 return GetStdHandle (STD_INPUT_HANDLE);
712 ves_icall_System_IO_MonoIO_get_ConsoleError ()
716 return GetStdHandle (STD_ERROR_HANDLE);
720 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
721 HANDLE *write_handle)
723 SECURITY_ATTRIBUTES attr;
728 attr.nLength=sizeof(SECURITY_ATTRIBUTES);
729 attr.bInheritHandle=TRUE;
730 attr.lpSecurityDescriptor=NULL;
732 ret=CreatePipe (read_handle, write_handle, &attr, 0);
734 /* FIXME: throw an exception? */
742 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
746 #if defined (PLATFORM_WIN32)
747 return (gunichar2) 0x003a; /* colon */
749 return (gunichar2) 0x002f; /* forward slash */
754 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
758 #if defined (PLATFORM_WIN32)
759 return (gunichar2) 0x005c; /* backslash */
761 return (gunichar2) 0x002f; /* forward slash */
766 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
770 #if defined (PLATFORM_WIN32)
771 return (gunichar2) 0x002f; /* forward slash */
773 return (gunichar2) 0x005c; /* backslash */
778 ves_icall_System_IO_MonoIO_get_PathSeparator ()
782 #if defined (PLATFORM_WIN32)
783 return (gunichar2) 0x003b; /* semicolon */
785 return (gunichar2) 0x003a; /* colon */
789 static gunichar2 invalid_path_chars [] = {
790 #if defined (PLATFORM_WIN32)
791 0x0022, /* double quote */
792 0x003c, /* less than */
793 0x003e, /* greater than */
800 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
808 domain = mono_domain_get ();
809 chars = mono_array_new (domain, mono_defaults.char_class, 5);
811 n = sizeof (invalid_path_chars) / sizeof (gunichar2);
813 for (i = 0; i < n; ++ i)
814 mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
820 ves_icall_System_IO_MonoIO_GetTempPath (MonoString **mono_name)
825 name=g_new0 (gunichar2, 256);
827 ret=GetTempPath (256, name);
829 /* Buffer was too short. Try again... */
831 name=g_new0 (gunichar2, ret+2); /* include the terminator */
832 ret=GetTempPath (ret, name);
837 g_message (G_GNUC_PRETTY_FUNCTION
838 ": Temp path is [%s] (len %d)", name, ret);
841 *mono_name=mono_string_new_utf16 (mono_domain_get (), name,