[netcore] Make the load hook ALC-aware (#16012)
[mono-project.git] / mono / metadata / w32file-win32.c
blobe952de61b7ddbea0a8e5bdef17cff7e96a6374cd
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_close (gpointer handle)
69 gboolean res;
70 MONO_ENTER_GC_SAFE;
71 res = CloseHandle (handle);
72 MONO_EXIT_GC_SAFE;
73 return res;
76 gboolean
77 mono_w32file_delete (const gunichar2 *name)
79 gboolean res;
80 MONO_ENTER_GC_SAFE;
81 res = DeleteFileW (name);
82 MONO_EXIT_GC_SAFE;
83 return res;
86 // See win32_wait_interrupt_handler for details.
87 static void
88 win32_io_interrupt_handler (gpointer ignored)
92 gboolean
93 mono_w32file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error)
95 gboolean res;
96 MonoThreadInfo *info = mono_thread_info_current ();
97 gboolean alerted = FALSE;
99 if (info) {
100 mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted);
101 if (alerted) {
102 SetLastError (ERROR_OPERATION_ABORTED);
103 *win32error = ERROR_OPERATION_ABORTED;
104 return FALSE;
106 mono_win32_enter_blocking_io_call (info, handle);
109 MONO_ENTER_GC_SAFE;
110 if (info && mono_thread_info_is_interrupt_state (info)) {
111 res = FALSE;
112 SetLastError (ERROR_OPERATION_ABORTED);
113 } else {
114 res = ReadFile (handle, buffer, numbytes, (PDWORD)bytesread, NULL);
116 if (!res)
117 *win32error = GetLastError ();
118 MONO_EXIT_GC_SAFE;
120 if (info) {
121 mono_win32_leave_blocking_io_call (info, handle);
122 mono_thread_info_uninstall_interrupt (&alerted);
125 return res;
128 gboolean
129 mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error)
131 gboolean res;
132 MonoThreadInfo *info = mono_thread_info_current ();
133 gboolean alerted = FALSE;
135 if (info) {
136 mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted);
137 if (alerted) {
138 SetLastError (ERROR_OPERATION_ABORTED);
139 *win32error = ERROR_OPERATION_ABORTED;
140 return FALSE;
142 mono_win32_enter_blocking_io_call (info, handle);
145 MONO_ENTER_GC_SAFE;
146 if (info && mono_thread_info_is_interrupt_state (info)) {
147 res = FALSE;
148 SetLastError (ERROR_OPERATION_ABORTED);
149 } else {
150 res = WriteFile (handle, buffer, numbytes, (PDWORD)byteswritten, NULL);
152 if (!res)
153 *win32error = GetLastError ();
154 MONO_EXIT_GC_SAFE;
156 if (info) {
157 mono_win32_leave_blocking_io_call (info, handle);
158 mono_thread_info_uninstall_interrupt (&alerted);
161 return res;
164 gboolean
165 mono_w32file_flush (gpointer handle)
167 gboolean res;
168 MONO_ENTER_GC_SAFE;
169 res = FlushFileBuffers (handle);
170 MONO_EXIT_GC_SAFE;
171 return res;
174 gboolean
175 mono_w32file_truncate (gpointer handle)
177 gboolean res;
178 MONO_ENTER_GC_SAFE;
179 res = SetEndOfFile (handle);
180 MONO_EXIT_GC_SAFE;
181 return res;
184 guint32
185 mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method)
187 guint32 res;
188 MONO_ENTER_GC_SAFE;
189 res = SetFilePointer (handle, movedistance, (PLONG)highmovedistance, method);
190 MONO_EXIT_GC_SAFE;
191 return res;
194 gint
195 mono_w32file_get_type (gpointer handle)
197 gint res;
198 MONO_ENTER_GC_SAFE;
199 res = GetFileType (handle);
200 MONO_EXIT_GC_SAFE;
201 return res;
204 gboolean
205 mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time)
207 gboolean res;
208 MONO_ENTER_GC_SAFE;
209 res = SetFileTime (handle, create_time, access_time, write_time);
210 MONO_EXIT_GC_SAFE;
211 return res;
214 gboolean
215 mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time)
217 gboolean res;
218 MONO_ENTER_GC_SAFE;
219 res = FileTimeToSystemTime (file_time, system_time);
220 MONO_EXIT_GC_SAFE;
221 return res;
224 gpointer
225 mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATAW *find_data)
227 gpointer res;
228 MONO_ENTER_GC_SAFE;
229 res = FindFirstFileW (pattern, find_data);
230 MONO_EXIT_GC_SAFE;
231 return res;
234 gboolean
235 mono_w32file_find_next (gpointer handle, WIN32_FIND_DATAW *find_data)
237 gboolean res;
238 MONO_ENTER_GC_SAFE;
239 res = FindNextFileW (handle, find_data);
240 MONO_EXIT_GC_SAFE;
241 return res;
244 gboolean
245 mono_w32file_find_close (gpointer handle)
247 gboolean res;
248 MONO_ENTER_GC_SAFE;
249 res = FindClose (handle);
250 MONO_EXIT_GC_SAFE;
251 return res;
254 gboolean
255 mono_w32file_create_directory (const gunichar2 *name)
257 gboolean res;
258 MONO_ENTER_GC_SAFE;
259 res = CreateDirectoryW (name, NULL);
260 MONO_EXIT_GC_SAFE;
261 return res;
264 gboolean
265 mono_w32file_remove_directory (const gunichar2 *name)
267 gboolean res;
268 MONO_ENTER_GC_SAFE;
269 res = RemoveDirectoryW (name);
270 MONO_EXIT_GC_SAFE;
271 return res;
275 * GetFileAttributes|Ex () seems to try opening the file, which might lead to sharing violation errors, whereas
276 * FindFirstFile always succeeds.
278 guint32
279 mono_w32file_get_attributes (const gunichar2 *name)
281 guint32 res;
282 HANDLE find_handle;
283 WIN32_FIND_DATAW find_data;
285 MONO_ENTER_GC_SAFE;
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;
293 } else {
294 res = INVALID_FILE_ATTRIBUTES;
298 MONO_EXIT_GC_SAFE;
300 return res;
303 static gint64
304 convert_filetime (const FILETIME *filetime)
306 return (gint64) ((((guint64) filetime->dwHighDateTime) << 32) + filetime->dwLowDateTime);
309 gboolean
310 mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat)
312 gboolean res;
313 HANDLE find_handle;
314 WIN32_FIND_DATAW find_data;
315 WIN32_FILE_ATTRIBUTE_DATA file_attribute_data;
317 MONO_ENTER_GC_SAFE;
319 res = GetFileAttributesExW (name, GetFileExInfoStandard, &file_attribute_data);
320 if (res) {
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;
335 res = TRUE;
339 MONO_EXIT_GC_SAFE;
341 return res;
344 gboolean
345 mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
347 gboolean res;
348 MONO_ENTER_GC_SAFE;
349 res = SetFileAttributesW (name, attrs);
350 MONO_EXIT_GC_SAFE;
351 return res;
354 guint32
355 mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
357 guint32 res;
358 MONO_ENTER_GC_SAFE;
359 res = GetCurrentDirectoryW (length, buffer);
360 MONO_EXIT_GC_SAFE;
361 return res;
364 gboolean
365 mono_w32file_set_cwd (const gunichar2 *path)
367 gboolean res;
368 MONO_ENTER_GC_SAFE;
369 res = SetCurrentDirectoryW (path);
370 MONO_EXIT_GC_SAFE;
371 return res;
374 gboolean
375 mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
377 gboolean res;
378 SECURITY_ATTRIBUTES attr;
379 attr.nLength = sizeof(SECURITY_ATTRIBUTES);
380 attr.bInheritHandle = TRUE;
381 attr.lpSecurityDescriptor = NULL;
382 MONO_ENTER_GC_SAFE;
383 res = CreatePipe (readpipe, writepipe, &attr, size);
384 MONO_EXIT_GC_SAFE;
385 return res;
388 #ifndef PLATFORM_NO_DRIVEINFO
389 gboolean
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)
392 gboolean result;
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);
401 MONO_ENTER_GC_SAFE;
402 result = GetDiskFreeSpaceExW (path_name, &wapi_free_bytes_avail, &wapi_total_number_of_bytes, &wapi_total_number_of_free_bytes);
403 MONO_EXIT_GC_SAFE;
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;
409 return result;
411 #endif // PLATFORM_NO_DRIVEINFO
413 gboolean
414 mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize)
416 gboolean res;
417 MONO_ENTER_GC_SAFE;
418 res = GetVolumeInformationW (path, NULL, 0, NULL, NULL, NULL, fsbuffer, fsbuffersize);
419 MONO_EXIT_GC_SAFE;
420 return res;
423 #if HAVE_API_SUPPORT_WIN32_MOVE_FILE
424 gboolean
425 mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error)
427 gboolean result;
429 MONO_ENTER_GC_SAFE;
431 result = MoveFileW (path, dest);
432 if (!result)
433 *error = GetLastError ();
435 MONO_EXIT_GC_SAFE;
437 return result;
439 #endif
441 #if HAVE_API_SUPPORT_WIN32_REPLACE_FILE
442 gboolean
443 mono_w32file_replace (const gunichar2 *destinationFileName, const gunichar2 *sourceFileName, const gunichar2 *destinationBackupFileName, guint32 flags, gint32 *error)
445 gboolean result;
447 MONO_ENTER_GC_SAFE;
449 result = ReplaceFileW (destinationFileName, sourceFileName, destinationBackupFileName, flags, NULL, NULL);
450 if (!result)
451 *error = GetLastError ();
453 MONO_EXIT_GC_SAFE;
455 return result;
457 #endif
459 #if HAVE_API_SUPPORT_WIN32_COPY_FILE
460 // Support older UWP SDK?
461 WINBASEAPI
462 BOOL
463 WINAPI
464 CopyFileW (
465 PCWSTR ExistingFileName,
466 PCWSTR NewFileName,
467 BOOL FailIfExists
470 gboolean
471 mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error)
473 gboolean result;
475 MONO_ENTER_GC_SAFE;
477 result = CopyFileW (path, dest, !overwrite);
478 if (!result)
479 *error = GetLastError ();
481 MONO_EXIT_GC_SAFE;
483 return result;
485 #endif
487 #if HAVE_API_SUPPORT_WIN32_LOCK_FILE
488 gboolean
489 mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error)
491 gboolean result;
493 MONO_ENTER_GC_SAFE;
495 result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
496 if (!result)
497 *error = GetLastError ();
499 MONO_EXIT_GC_SAFE;
501 return result;
503 #endif
505 #if HAVE_API_SUPPORT_WIN32_UNLOCK_FILE
506 gboolean
507 mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error)
509 gboolean result;
511 MONO_ENTER_GC_SAFE;
513 result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32);
514 if (!result)
515 *error = GetLastError ();
517 MONO_EXIT_GC_SAFE;
519 return result;
521 #endif
523 #if HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE
524 HANDLE
525 mono_w32file_get_console_input (void)
527 HANDLE res;
528 MONO_ENTER_GC_SAFE;
529 res = GetStdHandle (STD_INPUT_HANDLE);
530 MONO_EXIT_GC_SAFE;
531 return res;
534 HANDLE
535 mono_w32file_get_console_output (void)
537 HANDLE res;
538 MONO_ENTER_GC_SAFE;
539 res = GetStdHandle (STD_OUTPUT_HANDLE);
540 MONO_EXIT_GC_SAFE;
541 return res;
544 HANDLE
545 mono_w32file_get_console_error (void)
547 HANDLE res;
548 MONO_ENTER_GC_SAFE;
549 res = GetStdHandle (STD_ERROR_HANDLE);
550 MONO_EXIT_GC_SAFE;
551 return res;
553 #endif // HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE
555 #if HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX
557 gint64
558 mono_w32file_get_file_size (HANDLE handle, gint32 *error)
560 LARGE_INTEGER length;
562 MONO_ENTER_GC_SAFE;
564 if (!GetFileSizeEx (handle, &length)) {
565 *error=GetLastError ();
566 length.QuadPart = INVALID_FILE_SIZE;
569 MONO_EXIT_GC_SAFE;
570 return length.QuadPart;
573 #endif // HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX
575 // Support older UWP SDK.
576 WINBASEAPI
577 UINT
578 WINAPI
579 GetDriveTypeW (
580 PCWSTR RootPathName
583 guint32
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
588 guint32 res;
589 MONO_ENTER_GC_SAFE;
590 res = GetDriveTypeW (root_path_name);
591 MONO_EXIT_GC_SAFE;
592 return res;
593 #else
594 g_unsupported_api ("GetDriveType");
595 mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetDriveType");
596 return DRIVE_UNKNOWN;
597 #endif
600 #if HAVE_API_SUPPORT_WIN32_GET_LOGICAL_DRIVE_STRINGS
601 gint32
602 mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
604 gint32 res;
605 MONO_ENTER_GC_SAFE;
606 res = GetLogicalDriveStringsW (len, buf);
607 MONO_EXIT_GC_SAFE;
608 return res;
610 #endif