3 * Windows File IO internal calls.
5 * Copyright 2016 Microsoft
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include "mono/metadata/w32file-win32-internals.h"
14 #include "mono/metadata/w32subset.h"
15 #include "icall-decl.h"
18 mono_w32file_init (void)
23 mono_w32file_cleanup (void)
28 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
30 return (gunichar2
) ':'; /* colon */
34 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
36 return (gunichar2
) '\\'; /* backslash */
40 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
42 return (gunichar2
) '/'; /* forward slash */
46 ves_icall_System_IO_MonoIO_get_PathSeparator ()
48 return (gunichar2
) ';'; /* semicolon */
51 void ves_icall_System_IO_MonoIO_DumpHandles (void)
57 mono_w32file_create(const gunichar2
*name
, guint32 fileaccess
, guint32 sharemode
, guint32 createmode
, guint32 attrs
)
61 res
= CreateFileW (name
, fileaccess
, sharemode
, NULL
, createmode
, attrs
, NULL
);
67 mono_w32file_cancel (gpointer handle
)
69 return CancelIoEx (handle
, NULL
);
73 mono_w32file_close (gpointer handle
)
77 res
= CloseHandle (handle
);
83 mono_w32file_delete (const gunichar2
*name
)
87 res
= DeleteFileW (name
);
92 // See win32_wait_interrupt_handler for details.
94 win32_io_interrupt_handler (gpointer ignored
)
99 mono_w32file_read(gpointer handle
, gpointer buffer
, guint32 numbytes
, guint32
*bytesread
, gint32
*win32error
)
102 MonoThreadInfo
*info
= mono_thread_info_current ();
103 gboolean alerted
= FALSE
;
106 mono_thread_info_install_interrupt (win32_io_interrupt_handler
, NULL
, &alerted
);
108 SetLastError (ERROR_OPERATION_ABORTED
);
109 *win32error
= ERROR_OPERATION_ABORTED
;
112 mono_win32_enter_blocking_io_call (info
, handle
);
116 if (info
&& mono_thread_info_is_interrupt_state (info
)) {
118 SetLastError (ERROR_OPERATION_ABORTED
);
120 res
= ReadFile (handle
, buffer
, numbytes
, (PDWORD
)bytesread
, NULL
);
123 *win32error
= GetLastError ();
127 mono_win32_leave_blocking_io_call (info
, handle
);
128 mono_thread_info_uninstall_interrupt (&alerted
);
135 mono_w32file_write (gpointer handle
, gconstpointer buffer
, guint32 numbytes
, guint32
*byteswritten
, gint32
*win32error
)
138 MonoThreadInfo
*info
= mono_thread_info_current ();
139 gboolean alerted
= FALSE
;
142 mono_thread_info_install_interrupt (win32_io_interrupt_handler
, NULL
, &alerted
);
144 SetLastError (ERROR_OPERATION_ABORTED
);
145 *win32error
= ERROR_OPERATION_ABORTED
;
148 mono_win32_enter_blocking_io_call (info
, handle
);
152 if (info
&& mono_thread_info_is_interrupt_state (info
)) {
154 SetLastError (ERROR_OPERATION_ABORTED
);
156 res
= WriteFile (handle
, buffer
, numbytes
, (PDWORD
)byteswritten
, NULL
);
159 *win32error
= GetLastError ();
163 mono_win32_leave_blocking_io_call (info
, handle
);
164 mono_thread_info_uninstall_interrupt (&alerted
);
171 mono_w32file_flush (gpointer handle
)
175 res
= FlushFileBuffers (handle
);
181 mono_w32file_truncate (gpointer handle
)
185 res
= SetEndOfFile (handle
);
191 mono_w32file_seek (gpointer handle
, gint32 movedistance
, gint32
*highmovedistance
, guint32 method
)
195 res
= SetFilePointer (handle
, movedistance
, (PLONG
)highmovedistance
, method
);
201 mono_w32file_get_type (gpointer handle
)
205 res
= GetFileType (handle
);
211 mono_w32file_set_times (gpointer handle
, const FILETIME
*create_time
, const FILETIME
*access_time
, const FILETIME
*write_time
)
215 res
= SetFileTime (handle
, create_time
, access_time
, write_time
);
221 mono_w32file_filetime_to_systemtime (const FILETIME
*file_time
, SYSTEMTIME
*system_time
)
225 res
= FileTimeToSystemTime (file_time
, system_time
);
231 mono_w32file_find_first (const gunichar2
*pattern
, WIN32_FIND_DATAW
*find_data
)
235 res
= FindFirstFileW (pattern
, find_data
);
241 mono_w32file_find_next (gpointer handle
, WIN32_FIND_DATAW
*find_data
)
245 res
= FindNextFileW (handle
, find_data
);
251 mono_w32file_find_close (gpointer handle
)
255 res
= FindClose (handle
);
261 mono_w32file_create_directory (const gunichar2
*name
)
265 res
= CreateDirectoryW (name
, NULL
);
271 mono_w32file_remove_directory (const gunichar2
*name
)
275 res
= RemoveDirectoryW (name
);
281 * GetFileAttributes|Ex () seems to try opening the file, which might lead to sharing violation errors, whereas
282 * FindFirstFile always succeeds.
285 mono_w32file_get_attributes (const gunichar2
*name
)
289 WIN32_FIND_DATAW find_data
;
293 res
= GetFileAttributesW (name
);
294 if (res
== INVALID_FILE_ATTRIBUTES
&& GetLastError () == ERROR_SHARING_VIOLATION
) {
295 find_handle
= FindFirstFileW (name
, &find_data
);
296 if (find_handle
!= INVALID_HANDLE_VALUE
) {
297 FindClose (find_handle
);
298 res
= find_data
.dwFileAttributes
;
300 res
= INVALID_FILE_ATTRIBUTES
;
310 convert_filetime (const FILETIME
*filetime
)
312 return (gint64
) ((((guint64
) filetime
->dwHighDateTime
) << 32) + filetime
->dwLowDateTime
);
316 mono_w32file_get_attributes_ex (const gunichar2
*name
, MonoIOStat
*stat
)
320 WIN32_FIND_DATAW find_data
;
321 WIN32_FILE_ATTRIBUTE_DATA file_attribute_data
;
325 res
= GetFileAttributesExW (name
, GetFileExInfoStandard
, &file_attribute_data
);
327 stat
->attributes
= file_attribute_data
.dwFileAttributes
;
328 stat
->creation_time
= convert_filetime (&file_attribute_data
.ftCreationTime
);
329 stat
->last_access_time
= convert_filetime (&file_attribute_data
.ftLastAccessTime
);
330 stat
->last_write_time
= convert_filetime (&file_attribute_data
.ftLastWriteTime
);
331 stat
->length
= ((gint64
)file_attribute_data
.nFileSizeHigh
<< 32) | file_attribute_data
.nFileSizeLow
;
332 } else if (!res
&& GetLastError () == ERROR_SHARING_VIOLATION
) {
333 find_handle
= FindFirstFileW (name
, &find_data
);
334 if (find_handle
!= INVALID_HANDLE_VALUE
) {
335 FindClose (find_handle
);
336 stat
->attributes
= find_data
.dwFileAttributes
;
337 stat
->creation_time
= convert_filetime (&find_data
.ftCreationTime
);
338 stat
->last_access_time
= convert_filetime (&find_data
.ftLastAccessTime
);
339 stat
->last_write_time
= convert_filetime (&find_data
.ftLastWriteTime
);
340 stat
->length
= ((gint64
)find_data
.nFileSizeHigh
<< 32) | find_data
.nFileSizeLow
;
351 mono_w32file_set_attributes (const gunichar2
*name
, guint32 attrs
)
355 res
= SetFileAttributesW (name
, attrs
);
361 mono_w32file_get_cwd (guint32 length
, gunichar2
*buffer
)
365 res
= GetCurrentDirectoryW (length
, buffer
);
371 mono_w32file_set_cwd (const gunichar2
*path
)
375 res
= SetCurrentDirectoryW (path
);
381 mono_w32file_create_pipe (gpointer
*readpipe
, gpointer
*writepipe
, guint32 size
)
384 SECURITY_ATTRIBUTES attr
;
385 attr
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
386 attr
.bInheritHandle
= TRUE
;
387 attr
.lpSecurityDescriptor
= NULL
;
389 res
= CreatePipe (readpipe
, writepipe
, &attr
, size
);
394 #ifndef PLATFORM_NO_DRIVEINFO
396 mono_w32file_get_disk_free_space (const gunichar2
*path_name
, guint64
*free_bytes_avail
, guint64
*total_number_of_bytes
, guint64
*total_number_of_free_bytes
)
399 ULARGE_INTEGER wapi_free_bytes_avail
= { 0 };
400 ULARGE_INTEGER wapi_total_number_of_bytes
= { 0 };
401 ULARGE_INTEGER wapi_total_number_of_free_bytes
= { 0 };
403 g_assert (free_bytes_avail
);
404 g_assert (total_number_of_bytes
);
405 g_assert (total_number_of_free_bytes
);
408 result
= GetDiskFreeSpaceExW (path_name
, &wapi_free_bytes_avail
, &wapi_total_number_of_bytes
, &wapi_total_number_of_free_bytes
);
411 *free_bytes_avail
= wapi_free_bytes_avail
.QuadPart
;
412 *total_number_of_bytes
= wapi_total_number_of_bytes
.QuadPart
;
413 *total_number_of_free_bytes
= wapi_total_number_of_free_bytes
.QuadPart
;
417 #endif // PLATFORM_NO_DRIVEINFO
420 mono_w32file_get_file_system_type (const gunichar2
*path
, gunichar2
*fsbuffer
, gint fsbuffersize
)
424 res
= GetVolumeInformationW (path
, NULL
, 0, NULL
, NULL
, NULL
, fsbuffer
, fsbuffersize
);
429 #if HAVE_API_SUPPORT_WIN32_MOVE_FILE
431 mono_w32file_move (const gunichar2
*path
, const gunichar2
*dest
, gint32
*error
)
437 result
= MoveFileW (path
, dest
);
439 *error
= GetLastError ();
447 #if HAVE_API_SUPPORT_WIN32_REPLACE_FILE
449 mono_w32file_replace (const gunichar2
*destinationFileName
, const gunichar2
*sourceFileName
, const gunichar2
*destinationBackupFileName
, guint32 flags
, gint32
*error
)
455 result
= ReplaceFileW (destinationFileName
, sourceFileName
, destinationBackupFileName
, flags
, NULL
, NULL
);
457 *error
= GetLastError ();
465 #if HAVE_API_SUPPORT_WIN32_COPY_FILE
466 // Support older UWP SDK?
471 PCWSTR ExistingFileName
,
477 mono_w32file_copy (const gunichar2
*path
, const gunichar2
*dest
, gboolean overwrite
, gint32
*error
)
483 result
= CopyFileW (path
, dest
, !overwrite
);
485 *error
= GetLastError ();
493 #if HAVE_API_SUPPORT_WIN32_LOCK_FILE
495 mono_w32file_lock (gpointer handle
, gint64 position
, gint64 length
, gint32
*error
)
501 result
= LockFile (handle
, position
& 0xFFFFFFFF, position
>> 32, length
& 0xFFFFFFFF, length
>> 32);
503 *error
= GetLastError ();
511 #if HAVE_API_SUPPORT_WIN32_UNLOCK_FILE
513 mono_w32file_unlock (gpointer handle
, gint64 position
, gint64 length
, gint32
*error
)
519 result
= UnlockFile (handle
, position
& 0xFFFFFFFF, position
>> 32, length
& 0xFFFFFFFF, length
>> 32);
521 *error
= GetLastError ();
529 #if HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE
531 mono_w32file_get_console_input (void)
535 res
= GetStdHandle (STD_INPUT_HANDLE
);
541 mono_w32file_get_console_output (void)
545 res
= GetStdHandle (STD_OUTPUT_HANDLE
);
551 mono_w32file_get_console_error (void)
555 res
= GetStdHandle (STD_ERROR_HANDLE
);
559 #endif // HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE
561 #if HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX
564 mono_w32file_get_file_size (HANDLE handle
, gint32
*error
)
566 LARGE_INTEGER length
;
570 if (!GetFileSizeEx (handle
, &length
)) {
571 *error
=GetLastError ();
572 length
.QuadPart
= INVALID_FILE_SIZE
;
576 return length
.QuadPart
;
579 #endif // HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX
581 // Support older UWP SDK.
590 ves_icall_System_IO_DriveInfo_GetDriveType (const gunichar2
*root_path_name
, gint32 root_path_name_length
, MonoError
*error
)
592 // FIXME Check for embedded nuls here or in native.
593 #if HAVE_API_SUPPORT_WIN32_GET_DRIVE_TYPE
596 res
= GetDriveTypeW (root_path_name
);
600 g_unsupported_api ("GetDriveType");
601 mono_error_set_not_supported (error
, G_UNSUPPORTED_API
, "GetDriveType");
602 return DRIVE_UNKNOWN
;
606 #if HAVE_API_SUPPORT_WIN32_GET_LOGICAL_DRIVE_STRINGS
608 mono_w32file_get_logical_drive (guint32 len
, gunichar2
*buf
)
612 res
= GetLogicalDriveStringsW (len
, buf
);