Fix infrequent hangs in test-runner. (#16793)
[mono-project.git] / mono / metadata / w32file-win32.c
blob112f54670664dbed308098be35d84845e355bb97
1 /**
2 * \file
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.
7 */
8 #include <config.h>
9 #include <glib.h>
11 #include <winsock2.h>
12 #include <windows.h>
13 #include "mono/metadata/w32file-win32-internals.h"
14 #include "mono/metadata/w32subset.h"
15 #include "icall-decl.h"
17 void
18 mono_w32file_init (void)
22 void
23 mono_w32file_cleanup (void)
27 gunichar2
28 ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar ()
30 return (gunichar2) ':'; /* colon */
33 gunichar2
34 ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar ()
36 return (gunichar2) '\\'; /* backslash */
39 gunichar2
40 ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar ()
42 return (gunichar2) '/'; /* forward slash */
45 gunichar2
46 ves_icall_System_IO_MonoIO_get_PathSeparator ()
48 return (gunichar2) ';'; /* semicolon */
51 void ves_icall_System_IO_MonoIO_DumpHandles (void)
53 return;
56 gpointer
57 mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs)
59 gpointer res;
60 MONO_ENTER_GC_SAFE;
61 res = CreateFileW (name, fileaccess, sharemode, NULL, createmode, attrs, NULL);
62 MONO_EXIT_GC_SAFE;
63 return res;
66 gboolean
67 mono_w32file_cancel (gpointer handle)
69 return CancelIoEx (handle, NULL);
72 gboolean
73 mono_w32file_close (gpointer handle)
75 gboolean res;
76 MONO_ENTER_GC_SAFE;
77 res = CloseHandle (handle);
78 MONO_EXIT_GC_SAFE;
79 return res;
82 gboolean
83 mono_w32file_delete (const gunichar2 *name)
85 gboolean res;
86 MONO_ENTER_GC_SAFE;
87 res = DeleteFileW (name);
88 MONO_EXIT_GC_SAFE;
89 return res;
92 // See win32_wait_interrupt_handler for details.
93 static void
94 win32_io_interrupt_handler (gpointer ignored)
98 gboolean
99 mono_w32file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error)
101 gboolean res;
102 MonoThreadInfo *info = mono_thread_info_current ();
103 gboolean alerted = FALSE;
105 if (info) {
106 mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted);
107 if (alerted) {
108 SetLastError (ERROR_OPERATION_ABORTED);
109 *win32error = ERROR_OPERATION_ABORTED;
110 return FALSE;
112 mono_win32_enter_blocking_io_call (info, handle);
115 MONO_ENTER_GC_SAFE;
116 if (info && mono_thread_info_is_interrupt_state (info)) {
117 res = FALSE;
118 SetLastError (ERROR_OPERATION_ABORTED);
119 } else {
120 res = ReadFile (handle, buffer, numbytes, (PDWORD)bytesread, NULL);
122 if (!res)
123 *win32error = GetLastError ();
124 MONO_EXIT_GC_SAFE;
126 if (info) {
127 mono_win32_leave_blocking_io_call (info, handle);
128 mono_thread_info_uninstall_interrupt (&alerted);
131 return res;
134 gboolean
135 mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error)
137 gboolean res;
138 MonoThreadInfo *info = mono_thread_info_current ();
139 gboolean alerted = FALSE;
141 if (info) {
142 mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted);
143 if (alerted) {
144 SetLastError (ERROR_OPERATION_ABORTED);
145 *win32error = ERROR_OPERATION_ABORTED;
146 return FALSE;
148 mono_win32_enter_blocking_io_call (info, handle);
151 MONO_ENTER_GC_SAFE;
152 if (info && mono_thread_info_is_interrupt_state (info)) {
153 res = FALSE;
154 SetLastError (ERROR_OPERATION_ABORTED);
155 } else {
156 res = WriteFile (handle, buffer, numbytes, (PDWORD)byteswritten, NULL);
158 if (!res)
159 *win32error = GetLastError ();
160 MONO_EXIT_GC_SAFE;
162 if (info) {
163 mono_win32_leave_blocking_io_call (info, handle);
164 mono_thread_info_uninstall_interrupt (&alerted);
167 return res;
170 gboolean
171 mono_w32file_flush (gpointer handle)
173 gboolean res;
174 MONO_ENTER_GC_SAFE;
175 res = FlushFileBuffers (handle);
176 MONO_EXIT_GC_SAFE;
177 return res;
180 gboolean
181 mono_w32file_truncate (gpointer handle)
183 gboolean res;
184 MONO_ENTER_GC_SAFE;
185 res = SetEndOfFile (handle);
186 MONO_EXIT_GC_SAFE;
187 return res;
190 guint32
191 mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method)
193 guint32 res;
194 MONO_ENTER_GC_SAFE;
195 res = SetFilePointer (handle, movedistance, (PLONG)highmovedistance, method);
196 MONO_EXIT_GC_SAFE;
197 return res;
200 gint
201 mono_w32file_get_type (gpointer handle)
203 gint res;
204 MONO_ENTER_GC_SAFE;
205 res = GetFileType (handle);
206 MONO_EXIT_GC_SAFE;
207 return res;
210 gboolean
211 mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time)
213 gboolean res;
214 MONO_ENTER_GC_SAFE;
215 res = SetFileTime (handle, create_time, access_time, write_time);
216 MONO_EXIT_GC_SAFE;
217 return res;
220 gboolean
221 mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time)
223 gboolean res;
224 MONO_ENTER_GC_SAFE;
225 res = FileTimeToSystemTime (file_time, system_time);
226 MONO_EXIT_GC_SAFE;
227 return res;
230 gpointer
231 mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATAW *find_data)
233 gpointer res;
234 MONO_ENTER_GC_SAFE;
235 res = FindFirstFileW (pattern, find_data);
236 MONO_EXIT_GC_SAFE;
237 return res;
240 gboolean
241 mono_w32file_find_next (gpointer handle, WIN32_FIND_DATAW *find_data)
243 gboolean res;
244 MONO_ENTER_GC_SAFE;
245 res = FindNextFileW (handle, find_data);
246 MONO_EXIT_GC_SAFE;
247 return res;
250 gboolean
251 mono_w32file_find_close (gpointer handle)
253 gboolean res;
254 MONO_ENTER_GC_SAFE;
255 res = FindClose (handle);
256 MONO_EXIT_GC_SAFE;
257 return res;
260 gboolean
261 mono_w32file_create_directory (const gunichar2 *name)
263 gboolean res;
264 MONO_ENTER_GC_SAFE;
265 res = CreateDirectoryW (name, NULL);
266 MONO_EXIT_GC_SAFE;
267 return res;
270 gboolean
271 mono_w32file_remove_directory (const gunichar2 *name)
273 gboolean res;
274 MONO_ENTER_GC_SAFE;
275 res = RemoveDirectoryW (name);
276 MONO_EXIT_GC_SAFE;
277 return res;
281 * GetFileAttributes|Ex () seems to try opening the file, which might lead to sharing violation errors, whereas
282 * FindFirstFile always succeeds.
284 guint32
285 mono_w32file_get_attributes (const gunichar2 *name)
287 guint32 res;
288 HANDLE find_handle;
289 WIN32_FIND_DATAW find_data;
291 MONO_ENTER_GC_SAFE;
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;
299 } else {
300 res = INVALID_FILE_ATTRIBUTES;
304 MONO_EXIT_GC_SAFE;
306 return res;
309 static gint64
310 convert_filetime (const FILETIME *filetime)
312 return (gint64) ((((guint64) filetime->dwHighDateTime) << 32) + filetime->dwLowDateTime);
315 gboolean
316 mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat)
318 gboolean res;
319 HANDLE find_handle;
320 WIN32_FIND_DATAW find_data;
321 WIN32_FILE_ATTRIBUTE_DATA file_attribute_data;
323 MONO_ENTER_GC_SAFE;
325 res = GetFileAttributesExW (name, GetFileExInfoStandard, &file_attribute_data);
326 if (res) {
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;
341 res = TRUE;
345 MONO_EXIT_GC_SAFE;
347 return res;
350 gboolean
351 mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
353 gboolean res;
354 MONO_ENTER_GC_SAFE;
355 res = SetFileAttributesW (name, attrs);
356 MONO_EXIT_GC_SAFE;
357 return res;
360 guint32
361 mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
363 guint32 res;
364 MONO_ENTER_GC_SAFE;
365 res = GetCurrentDirectoryW (length, buffer);
366 MONO_EXIT_GC_SAFE;
367 return res;
370 gboolean
371 mono_w32file_set_cwd (const gunichar2 *path)
373 gboolean res;
374 MONO_ENTER_GC_SAFE;
375 res = SetCurrentDirectoryW (path);
376 MONO_EXIT_GC_SAFE;
377 return res;
380 gboolean
381 mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
383 gboolean res;
384 SECURITY_ATTRIBUTES attr;
385 attr.nLength = sizeof(SECURITY_ATTRIBUTES);
386 attr.bInheritHandle = TRUE;
387 attr.lpSecurityDescriptor = NULL;
388 MONO_ENTER_GC_SAFE;
389 res = CreatePipe (readpipe, writepipe, &attr, size);
390 MONO_EXIT_GC_SAFE;
391 return res;
394 #ifndef PLATFORM_NO_DRIVEINFO
395 gboolean
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)
398 gboolean result;
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);
407 MONO_ENTER_GC_SAFE;
408 result = GetDiskFreeSpaceExW (path_name, &wapi_free_bytes_avail, &wapi_total_number_of_bytes, &wapi_total_number_of_free_bytes);
409 MONO_EXIT_GC_SAFE;
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;
415 return result;
417 #endif // PLATFORM_NO_DRIVEINFO
419 gboolean
420 mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize)
422 gboolean res;
423 MONO_ENTER_GC_SAFE;
424 res = GetVolumeInformationW (path, NULL, 0, NULL, NULL, NULL, fsbuffer, fsbuffersize);
425 MONO_EXIT_GC_SAFE;
426 return res;
429 #if HAVE_API_SUPPORT_WIN32_MOVE_FILE
430 gboolean
431 mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error)
433 gboolean result;
435 MONO_ENTER_GC_SAFE;
437 result = MoveFileW (path, dest);
438 if (!result)
439 *error = GetLastError ();
441 MONO_EXIT_GC_SAFE;
443 return result;
445 #endif
447 #if HAVE_API_SUPPORT_WIN32_REPLACE_FILE
448 gboolean
449 mono_w32file_replace (const gunichar2 *destinationFileName, const gunichar2 *sourceFileName, const gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error)
451 gboolean result;
453 MONO_ENTER_GC_SAFE;
455 result = ReplaceFileW (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
456 if (!result)
457 *error = GetLastError ();
459 MONO_EXIT_GC_SAFE;
461 return result;
463 #endif
465 #if HAVE_API_SUPPORT_WIN32_COPY_FILE
466 // Support older UWP SDK?
467 WINBASEAPI
468 BOOL
469 WINAPI
470 CopyFileW (
471 PCWSTR ExistingFileName,
472 PCWSTR NewFileName,
473 BOOL FailIfExists
476 gboolean
477 mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error)
479 gboolean result;
481 MONO_ENTER_GC_SAFE;
483 result = CopyFileW (path, dest, !overwrite);
484 if (!result)
485 *error = GetLastError ();
487 MONO_EXIT_GC_SAFE;
489 return result;
491 #endif
493 #if HAVE_API_SUPPORT_WIN32_LOCK_FILE
494 gboolean
495 mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error)
497 gboolean result;
499 MONO_ENTER_GC_SAFE;
501 result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
502 if (!result)
503 *error = GetLastError ();
505 MONO_EXIT_GC_SAFE;
507 return result;
509 #endif
511 #if HAVE_API_SUPPORT_WIN32_UNLOCK_FILE
512 gboolean
513 mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error)
515 gboolean result;
517 MONO_ENTER_GC_SAFE;
519 result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
520 if (!result)
521 *error = GetLastError ();
523 MONO_EXIT_GC_SAFE;
525 return result;
527 #endif
529 #if HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE
530 HANDLE
531 mono_w32file_get_console_input (void)
533 HANDLE res;
534 MONO_ENTER_GC_SAFE;
535 res = GetStdHandle (STD_INPUT_HANDLE);
536 MONO_EXIT_GC_SAFE;
537 return res;
540 HANDLE
541 mono_w32file_get_console_output (void)
543 HANDLE res;
544 MONO_ENTER_GC_SAFE;
545 res = GetStdHandle (STD_OUTPUT_HANDLE);
546 MONO_EXIT_GC_SAFE;
547 return res;
550 HANDLE
551 mono_w32file_get_console_error (void)
553 HANDLE res;
554 MONO_ENTER_GC_SAFE;
555 res = GetStdHandle (STD_ERROR_HANDLE);
556 MONO_EXIT_GC_SAFE;
557 return res;
559 #endif // HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE
561 #if HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX
563 gint64
564 mono_w32file_get_file_size (HANDLE handle, gint32 *error)
566 LARGE_INTEGER length;
568 MONO_ENTER_GC_SAFE;
570 if (!GetFileSizeEx (handle, &length)) {
571 *error=GetLastError ();
572 length.QuadPart = INVALID_FILE_SIZE;
575 MONO_EXIT_GC_SAFE;
576 return length.QuadPart;
579 #endif // HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX
581 // Support older UWP SDK.
582 WINBASEAPI
583 UINT
584 WINAPI
585 GetDriveTypeW (
586 PCWSTR RootPathName
589 guint32
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
594 guint32 res;
595 MONO_ENTER_GC_SAFE;
596 res = GetDriveTypeW (root_path_name);
597 MONO_EXIT_GC_SAFE;
598 return res;
599 #else
600 g_unsupported_api ("GetDriveType");
601 mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetDriveType");
602 return DRIVE_UNKNOWN;
603 #endif
606 #if HAVE_API_SUPPORT_WIN32_GET_LOGICAL_DRIVE_STRINGS
607 gint32
608 mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
610 gint32 res;
611 MONO_ENTER_GC_SAFE;
612 res = GetLogicalDriveStringsW (len, buf);
613 MONO_EXIT_GC_SAFE;
614 return res;
616 #endif