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/file-io-internals.h>
33 #include <mono/metadata/exception.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/marshal.h>
36 #include <mono/utils/strenc.h>
37 #include <utils/mono-io-portability.h>
38 #include <mono/metadata/w32handle.h>
42 /* conversion functions */
44 static guint32
convert_mode(MonoFileMode mono_mode
)
49 case FileMode_CreateNew
:
58 case FileMode_OpenOrCreate
:
61 case FileMode_Truncate
:
62 mode
=TRUNCATE_EXISTING
;
68 g_warning("System.IO.FileMode has unknown value 0x%x",
77 static guint32
convert_access(MonoFileAccess mono_access
)
85 case FileAccess_Write
:
88 case FileAccess_ReadWrite
:
89 access
=GENERIC_READ
|GENERIC_WRITE
;
92 g_warning("System.IO.FileAccess has unknown value 0x%x",
101 static guint32
convert_share(MonoFileShare mono_share
)
105 if (mono_share
& FileShare_Read
) {
106 share
|= FILE_SHARE_READ
;
108 if (mono_share
& FileShare_Write
) {
109 share
|= FILE_SHARE_WRITE
;
111 if (mono_share
& FileShare_Delete
) {
112 share
|= FILE_SHARE_DELETE
;
115 if (mono_share
& ~(FileShare_Read
|FileShare_Write
|FileShare_Delete
)) {
116 g_warning("System.IO.FileShare has unknown value 0x%x",
126 static guint32
convert_stdhandle(guint32 fd
)
132 stdhandle
=STD_INPUT_HANDLE
;
135 stdhandle
=STD_OUTPUT_HANDLE
;
138 stdhandle
=STD_ERROR_HANDLE
;
141 g_warning("unknown standard file descriptor %d", fd
);
142 stdhandle
=STD_INPUT_HANDLE
;
149 static guint32
convert_seekorigin(MonoSeekOrigin origin
)
154 case SeekOrigin_Begin
:
155 w32origin
=FILE_BEGIN
;
157 case SeekOrigin_Current
:
158 w32origin
=FILE_CURRENT
;
164 g_warning("System.IO.SeekOrigin has unknown value 0x%x",
167 w32origin
=FILE_CURRENT
;
173 static gint64
convert_filetime (const FILETIME
*filetime
)
175 guint64 ticks
= filetime
->dwHighDateTime
;
177 ticks
+= filetime
->dwLowDateTime
;
178 return (gint64
)ticks
;
181 static void convert_win32_file_attribute_data (const WIN32_FILE_ATTRIBUTE_DATA
*data
, MonoIOStat
*stat
)
183 stat
->attributes
= data
->dwFileAttributes
;
184 stat
->creation_time
= convert_filetime (&data
->ftCreationTime
);
185 stat
->last_access_time
= convert_filetime (&data
->ftLastAccessTime
);
186 stat
->last_write_time
= convert_filetime (&data
->ftLastWriteTime
);
187 stat
->length
= ((gint64
)data
->nFileSizeHigh
<< 32) | data
->nFileSizeLow
;
190 /* Managed file attributes have nearly but not quite the same values
191 * as the w32 equivalents.
193 static guint32
convert_attrs(MonoFileAttributes attrs
)
195 if(attrs
& FileAttributes_Encrypted
) {
196 attrs
= (MonoFileAttributes
)(attrs
| FILE_ATTRIBUTE_ENCRYPTED
);
203 * On Win32, GetFileAttributes|Ex () seems to try opening the file,
204 * which might lead to sharing violation errors, whereas FindFirstFile
205 * always succeeds. These 2 wrappers resort to FindFirstFile if
206 * GetFileAttributes|Ex () has failed.
209 get_file_attributes (const gunichar2
*path
)
212 WIN32_FIND_DATA find_data
;
216 res
= GetFileAttributes (path
);
220 error
= GetLastError ();
222 if (error
!= ERROR_SHARING_VIOLATION
)
225 find_handle
= FindFirstFile (path
, &find_data
);
227 if (find_handle
== INVALID_HANDLE_VALUE
)
230 FindClose (find_handle
);
232 return find_data
.dwFileAttributes
;
236 get_file_attributes_ex (const gunichar2
*path
, WIN32_FILE_ATTRIBUTE_DATA
*data
)
239 WIN32_FIND_DATA find_data
;
243 res
= GetFileAttributesEx (path
, GetFileExInfoStandard
, data
);
247 error
= GetLastError ();
249 if (error
!= ERROR_SHARING_VIOLATION
)
252 find_handle
= FindFirstFile (path
, &find_data
);
254 if (find_handle
== INVALID_HANDLE_VALUE
)
257 FindClose (find_handle
);
259 data
->dwFileAttributes
= find_data
.dwFileAttributes
;
260 data
->ftCreationTime
= find_data
.ftCreationTime
;
261 data
->ftLastAccessTime
= find_data
.ftLastAccessTime
;
262 data
->ftLastWriteTime
= find_data
.ftLastWriteTime
;
263 data
->nFileSizeHigh
= find_data
.nFileSizeHigh
;
264 data
->nFileSizeLow
= find_data
.nFileSizeLow
;
269 /* System.IO.MonoIO internal calls */
272 ves_icall_System_IO_MonoIO_CreateDirectory (MonoString
*path
, gint32
*error
)
277 *error
=ERROR_SUCCESS
;
279 ret
=CreateDirectory (mono_string_chars (path
), NULL
);
281 *error
=GetLastError ();
289 ves_icall_System_IO_MonoIO_RemoveDirectory (MonoString
*path
, gint32
*error
)
294 *error
=ERROR_SUCCESS
;
296 ret
=RemoveDirectory (mono_string_chars (path
));
298 *error
=GetLastError ();
306 get_search_dir (const gunichar2
*pattern
)
311 p
= g_utf16_to_utf8 (pattern
, -1, NULL
, NULL
, NULL
);
312 result
= g_path_get_dirname (p
);
318 get_filesystem_entries (const gunichar2
*path
,
319 const gunichar2
*path_with_pattern
,
320 gint attrs
, gint mask
,
324 WIN32_FIND_DATA data
;
326 GPtrArray
*names
= NULL
;
327 gchar
*utf8_path
= NULL
, *utf8_result
, *full_name
;
330 mask
= convert_attrs ((MonoFileAttributes
)mask
);
331 attributes
= get_file_attributes (path
);
332 if (attributes
!= -1) {
333 if ((attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0) {
334 *error
= ERROR_INVALID_NAME
;
338 *error
= GetLastError ();
342 find_handle
= FindFirstFile (path_with_pattern
, &data
);
343 if (find_handle
== INVALID_HANDLE_VALUE
) {
344 gint32 find_error
= GetLastError ();
346 if (find_error
== ERROR_FILE_NOT_FOUND
|| find_error
== ERROR_NO_MORE_FILES
) {
347 /* No files, so just return an empty array */
355 utf8_path
= get_search_dir (path_with_pattern
);
356 names
= g_ptr_array_new ();
359 if ((data
.cFileName
[0] == '.' && data
.cFileName
[1] == 0) ||
360 (data
.cFileName
[0] == '.' && data
.cFileName
[1] == '.' && data
.cFileName
[2] == 0)) {
364 if ((data
.dwFileAttributes
& mask
) == attrs
) {
365 utf8_result
= g_utf16_to_utf8 (data
.cFileName
, -1, NULL
, NULL
, NULL
);
366 if (utf8_result
== NULL
) {
370 full_name
= g_build_filename (utf8_path
, utf8_result
, NULL
);
371 g_ptr_array_add (names
, full_name
);
373 g_free (utf8_result
);
375 } while(FindNextFile (find_handle
, &data
));
377 if (FindClose (find_handle
) == FALSE
) {
378 *error
= GetLastError ();
386 for (i
= 0; i
< names
->len
; i
++)
387 g_free (g_ptr_array_index (names
, i
));
388 g_ptr_array_free (names
, TRUE
);
396 ves_icall_System_IO_MonoIO_GetFileSystemEntries (MonoString
*path
,
397 MonoString
*path_with_pattern
,
398 gint attrs
, gint mask
,
402 MonoDomain
*domain
= mono_domain_get ();
407 *ioerror
= ERROR_SUCCESS
;
410 names
= get_filesystem_entries (mono_string_chars (path
), mono_string_chars (path_with_pattern
), attrs
, mask
, ioerror
);
414 // If there's no array and no error, then return an empty array.
415 if (*ioerror
== ERROR_SUCCESS
) {
416 MonoArray
*arr
= mono_array_new_checked (domain
, mono_defaults
.string_class
, 0, &error
);
417 mono_error_set_pending_exception (&error
);
423 result
= mono_array_new_checked (domain
, mono_defaults
.string_class
, names
->len
, &error
);
424 if (mono_error_set_pending_exception (&error
))
426 for (i
= 0; i
< names
->len
; i
++) {
427 mono_array_setref (result
, i
, mono_string_new (domain
, (const char *)g_ptr_array_index (names
, i
)));
428 g_free (g_ptr_array_index (names
, i
));
431 g_ptr_array_free (names
, TRUE
);
442 incremental_find_check_match (IncrementalFind
*handle
, WIN32_FIND_DATA
*data
, MonoString
**result
)
447 if ((data
->cFileName
[0] == '.' && data
->cFileName
[1] == 0) || (data
->cFileName
[0] == '.' && data
->cFileName
[1] == '.' && data
->cFileName
[2] == 0))
450 utf8_result
= g_utf16_to_utf8 (data
->cFileName
, -1, NULL
, NULL
, NULL
);
451 if (utf8_result
== NULL
)
454 full_name
= g_build_filename (handle
->utf8_path
, utf8_result
, NULL
);
455 g_free (utf8_result
);
456 *result
= mono_string_new (mono_domain_get (), full_name
);
463 ves_icall_System_IO_MonoIO_FindFirstFile (MonoString
*path_with_pattern
, MonoString
**file_name
, gint32
*file_attr
, gint32
*ioerror
)
466 WIN32_FIND_DATA data
;
469 hnd
= FindFirstFile (mono_string_chars (path_with_pattern
), &data
);
471 if (hnd
== INVALID_HANDLE_VALUE
) {
474 *ioerror
= GetLastError ();
478 mono_gc_wbarrier_generic_store (file_name
, (MonoObject
*) mono_string_from_utf16_checked (data
.cFileName
, &error
));
479 mono_error_set_pending_exception (&error
);
481 *file_attr
= data
.dwFileAttributes
;
482 *ioerror
= ERROR_SUCCESS
;
488 ves_icall_System_IO_MonoIO_FindNextFile (HANDLE hnd
, MonoString
**file_name
, gint32
*file_attr
, gint32
*ioerror
)
491 WIN32_FIND_DATA data
;
494 res
= FindNextFile (hnd
, &data
);
499 *ioerror
= GetLastError ();
503 mono_gc_wbarrier_generic_store (file_name
, (MonoObject
*) mono_string_from_utf16_checked (data
.cFileName
, &error
));
504 mono_error_set_pending_exception (&error
);
506 *file_attr
= data
.dwFileAttributes
;
507 *ioerror
= ERROR_SUCCESS
;
513 ves_icall_System_IO_MonoIO_FindCloseFile (HANDLE hnd
)
515 return FindClose (hnd
);
518 /* FIXME make gc suspendable */
520 ves_icall_System_IO_MonoIO_FindFirst (MonoString
*path
,
521 MonoString
*path_with_pattern
,
522 gint32
*result_attr
, gint32
*ioerror
,
526 WIN32_FIND_DATA data
;
528 IncrementalFind
*ifh
;
531 *ioerror
= ERROR_SUCCESS
;
533 find_handle
= FindFirstFile (mono_string_chars (path_with_pattern
), &data
);
535 if (find_handle
== INVALID_HANDLE_VALUE
) {
536 gint32 find_error
= GetLastError ();
539 if (find_error
== ERROR_FILE_NOT_FOUND
)
542 *ioerror
= find_error
;
546 ifh
= g_new (IncrementalFind
, 1);
547 ifh
->find_handle
= find_handle
;
548 ifh
->utf8_path
= mono_string_to_utf8_checked (path
, &error
);
549 if (mono_error_set_pending_exception (&error
)) {
551 FindClose (find_handle
);
556 ifh
->domain
= mono_domain_get ();
559 while (incremental_find_check_match (ifh
, &data
, &result
) == 0){
560 if (FindNextFile (find_handle
, &data
) == FALSE
){
561 int e
= GetLastError ();
562 if (e
!= ERROR_NO_MORE_FILES
)
567 *result_attr
= data
.dwFileAttributes
;
572 /* FIXME make gc suspendable */
574 ves_icall_System_IO_MonoIO_FindNext (gpointer handle
, gint32
*result_attr
, gint32
*error
)
576 IncrementalFind
*ifh
= (IncrementalFind
*)handle
;
577 WIN32_FIND_DATA data
;
580 *error
= ERROR_SUCCESS
;
582 if (FindNextFile (ifh
->find_handle
, &data
) == FALSE
){
583 int e
= GetLastError ();
584 if (e
!= ERROR_NO_MORE_FILES
)
588 } while (incremental_find_check_match (ifh
, &data
, &result
) == 0);
590 *result_attr
= data
.dwFileAttributes
;
595 ves_icall_System_IO_MonoIO_FindClose (gpointer handle
)
597 IncrementalFind
*ifh
= (IncrementalFind
*)handle
;
601 if (FindClose (ifh
->find_handle
) == FALSE
){
602 error
= GetLastError ();
604 error
= ERROR_SUCCESS
;
605 g_free (ifh
->utf8_path
);
613 ves_icall_System_IO_MonoIO_GetCurrentDirectory (gint32
*io_error
)
620 len
= MAX_PATH
+ 1; /*FIXME this is too smal under most unix systems.*/
621 buf
= g_new (gunichar2
, len
);
623 mono_error_init (&error
);
624 *io_error
=ERROR_SUCCESS
;
627 res_len
= GetCurrentDirectory (len
, buf
);
628 if (res_len
> len
) { /*buf is too small.*/
629 int old_res_len
= res_len
;
631 buf
= g_new (gunichar2
, res_len
);
632 res_len
= GetCurrentDirectory (res_len
, buf
) == old_res_len
;
640 result
= mono_string_new_utf16_checked (mono_domain_get (), buf
, len
, &error
);
642 *io_error
=GetLastError ();
646 mono_error_set_pending_exception (&error
);
651 ves_icall_System_IO_MonoIO_SetCurrentDirectory (MonoString
*path
,
656 *error
=ERROR_SUCCESS
;
658 ret
=SetCurrentDirectory (mono_string_chars (path
));
660 *error
=GetLastError ();
666 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
668 mono_file_io_move_file (gunichar2
*path
, gunichar2
*dest
, gint32
*error
)
670 gboolean result
= FALSE
;
673 result
= MoveFile (path
, dest
);
674 if (result
== FALSE
) {
675 *error
=GetLastError ();
681 #endif /* HAVE_CLASSIC_WINAPI_SUPPORT */
684 ves_icall_System_IO_MonoIO_MoveFile (MonoString
*path
, MonoString
*dest
, gint32
*error
)
686 *error
=ERROR_SUCCESS
;
687 return mono_file_io_move_file (mono_string_chars (path
), mono_string_chars (dest
), error
);
690 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
692 mono_file_io_replace_file (gunichar2
*destinationFileName
, gunichar2
*sourceFileName
,
693 gunichar2
*destinationBackupFileName
, guint32 flags
, gint32
*error
)
695 gboolean result
= FALSE
;
698 result
= ReplaceFile (destinationFileName
, sourceFileName
, destinationBackupFileName
, flags
, NULL
, NULL
);
699 if (result
== FALSE
) {
700 *error
=GetLastError ();
706 #endif /* HAVE_CLASSIC_WINAPI_SUPPORT */
709 ves_icall_System_IO_MonoIO_ReplaceFile (MonoString
*sourceFileName
, MonoString
*destinationFileName
,
710 MonoString
*destinationBackupFileName
, MonoBoolean ignoreMetadataErrors
,
713 gunichar2
*utf16_sourceFileName
= NULL
, *utf16_destinationFileName
= NULL
, *utf16_destinationBackupFileName
= NULL
;
714 guint32 replaceFlags
= REPLACEFILE_WRITE_THROUGH
;
717 utf16_sourceFileName
= mono_string_chars (sourceFileName
);
718 if (destinationFileName
)
719 utf16_destinationFileName
= mono_string_chars (destinationFileName
);
720 if (destinationBackupFileName
)
721 utf16_destinationBackupFileName
= mono_string_chars (destinationBackupFileName
);
723 *error
= ERROR_SUCCESS
;
724 if (ignoreMetadataErrors
)
725 replaceFlags
|= REPLACEFILE_IGNORE_MERGE_ERRORS
;
727 /* FIXME: source and destination file names must not be NULL, but apparently they might be! */
728 return mono_file_io_replace_file (utf16_destinationFileName
, utf16_sourceFileName
,
729 utf16_destinationBackupFileName
, replaceFlags
, error
);
732 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
734 mono_file_io_copy_file (gunichar2
*path
, gunichar2
*dest
, gboolean overwrite
, gint32
*error
)
736 gboolean result
= FALSE
;
739 result
= CopyFile (path
, dest
, !overwrite
);
740 if (result
== FALSE
) {
741 *error
=GetLastError ();
747 #endif /* HAVE_CLASSIC_WINAPI_SUPPORT */
750 ves_icall_System_IO_MonoIO_CopyFile (MonoString
*path
, MonoString
*dest
,
751 MonoBoolean overwrite
, gint32
*error
)
753 *error
=ERROR_SUCCESS
;
754 return mono_file_io_copy_file (mono_string_chars (path
), mono_string_chars (dest
), overwrite
, error
);
758 ves_icall_System_IO_MonoIO_DeleteFile (MonoString
*path
, gint32
*error
)
763 *error
=ERROR_SUCCESS
;
765 ret
=DeleteFile (mono_string_chars (path
));
767 *error
=GetLastError ();
775 ves_icall_System_IO_MonoIO_GetFileAttributes (MonoString
*path
, gint32
*error
)
780 *error
=ERROR_SUCCESS
;
782 ret
=get_file_attributes (mono_string_chars (path
));
785 * The definition of INVALID_FILE_ATTRIBUTES in the cygwin win32
786 * headers is wrong, hence this temporary workaround.
788 * http://cygwin.com/ml/cygwin/2003-09/msg01771.html
791 /* if(ret==INVALID_FILE_ATTRIBUTES) { */
792 *error
=GetLastError ();
800 ves_icall_System_IO_MonoIO_SetFileAttributes (MonoString
*path
, gint32 attrs
,
806 *error
=ERROR_SUCCESS
;
808 ret
=SetFileAttributes (mono_string_chars (path
),
809 convert_attrs ((MonoFileAttributes
)attrs
));
811 *error
=GetLastError ();
819 ves_icall_System_IO_MonoIO_GetFileType (HANDLE handle
, gint32
*error
)
824 *error
=ERROR_SUCCESS
;
826 ret
=GetFileType (handle
);
827 if(ret
==FILE_TYPE_UNKNOWN
) {
828 /* Not necessarily an error, but the caller will have
829 * to decide based on the error value.
831 *error
=GetLastError ();
839 ves_icall_System_IO_MonoIO_GetFileStat (MonoString
*path
, MonoIOStat
*stat
,
843 WIN32_FILE_ATTRIBUTE_DATA data
;
846 *error
=ERROR_SUCCESS
;
848 result
= get_file_attributes_ex (mono_string_chars (path
), &data
);
851 convert_win32_file_attribute_data (&data
, stat
);
853 *error
=GetLastError ();
854 memset (stat
, 0, sizeof (MonoIOStat
));
862 ves_icall_System_IO_MonoIO_Open (MonoString
*filename
, gint32 mode
,
863 gint32 access_mode
, gint32 share
, gint32 options
,
867 int attributes
, attrs
;
871 chars
= mono_string_chars (filename
);
872 *error
=ERROR_SUCCESS
;
875 if (options
& FileOptions_Encrypted
)
876 attributes
= FILE_ATTRIBUTE_ENCRYPTED
;
878 attributes
= FILE_ATTRIBUTE_NORMAL
;
879 if (options
& FileOptions_DeleteOnClose
)
880 attributes
|= FILE_FLAG_DELETE_ON_CLOSE
;
881 if (options
& FileOptions_SequentialScan
)
882 attributes
|= FILE_FLAG_SEQUENTIAL_SCAN
;
883 if (options
& FileOptions_RandomAccess
)
884 attributes
|= FILE_FLAG_RANDOM_ACCESS
;
886 if (options
& FileOptions_Temporary
)
887 attributes
|= FILE_ATTRIBUTE_TEMPORARY
;
889 if (options
& FileOptions_WriteThrough
)
890 attributes
|= FILE_FLAG_WRITE_THROUGH
;
892 attributes
= FILE_ATTRIBUTE_NORMAL
;
894 /* If we're opening a directory we need to set the extra flag
896 attrs
= get_file_attributes (chars
);
897 if (attrs
!= INVALID_FILE_ATTRIBUTES
) {
898 if (attrs
& FILE_ATTRIBUTE_DIRECTORY
) {
899 attributes
|= FILE_FLAG_BACKUP_SEMANTICS
;
903 ret
=CreateFile (chars
, convert_access ((MonoFileAccess
)access_mode
),
904 convert_share ((MonoFileShare
)share
), NULL
, convert_mode ((MonoFileMode
)mode
),
906 if(ret
==INVALID_HANDLE_VALUE
) {
907 *error
=GetLastError ();
915 ves_icall_System_IO_MonoIO_Close (HANDLE handle
, gint32
*error
)
920 *error
=ERROR_SUCCESS
;
922 ret
=CloseHandle (handle
);
924 *error
=GetLastError ();
932 ves_icall_System_IO_MonoIO_Read (HANDLE handle
, MonoArray
*dest
,
933 gint32 dest_offset
, gint32 count
,
940 *error
=ERROR_SUCCESS
;
942 MONO_CHECK_ARG_NULL (dest
, 0);
944 if (dest_offset
> mono_array_length (dest
) - count
) {
945 mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
949 buffer
= mono_array_addr (dest
, guchar
, dest_offset
);
952 result
= ReadFile (handle
, buffer
, count
, &n
, NULL
);
956 *error
=GetLastError ();
964 ves_icall_System_IO_MonoIO_Write (HANDLE handle
, MonoArray
*src
,
965 gint32 src_offset
, gint32 count
,
972 *error
=ERROR_SUCCESS
;
974 MONO_CHECK_ARG_NULL (src
, 0);
976 if (src_offset
> mono_array_length (src
) - count
) {
977 mono_set_pending_exception (mono_get_exception_argument ("array", "array too small. numBytes/offset wrong."));
981 buffer
= mono_array_addr (src
, guchar
, src_offset
);
983 result
= WriteFile (handle
, buffer
, count
, &n
, NULL
);
987 *error
=GetLastError ();
995 ves_icall_System_IO_MonoIO_Seek (HANDLE handle
, gint64 offset
, gint32 origin
,
1001 *error
=ERROR_SUCCESS
;
1003 offset_hi
= offset
>> 32;
1004 offset
= SetFilePointer (handle
, (gint32
) (offset
& 0xFFFFFFFF), &offset_hi
,
1005 convert_seekorigin ((MonoSeekOrigin
)origin
));
1007 if(offset
==INVALID_SET_FILE_POINTER
) {
1008 *error
=GetLastError ();
1012 return offset
| ((gint64
)offset_hi
<< 32);
1016 ves_icall_System_IO_MonoIO_Flush (HANDLE handle
, gint32
*error
)
1021 *error
=ERROR_SUCCESS
;
1023 ret
=FlushFileBuffers (handle
);
1025 *error
=GetLastError ();
1032 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1034 mono_file_io_get_file_size (HANDLE handle
, gint32
*error
)
1041 length
= GetFileSize (handle
, &length_hi
);
1042 if(length
==INVALID_FILE_SIZE
) {
1043 *error
=GetLastError ();
1047 return length
| ((gint64
)length_hi
<< 32);
1049 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
1052 ves_icall_System_IO_MonoIO_GetLength (HANDLE handle
, gint32
*error
)
1054 *error
=ERROR_SUCCESS
;
1055 return mono_file_io_get_file_size (handle
, error
);
1058 /* FIXME make gc suspendable */
1060 ves_icall_System_IO_MonoIO_SetLength (HANDLE handle
, gint64 length
,
1063 gint64 offset
, offset_set
;
1068 *error
=ERROR_SUCCESS
;
1070 /* save file pointer */
1073 offset
= SetFilePointer (handle
, 0, &offset_hi
, FILE_CURRENT
);
1074 if(offset
==INVALID_SET_FILE_POINTER
) {
1075 *error
=GetLastError ();
1079 /* extend or truncate */
1081 length_hi
= length
>> 32;
1082 offset_set
=SetFilePointer (handle
, length
& 0xFFFFFFFF, &length_hi
,
1084 if(offset_set
==INVALID_SET_FILE_POINTER
) {
1085 *error
=GetLastError ();
1089 result
= SetEndOfFile (handle
);
1091 *error
=GetLastError ();
1095 /* restore file pointer */
1097 offset_set
=SetFilePointer (handle
, offset
& 0xFFFFFFFF, &offset_hi
,
1099 if(offset_set
==INVALID_SET_FILE_POINTER
) {
1100 *error
=GetLastError ();
1108 ves_icall_System_IO_MonoIO_SetFileTime (HANDLE handle
, gint64 creation_time
,
1109 gint64 last_access_time
,
1110 gint64 last_write_time
, gint32
*error
)
1113 const FILETIME
*creation_filetime
;
1114 const FILETIME
*last_access_filetime
;
1115 const FILETIME
*last_write_filetime
;
1118 *error
=ERROR_SUCCESS
;
1120 if (creation_time
< 0)
1121 creation_filetime
= NULL
;
1123 creation_filetime
= (FILETIME
*)&creation_time
;
1125 if (last_access_time
< 0)
1126 last_access_filetime
= NULL
;
1128 last_access_filetime
= (FILETIME
*)&last_access_time
;
1130 if (last_write_time
< 0)
1131 last_write_filetime
= NULL
;
1133 last_write_filetime
= (FILETIME
*)&last_write_time
;
1135 ret
=SetFileTime (handle
, creation_filetime
, last_access_filetime
, last_write_filetime
);
1137 *error
=GetLastError ();
1144 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1146 mono_file_io_get_console_output (void)
1148 return GetStdHandle (STD_OUTPUT_HANDLE
);
1150 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
1153 ves_icall_System_IO_MonoIO_get_ConsoleOutput ()
1155 return mono_file_io_get_console_output ();
1158 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1160 mono_file_io_get_console_input (void)
1162 return GetStdHandle (STD_INPUT_HANDLE
);
1164 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
1167 ves_icall_System_IO_MonoIO_get_ConsoleInput ()
1169 return mono_file_io_get_console_input ();
1172 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1174 mono_file_io_get_console_error (void)
1176 return GetStdHandle (STD_ERROR_HANDLE
);
1178 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
1181 ves_icall_System_IO_MonoIO_get_ConsoleError ()
1183 return mono_file_io_get_console_error ();
1187 ves_icall_System_IO_MonoIO_CreatePipe (HANDLE
*read_handle
, HANDLE
*write_handle
, gint32
*error
)
1189 SECURITY_ATTRIBUTES attr
;
1192 attr
.nLength
=sizeof(SECURITY_ATTRIBUTES
);
1193 attr
.bInheritHandle
=TRUE
;
1194 attr
.lpSecurityDescriptor
=NULL
;
1197 ret
=CreatePipe (read_handle
, write_handle
, &attr
, 0);
1201 *error
= GetLastError ();
1202 /* FIXME: throw an exception? */
1210 ves_icall_System_IO_MonoIO_DuplicateHandle (HANDLE source_process_handle
, HANDLE source_handle
,
1211 HANDLE target_process_handle
, HANDLE
*target_handle
, gint32 access
, gint32 inherit
, gint32 options
, gint32
*error
)
1213 /* This is only used on Windows */
1218 ret
=DuplicateHandle (source_process_handle
, source_handle
, target_process_handle
, target_handle
, access
, inherit
, options
);
1220 mono_w32handle_ref (source_handle
);
1221 *target_handle
= source_handle
;
1227 *error
= GetLastError ();
1228 /* FIXME: throw an exception? */
1237 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
1239 return (gunichar2
) '/'; /* forward slash */
1243 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
1245 return (gunichar2
) '/'; /* forward slash */
1249 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
1251 if (IS_PORTABILITY_SET
)
1252 return (gunichar2
) '\\'; /* backslash */
1254 return (gunichar2
) '/'; /* forward slash */
1258 ves_icall_System_IO_MonoIO_get_PathSeparator ()
1260 return (gunichar2
) ':'; /* colon */
1262 #endif /* !HOST_WIN32 */
1264 static const gunichar2
1265 invalid_path_chars
[] = {
1266 #if defined (TARGET_WIN32)
1267 0x0022, /* double quote, which seems allowed in MS.NET but should be rejected */
1268 0x003c, /* less than */
1269 0x003e, /* greater than */
1286 ves_icall_System_IO_MonoIO_get_InvalidPathChars ()
1293 domain
= mono_domain_get ();
1294 n
= sizeof (invalid_path_chars
) / sizeof (gunichar2
);
1295 chars
= mono_array_new_checked (domain
, mono_defaults
.char_class
, n
, &error
);
1296 if (mono_error_set_pending_exception (&error
))
1299 for (i
= 0; i
< n
; ++ i
)
1300 mono_array_set (chars
, gunichar2
, i
, invalid_path_chars
[i
]);
1305 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1307 mono_file_io_lock_file (HANDLE handle
, gint64 position
, gint64 length
, gint32
*error
)
1309 gboolean result
= FALSE
;
1312 result
= LockFile (handle
, position
& 0xFFFFFFFF, position
>> 32,
1313 length
& 0xFFFFFFFF, length
>> 32);
1315 if (result
== FALSE
) {
1316 *error
= GetLastError ();
1322 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
1324 void ves_icall_System_IO_MonoIO_Lock (HANDLE handle
, gint64 position
,
1325 gint64 length
, gint32
*error
)
1327 *error
=ERROR_SUCCESS
;
1328 mono_file_io_lock_file (handle
, position
, length
, error
);
1331 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1333 mono_file_io_unlock_file (HANDLE handle
, gint64 position
, gint64 length
, gint32
*error
)
1335 gboolean result
= FALSE
;
1338 result
= UnlockFile (handle
, position
& 0xFFFFFFFF, position
>> 32,
1339 length
& 0xFFFFFFFF, length
>> 32);
1341 if (result
== FALSE
) {
1342 *error
= GetLastError ();
1348 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
1350 void ves_icall_System_IO_MonoIO_Unlock (HANDLE handle
, gint64 position
,
1351 gint64 length
, gint32
*error
)
1353 *error
=ERROR_SUCCESS
;
1354 mono_file_io_unlock_file (handle
, position
, length
, error
);
1357 //Support for io-layer free mmap'd files.
1359 #if defined (TARGET_IOS) || defined (TARGET_ANDROID)
1362 mono_filesize_from_path (MonoString
*string
)
1367 char *path
= mono_string_to_utf8_checked (string
, &error
);
1368 mono_error_raise_exception (&error
); /* OK to throw, external only without a good alternative */
1371 if (stat (path
, &buf
) == -1)
1374 res
= (gint64
)buf
.st_size
;
1383 mono_filesize_from_fd (int fd
)
1389 res
= fstat (fd
, &buf
);
1395 return (gint64
)buf
.st_size
;
1401 void mono_w32handle_dump (void);
1403 void ves_icall_System_IO_MonoIO_DumpHandles (void)
1406 mono_w32handle_dump ();
1408 #endif /* !HOST_WIN32 */