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_close (gpointer handle
)
71 res
= CloseHandle (handle
);
77 mono_w32file_delete (const gunichar2
*name
)
81 res
= DeleteFileW (name
);
86 // See win32_wait_interrupt_handler for details.
88 win32_io_interrupt_handler (gpointer ignored
)
93 mono_w32file_read(gpointer handle
, gpointer buffer
, guint32 numbytes
, guint32
*bytesread
, gint32
*win32error
)
96 MonoThreadInfo
*info
= mono_thread_info_current ();
97 gboolean alerted
= FALSE
;
100 mono_thread_info_install_interrupt (win32_io_interrupt_handler
, NULL
, &alerted
);
102 SetLastError (ERROR_OPERATION_ABORTED
);
103 *win32error
= ERROR_OPERATION_ABORTED
;
106 mono_win32_enter_blocking_io_call (info
, handle
);
110 if (info
&& mono_thread_info_is_interrupt_state (info
)) {
112 SetLastError (ERROR_OPERATION_ABORTED
);
114 res
= ReadFile (handle
, buffer
, numbytes
, (PDWORD
)bytesread
, NULL
);
117 *win32error
= GetLastError ();
121 mono_win32_leave_blocking_io_call (info
, handle
);
122 mono_thread_info_uninstall_interrupt (&alerted
);
129 mono_w32file_write (gpointer handle
, gconstpointer buffer
, guint32 numbytes
, guint32
*byteswritten
, gint32
*win32error
)
132 MonoThreadInfo
*info
= mono_thread_info_current ();
133 gboolean alerted
= FALSE
;
136 mono_thread_info_install_interrupt (win32_io_interrupt_handler
, NULL
, &alerted
);
138 SetLastError (ERROR_OPERATION_ABORTED
);
139 *win32error
= ERROR_OPERATION_ABORTED
;
142 mono_win32_enter_blocking_io_call (info
, handle
);
146 if (info
&& mono_thread_info_is_interrupt_state (info
)) {
148 SetLastError (ERROR_OPERATION_ABORTED
);
150 res
= WriteFile (handle
, buffer
, numbytes
, (PDWORD
)byteswritten
, NULL
);
153 *win32error
= GetLastError ();
157 mono_win32_leave_blocking_io_call (info
, handle
);
158 mono_thread_info_uninstall_interrupt (&alerted
);
165 mono_w32file_flush (gpointer handle
)
169 res
= FlushFileBuffers (handle
);
175 mono_w32file_truncate (gpointer handle
)
179 res
= SetEndOfFile (handle
);
185 mono_w32file_seek (gpointer handle
, gint32 movedistance
, gint32
*highmovedistance
, guint32 method
)
189 res
= SetFilePointer (handle
, movedistance
, (PLONG
)highmovedistance
, method
);
195 mono_w32file_get_type (gpointer handle
)
199 res
= GetFileType (handle
);
205 mono_w32file_set_times (gpointer handle
, const FILETIME
*create_time
, const FILETIME
*access_time
, const FILETIME
*write_time
)
209 res
= SetFileTime (handle
, create_time
, access_time
, write_time
);
215 mono_w32file_filetime_to_systemtime (const FILETIME
*file_time
, SYSTEMTIME
*system_time
)
219 res
= FileTimeToSystemTime (file_time
, system_time
);
225 mono_w32file_find_first (const gunichar2
*pattern
, WIN32_FIND_DATAW
*find_data
)
229 res
= FindFirstFileW (pattern
, find_data
);
235 mono_w32file_find_next (gpointer handle
, WIN32_FIND_DATAW
*find_data
)
239 res
= FindNextFileW (handle
, find_data
);
245 mono_w32file_find_close (gpointer handle
)
249 res
= FindClose (handle
);
255 mono_w32file_create_directory (const gunichar2
*name
)
259 res
= CreateDirectoryW (name
, NULL
);
265 mono_w32file_remove_directory (const gunichar2
*name
)
269 res
= RemoveDirectoryW (name
);
275 * GetFileAttributes|Ex () seems to try opening the file, which might lead to sharing violation errors, whereas
276 * FindFirstFile always succeeds.
279 mono_w32file_get_attributes (const gunichar2
*name
)
283 WIN32_FIND_DATAW find_data
;
287 res
= GetFileAttributesW (name
);
288 if (res
== INVALID_FILE_ATTRIBUTES
&& GetLastError () == ERROR_SHARING_VIOLATION
) {
289 find_handle
= FindFirstFileW (name
, &find_data
);
290 if (find_handle
!= INVALID_HANDLE_VALUE
) {
291 FindClose (find_handle
);
292 res
= find_data
.dwFileAttributes
;
294 res
= INVALID_FILE_ATTRIBUTES
;
304 convert_filetime (const FILETIME
*filetime
)
306 return (gint64
) ((((guint64
) filetime
->dwHighDateTime
) << 32) + filetime
->dwLowDateTime
);
310 mono_w32file_get_attributes_ex (const gunichar2
*name
, MonoIOStat
*stat
)
314 WIN32_FIND_DATAW find_data
;
315 WIN32_FILE_ATTRIBUTE_DATA file_attribute_data
;
319 res
= GetFileAttributesExW (name
, GetFileExInfoStandard
, &file_attribute_data
);
321 stat
->attributes
= file_attribute_data
.dwFileAttributes
;
322 stat
->creation_time
= convert_filetime (&file_attribute_data
.ftCreationTime
);
323 stat
->last_access_time
= convert_filetime (&file_attribute_data
.ftLastAccessTime
);
324 stat
->last_write_time
= convert_filetime (&file_attribute_data
.ftLastWriteTime
);
325 stat
->length
= ((gint64
)file_attribute_data
.nFileSizeHigh
<< 32) | file_attribute_data
.nFileSizeLow
;
326 } else if (!res
&& GetLastError () == ERROR_SHARING_VIOLATION
) {
327 find_handle
= FindFirstFileW (name
, &find_data
);
328 if (find_handle
!= INVALID_HANDLE_VALUE
) {
329 FindClose (find_handle
);
330 stat
->attributes
= find_data
.dwFileAttributes
;
331 stat
->creation_time
= convert_filetime (&find_data
.ftCreationTime
);
332 stat
->last_access_time
= convert_filetime (&find_data
.ftLastAccessTime
);
333 stat
->last_write_time
= convert_filetime (&find_data
.ftLastWriteTime
);
334 stat
->length
= ((gint64
)find_data
.nFileSizeHigh
<< 32) | find_data
.nFileSizeLow
;
345 mono_w32file_set_attributes (const gunichar2
*name
, guint32 attrs
)
349 res
= SetFileAttributesW (name
, attrs
);
355 mono_w32file_get_cwd (guint32 length
, gunichar2
*buffer
)
359 res
= GetCurrentDirectoryW (length
, buffer
);
365 mono_w32file_set_cwd (const gunichar2
*path
)
369 res
= SetCurrentDirectoryW (path
);
375 mono_w32file_create_pipe (gpointer
*readpipe
, gpointer
*writepipe
, guint32 size
)
378 SECURITY_ATTRIBUTES attr
;
379 attr
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
380 attr
.bInheritHandle
= TRUE
;
381 attr
.lpSecurityDescriptor
= NULL
;
383 res
= CreatePipe (readpipe
, writepipe
, &attr
, size
);
388 #ifndef PLATFORM_NO_DRIVEINFO
390 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
)
393 ULARGE_INTEGER wapi_free_bytes_avail
= { 0 };
394 ULARGE_INTEGER wapi_total_number_of_bytes
= { 0 };
395 ULARGE_INTEGER wapi_total_number_of_free_bytes
= { 0 };
397 g_assert (free_bytes_avail
);
398 g_assert (total_number_of_bytes
);
399 g_assert (total_number_of_free_bytes
);
402 result
= GetDiskFreeSpaceExW (path_name
, &wapi_free_bytes_avail
, &wapi_total_number_of_bytes
, &wapi_total_number_of_free_bytes
);
405 *free_bytes_avail
= wapi_free_bytes_avail
.QuadPart
;
406 *total_number_of_bytes
= wapi_total_number_of_bytes
.QuadPart
;
407 *total_number_of_free_bytes
= wapi_total_number_of_free_bytes
.QuadPart
;
411 #endif // PLATFORM_NO_DRIVEINFO
414 mono_w32file_get_file_system_type (const gunichar2
*path
, gunichar2
*fsbuffer
, gint fsbuffersize
)
418 res
= GetVolumeInformationW (path
, NULL
, 0, NULL
, NULL
, NULL
, fsbuffer
, fsbuffersize
);
423 #if HAVE_API_SUPPORT_WIN32_MOVE_FILE
425 mono_w32file_move (const gunichar2
*path
, const gunichar2
*dest
, gint32
*error
)
431 result
= MoveFileW (path
, dest
);
433 *error
= GetLastError ();
441 #if HAVE_API_SUPPORT_WIN32_REPLACE_FILE
443 mono_w32file_replace (const gunichar2
*destinationFileName
, const gunichar2
*sourceFileName
, const gunichar2
*destinationBackupFileName
, guint32 flags
, gint32
*error
)
449 result
= ReplaceFileW (destinationFileName
, sourceFileName
, destinationBackupFileName
, flags
, NULL
, NULL
);
451 *error
= GetLastError ();
459 #if HAVE_API_SUPPORT_WIN32_COPY_FILE
460 // Support older UWP SDK?
465 PCWSTR ExistingFileName
,
471 mono_w32file_copy (const gunichar2
*path
, const gunichar2
*dest
, gboolean overwrite
, gint32
*error
)
477 result
= CopyFileW (path
, dest
, !overwrite
);
479 *error
= GetLastError ();
487 #if HAVE_API_SUPPORT_WIN32_LOCK_FILE
489 mono_w32file_lock (gpointer handle
, gint64 position
, gint64 length
, gint32
*error
)
495 result
= LockFile (handle
, position
& 0xFFFFFFFF, position
>> 32, length
& 0xFFFFFFFF, length
>> 32);
497 *error
= GetLastError ();
505 #if HAVE_API_SUPPORT_WIN32_UNLOCK_FILE
507 mono_w32file_unlock (gpointer handle
, gint64 position
, gint64 length
, gint32
*error
)
513 result
= UnlockFile (handle
, position
& 0xFFFFFFFF, position
>> 32, length
& 0xFFFFFFFF, length
>> 32);
515 *error
= GetLastError ();
523 #if HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE
525 mono_w32file_get_console_input (void)
529 res
= GetStdHandle (STD_INPUT_HANDLE
);
535 mono_w32file_get_console_output (void)
539 res
= GetStdHandle (STD_OUTPUT_HANDLE
);
545 mono_w32file_get_console_error (void)
549 res
= GetStdHandle (STD_ERROR_HANDLE
);
553 #endif // HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE
555 #if HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX
558 mono_w32file_get_file_size (HANDLE handle
, gint32
*error
)
560 LARGE_INTEGER length
;
564 if (!GetFileSizeEx (handle
, &length
)) {
565 *error
=GetLastError ();
566 length
.QuadPart
= INVALID_FILE_SIZE
;
570 return length
.QuadPart
;
573 #endif // HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX
575 // Support older UWP SDK.
584 ves_icall_System_IO_DriveInfo_GetDriveType (const gunichar2
*root_path_name
, gint32 root_path_name_length
, MonoError
*error
)
586 // FIXME Check for embedded nuls here or in native.
587 #if HAVE_API_SUPPORT_WIN32_GET_DRIVE_TYPE
590 res
= GetDriveTypeW (root_path_name
);
594 g_unsupported_api ("GetDriveType");
595 mono_error_set_not_supported (error
, G_UNSUPPORTED_API
, "GetDriveType");
596 return DRIVE_UNKNOWN
;
600 #if HAVE_API_SUPPORT_WIN32_GET_LOGICAL_DRIVE_STRINGS
602 mono_w32file_get_logical_drive (guint32 len
, gunichar2
*buf
)
606 res
= GetLogicalDriveStringsW (len
, buf
);