[w32file] Push win32 specific error to win32 specific implementation (#5665)
[mono.git] / mono / metadata / w32file-win32.c
index 953f7926c76a72175b3fef48d6eee9f0efbb344a..6ecb7ff9d5f40c58d05e8c72cff844bb9b1ee634 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * w32file-win32.c: Windows File IO internal calls.
+/**
+ * \file
+ * Windows File IO internal calls.
  *
  * Copyright 2016 Microsoft
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
@@ -53,173 +54,322 @@ void ves_icall_System_IO_MonoIO_DumpHandles (void)
 gpointer
 mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs)
 {
-       return CreateFile (name, fileaccess, sharemode, NULL, createmode, attrs, NULL);
+       gpointer res;
+       MONO_ENTER_GC_SAFE;
+       res = CreateFile (name, fileaccess, sharemode, NULL, createmode, attrs, NULL);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_close (gpointer handle)
 {
-       return CloseHandle (handle);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = CloseHandle (handle);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_delete (const gunichar2 *name)
 {
-       return DeleteFile (name);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = DeleteFile (name);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread)
 {
-       return ReadFile (handle, buffer, numbytes, bytesread, NULL);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = ReadFile (handle, buffer, numbytes, bytesread, NULL);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten)
 {
-       return WriteFile (handle, buffer, numbytes, byteswritten, NULL);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = WriteFile (handle, buffer, numbytes, byteswritten, NULL);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_flush (gpointer handle)
 {
-       return FlushFileBuffers (handle);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = FlushFileBuffers (handle);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_truncate (gpointer handle)
 {
-       return SetEndOfFile (handle);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = SetEndOfFile (handle);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 guint32
 mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method)
 {
-       return SetFilePointer (handle, movedistance, highmovedistance, method);
+       guint32 res;
+       MONO_ENTER_GC_SAFE;
+       res = SetFilePointer (handle, movedistance, highmovedistance, method);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gint
 mono_w32file_get_type (gpointer handle)
 {
-       return GetFileType (handle);
+       gint res;
+       MONO_ENTER_GC_SAFE;
+       res = GetFileType (handle);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_get_times (gpointer handle, FILETIME *create_time, FILETIME *access_time, FILETIME *write_time)
 {
-       return GetFileTime (handle, create_time, access_time, write_time);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = GetFileTime (handle, create_time, access_time, write_time);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time)
 {
-       return SetFileTime (handle, create_time, access_time, write_time);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = SetFileTime (handle, create_time, access_time, write_time);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time)
 {
-       return FileTimeToSystemTime (file_time, system_time);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = FileTimeToSystemTime (file_time, system_time);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gpointer
 mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data)
 {
-       return FindFirstFile (pattern, find_data);
+       gpointer res;
+       MONO_ENTER_GC_SAFE;
+       res = FindFirstFile (pattern, find_data);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data)
 {
-       return FindNextFile (handle, find_data);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = FindNextFile (handle, find_data);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_find_close (gpointer handle)
 {
-       return FindClose (handle);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = FindClose (handle);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_create_directory (const gunichar2 *name)
 {
-       return CreateDirectory (name, NULL);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = CreateDirectory (name, NULL);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_remove_directory (const gunichar2 *name)
 {
-       return RemoveDirectory (name);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = RemoveDirectory (name);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
+/*
+ * GetFileAttributes|Ex () seems to try opening the file, which might lead to sharing violation errors, whereas
+ * FindFirstFile always succeeds.
+ */
 guint32
 mono_w32file_get_attributes (const gunichar2 *name)
 {
-       return GetFileAttributes (name);
+       guint32 res;
+       guint32 error;
+       HANDLE find_handle;
+       WIN32_FIND_DATA find_data;
+
+       MONO_ENTER_GC_SAFE;
+       res = GetFileAttributes (name);
+       MONO_EXIT_GC_SAFE;
+
+       if (res != INVALID_FILE_ATTRIBUTES)
+               return res;
+
+       error = GetLastError ();
+       if (error != ERROR_SHARING_VIOLATION)
+               return INVALID_FILE_ATTRIBUTES;
+
+       MONO_ENTER_GC_SAFE;
+       find_handle = FindFirstFile (name, &find_data);
+       MONO_EXIT_GC_SAFE;
+
+       if (find_handle == INVALID_HANDLE_VALUE)
+               return INVALID_FILE_ATTRIBUTES;
+
+       MONO_ENTER_GC_SAFE;
+       FindClose (find_handle);
+       MONO_EXIT_GC_SAFE;
+
+       return find_data.dwFileAttributes;
+}
+
+static gint64
+convert_filetime (const FILETIME *filetime)
+{
+       return (gint64) ((((guint64) filetime->dwHighDateTime) << 32) + filetime->dwLowDateTime);
 }
 
 gboolean
 mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat)
 {
-       gboolean result;
-       WIN32_FILE_ATTRIBUTE_DATA data;
+       gboolean res;
+       guint32 error;
+       HANDLE find_handle;
+       WIN32_FIND_DATA find_data;
+       WIN32_FILE_ATTRIBUTE_DATA file_attribute_data;
 
-       result = GetFileAttributesEx (name, GetFileExInfoStandard, &data);
-       if (result) {
-               stat->attributes = data.dwFileAttributes;
-               stat->creation_time = (gint64) ((((guint64) data.ftCreationTime.dwHighDateTime) << 32) + data.ftCreationTime.dwLowDateTime);
-               stat->last_access_time = (gint64) ((((guint64) data.ftLastAccessTime.dwHighDateTime) << 32) + data.ftLastAccessTime.dwLowDateTime);
-               stat->last_write_time = (gint64) ((((guint64) data.ftLastWriteTime.dwHighDateTime) << 32) + data.ftLastWriteTime.dwLowDateTime);
-               stat->length = ((gint64)data.nFileSizeHigh << 32) | data.nFileSizeLow;
+       MONO_ENTER_GC_SAFE;
+       res = GetFileAttributesEx (name, GetFileExInfoStandard, &file_attribute_data);
+       MONO_EXIT_GC_SAFE;
+       if (res) {
+               stat->attributes = file_attribute_data.dwFileAttributes;
+               stat->creation_time = convert_filetime (&file_attribute_data.ftCreationTime);
+               stat->last_access_time = convert_filetime (&file_attribute_data.ftLastAccessTime);
+               stat->last_write_time = convert_filetime (&file_attribute_data.ftLastWriteTime);
+               stat->length = ((gint64)file_attribute_data.nFileSizeHigh << 32) | file_attribute_data.nFileSizeLow;
+               return TRUE;
        }
 
-       return result;
+       error = GetLastError ();
+       if (error != ERROR_SHARING_VIOLATION)
+               return FALSE;
+
+       MONO_ENTER_GC_SAFE;
+       find_handle = FindFirstFile (name, &find_data);
+       MONO_EXIT_GC_SAFE;
+
+       if (find_handle == INVALID_HANDLE_VALUE)
+               return FALSE;
+
+       MONO_ENTER_GC_SAFE;
+       FindClose (find_handle);
+       MONO_EXIT_GC_SAFE;
+
+       stat->attributes = find_data.dwFileAttributes;
+       stat->creation_time = convert_filetime (&find_data.ftCreationTime);
+       stat->last_access_time = convert_filetime (&find_data.ftLastAccessTime);
+       stat->last_write_time = convert_filetime (&find_data.ftLastWriteTime);
+       stat->length = ((gint64)find_data.nFileSizeHigh << 32) | find_data.nFileSizeLow;
+       return TRUE;
 }
 
 gboolean
 mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs)
 {
-       return SetFileAttributes (name, attrs);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = SetFileAttributes (name, attrs);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 guint32
 mono_w32file_get_cwd (guint32 length, gunichar2 *buffer)
 {
-       return GetCurrentDirectory (length, buffer);
+       guint32 res;
+       MONO_ENTER_GC_SAFE;
+       res = GetCurrentDirectory (length, buffer);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_set_cwd (const gunichar2 *path)
 {
-       return SetCurrentDirectory (path);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = SetCurrentDirectory (path);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size)
 {
+       gboolean res;
        SECURITY_ATTRIBUTES attr;
        attr.nLength = sizeof(SECURITY_ATTRIBUTES);
        attr.bInheritHandle = TRUE;
        attr.lpSecurityDescriptor = NULL;
-       return CreatePipe (readpipe, writepipe, &attr, size);
+       MONO_ENTER_GC_SAFE;
+       res = CreatePipe (readpipe, writepipe, &attr, size);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gboolean
 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)
 {
        gboolean result;
-       ULARGE_INTEGER *wapi_free_bytes_avail;
-       ULARGE_INTEGER *wapi_total_number_of_bytes;
-       ULARGE_INTEGER *wapi_total_number_of_free_bytes;
+       ULARGE_INTEGER wapi_free_bytes_avail;
+       ULARGE_INTEGER wapi_total_number_of_bytes;
+       ULARGE_INTEGER wapi_total_number_of_free_bytes;
 
-       result = GetDiskFreeSpaceEx (path_name, wapi_free_bytes_avail, wapi_total_number_of_bytes, wapi_total_number_of_free_bytes);
+       MONO_ENTER_GC_SAFE;
+       result = GetDiskFreeSpaceEx (path_name, &wapi_free_bytes_avail, &wapi_total_number_of_bytes, &wapi_total_number_of_free_bytes);
+       MONO_EXIT_GC_SAFE;
        if (result) {
                if (free_bytes_avail)
-                       *free_bytes_avail = wapi_free_bytes_avail->QuadPart;
+                       *free_bytes_avail = wapi_free_bytes_avail.QuadPart;
                if (total_number_of_bytes)
-                       *total_number_of_bytes = wapi_total_number_of_bytes->QuadPart;
+                       *total_number_of_bytes = wapi_total_number_of_bytes.QuadPart;
                if (total_number_of_free_bytes)
-                       *total_number_of_free_bytes = wapi_total_number_of_free_bytes->QuadPart;
+                       *total_number_of_free_bytes = wapi_total_number_of_free_bytes.QuadPart;
        }
 
        return result;
@@ -228,7 +378,11 @@ mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_byte
 gboolean
 mono_w32file_get_volume_information (const gunichar2 *path, gunichar2 *volumename, gint volumesize, gint *outserial, gint *maxcomp, gint *fsflags, gunichar2 *fsbuffer, gint fsbuffersize)
 {
-       return GetVolumeInformation (path, volumename, volumesize, outserial, maxcomp, fsflags, fsbuffer, fsbuffersize);
+       gboolean res;
+       MONO_ENTER_GC_SAFE;
+       res = GetVolumeInformation (path, volumename, volumesize, outserial, maxcomp, fsflags, fsbuffer, fsbuffersize);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
@@ -316,19 +470,31 @@ mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *er
 HANDLE
 mono_w32file_get_console_input (void)
 {
-       return GetStdHandle (STD_INPUT_HANDLE);
+       HANDLE res;
+       MONO_ENTER_GC_SAFE;
+       res = GetStdHandle (STD_INPUT_HANDLE);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 HANDLE
 mono_w32file_get_console_output (void)
 {
-       return GetStdHandle (STD_OUTPUT_HANDLE);
+       HANDLE res;
+       MONO_ENTER_GC_SAFE;
+       res = GetStdHandle (STD_OUTPUT_HANDLE);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 HANDLE
 mono_w32file_get_console_error (void)
 {
-       return GetStdHandle (STD_ERROR_HANDLE);
+       HANDLE res;
+       MONO_ENTER_GC_SAFE;
+       res = GetStdHandle (STD_ERROR_HANDLE);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gint64
@@ -352,13 +518,21 @@ mono_w32file_get_file_size (gpointer handle, gint32 *error)
 guint32
 mono_w32file_get_drive_type (const gunichar2 *root_path_name)
 {
-       return GetDriveType (root_path_name);
+       guint32 res;
+       MONO_ENTER_GC_SAFE;
+       res = GetDriveType (root_path_name);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 gint32
 mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf)
 {
-       return GetLogicalDriveStrings (len, buf);
+       gint32 res;
+       MONO_ENTER_GC_SAFE;
+       res = GetLogicalDriveStrings (len, buf);
+       MONO_EXIT_GC_SAFE;
+       return res;
 }
 
 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */