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)
157 guint64 ticks = filetime->dwHighDateTime;
159 ticks += filetime->dwLowDateTime;
160 return (gint64)ticks;
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 /* Managed file attributes have nearly but not quite the same values
181 * as the w32 equivalents.
183 static guint32 convert_attrs(MonoFileAttributes attrs)
185 if(attrs & FileAttributes_Encrypted) {
186 attrs |= FILE_ATTRIBUTE_ENCRYPTED;
192 /* System.IO.MonoIO internal calls */
195 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
201 *error=ERROR_SUCCESS;
203 ret=CreateDirectory (mono_string_chars (path), NULL);
205 *error=GetLastError ();
212 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
218 *error=ERROR_SUCCESS;
220 ret=RemoveDirectory (mono_string_chars (path));
222 *error=GetLastError ();
229 ves_icall_System_IO_MonoIO_FindFirstFile (MonoString *path, MonoIOStat *stat,
232 WIN32_FIND_DATA data;
237 *error=ERROR_SUCCESS;
239 result = FindFirstFile (mono_string_chars (path), &data);
241 /* note: WIN32_FIND_DATA is an extension of WIN32_FILE_ATTRIBUTE_DATA */
243 if (result != INVALID_HANDLE_VALUE) {
244 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
245 &data.cFileName [0], stat);
247 *error=GetLastError ();
254 ves_icall_System_IO_MonoIO_FindNextFile (HANDLE find, MonoIOStat *stat,
257 WIN32_FIND_DATA data;
262 *error=ERROR_SUCCESS;
264 result = FindNextFile (find, &data);
266 convert_win32_file_attribute_data ((const WIN32_FILE_ATTRIBUTE_DATA *)&data,
267 &data.cFileName [0], stat);
269 *error=GetLastError ();
276 ves_icall_System_IO_MonoIO_FindClose (HANDLE find, gint32 *error)
282 *error=ERROR_SUCCESS;
284 ret=FindClose (find);
286 *error=GetLastError ();
293 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *error)
302 buf = g_new (gunichar2, len);
304 *error=ERROR_SUCCESS;
307 if (GetCurrentDirectory (len, buf) > 0) {
312 result = mono_string_new_utf16 (mono_domain_get (), buf, len);
314 *error=GetLastError ();
322 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
329 *error=ERROR_SUCCESS;
331 ret=SetCurrentDirectory (mono_string_chars (path));
333 *error=GetLastError ();
340 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
347 *error=ERROR_SUCCESS;
349 ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
351 *error=GetLastError ();
358 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
359 MonoBoolean overwrite, gint32 *error)
365 *error=ERROR_SUCCESS;
367 ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
369 *error=GetLastError ();
376 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
382 *error=ERROR_SUCCESS;
384 ret=DeleteFile (mono_string_chars (path));
386 *error=GetLastError ();
393 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
399 *error=ERROR_SUCCESS;
401 ret=GetFileAttributes (mono_string_chars (path));
402 if(ret==INVALID_FILE_ATTRIBUTES) {
403 *error=GetLastError ();
410 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
417 *error=ERROR_SUCCESS;
419 ret=SetFileAttributes (mono_string_chars (path),
420 convert_attrs (attrs));
422 *error=GetLastError ();
429 ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
435 *error=ERROR_SUCCESS;
437 ret=GetFileType (handle);
438 if(ret==FILE_TYPE_UNKNOWN) {
439 /* Not necessarily an error, but the caller will have
440 * to decide based on the error value.
442 *error=GetLastError ();
449 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
453 WIN32_FILE_ATTRIBUTE_DATA data;
457 *error=ERROR_SUCCESS;
459 result = GetFileAttributesEx (mono_string_chars (path), GetFileExInfoStandard, &data);
462 convert_win32_file_attribute_data (&data,
463 mono_string_chars (path),
466 *error=GetLastError ();
473 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
474 gint32 access_mode, gint32 share,
481 *error=ERROR_SUCCESS;
483 ret=CreateFile (mono_string_chars (filename),
484 convert_access (access_mode), convert_share (share),
485 NULL, convert_mode (mode), FILE_ATTRIBUTE_NORMAL,
487 if(ret==INVALID_HANDLE_VALUE) {
488 *error=GetLastError ();
495 ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
501 *error=ERROR_SUCCESS;
503 ret=CloseHandle (handle);
505 *error=GetLastError ();
512 ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
513 gint32 dest_offset, gint32 count,
522 *error=ERROR_SUCCESS;
524 if (dest_offset + count > mono_array_length (dest))
527 buffer = mono_array_addr (dest, guchar, dest_offset);
528 result = ReadFile (handle, buffer, count, &n, NULL);
531 *error=GetLastError ();
539 ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
540 gint32 src_offset, gint32 count,
549 *error=ERROR_SUCCESS;
551 if (src_offset + count > mono_array_length (src))
554 buffer = mono_array_addr (src, guchar, src_offset);
555 result = WriteFile (handle, buffer, count, &n, NULL);
558 *error=GetLastError ();
566 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
573 *error=ERROR_SUCCESS;
575 offset_hi = offset >> 32;
576 offset = SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
577 convert_seekorigin (origin));
579 if(offset==INVALID_SET_FILE_POINTER) {
580 *error=GetLastError ();
583 return offset | ((gint64)offset_hi << 32);
587 ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
593 *error=ERROR_SUCCESS;
595 ret=FlushFileBuffers (handle);
597 *error=GetLastError ();
604 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
611 *error=ERROR_SUCCESS;
613 length = GetFileSize (handle, &length_hi);
614 if(length==INVALID_FILE_SIZE) {
615 *error=GetLastError ();
618 return length | ((gint64)length_hi << 32);
622 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
625 gint64 offset, offset_set;
632 *error=ERROR_SUCCESS;
634 /* save file pointer */
637 offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
638 if(offset==INVALID_SET_FILE_POINTER) {
639 *error=GetLastError ();
643 /* extend or truncate */
645 length_hi = length >> 32;
646 offset_set=SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi,
648 if(offset_set==INVALID_SET_FILE_POINTER) {
649 *error=GetLastError ();
653 result = SetEndOfFile (handle);
655 *error=GetLastError ();
659 /* restore file pointer */
661 offset_set=SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
663 if(offset_set==INVALID_SET_FILE_POINTER) {
664 *error=GetLastError ();
672 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
673 gint64 last_access_time,
674 gint64 last_write_time, gint32 *error)
677 const FILETIME *creation_filetime;
678 const FILETIME *last_access_filetime;
679 const FILETIME *last_write_filetime;
683 *error=ERROR_SUCCESS;
685 if (creation_time < 0)
686 creation_filetime = NULL;
688 creation_filetime = (FILETIME *)&creation_time;
690 if (last_access_time < 0)
691 last_access_filetime = NULL;
693 last_access_filetime = (FILETIME *)&last_access_time;
695 if (last_write_time < 0)
696 last_write_filetime = NULL;
698 last_write_filetime = (FILETIME *)&last_write_time;
700 ret=SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
702 *error=GetLastError ();
709 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
713 return GetStdHandle (STD_OUTPUT_HANDLE);
717 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
721 return GetStdHandle (STD_INPUT_HANDLE);
725 ves_icall_System_IO_MonoIO_get_ConsoleError ()
729 return GetStdHandle (STD_ERROR_HANDLE);
733 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle,
734 HANDLE *write_handle)
736 SECURITY_ATTRIBUTES attr;
741 attr.nLength=sizeof(SECURITY_ATTRIBUTES);
742 attr.bInheritHandle=TRUE;
743 attr.lpSecurityDescriptor=NULL;
745 ret=CreatePipe (read_handle, write_handle, &attr, 0);
747 /* FIXME: throw an exception? */
755 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
759 #if defined (PLATFORM_WIN32)
760 return (gunichar2) 0x003a; /* colon */
762 return (gunichar2) 0x002f; /* forward slash */
767 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
771 #if defined (PLATFORM_WIN32)
772 return (gunichar2) 0x005c; /* backslash */
774 return (gunichar2) 0x002f; /* forward slash */
779 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
783 #if defined (PLATFORM_WIN32)
784 return (gunichar2) 0x002f; /* forward slash */
786 return (gunichar2) 0x005c; /* backslash */
791 ves_icall_System_IO_MonoIO_get_PathSeparator ()
795 #if defined (PLATFORM_WIN32)
796 return (gunichar2) 0x003b; /* semicolon */
798 return (gunichar2) 0x003a; /* colon */
802 static gunichar2 invalid_path_chars [] = {
803 #if defined (PLATFORM_WIN32)
804 0x0022, /* double quote */
805 0x003c, /* less than */
806 0x003e, /* greater than */
813 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
821 domain = mono_domain_get ();
822 chars = mono_array_new (domain, mono_defaults.char_class, 5);
824 n = sizeof (invalid_path_chars) / sizeof (gunichar2);
826 for (i = 0; i < n; ++ i)
827 mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
833 ves_icall_System_IO_MonoIO_GetTempPath (MonoString **mono_name)
838 name=g_new0 (gunichar2, 256);
840 ret=GetTempPath (256, name);
842 /* Buffer was too short. Try again... */
844 name=g_new0 (gunichar2, ret+2); /* include the terminator */
845 ret=GetTempPath (ret, name);
850 g_message (G_GNUC_PRETTY_FUNCTION
851 ": Temp path is [%s] (len %d)", name, ret);
854 *mono_name=mono_string_new_utf16 (mono_domain_get (), name,