2 * file-io.c: File IO internal calls
5 * Dick Porter (dick@ximian.com)
6 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
22 #ifdef HAVE_SYS_STAT_H
25 #ifdef HAVE_SYS_TYPES_H
26 #include <sys/types.h>
29 #include <mono/metadata/object.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/metadata/file-io.h>
32 #include <mono/metadata/exception.h>
33 #include <mono/metadata/appdomain.h>
34 #include <mono/metadata/marshal.h>
35 #include <mono/utils/strenc.h>
36 #include <utils/mono-io-portability.h>
40 /* conversion functions */
42 static guint32 convert_mode(MonoFileMode mono_mode)
47 case FileMode_CreateNew:
56 case FileMode_OpenOrCreate:
59 case FileMode_Truncate:
60 mode=TRUNCATE_EXISTING;
66 g_warning("System.IO.FileMode has unknown value 0x%x",
75 static guint32 convert_access(MonoFileAccess mono_access)
83 case FileAccess_Write:
86 case FileAccess_ReadWrite:
87 access=GENERIC_READ|GENERIC_WRITE;
90 g_warning("System.IO.FileAccess has unknown value 0x%x",
99 static guint32 convert_share(MonoFileShare mono_share)
103 if (mono_share & FileShare_Read) {
104 share |= FILE_SHARE_READ;
106 if (mono_share & FileShare_Write) {
107 share |= FILE_SHARE_WRITE;
109 if (mono_share & FileShare_Delete) {
110 share |= FILE_SHARE_DELETE;
113 if (mono_share & ~(FileShare_Read|FileShare_Write|FileShare_Delete)) {
114 g_warning("System.IO.FileShare has unknown value 0x%x",
124 static guint32 convert_stdhandle(guint32 fd)
130 stdhandle=STD_INPUT_HANDLE;
133 stdhandle=STD_OUTPUT_HANDLE;
136 stdhandle=STD_ERROR_HANDLE;
139 g_warning("unknown standard file descriptor %d", fd);
140 stdhandle=STD_INPUT_HANDLE;
147 static guint32 convert_seekorigin(MonoSeekOrigin origin)
152 case SeekOrigin_Begin:
153 w32origin=FILE_BEGIN;
155 case SeekOrigin_Current:
156 w32origin=FILE_CURRENT;
162 g_warning("System.IO.SeekOrigin has unknown value 0x%x",
165 w32origin=FILE_CURRENT;
171 static gint64 convert_filetime (const FILETIME *filetime)
173 guint64 ticks = filetime->dwHighDateTime;
175 ticks += filetime->dwLowDateTime;
176 return (gint64)ticks;
179 static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA *data, MonoIOStat *stat)
181 stat->attributes = data->dwFileAttributes;
182 stat->creation_time = convert_filetime (&data->ftCreationTime);
183 stat->last_access_time = convert_filetime (&data->ftLastAccessTime);
184 stat->last_write_time = convert_filetime (&data->ftLastWriteTime);
185 stat->length = ((gint64)data->nFileSizeHigh << 32) | data->nFileSizeLow;
188 /* Managed file attributes have nearly but not quite the same values
189 * as the w32 equivalents.
191 static guint32 convert_attrs(MonoFileAttributes attrs)
193 if(attrs & FileAttributes_Encrypted) {
194 attrs = (MonoFileAttributes)(attrs | FILE_ATTRIBUTE_ENCRYPTED);
201 * On Win32, GetFileAttributes|Ex () seems to try opening the file,
202 * which might lead to sharing violation errors, whereas FindFirstFile
203 * always succeeds. These 2 wrappers resort to FindFirstFile if
204 * GetFileAttributes|Ex () has failed.
207 get_file_attributes (const gunichar2 *path)
210 WIN32_FIND_DATA find_data;
214 res = GetFileAttributes (path);
218 error = GetLastError ();
220 if (error != ERROR_SHARING_VIOLATION)
223 find_handle = FindFirstFile (path, &find_data);
225 if (find_handle == INVALID_HANDLE_VALUE)
228 FindClose (find_handle);
230 return find_data.dwFileAttributes;
234 get_file_attributes_ex (const gunichar2 *path, WIN32_FILE_ATTRIBUTE_DATA *data)
237 WIN32_FIND_DATA find_data;
241 res = GetFileAttributesEx (path, GetFileExInfoStandard, data);
245 error = GetLastError ();
247 if (error != ERROR_SHARING_VIOLATION)
250 find_handle = FindFirstFile (path, &find_data);
252 if (find_handle == INVALID_HANDLE_VALUE)
255 FindClose (find_handle);
257 data->dwFileAttributes = find_data.dwFileAttributes;
258 data->ftCreationTime = find_data.ftCreationTime;
259 data->ftLastAccessTime = find_data.ftLastAccessTime;
260 data->ftLastWriteTime = find_data.ftLastWriteTime;
261 data->nFileSizeHigh = find_data.nFileSizeHigh;
262 data->nFileSizeLow = find_data.nFileSizeLow;
267 /* System.IO.MonoIO internal calls */
270 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString *path, gint32 *error)
273 MONO_PREPARE_BLOCKING;
275 *error=ERROR_SUCCESS;
277 ret=CreateDirectory (mono_string_chars (path), NULL);
279 *error=GetLastError ();
282 MONO_FINISH_BLOCKING;
287 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString *path, gint32 *error)
290 MONO_PREPARE_BLOCKING;
292 *error=ERROR_SUCCESS;
294 ret=RemoveDirectory (mono_string_chars (path));
296 *error=GetLastError ();
299 MONO_FINISH_BLOCKING;
304 get_search_dir (const gunichar2 *pattern)
309 p = g_utf16_to_utf8 (pattern, -1, NULL, NULL, NULL);
310 result = g_path_get_dirname (p);
316 get_filesystem_entries (const gunichar2 *path,
317 const gunichar2 *path_with_pattern,
318 gint attrs, gint mask,
322 WIN32_FIND_DATA data;
324 GPtrArray *names = NULL;
325 gchar *utf8_path = NULL, *utf8_result, *full_name;
328 mask = convert_attrs ((MonoFileAttributes)mask);
329 attributes = get_file_attributes (path);
330 if (attributes != -1) {
331 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
332 *error = ERROR_INVALID_NAME;
336 *error = GetLastError ();
340 find_handle = FindFirstFile (path_with_pattern, &data);
341 if (find_handle == INVALID_HANDLE_VALUE) {
342 gint32 find_error = GetLastError ();
344 if (find_error == ERROR_FILE_NOT_FOUND || find_error == ERROR_NO_MORE_FILES) {
345 /* No files, so just return an empty array */
353 utf8_path = get_search_dir (path_with_pattern);
354 names = g_ptr_array_new ();
357 if ((data.cFileName[0] == '.' && data.cFileName[1] == 0) ||
358 (data.cFileName[0] == '.' && data.cFileName[1] == '.' && data.cFileName[2] == 0)) {
362 if ((data.dwFileAttributes & mask) == attrs) {
363 utf8_result = g_utf16_to_utf8 (data.cFileName, -1, NULL, NULL, NULL);
364 if (utf8_result == NULL) {
368 full_name = g_build_filename (utf8_path, utf8_result, NULL);
369 g_ptr_array_add (names, full_name);
371 g_free (utf8_result);
373 } while(FindNextFile (find_handle, &data));
375 if (FindClose (find_handle) == FALSE) {
376 *error = GetLastError ();
384 for (i = 0; i < names->len; i++)
385 g_free (g_ptr_array_index (names, i));
386 g_ptr_array_free (names, TRUE);
394 ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString *path,
395 MonoString *path_with_pattern,
396 gint attrs, gint mask,
399 MonoDomain *domain = mono_domain_get ();
404 *error = ERROR_SUCCESS;
406 MONO_PREPARE_BLOCKING;
407 names = get_filesystem_entries (mono_string_chars (path), mono_string_chars (path_with_pattern), attrs, mask, error);
408 MONO_FINISH_BLOCKING;
411 // If there's no array and no error, then return an empty array.
412 if (*error == ERROR_SUCCESS)
413 return mono_array_new (domain, mono_defaults.string_class, 0);
417 result = mono_array_new (domain, mono_defaults.string_class, names->len);
418 for (i = 0; i < names->len; i++) {
419 mono_array_setref (result, i, mono_string_new (domain, (const char *)g_ptr_array_index (names, i)));
420 g_free (g_ptr_array_index (names, i));
422 g_ptr_array_free (names, TRUE);
433 incremental_find_check_match (IncrementalFind *handle, WIN32_FIND_DATA *data, MonoString **result)
438 if ((data->cFileName[0] == '.' && data->cFileName[1] == 0) || (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0))
441 utf8_result = g_utf16_to_utf8 (data->cFileName, -1, NULL, NULL, NULL);
442 if (utf8_result == NULL)
445 full_name = g_build_filename (handle->utf8_path, utf8_result, NULL);
446 g_free (utf8_result);
447 *result = mono_string_new (mono_domain_get (), full_name);
453 /* FIXME make gc suspendable */
455 ves_icall_System_IO_MonoIO_FindFirst (MonoString *path,
456 MonoString *path_with_pattern,
457 gint32 *result_attr, gint32 *error,
460 WIN32_FIND_DATA data;
462 IncrementalFind *ifh;
465 *error = ERROR_SUCCESS;
467 find_handle = FindFirstFile (mono_string_chars (path_with_pattern), &data);
469 if (find_handle == INVALID_HANDLE_VALUE) {
470 gint32 find_error = GetLastError ();
473 if (find_error == ERROR_FILE_NOT_FOUND)
480 ifh = g_new (IncrementalFind, 1);
481 ifh->find_handle = find_handle;
482 ifh->utf8_path = mono_string_to_utf8 (path);
483 ifh->domain = mono_domain_get ();
486 while (incremental_find_check_match (ifh, &data, &result) == 0){
487 if (FindNextFile (find_handle, &data) == FALSE){
488 int e = GetLastError ();
489 if (e != ERROR_NO_MORE_FILES)
494 *result_attr = data.dwFileAttributes;
499 /* FIXME make gc suspendable */
501 ves_icall_System_IO_MonoIO_FindNext (gpointer handle, gint32 *result_attr, gint32 *error)
503 IncrementalFind *ifh = (IncrementalFind *)handle;
504 WIN32_FIND_DATA data;
507 *error = ERROR_SUCCESS;
509 if (FindNextFile (ifh->find_handle, &data) == FALSE){
510 int e = GetLastError ();
511 if (e != ERROR_NO_MORE_FILES)
515 } while (incremental_find_check_match (ifh, &data, &result) == 0);
517 *result_attr = data.dwFileAttributes;
522 ves_icall_System_IO_MonoIO_FindClose (gpointer handle)
524 IncrementalFind *ifh = (IncrementalFind *)handle;
527 MONO_PREPARE_BLOCKING;
528 if (FindClose (ifh->find_handle) == FALSE){
529 error = GetLastError ();
531 error = ERROR_SUCCESS;
532 g_free (ifh->utf8_path);
534 MONO_FINISH_BLOCKING;
540 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32 *io_error)
547 len = MAX_PATH + 1; /*FIXME this is too smal under most unix systems.*/
548 buf = g_new (gunichar2, len);
550 mono_error_init (&error);
551 *io_error=ERROR_SUCCESS;
554 res_len = GetCurrentDirectory (len, buf);
555 if (res_len > len) { /*buf is too small.*/
556 int old_res_len = res_len;
558 buf = g_new (gunichar2, res_len);
559 res_len = GetCurrentDirectory (res_len, buf) == old_res_len;
567 result = mono_string_new_utf16_checked (mono_domain_get (), buf, len, &error);
569 *io_error=GetLastError ();
573 mono_error_set_pending_exception (&error);
578 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString *path,
583 *error=ERROR_SUCCESS;
585 ret=SetCurrentDirectory (mono_string_chars (path));
587 *error=GetLastError ();
594 ves_icall_System_IO_MonoIO_MoveFile (MonoString *path, MonoString *dest,
598 MONO_PREPARE_BLOCKING;
600 *error=ERROR_SUCCESS;
602 ret=MoveFile (mono_string_chars (path), mono_string_chars (dest));
604 *error=GetLastError ();
607 MONO_FINISH_BLOCKING;
612 ves_icall_System_IO_MonoIO_ReplaceFile (MonoString *sourceFileName, MonoString *destinationFileName,
613 MonoString *destinationBackupFileName, MonoBoolean ignoreMetadataErrors,
617 gunichar2 *utf16_sourceFileName = NULL, *utf16_destinationFileName = NULL, *utf16_destinationBackupFileName = NULL;
618 guint32 replaceFlags = REPLACEFILE_WRITE_THROUGH;
619 MONO_PREPARE_BLOCKING;
622 utf16_sourceFileName = mono_string_chars (sourceFileName);
623 if (destinationFileName)
624 utf16_destinationFileName = mono_string_chars (destinationFileName);
625 if (destinationBackupFileName)
626 utf16_destinationBackupFileName = mono_string_chars (destinationBackupFileName);
628 *error = ERROR_SUCCESS;
629 if (ignoreMetadataErrors)
630 replaceFlags |= REPLACEFILE_IGNORE_MERGE_ERRORS;
632 /* FIXME: source and destination file names must not be NULL, but apparently they might be! */
633 ret = ReplaceFile (utf16_destinationFileName, utf16_sourceFileName, utf16_destinationBackupFileName,
634 replaceFlags, NULL, NULL);
636 *error = GetLastError ();
638 MONO_FINISH_BLOCKING;
643 ves_icall_System_IO_MonoIO_CopyFile (MonoString *path, MonoString *dest,
644 MonoBoolean overwrite, gint32 *error)
647 MONO_PREPARE_BLOCKING;
649 *error=ERROR_SUCCESS;
651 ret=CopyFile (mono_string_chars (path), mono_string_chars (dest), !overwrite);
653 *error=GetLastError ();
656 MONO_FINISH_BLOCKING;
661 ves_icall_System_IO_MonoIO_DeleteFile (MonoString *path, gint32 *error)
664 MONO_PREPARE_BLOCKING;
666 *error=ERROR_SUCCESS;
668 ret=DeleteFile (mono_string_chars (path));
670 *error=GetLastError ();
673 MONO_FINISH_BLOCKING;
678 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString *path, gint32 *error)
681 MONO_PREPARE_BLOCKING;
683 *error=ERROR_SUCCESS;
685 ret=get_file_attributes (mono_string_chars (path));
688 * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
689 * headers is wrong, hence this temporary workaround.
691 * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
694 /* if(ret==INVALID_FILE_ATTRIBUTES) { */
695 *error=GetLastError ();
698 MONO_FINISH_BLOCKING;
703 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString *path, gint32 attrs,
707 MONO_PREPARE_BLOCKING;
709 *error=ERROR_SUCCESS;
711 ret=SetFileAttributes (mono_string_chars (path),
712 convert_attrs ((MonoFileAttributes)attrs));
714 *error=GetLastError ();
717 MONO_FINISH_BLOCKING;
722 ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle, gint32 *error)
725 MONO_PREPARE_BLOCKING;
727 *error=ERROR_SUCCESS;
729 ret=GetFileType (handle);
730 if(ret==FILE_TYPE_UNKNOWN) {
731 /* Not necessarily an error, but the caller will have
732 * to decide based on the error value.
734 *error=GetLastError ();
737 MONO_FINISH_BLOCKING;
742 ves_icall_System_IO_MonoIO_GetFileStat (MonoString *path, MonoIOStat *stat,
746 WIN32_FILE_ATTRIBUTE_DATA data;
747 MONO_PREPARE_BLOCKING;
749 *error=ERROR_SUCCESS;
751 result = get_file_attributes_ex (mono_string_chars (path), &data);
754 convert_win32_file_attribute_data (&data, stat);
756 *error=GetLastError ();
757 memset (stat, 0, sizeof (MonoIOStat));
760 MONO_FINISH_BLOCKING;
765 ves_icall_System_IO_MonoIO_Open (MonoString *filename, gint32 mode,
766 gint32 access_mode, gint32 share, gint32 options,
770 int attributes, attrs;
772 MONO_PREPARE_BLOCKING;
774 chars = mono_string_chars (filename);
775 *error=ERROR_SUCCESS;
778 if (options & FileOptions_Encrypted)
779 attributes = FILE_ATTRIBUTE_ENCRYPTED;
781 attributes = FILE_ATTRIBUTE_NORMAL;
782 if (options & FileOptions_DeleteOnClose)
783 attributes |= FILE_FLAG_DELETE_ON_CLOSE;
784 if (options & FileOptions_SequentialScan)
785 attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
786 if (options & FileOptions_RandomAccess)
787 attributes |= FILE_FLAG_RANDOM_ACCESS;
789 if (options & FileOptions_Temporary)
790 attributes |= FILE_ATTRIBUTE_TEMPORARY;
792 /* Not sure if we should set FILE_FLAG_OVERLAPPED, how does this mix with the "Async" bool here? */
793 if (options & FileOptions_Asynchronous)
794 attributes |= FILE_FLAG_OVERLAPPED;
796 if (options & FileOptions_WriteThrough)
797 attributes |= FILE_FLAG_WRITE_THROUGH;
799 attributes = FILE_ATTRIBUTE_NORMAL;
801 /* If we're opening a directory we need to set the extra flag
803 attrs = get_file_attributes (chars);
804 if (attrs != INVALID_FILE_ATTRIBUTES) {
805 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
806 attributes |= FILE_FLAG_BACKUP_SEMANTICS;
810 ret=CreateFile (chars, convert_access ((MonoFileAccess)access_mode),
811 convert_share ((MonoFileShare)share), NULL, convert_mode ((MonoFileMode)mode),
813 if(ret==INVALID_HANDLE_VALUE) {
814 *error=GetLastError ();
817 MONO_FINISH_BLOCKING;
822 ves_icall_System_IO_MonoIO_Close (HANDLE handle, gint32 *error)
825 MONO_PREPARE_BLOCKING;
827 *error=ERROR_SUCCESS;
829 ret=CloseHandle (handle);
831 *error=GetLastError ();
834 MONO_FINISH_BLOCKING;
839 ves_icall_System_IO_MonoIO_Read (HANDLE handle, MonoArray *dest,
840 gint32 dest_offset, gint32 count,
847 *error=ERROR_SUCCESS;
849 MONO_CHECK_ARG_NULL (dest, 0);
851 if (dest_offset > mono_array_length (dest) - count) {
852 mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
856 buffer = mono_array_addr (dest, guchar, dest_offset);
858 MONO_PREPARE_BLOCKING;
859 result = ReadFile (handle, buffer, count, &n, NULL);
860 MONO_FINISH_BLOCKING;
863 *error=GetLastError ();
871 ves_icall_System_IO_MonoIO_Write (HANDLE handle, MonoArray *src,
872 gint32 src_offset, gint32 count,
879 *error=ERROR_SUCCESS;
881 MONO_CHECK_ARG_NULL (src, 0);
883 if (src_offset > mono_array_length (src) - count) {
884 mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
888 buffer = mono_array_addr (src, guchar, src_offset);
889 MONO_PREPARE_BLOCKING;
890 result = WriteFile (handle, buffer, count, &n, NULL);
891 MONO_FINISH_BLOCKING;
894 *error=GetLastError ();
902 ves_icall_System_IO_MonoIO_Seek (HANDLE handle, gint64 offset, gint32 origin,
906 MONO_PREPARE_BLOCKING;
908 *error=ERROR_SUCCESS;
910 offset_hi = offset >> 32;
911 offset = SetFilePointer (handle, (gint32) (offset & 0xFFFFFFFF), &offset_hi,
912 convert_seekorigin ((MonoSeekOrigin)origin));
914 if(offset==INVALID_SET_FILE_POINTER) {
915 *error=GetLastError ();
918 MONO_FINISH_BLOCKING;
919 return offset | ((gint64)offset_hi << 32);
923 ves_icall_System_IO_MonoIO_Flush (HANDLE handle, gint32 *error)
926 MONO_PREPARE_BLOCKING;
928 *error=ERROR_SUCCESS;
930 ret=FlushFileBuffers (handle);
932 *error=GetLastError ();
935 MONO_FINISH_BLOCKING;
940 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle, gint32 *error)
944 MONO_PREPARE_BLOCKING;
946 *error=ERROR_SUCCESS;
948 length = GetFileSize (handle, &length_hi);
949 if(length==INVALID_FILE_SIZE) {
950 *error=GetLastError ();
953 MONO_FINISH_BLOCKING;
954 return length | ((gint64)length_hi << 32);
957 /* FIXME make gc suspendable */
959 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle, gint64 length,
962 gint64 offset, offset_set;
967 *error=ERROR_SUCCESS;
969 /* save file pointer */
972 offset = SetFilePointer (handle, 0, &offset_hi, FILE_CURRENT);
973 if(offset==INVALID_SET_FILE_POINTER) {
974 *error=GetLastError ();
978 /* extend or truncate */
980 length_hi = length >> 32;
981 offset_set=SetFilePointer (handle, length & 0xFFFFFFFF, &length_hi,
983 if(offset_set==INVALID_SET_FILE_POINTER) {
984 *error=GetLastError ();
988 result = SetEndOfFile (handle);
990 *error=GetLastError ();
994 /* restore file pointer */
996 offset_set=SetFilePointer (handle, offset & 0xFFFFFFFF, &offset_hi,
998 if(offset_set==INVALID_SET_FILE_POINTER) {
999 *error=GetLastError ();
1007 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle, gint64 creation_time,
1008 gint64 last_access_time,
1009 gint64 last_write_time, gint32 *error)
1012 const FILETIME *creation_filetime;
1013 const FILETIME *last_access_filetime;
1014 const FILETIME *last_write_filetime;
1015 MONO_PREPARE_BLOCKING;
1017 *error=ERROR_SUCCESS;
1019 if (creation_time < 0)
1020 creation_filetime = NULL;
1022 creation_filetime = (FILETIME *)&creation_time;
1024 if (last_access_time < 0)
1025 last_access_filetime = NULL;
1027 last_access_filetime = (FILETIME *)&last_access_time;
1029 if (last_write_time < 0)
1030 last_write_filetime = NULL;
1032 last_write_filetime = (FILETIME *)&last_write_time;
1034 ret=SetFileTime (handle, creation_filetime, last_access_filetime, last_write_filetime);
1036 *error=GetLastError ();
1039 MONO_FINISH_BLOCKING;
1044 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
1046 return GetStdHandle (STD_OUTPUT_HANDLE);
1050 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
1052 return GetStdHandle (STD_INPUT_HANDLE);
1056 ves_icall_System_IO_MonoIO_get_ConsoleError ()
1058 return GetStdHandle (STD_ERROR_HANDLE);
1062 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE *read_handle, HANDLE *write_handle, gint32 *error)
1064 SECURITY_ATTRIBUTES attr;
1067 attr.nLength=sizeof(SECURITY_ATTRIBUTES);
1068 attr.bInheritHandle=TRUE;
1069 attr.lpSecurityDescriptor=NULL;
1071 MONO_PREPARE_BLOCKING;
1072 ret=CreatePipe (read_handle, write_handle, &attr, 0);
1073 MONO_FINISH_BLOCKING;
1076 *error = GetLastError ();
1077 /* FIXME: throw an exception? */
1085 ves_icall_System_IO_MonoIO_DuplicateHandle (HANDLE source_process_handle, HANDLE source_handle,
1086 HANDLE target_process_handle, HANDLE *target_handle, gint32 access, gint32 inherit, gint32 options, gint32 *error)
1088 /* This is only used on Windows */
1091 MONO_PREPARE_BLOCKING;
1092 ret=DuplicateHandle (source_process_handle, source_handle, target_process_handle, target_handle, access, inherit, options);
1093 MONO_FINISH_BLOCKING;
1096 *error = GetLastError ();
1097 /* FIXME: throw an exception? */
1105 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
1107 #if defined (TARGET_WIN32)
1108 return (gunichar2) ':'; /* colon */
1110 return (gunichar2) '/'; /* forward slash */
1115 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
1117 #if defined (TARGET_WIN32)
1118 return (gunichar2) '\\'; /* backslash */
1120 return (gunichar2) '/'; /* forward slash */
1125 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
1127 #if defined (TARGET_WIN32)
1128 return (gunichar2) '/'; /* forward slash */
1130 if (IS_PORTABILITY_SET)
1131 return (gunichar2) '\\'; /* backslash */
1133 return (gunichar2) '/'; /* forward slash */
1138 ves_icall_System_IO_MonoIO_get_PathSeparator ()
1140 #if defined (TARGET_WIN32)
1141 return (gunichar2) ';'; /* semicolon */
1143 return (gunichar2) ':'; /* colon */
1147 static const gunichar2
1148 invalid_path_chars [] = {
1149 #if defined (TARGET_WIN32)
1150 0x0022, /* double quote, which seems allowed in MS.NET but should be rejected */
1151 0x003c, /* less than */
1152 0x003e, /* greater than */
1169 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
1175 domain = mono_domain_get ();
1176 n = sizeof (invalid_path_chars) / sizeof (gunichar2);
1177 chars = mono_array_new (domain, mono_defaults.char_class, n);
1179 for (i = 0; i < n; ++ i)
1180 mono_array_set (chars, gunichar2, i, invalid_path_chars [i]);
1185 void ves_icall_System_IO_MonoIO_Lock (HANDLE handle, gint64 position,
1186 gint64 length, gint32 *error)
1189 MONO_PREPARE_BLOCKING;
1191 *error=ERROR_SUCCESS;
1193 ret=LockFile (handle, position & 0xFFFFFFFF, position >> 32,
1194 length & 0xFFFFFFFF, length >> 32);
1196 *error = GetLastError ();
1199 MONO_FINISH_BLOCKING;
1202 void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle, gint64 position,
1203 gint64 length, gint32 *error)
1206 MONO_PREPARE_BLOCKING;
1208 *error=ERROR_SUCCESS;
1210 ret=UnlockFile (handle, position & 0xFFFFFFFF, position >> 32,
1211 length & 0xFFFFFFFF, length >> 32);
1213 *error = GetLastError ();
1216 MONO_FINISH_BLOCKING;
1219 //Support for io-layer free mmap'd files.
1221 #if defined (TARGET_IOS) || defined (TARGET_ANDROID)
1224 mono_filesize_from_path (MonoString *string)
1228 char *path = mono_string_to_utf8 (string);
1230 MONO_PREPARE_BLOCKING;
1231 if (stat (path, &buf) == -1)
1234 res = (gint64)buf.st_size;
1238 MONO_FINISH_BLOCKING;
1243 mono_filesize_from_fd (int fd)
1248 MONO_PREPARE_BLOCKING;
1249 res = fstat (fd, &buf);
1250 MONO_FINISH_BLOCKING;
1255 return (gint64)buf.st_size;
1260 void _wapi_handle_dump (void);
1262 void ves_icall_System_IO_MonoIO_DumpHandles (void)
1265 _wapi_handle_dump ();