diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetLastError.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetLastError.cs new file mode 100644 index 00000000000000..bc18e843404406 --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetLastError.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + [SuppressGCTransition] + internal static extern int GetLastError(); + } +} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs new file mode 100644 index 00000000000000..d4919d725a52cd --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + internal const int WAIT_FAILED = unchecked((int)0xFFFFFFFF); + + [DllImport(Libraries.Kernel32)] + internal static extern uint WaitForMultipleObjectsEx(uint nCount, IntPtr lpHandles, BOOL bWaitAll, uint dwMilliseconds, BOOL bAlertable); + + [DllImport(Libraries.Kernel32)] + internal static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); + + [DllImport(Libraries.Kernel32)] + internal static extern uint SignalObjectAndWait(IntPtr hObjectToSignal, IntPtr hObjectToWaitOn, uint dwMilliseconds, BOOL bAlertable); + + [DllImport(Libraries.Kernel32)] + internal static extern void Sleep(uint milliseconds); + + internal const uint CREATE_SUSPENDED = 0x00000004; + internal const uint STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000; + + [DllImport(Libraries.Kernel32)] + internal static extern unsafe SafeWaitHandle CreateThread( + IntPtr lpThreadAttributes, + IntPtr dwStackSize, + delegate* unmanaged lpStartAddress, + IntPtr lpParameter, + uint dwCreationFlags, + out uint lpThreadId); + + [DllImport(Libraries.Kernel32)] + internal static extern uint ResumeThread(SafeWaitHandle hThread); + + [DllImport(Libraries.Kernel32)] + internal static extern IntPtr GetCurrentThread(); + + internal const int DUPLICATE_SAME_ACCESS = 2; + + [DllImport(Libraries.Kernel32, SetLastError = true)] + internal static extern bool DuplicateHandle( + IntPtr hSourceProcessHandle, + IntPtr hSourceHandle, + IntPtr hTargetProcessHandle, + out SafeWaitHandle lpTargetHandle, + uint dwDesiredAccess, + bool bInheritHandle, + uint dwOptions); + + internal enum ThreadPriority : int + { + Idle = -15, + Lowest = -2, + BelowNormal = -1, + Normal = 0, + AboveNormal = 1, + Highest = 2, + TimeCritical = 15, + + ErrorReturn = 0x7FFFFFFF + } + + [DllImport(Libraries.Kernel32)] + internal static extern ThreadPriority GetThreadPriority(SafeWaitHandle hThread); + + [DllImport(Libraries.Kernel32)] + internal static extern bool SetThreadPriority(SafeWaitHandle hThread, int nPriority); + } +} diff --git a/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs b/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs index e18e564bd48f33..dadc27e2fbf2b3 100644 --- a/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs +++ b/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs @@ -8,4 +8,5 @@ // create unique identities for every test to allow every test to have // it's own store. [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] +[assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [assembly: SkipOnMono("System.IO.IsolatedStorage is not supported on Browser", TestPlatforms.Browser)] diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 2278e4046c6de1..68b2ac5565d3cc 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -2998,6 +2998,9 @@ Value was either too large or too small for an Int64. + + The current thread attempted to reacquire a mutex that has reached its maximum acquire count. + Negating the minimum value of a twos complement number is invalid. @@ -3577,6 +3580,9 @@ COM unregister function must have a System.Type parameter and a void return type. + + The handle is invalid. + Type '{0}' has more than one COM registration function. diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index d9900d80412cd2..b8cd92ad427082 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1980,4 +1980,24 @@ + + + + + + + + + + + + + + + Interop\Windows\Kernel32\Interop.GetLastError.cs + + + Interop\Windows\Kernel32\Interop.Threading.cs + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs index 78053e44621752..33c9dcb575ced8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs @@ -161,6 +161,13 @@ public void DangerousAddRef(ref bool success) success = true; } + // Used by internal callers to avoid declaring a bool to pass by ref + internal void DangerousAddRef() + { + bool success = false; + DangerousAddRef(ref success); + } + public void DangerousRelease() => InternalRelease(disposeOrFinalizeOperation: false); private void InternalRelease(bool disposeOrFinalizeOperation) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.cs index 2cdaeb6bb55c7a..eb9b4b171d4133 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.cs @@ -10,7 +10,7 @@ namespace System.Threading { public partial class EventWaitHandle { - private void CreateEventCore(bool initialState, EventResetMode mode, string name, out bool createdNew) + private void CreateEventCore(bool initialState, EventResetMode mode, string? name, out bool createdNew) { if (name != null) throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); @@ -19,7 +19,7 @@ private void CreateEventCore(bool initialState, EventResetMode mode, string name createdNew = true; } - private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle result) + private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle? result) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.Unix.cs index 92485a329a8f8e..4b3dfb3be1cc4b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.Unix.cs @@ -44,6 +44,19 @@ private void WaitCore() Interop.Sys.LowLevelMonitor_Wait(_nativeMonitor); } + private bool WaitCore(int timeoutMilliseconds) + { + Debug.Assert(timeoutMilliseconds >= -1); + + if (timeoutMilliseconds < 0) + { + WaitCore(); + return true; + } + + return Interop.Sys.LowLevelMonitor_TimedWait(_nativeMonitor, timeoutMilliseconds); + } + private void Signal_ReleaseCore() { Interop.Sys.LowLevelMonitor_Signal_Release(_nativeMonitor); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.cs index 6aa1e0cc195fa2..c9139eabd3613c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.cs @@ -90,6 +90,16 @@ public void Wait() SetOwnerThreadToCurrent(); } + public bool Wait(int timeoutMilliseconds) + { + Debug.Assert(timeoutMilliseconds >= -1); + + ResetOwnerThread(); + bool waitResult = WaitCore(timeoutMilliseconds); + SetOwnerThreadToCurrent(); + return waitResult; + } + public void Signal_Release() { ResetOwnerThread(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs index 27f1d170916039..5b1361247ae585 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs @@ -10,8 +10,9 @@ namespace System.Threading { public sealed partial class Mutex { - private void CreateMutexCore(bool initiallyOwned, string name, out bool createdNew) + private void CreateMutexCore(bool initiallyOwned, string? name, out bool createdNew) { + // See https://github.com/dotnet/runtime/issues/48720 if (name != null) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); @@ -21,7 +22,7 @@ private void CreateMutexCore(bool initiallyOwned, string name, out bool createdN createdNew = true; } - private static OpenExistingResult OpenExistingWorker(string name, out Mutex result) + private static OpenExistingResult OpenExistingWorker(string name, out Mutex? result) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.cs index b2184b6af4adef..61975a86ebb3f4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.cs @@ -10,7 +10,7 @@ namespace System.Threading { public sealed partial class Semaphore { - private void CreateSemaphoreCore(int initialCount, int maximumCount, string name, out bool createdNew) + private void CreateSemaphoreCore(int initialCount, int maximumCount, string? name, out bool createdNew) { if (name != null) { @@ -21,7 +21,7 @@ private void CreateSemaphoreCore(int initialCount, int maximumCount, string name createdNew = true; } - private static OpenExistingResult OpenExistingWorker(string name, out Semaphore result) + private static OpenExistingResult OpenExistingWorker(string name, out Semaphore? result) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs new file mode 100644 index 00000000000000..af3a8a38461c81 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs @@ -0,0 +1,173 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.IO; +using System.Runtime; +using System.Runtime.InteropServices; + +namespace System.Threading +{ + public abstract partial class WaitHandle + { + internal static unsafe int WaitMultipleIgnoringSyncContext(Span handles, bool waitAll, int millisecondsTimeout) + { + fixed (IntPtr* pHandles = &MemoryMarshal.GetReference(handles)) + { + return WaitForMultipleObjectsIgnoringSyncContext(pHandles, handles.Length, waitAll, millisecondsTimeout); + } + } + + private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHandles, int numHandles, bool waitAll, int millisecondsTimeout) + { + Debug.Assert(millisecondsTimeout >= -1); + + // Normalize waitAll + if (numHandles == 1) + waitAll = false; + +#if CORERT // TODO: reentrant wait support https://github.com/dotnet/runtime/issues/49518 + bool reentrantWait = Thread.ReentrantWaitsEnabled; + + if (reentrantWait) + { + // + // In the CLR, we use CoWaitForMultipleHandles to pump messages while waiting in an STA. In that case, we cannot use WAIT_ALL. + // That's because the wait would only be satisfied if a message arrives while the handles are signalled. + // + if (waitAll) + throw new NotSupportedException(SR.NotSupported_WaitAllSTAThread); + + // CoWaitForMultipleHandles does not support more than 63 handles. It returns RPC_S_CALLPENDING for more than 63 handles + // that is impossible to differentiate from timeout. + if (numHandles > 63) + throw new NotSupportedException(SR.NotSupported_MaxWaitHandles_STA); + } +#endif + + Thread currentThread = Thread.CurrentThread; + currentThread.SetWaitSleepJoinState(); + +#if CORERT + int result; + if (reentrantWait) + { + Debug.Assert(!waitAll); + result = RuntimeImports.RhCompatibleReentrantWaitAny(false, millisecondsTimeout, numHandles, pHandles); + } + else + { + result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, (uint)millisecondsTimeout, Interop.BOOL.FALSE); + } +#else + int result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, (uint)millisecondsTimeout, Interop.BOOL.FALSE); +#endif + currentThread.ClearWaitSleepJoinState(); + + if (result == Interop.Kernel32.WAIT_FAILED) + { + int errorCode = Interop.Kernel32.GetLastError(); + if (waitAll && errorCode == Interop.Errors.ERROR_INVALID_PARAMETER) + { + // Check for duplicate handles. This is a brute force O(n^2) search, which is intended since the typical + // array length is short enough that this would actually be faster than using a hash set. Also, the worst + // case is not so bad considering that the array length is limited by + // . + for (int i = 1; i < numHandles; ++i) + { + IntPtr handle = pHandles[i]; + for (int j = 0; j < i; ++j) + { + if (pHandles[j] == handle) + { + throw new DuplicateWaitObjectException("waitHandles[" + i + ']'); + } + } + } + } + + ThrowWaitFailedException(errorCode); + } + + return result; + } + + internal static unsafe int WaitOneCore(IntPtr handle, int millisecondsTimeout) + { + return WaitForMultipleObjectsIgnoringSyncContext(&handle, 1, false, millisecondsTimeout); + } + + private static int SignalAndWaitCore(IntPtr handleToSignal, IntPtr handleToWaitOn, int millisecondsTimeout) + { + Debug.Assert(millisecondsTimeout >= -1); + + int ret = (int)Interop.Kernel32.SignalObjectAndWait(handleToSignal, handleToWaitOn, (uint)millisecondsTimeout, Interop.BOOL.FALSE); + + if (ret == Interop.Kernel32.WAIT_FAILED) + { + ThrowWaitFailedException(Interop.Kernel32.GetLastError()); + } + + return ret; + } + + private static void ThrowWaitFailedException(int errorCode) + { + switch (errorCode) + { + case Interop.Errors.ERROR_INVALID_HANDLE: + ThrowInvalidHandleException(); + return; + + case Interop.Errors.ERROR_INVALID_PARAMETER: + throw new ArgumentException(); + + case Interop.Errors.ERROR_ACCESS_DENIED: + throw new UnauthorizedAccessException(); + + case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: + throw new OutOfMemoryException(); + + case Interop.Errors.ERROR_TOO_MANY_POSTS: + // Only applicable to . Note however, that + // if the semahpore already has the maximum signal count, the Windows SignalObjectAndWait function does not + // return an error, but this code is kept for historical reasons and to convey the intent, since ideally, + // that should be an error. + throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts); + + case Interop.Errors.ERROR_NOT_OWNER: + // Only applicable to when signaling a mutex + // that is locked by a different thread. Note that if the mutex is already unlocked, the Windows + // SignalObjectAndWait function does not return an error. + throw new ApplicationException(SR.Arg_SynchronizationLockException); + + case Interop.Errors.ERROR_MUTANT_LIMIT_EXCEEDED: + throw new OverflowException(SR.Overflow_MutexReacquireCount); + + default: + throw new Exception { HResult = errorCode }; + } + } + + internal static Exception ExceptionFromCreationError(int errorCode, string path) + { + switch (errorCode) + { + case Interop.Errors.ERROR_PATH_NOT_FOUND: + return new IOException(SR.Format(SR.IO_PathNotFound_Path, path)); + + case Interop.Errors.ERROR_ACCESS_DENIED: + return new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, path)); + + case Interop.Errors.ERROR_ALREADY_EXISTS: + return new IOException(SR.Format(SR.IO_AlreadyExists_Name, path)); + + case Interop.Errors.ERROR_FILENAME_EXCED_RANGE: + return new PathTooLongException(); + + default: + return new IOException(SR.Arg_IOException, errorCode); + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs index 8311d9dadee04b..c82450488734ae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs @@ -409,6 +409,13 @@ private static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, int } } + internal static void ThrowInvalidHandleException() + { + var ex = new InvalidOperationException(SR.InvalidOperation_InvalidHandle); + ex.HResult = HResults.E_HANDLE; + throw ex; + } + public virtual bool WaitOne(TimeSpan timeout) => WaitOneNoCheck(ToTimeoutMilliseconds(timeout)); public virtual bool WaitOne() => WaitOneNoCheck(-1); public virtual bool WaitOne(int millisecondsTimeout, bool exitContext) => WaitOne(millisecondsTimeout); @@ -429,6 +436,8 @@ public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout) => WaitMultiple(waitHandles, false, millisecondsTimeout); internal static int WaitAny(ReadOnlySpan safeWaitHandles, int millisecondsTimeout) => WaitAnyMultiple(safeWaitHandles, millisecondsTimeout); + internal static int WaitAny(ReadOnlySpan waitHandles, int millisecondsTimeout) => + WaitMultiple(waitHandles, false, millisecondsTimeout); public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout) => WaitMultiple(waitHandles, false, ToTimeoutMilliseconds(timeout)); public static int WaitAny(WaitHandle[] waitHandles) => diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs index dc922c465aa40b..1ef3fabfde518b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs @@ -16,7 +16,7 @@ public static IntPtr NewHandle(WaitableObject waitableObject) { Debug.Assert(waitableObject != null); - IntPtr handle = RuntimeImports.RhHandleAlloc(waitableObject, GCHandleType.Normal); + IntPtr handle = GCHandle.ToIntPtr(GCHandle.Alloc(waitableObject, GCHandleType.Normal)); // SafeWaitHandle treats -1 and 0 as invalid, and the handle should not be these values anyway Debug.Assert(handle != IntPtr.Zero); @@ -33,7 +33,7 @@ public static WaitableObject FromHandle(IntPtr handle) // We don't know if any other handles are invalid, and this may crash or otherwise do bad things, that is by // design, IntPtr is unsafe by nature. - return (WaitableObject)RuntimeImports.RhHandleGet(handle); + return (WaitableObject)GCHandle.FromIntPtr(handle).Target!; } /// @@ -48,8 +48,8 @@ public static void DeleteHandle(IntPtr handle) // We don't know if any other handles are invalid, and this may crash or otherwise do bad things, that is by // design, IntPtr is unsafe by nature. - ((WaitableObject)RuntimeImports.RhHandleGet(handle)).OnDeleteHandle(); - RuntimeImports.RhHandleFree(handle); + FromHandle(handle).OnDeleteHandle(); + GCHandle.FromIntPtr(handle).Free(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs index 92c67fcbfb6769..58f61e4cd2ed75 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs @@ -53,7 +53,7 @@ public sealed class ThreadWaitInfo /// - The filled count is /// - Indexes in all arrays that use correspond /// - private WaitableObject[] _waitedObjects; + private WaitableObject?[] _waitedObjects; /// /// - Nodes used for registering a thread's wait on each , in the @@ -84,7 +84,7 @@ public sealed class ThreadWaitInfo /// the thread exits. The linked list has only a head and no tail, which means acquired mutexes are prepended and /// mutexes are abandoned in reverse order. /// - private WaitableObject _lockedMutexesHead; + private WaitableObject? _lockedMutexesHead; public ThreadWaitInfo(Thread thread) { @@ -120,7 +120,7 @@ private bool IsWaiting /// Callers must ensure to clear the array after use. Once is called (followed /// by a call to , the array will be cleared automatically. /// - public WaitableObject[] GetWaitedObjectArray(int requiredCapacity) + public WaitableObject?[] GetWaitedObjectArray(int requiredCapacity) { Debug.Assert(_thread == Thread.CurrentThread); Debug.Assert(_waitedCount == 0); @@ -174,7 +174,7 @@ public void RegisterWait(int waitedCount, bool prioritize, bool isWaitForAll) Debug.Assert(_waitedCount == 0); - WaitableObject[] waitedObjects = _waitedObjects; + WaitableObject?[] waitedObjects = _waitedObjects; #if DEBUG for (int i = 0; i < waitedCount; ++i) { @@ -212,14 +212,14 @@ public void RegisterWait(int waitedCount, bool prioritize, bool isWaitForAll) { for (int i = 0; i < waitedCount; ++i) { - waitedListNodes[i].RegisterPrioritizedWait(waitedObjects[i]); + waitedListNodes[i].RegisterPrioritizedWait(waitedObjects[i]!); } } else { for (int i = 0; i < waitedCount; ++i) { - waitedListNodes[i].RegisterWait(waitedObjects[i]); + waitedListNodes[i].RegisterWait(waitedObjects[i]!); } } } @@ -231,7 +231,7 @@ public void UnregisterWait() for (int i = 0; i < _waitedCount; ++i) { - _waitedListNodes[i].UnregisterWait(_waitedObjects[i]); + _waitedListNodes[i].UnregisterWait(_waitedObjects[i]!); _waitedObjects[i] = null; } _waitedCount = 0; @@ -538,7 +538,7 @@ private bool CheckAndResetPendingInterrupt_NotLocked } } - public WaitableObject LockedMutexesHead + public WaitableObject? LockedMutexesHead { get { @@ -561,7 +561,7 @@ public void OnThreadExiting() { while (true) { - WaitableObject waitableObject = LockedMutexesHead; + WaitableObject? waitableObject = LockedMutexesHead; if (waitableObject == null) { break; @@ -593,7 +593,7 @@ public sealed class WaitedListNode /// /// Link in the linked list /// - private WaitedListNode _previous, _next; + private WaitedListNode? _previous, _next; public WaitedListNode(ThreadWaitInfo waitInfo, int waitedObjectIndex) { @@ -623,7 +623,7 @@ public int WaitedObjectIndex } } - public WaitedListNode Previous + public WaitedListNode? Previous { get { @@ -632,7 +632,7 @@ public WaitedListNode Previous } } - public WaitedListNode Next + public WaitedListNode? Next { get { @@ -651,7 +651,7 @@ public void RegisterWait(WaitableObject waitableObject) Debug.Assert(_previous == null); Debug.Assert(_next == null); - WaitedListNode tail = waitableObject.WaitersTail; + WaitedListNode? tail = waitableObject.WaitersTail; if (tail != null) { _previous = tail; @@ -674,7 +674,7 @@ public void RegisterPrioritizedWait(WaitableObject waitableObject) Debug.Assert(_previous == null); Debug.Assert(_next == null); - WaitedListNode head = waitableObject.WaitersHead; + WaitedListNode? head = waitableObject.WaitersHead; if (head != null) { _next = head; @@ -692,8 +692,8 @@ public void UnregisterWait(WaitableObject waitableObject) s_lock.VerifyIsLocked(); Debug.Assert(waitableObject != null); - WaitedListNode previous = _previous; - WaitedListNode next = _next; + WaitedListNode? previous = _previous; + WaitedListNode? next = _next; if (previous != null) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs index 91d21a140c9def..bd622d9f69401b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs @@ -113,7 +113,9 @@ namespace System.Threading /// - Since provides mutual exclusion for the states of all s in the /// process, any operation that does not involve waiting or releasing a wait can occur with minimal p/invokes /// +#if CORERT [EagerStaticClassConstruction] // the wait subsystem is used during lazy class construction +#endif internal static partial class WaitSubsystem { private static readonly LowLevelLock s_lock = new LowLevelLock(); @@ -121,7 +123,7 @@ internal static partial class WaitSubsystem private static SafeWaitHandle NewHandle(WaitableObject waitableObject) { IntPtr handle = HandleManager.NewHandle(waitableObject); - SafeWaitHandle safeWaitHandle = null; + SafeWaitHandle? safeWaitHandle = null; try { safeWaitHandle = new SafeWaitHandle(handle, ownsHandle: true); @@ -280,7 +282,7 @@ public static int Wait( Debug.Assert(timeoutMilliseconds >= -1); ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; - WaitableObject[] waitableObjects = waitInfo.GetWaitedObjectArray(waitHandles.Length); + WaitableObject?[] waitableObjects = waitInfo.GetWaitedObjectArray(waitHandles.Length); bool success = false; try { @@ -320,7 +322,7 @@ public static int Wait( if (waitHandles.Length == 1) { - WaitableObject waitableObject = waitableObjects[0]; + WaitableObject waitableObject = waitableObjects[0]!; waitableObjects[0] = null; return waitableObject.Wait(waitInfo, timeoutMilliseconds, interruptible: true, prioritize : false); @@ -373,7 +375,14 @@ public static int SignalAndWait( throw new ThreadInterruptedException(); } - waitableObjectToSignal.Signal(1); + try + { + waitableObjectToSignal.Signal(1); + } + catch (SemaphoreFullException ex) + { + throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts, ex); + } waitCalled = true; return waitableObjectToWaitOn.Wait_Locked(waitInfo, timeoutMilliseconds, interruptible, prioritize); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs index 8963e7b04415d6..f5f37471440f7d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs @@ -22,18 +22,18 @@ public sealed class WaitableObject /// Only has a thread ownership requirement, and it's a less common type to be used, so /// ownership info is separated to reduce the size. For other types, this is null. /// - private readonly OwnershipInfo _ownershipInfo; + private readonly OwnershipInfo? _ownershipInfo; /// /// Linked list of information about waiting threads /// - private ThreadWaitInfo.WaitedListNode _waitersHead, _waitersTail; + private ThreadWaitInfo.WaitedListNode? _waitersHead, _waitersTail; private WaitableObject( WaitableObjectType type, int initialSignalCount, int maximumSignalCount, - OwnershipInfo ownershipInfo) + OwnershipInfo? ownershipInfo) { Debug.Assert(initialSignalCount >= 0); Debug.Assert(maximumSignalCount > 0); @@ -157,11 +157,11 @@ private bool IsAbandonedMutex get { s_lock.VerifyIsLocked(); - return IsMutex && _ownershipInfo.IsAbandoned; + return IsMutex && _ownershipInfo != null && _ownershipInfo.IsAbandoned; } } - public ThreadWaitInfo.WaitedListNode WaitersHead + public ThreadWaitInfo.WaitedListNode? WaitersHead { get { @@ -175,7 +175,7 @@ public ThreadWaitInfo.WaitedListNode WaitersHead } } - public ThreadWaitInfo.WaitedListNode WaitersTail + public ThreadWaitInfo.WaitedListNode? WaitersTail { get { @@ -196,7 +196,7 @@ private bool IsSignaled s_lock.VerifyIsLocked(); bool isSignaled = _signalCount != 0; - Debug.Assert(isSignaled || !IsMutex || _ownershipInfo.Thread != null); + Debug.Assert(isSignaled || !IsMutex || (_ownershipInfo != null && _ownershipInfo.Thread != null)); return isSignaled; } } @@ -220,7 +220,7 @@ private void AcceptSignal(ThreadWaitInfo waitInfo) Debug.Assert(_type == WaitableObjectType.Mutex); --_signalCount; - Debug.Assert(_ownershipInfo.Thread == null); + Debug.Assert(_ownershipInfo!.Thread == null); _ownershipInfo.AssignOwnership(this, waitInfo); return; } @@ -267,7 +267,7 @@ public int Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool in return isAbandoned ? WaitHandle.WaitAbandoned : WaitHandle.WaitSuccess; } - if (IsMutex && _ownershipInfo.Thread == waitInfo.Thread) + if (IsMutex && _ownershipInfo != null && _ownershipInfo.Thread == waitInfo.Thread) { if (!_ownershipInfo.CanIncrementReacquireCount) { @@ -282,7 +282,7 @@ public int Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool in return WaitHandle.WaitTimeout; } - WaitableObject[] waitableObjects = waitInfo.GetWaitedObjectArray(1); + WaitableObject?[] waitableObjects = waitInfo.GetWaitedObjectArray(1); waitableObjects[0] = this; waitInfo.RegisterWait(1, prioritize, isWaitForAll: false); needToWait = true; @@ -304,7 +304,7 @@ public int Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool in } public static int Wait( - WaitableObject[] waitableObjects, + WaitableObject?[]? waitableObjects, int count, bool waitForAll, ThreadWaitInfo waitInfo, @@ -335,7 +335,7 @@ public static int Wait( // Check if any is already signaled for (int i = 0; i < count; ++i) { - WaitableObject waitableObject = waitableObjects[i]; + WaitableObject waitableObject = waitableObjects[i]!; Debug.Assert(waitableObject != null); if (waitableObject.IsSignaled) @@ -351,7 +351,7 @@ public static int Wait( if (waitableObject.IsMutex) { - OwnershipInfo ownershipInfo = waitableObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitableObject._ownershipInfo!; if (ownershipInfo.Thread == waitInfo.Thread) { if (!ownershipInfo.CanIncrementReacquireCount) @@ -371,7 +371,7 @@ public static int Wait( bool isAnyAbandonedMutex = false; for (int i = 0; i < count; ++i) { - WaitableObject waitableObject = waitableObjects[i]; + WaitableObject waitableObject = waitableObjects[i]!; Debug.Assert(waitableObject != null); if (waitableObject.IsSignaled) @@ -385,7 +385,7 @@ public static int Wait( if (waitableObject.IsMutex) { - OwnershipInfo ownershipInfo = waitableObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitableObject._ownershipInfo!; if (ownershipInfo.Thread == waitInfo.Thread) { if (!ownershipInfo.CanIncrementReacquireCount) @@ -404,7 +404,7 @@ public static int Wait( { for (int i = 0; i < count; ++i) { - WaitableObject waitableObject = waitableObjects[i]; + WaitableObject waitableObject = waitableObjects[i]!; if (waitableObject.IsSignaled) { waitableObject.AcceptSignal(waitInfo); @@ -412,7 +412,7 @@ public static int Wait( } Debug.Assert(waitableObject.IsMutex); - OwnershipInfo ownershipInfo = waitableObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitableObject._ownershipInfo!; Debug.Assert(ownershipInfo.Thread == waitInfo.Thread); ownershipInfo.IncrementReacquireCount(); } @@ -456,7 +456,7 @@ public static int Wait( public static bool WouldWaitForAllBeSatisfiedOrAborted( Thread waitingThread, - WaitableObject[] waitedObjects, + WaitableObject?[] waitedObjects, int waitedCount, int signaledWaitedObjectIndex, ref bool wouldAnyMutexReacquireCountOverflow, @@ -480,7 +480,7 @@ public static bool WouldWaitForAllBeSatisfiedOrAborted( continue; } - WaitableObject waitedObject = waitedObjects[i]; + WaitableObject waitedObject = waitedObjects[i]!; if (waitedObject.IsSignaled) { if (!isAnyAbandonedMutex && waitedObject.IsAbandonedMutex) @@ -492,7 +492,7 @@ public static bool WouldWaitForAllBeSatisfiedOrAborted( if (waitedObject.IsMutex) { - OwnershipInfo ownershipInfo = waitedObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitedObject._ownershipInfo!; if (ownershipInfo.Thread == waitingThread) { if (!ownershipInfo.CanIncrementReacquireCount) @@ -513,7 +513,7 @@ public static bool WouldWaitForAllBeSatisfiedOrAborted( public static void SatisfyWaitForAll( ThreadWaitInfo waitInfo, - WaitableObject[] waitedObjects, + WaitableObject?[] waitedObjects, int waitedCount, int signaledWaitedObjectIndex) { @@ -534,7 +534,7 @@ public static void SatisfyWaitForAll( continue; } - WaitableObject waitedObject = waitedObjects[i]; + WaitableObject waitedObject = waitedObjects[i]!; if (waitedObject.IsSignaled) { waitedObject.AcceptSignal(waitInfo); @@ -542,7 +542,7 @@ public static void SatisfyWaitForAll( } Debug.Assert(waitedObject.IsMutex); - OwnershipInfo ownershipInfo = waitedObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitedObject._ownershipInfo!; Debug.Assert(ownershipInfo.Thread == waitInfo.Thread); ownershipInfo.IncrementReacquireCount(); } @@ -606,7 +606,7 @@ private void SignalManualResetEvent() return; } - for (ThreadWaitInfo.WaitedListNode waiterNode = _waitersHead, nextWaiterNode; + for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { @@ -629,7 +629,7 @@ private void SignalAutoResetEvent() return; } - for (ThreadWaitInfo.WaitedListNode waiterNode = _waitersHead, nextWaiterNode; + for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { @@ -684,7 +684,7 @@ public int SignalSemaphore(int count) return oldSignalCount; } - for (ThreadWaitInfo.WaitedListNode waiterNode = _waitersHead, nextWaiterNode; + for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { @@ -710,12 +710,12 @@ public void SignalMutex() WaitHandle.ThrowInvalidHandleException(); } - if (IsSignaled || _ownershipInfo.Thread != Thread.CurrentThread) + if (IsSignaled || _ownershipInfo!.Thread != Thread.CurrentThread) { throw new ApplicationException(SR.Arg_SynchronizationLockException); } - if (!_ownershipInfo.TryDecrementReacquireCount()) + if (!_ownershipInfo!.TryDecrementReacquireCount()) { SignalMutex(isAbandoned: false); } @@ -743,10 +743,11 @@ private void SignalMutex(bool isAbandoned) Debug.Assert(IsMutex); Debug.Assert(!IsSignaled); + Debug.Assert(_ownershipInfo != null); _ownershipInfo.RelinquishOwnership(this, isAbandoned); - for (ThreadWaitInfo.WaitedListNode waiterNode = _waitersHead, nextWaiterNode; + for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { @@ -767,21 +768,21 @@ private void SignalMutex(bool isAbandoned) private sealed class OwnershipInfo { - private Thread _thread; + private Thread? _thread; private int _reacquireCount; private bool _isAbandoned; /// /// Link in the linked list /// - private WaitableObject _previous; + private WaitableObject? _previous; /// /// Link in the linked list /// - private WaitableObject _next; + private WaitableObject? _next; - public Thread Thread + public Thread? Thread { get { @@ -815,11 +816,11 @@ public void AssignOwnership(WaitableObject waitableObject, ThreadWaitInfo waitIn _thread = waitInfo.Thread; _isAbandoned = false; - WaitableObject head = waitInfo.LockedMutexesHead; + WaitableObject? head = waitInfo.LockedMutexesHead; if (head != null) { _next = head; - head._ownershipInfo._previous = waitableObject; + head._ownershipInfo!._previous = waitableObject; } waitInfo.LockedMutexesHead = waitableObject; } @@ -844,12 +845,12 @@ public void RelinquishOwnership(WaitableObject waitableObject, bool isAbandoned) _isAbandoned = isAbandoned; } - WaitableObject previous = _previous; - WaitableObject next = _next; + WaitableObject? previous = _previous; + WaitableObject? next = _next; if (previous != null) { - previous._ownershipInfo._next = next; + previous._ownershipInfo!._next = next; _previous = null; } else @@ -860,7 +861,7 @@ public void RelinquishOwnership(WaitableObject waitableObject, bool isAbandoned) if (next != null) { - next._ownershipInfo._previous = previous; + next._ownershipInfo!._previous = previous; _next = null; } } diff --git a/src/libraries/System.Threading.Thread/tests/ThreadTests.cs b/src/libraries/System.Threading.Thread/tests/ThreadTests.cs index c3545ca12cc6b0..4e680e0c2b07d3 100644 --- a/src/libraries/System.Threading.Thread/tests/ThreadTests.cs +++ b/src/libraries/System.Threading.Thread/tests/ThreadTests.cs @@ -913,6 +913,7 @@ public static void LocalDataSlotTest() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/49521", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public static void InterruptTest() { // Interrupting a thread that is not blocked does not do anything, but once the thread starts blocking, it gets @@ -962,6 +963,7 @@ public static void InterruptTest() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/49521", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public static void InterruptInFinallyBlockTest_SkipOnDesktopFramework() { // A wait in a finally block can be interrupted. The .NET Framework applies the same rules as thread abort, and diff --git a/src/libraries/System.Threading/tests/MutexTests.cs b/src/libraries/System.Threading/tests/MutexTests.cs index 73e7d02a4a8031..a893662df15195 100644 --- a/src/libraries/System.Threading/tests/MutexTests.cs +++ b/src/libraries/System.Threading/tests/MutexTests.cs @@ -45,6 +45,7 @@ public void Ctor_InvalidNames_Unix() } [Theory] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(GetValidNames))] public void Ctor_ValidName(string name) { @@ -96,6 +97,7 @@ public void Ctor_TryCreateGlobalMutexTest_Uwp() } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(GetValidNames))] public void OpenExisting(string name) { @@ -130,6 +132,7 @@ public void OpenExisting_InvalidNames() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void OpenExisting_UnavailableName() { string name = Guid.NewGuid().ToString("N"); @@ -225,6 +228,7 @@ public static IEnumerable AbandonExisting_MemberData() } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(AbandonExisting_MemberData))] public void AbandonExisting( string name, @@ -465,6 +469,7 @@ private static void IncrementValueInFileNTimes(Mutex mutex, string fileName, int } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void NamedMutex_ThreadExitDisposeRaceTest() { var mutexName = Guid.NewGuid().ToString("N"); @@ -525,6 +530,7 @@ public void NamedMutex_ThreadExitDisposeRaceTest() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void NamedMutex_DisposeWhenLockedRaceTest() { var mutexName = Guid.NewGuid().ToString("N"); diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index fcb64a0ae6947b..6faf1e8ca4f7cb 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -254,14 +254,9 @@ - - - - - diff --git a/src/mono/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.Unix.Mono.cs b/src/mono/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.Unix.Mono.cs deleted file mode 100644 index 37e0b6a5962834..00000000000000 --- a/src/mono/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.Unix.Mono.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.CompilerServices; - -namespace Microsoft.Win32.SafeHandles -{ - public partial class SafeWaitHandle - { - protected override bool ReleaseHandle() - { - CloseEventInternal(handle); - return true; - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern void CloseEventInternal(IntPtr handle); - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.Mono.cs deleted file mode 100644 index 854a6b4eae7086..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.Mono.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Win32.SafeHandles; -using System.Runtime.CompilerServices; - -namespace System.Threading -{ - public partial class EventWaitHandle - { - public bool Set() - { - SafeWaitHandle handle = ValidateHandle(out bool release); - - try - { - return SetEventInternal(handle.DangerousGetHandle()); - } - finally - { - if (release) - handle.DangerousRelease(); - } - } - - public bool Reset() - { - SafeWaitHandle handle = ValidateHandle(out bool release); - - try - { - return ResetEventInternal(handle.DangerousGetHandle()); - } - finally - { - if (release) - handle.DangerousRelease(); - } - } - - private unsafe void CreateEventCore(bool initialState, EventResetMode mode, string? name, out bool createdNew) - { - if (name != null) - throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); - - SafeWaitHandle handle = new SafeWaitHandle(CreateEventInternal(mode == EventResetMode.ManualReset, initialState, null, 0, out int errorCode), ownsHandle: true); - if (errorCode != 0) - throw new NotImplementedException("errorCode"); - SafeWaitHandle = handle; - - createdNew = true; - } - - private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle result) - { - throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); - } - - internal static bool Set(SafeWaitHandle waitHandle) - { - bool release = false; - try - { - waitHandle.DangerousAddRef(ref release); - return SetEventInternal(waitHandle.DangerousGetHandle()); - } - finally - { - if (release) - waitHandle.DangerousRelease(); - } - } - - private SafeWaitHandle ValidateHandle(out bool success) - { - // The field value is modifiable via the public property, save it locally - // to ensure that one instance is used in all places in this method - SafeWaitHandle waitHandle = SafeWaitHandle; - if (waitHandle.IsInvalid) - { - throw new InvalidOperationException(); - } - - success = false; - waitHandle.DangerousAddRef(ref success); - return waitHandle; - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr CreateEventInternal(bool manual, bool initialState, char* name, int name_length, out int errorCode); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern bool ResetEventInternal(IntPtr handle); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern bool SetEventInternal(IntPtr handle); - - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Mutex.Unix.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Mutex.Unix.Mono.cs deleted file mode 100644 index fc25c741a937dd..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Mutex.Unix.Mono.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using System.IO; - -namespace System.Threading -{ - public partial class Mutex - { - private Mutex(IntPtr handle) => Handle = handle; - - public void ReleaseMutex() - { - if (!ReleaseMutex_internal(Handle)) - throw new ApplicationException(SR.Arg_SynchronizationLockException); - } - - private void CreateMutexCore(bool initiallyOwned, string? name, out bool createdNew) => - Handle = CreateMutex_internal(initiallyOwned, name, out createdNew); - - private static unsafe IntPtr CreateMutex_internal(bool initiallyOwned, string? name, out bool created) - { - fixed (char* fixed_name = name) - return CreateMutex_icall(initiallyOwned, fixed_name, - name?.Length ?? 0, out created); - } - - private static OpenExistingResult OpenExistingWorker(string name, out Mutex? result) - { - if (name == null) - throw new ArgumentNullException(nameof(name)); - - result = null; - if ((name.Length == 0) || - (name.Length > 260)) - { - return OpenExistingResult.NameInvalid; - } - - MonoIOError error; - IntPtr handle = OpenMutex_internal(name, out error); - if (handle == IntPtr.Zero) - { - if (error == MonoIOError.ERROR_FILE_NOT_FOUND) - { - return OpenExistingResult.NameNotFound; - } - else if (error == MonoIOError.ERROR_ACCESS_DENIED) - { - throw new UnauthorizedAccessException(); - } - else - { - return OpenExistingResult.PathNotFound; - } - } - - result = new Mutex(handle); - return OpenExistingResult.Success; - } - - private static unsafe IntPtr OpenMutex_internal(string name, out MonoIOError error) - { - fixed (char* fixed_name = name) - return OpenMutex_icall(fixed_name, name?.Length ?? 0, 0x000001 /* MutexRights.Modify */, out error); - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr CreateMutex_icall(bool initiallyOwned, char* name, int name_length, out bool created); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr OpenMutex_icall(char* name, int name_length, int rights, out MonoIOError error); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern bool ReleaseMutex_internal(IntPtr handle); - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.Mono.cs deleted file mode 100644 index ac51ec48210cca..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.Mono.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using Microsoft.Win32.SafeHandles; -using System.IO; - -namespace System.Threading -{ - public partial class Semaphore - { - private const int MAX_PATH = 260; - - private Semaphore(SafeWaitHandle handle) => this.SafeWaitHandle = handle; - - private int ReleaseCore(int releaseCount) - { - if (!ReleaseSemaphore_internal(SafeWaitHandle.DangerousGetHandle(), releaseCount, out int previousCount)) - throw new SemaphoreFullException(); - - return previousCount; - } - - private static OpenExistingResult OpenExistingWorker(string name, out Semaphore? result) - { - if (name == null) - throw new ArgumentNullException(nameof(name)); - - if (name.Length == 0) - throw new ArgumentException(SR.Argument_StringZeroLength, nameof(name)); - - if (name.Length > MAX_PATH) - throw new ArgumentException(SR.Argument_WaitHandleNameTooLong); - - var myHandle = new SafeWaitHandle(OpenSemaphore_internal(name, - /*SemaphoreRights.Modify | SemaphoreRights.Synchronize*/ 0x000002 | 0x100000, - out MonoIOError errorCode), true); - - if (myHandle.IsInvalid) - { - result = null; - switch (errorCode) - { - case MonoIOError.ERROR_FILE_NOT_FOUND: - case MonoIOError.ERROR_INVALID_NAME: - return OpenExistingResult.NameNotFound; - case MonoIOError.ERROR_PATH_NOT_FOUND: - return OpenExistingResult.PathNotFound; - case MonoIOError.ERROR_INVALID_HANDLE when !string.IsNullOrEmpty(name): - return OpenExistingResult.NameInvalid; - default: - //this is for passed through NativeMethods Errors - throw new IOException($"Unknown Error '{errorCode}'"); - } - } - - result = new Semaphore(myHandle); - return OpenExistingResult.Success; - } - - private void CreateSemaphoreCore(int initialCount, int maximumCount, string? name, out bool createdNew) - { - if (name?.Length > MAX_PATH) - throw new ArgumentException(SR.Argument_WaitHandleNameTooLong); - - var myHandle = new SafeWaitHandle(CreateSemaphore_internal(initialCount, maximumCount, name, out MonoIOError errorCode), true); - - if (myHandle.IsInvalid) - { - if (errorCode == MonoIOError.ERROR_INVALID_HANDLE && !string.IsNullOrEmpty(name)) - throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); - - throw new IOException($"Unknown Error '{errorCode}'"); - } - - this.SafeWaitHandle = myHandle; - createdNew = errorCode != MonoIOError.ERROR_ALREADY_EXISTS; - } - - private static unsafe IntPtr CreateSemaphore_internal(int initialCount, int maximumCount, string? name, out MonoIOError errorCode) - { - // FIXME Check for embedded nuls in name. - fixed (char* fixed_name = name) - return CreateSemaphore_icall(initialCount, maximumCount, - fixed_name, name?.Length ?? 0, out errorCode); - } - - private static unsafe IntPtr OpenSemaphore_internal(string name, int rights, out MonoIOError errorCode) - { - // FIXME Check for embedded nuls in name. - fixed (char* fixed_name = name) - return OpenSemaphore_icall(fixed_name, name?.Length ?? 0, rights, out errorCode); - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr CreateSemaphore_icall(int initialCount, int maximumCount, char* name, int nameLength, out MonoIOError errorCode); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr OpenSemaphore_icall(char* name, int nameLength, int rights, out MonoIOError errorCode); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern bool ReleaseSemaphore_internal(IntPtr handle, int releaseCount, out int previousCount); - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index ddc62e11d11f83..c1978eab5f1114 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -17,7 +17,7 @@ namespace System.Threading public partial class Thread { #pragma warning disable 169, 414, 649 - #region Sync with metadata/object-internals.h and InternalThread in mcs/class/corlib/System.Threading/Thread.cs + #region Sync with metadata/object-internals.h private int lock_thread_id; // stores a thread handle private IntPtr handle; @@ -37,9 +37,7 @@ public partial class Thread private int interruption_requested; private IntPtr longlived; internal bool threadpool_thread; - private bool thread_interrupt_requested; /* These are used from managed code */ - internal int stack_size; internal byte apartment_state; internal int managed_id; private int small_id; @@ -67,6 +65,9 @@ public partial class Thread private StartHelper? _startHelper; internal ExecutionContext? _executionContext; internal SynchronizationContext? _synchronizationContext; +#if TARGET_UNIX || TARGET_BROWSER + internal WaitSubsystem.ThreadWaitInfo _waitInfo; +#endif // This is used for a quick check on thread pool threads after running a work item to determine if the name, background // state, or priority were changed by the work item, and if so to reset it. Other threads may also change some of those, @@ -75,11 +76,14 @@ public partial class Thread private Thread() { - InitInternal(this); + Initialize(); } ~Thread() { +#if TARGET_UNIX || TARGET_BROWSER + WaitSubsystem.OnThreadExiting(this); +#endif FreeInternal(); } @@ -146,6 +150,10 @@ internal static int OptimalMaxSpinWaitsPerSpinIteration } } +#if TARGET_UNIX || TARGET_BROWSER + internal WaitSubsystem.ThreadWaitInfo WaitInfo => _waitInfo; +#endif + public ThreadPriority Priority { get @@ -188,6 +196,9 @@ public static int GetCurrentProcessorId() public void Interrupt() { +#if TARGET_UNIX || TARGET_BROWSER // TODO: https://github.com/dotnet/runtime/issues/49521 + WaitSubsystem.Interrupt(this); +#endif InterruptInternal(this); } @@ -198,13 +209,24 @@ public bool Join(int millisecondsTimeout) return JoinInternal(this, millisecondsTimeout); } +#if TARGET_UNIX || TARGET_BROWSER + [MemberNotNull(nameof(_waitInfo))] +#endif private void Initialize() { InitInternal(this); +#if TARGET_UNIX || TARGET_BROWSER + _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); +#endif + } - // TODO: This can go away once the mono/mono mirror is disabled - stack_size = _startHelper!._maxStackSize; +#if TARGET_UNIX || TARGET_BROWSER + private void EnsureWaitInfo() + { + if (_waitInfo == null) + _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); } +#endif public static void SpinWait(int iterations) { @@ -240,13 +262,13 @@ internal void StartCallback() private void StartCore() { - StartInternal(this); + StartInternal(this, _startHelper?._maxStackSize ?? 0); } [DynamicDependency(nameof(StartCallback))] [DynamicDependency(nameof(ThrowThreadStartException))] [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern void StartInternal(Thread runtime_thread); + private static extern void StartInternal(Thread runtimeThread, int stackSize); partial void ThreadNameChanged(string? value) { @@ -282,6 +304,22 @@ private ThreadState ValidateThreadState() return state; } + internal void SetWaitSleepJoinState() + { + Debug.Assert(this == CurrentThread); + Debug.Assert((GetState(this) & ThreadState.WaitSleepJoin) == 0); + + SetState(this, ThreadState.WaitSleepJoin); + } + + internal void ClearWaitSleepJoinState() + { + Debug.Assert(this == CurrentThread); + Debug.Assert((GetState(this) & ThreadState.WaitSleepJoin) != 0); + + ClrState(this, ThreadState.WaitSleepJoin); + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern ulong GetCurrentOSThreadId(); @@ -296,6 +334,9 @@ private ThreadState ValidateThreadState() private static Thread InitializeCurrentThread() { InitializeCurrentThread_icall(ref t_currentThread); +#if TARGET_UNIX || TARGET_BROWSER + t_currentThread.EnsureWaitInfo(); +#endif return t_currentThread; } diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/WaitHandle.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/WaitHandle.Mono.cs deleted file mode 100644 index 08ad89b8d032ce..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/WaitHandle.Mono.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace System.Threading -{ - public partial class WaitHandle - { - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe int Wait_internal(IntPtr* handles, int numHandles, bool waitAll, int ms); - - private static int WaitOneCore(IntPtr waitHandle, int millisecondsTimeout) - { - unsafe - { - return Wait_internal(&waitHandle, 1, false, millisecondsTimeout); - } - } - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int SignalAndWait_Internal(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout); - - private const int ERROR_TOO_MANY_POSTS = 0x12A; - private const int ERROR_NOT_OWNED_BY_CALLER = 0x12B; - - private static int SignalAndWaitCore(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout) - { - int ret = SignalAndWait_Internal(waitHandleToSignal, waitHandleToWaitOn, millisecondsTimeout); - if (ret == ERROR_TOO_MANY_POSTS) - throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts); - if (ret == ERROR_NOT_OWNED_BY_CALLER) - throw new ApplicationException("Attempt to release mutex not owned by caller"); - return ret; - } - - internal static int WaitMultipleIgnoringSyncContext(Span waitHandles, bool waitAll, int millisecondsTimeout) - { - unsafe - { - fixed (IntPtr* handles = &MemoryMarshal.GetReference(waitHandles)) - { - return Wait_internal(handles, waitHandles.Length, waitAll, millisecondsTimeout); - } - } - } - - // FIXME: Move to shared - internal static int WaitAny(ReadOnlySpan waitHandles, int millisecondsTimeout) => - WaitMultiple(waitHandles, false, millisecondsTimeout); - } -} diff --git a/src/mono/mono/metadata/CMakeLists.txt b/src/mono/mono/metadata/CMakeLists.txt index 5f200c5ffe5d88..b78a4a6625db47 100644 --- a/src/mono/mono/metadata/CMakeLists.txt +++ b/src/mono/mono/metadata/CMakeLists.txt @@ -34,24 +34,16 @@ set(metadata_win32_sources icall-windows.c marshal-windows.c mono-security-windows.c - w32mutex-win32.c - w32semaphore-win32.c w32event-win32.c - w32socket-win32.c w32error-win32.c) set(metadata_unix_sources - w32mutex-unix.c - w32semaphore-unix.c w32event-unix.c w32process-unix-osx.c w32process-unix-bsd.c w32process-unix-haiku.c w32process-unix-default.c - w32socket-unix.c w32file-unix.c - w32file-unix-glob.c - w32file-unix-glob.h w32error-unix.c) if(HOST_WIN32) @@ -94,7 +86,6 @@ set(metadata_common_sources exception.h exception-internals.h w32file.h - w32file-internals.h gc-internals.h icall.c icall-internals.h @@ -144,8 +135,6 @@ set(metadata_common_sources opcodes.c property-bag.h property-bag.c - w32socket.h - w32socket-internals.h w32process.h profiler.c profiler-private.h @@ -180,8 +169,6 @@ set(metadata_common_sources seq-points-data.c handle.c handle.h - w32mutex.h - w32semaphore.h w32event.h w32handle-namespace.h w32handle-namespace.c diff --git a/src/mono/mono/metadata/appdomain.c b/src/mono/mono/metadata/appdomain.c index e6bcf98bbaef53..170560c081f7b0 100644 --- a/src/mono/mono/metadata/appdomain.c +++ b/src/mono/mono/metadata/appdomain.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mono/mono/metadata/domain.c b/src/mono/mono/metadata/domain.c index 78e552336d84a1..929c4ed538e6bc 100644 --- a/src/mono/mono/metadata/domain.c +++ b/src/mono/mono/metadata/domain.c @@ -42,8 +42,6 @@ #include #include #include -#include -#include #include #include #include @@ -369,8 +367,6 @@ mono_init_internal (const char *filename, const char *exe_filename, const char * mono_w32handle_namespace_init (); #endif - mono_w32mutex_init (); - mono_w32semaphore_init (); mono_w32event_init (); mono_w32file_init (); diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index 1d233f24600d1a..6e44d3b055cdcf 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -27,9 +27,6 @@ #include "mono/utils/mono-forward-internal.h" #include "w32event.h" #include "w32file.h" -#include "w32mutex.h" -#include "w32semaphore.h" -#include "w32socket.h" #include "mono/utils/mono-proclib.h" /* From MonoProperty.cs */ @@ -225,10 +222,6 @@ ICALL_EXPORT gpointer ves_icall_System_Runtime_InteropServices_Marshal_ReAlloc ICALL_EXPORT char* ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (const gunichar2*, int); ICALL_EXPORT gunichar2* ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (const gunichar2*, int); -ICALL_EXPORT gpointer ves_icall_System_Threading_Semaphore_CreateSemaphore_icall (gint32 initialCount, gint32 maximumCount, const gunichar2 *name, gint32 name_length, gint32 *win32error); -ICALL_EXPORT gpointer ves_icall_System_Threading_Semaphore_OpenSemaphore_icall (const gunichar2 *name, gint32 name_length, gint32 rights, gint32 *win32error); -ICALL_EXPORT MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount); - ICALL_EXPORT gpointer ves_icall_System_Threading_LowLevelLifoSemaphore_InitInternal (void); ICALL_EXPORT void ves_icall_System_Threading_LowLevelLifoSemaphore_DeleteInternal (gpointer sem_ptr); ICALL_EXPORT gint32 ves_icall_System_Threading_LowLevelLifoSemaphore_TimedWaitInternal (gpointer sem_ptr, gint32 timeout_ms); diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index 73c3dfca687c4d..f926dc3eb2c748 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -1,6 +1,3 @@ -ICALL_TYPE(SAFEWAITHANDLE, "Microsoft.Win32.SafeHandles.SafeWaitHandle", SAFEWAITHANDLE_1) // && UNIX -NOHANDLES(ICALL(SAFEWAITHANDLE_1, "CloseEventInternal", ves_icall_System_Threading_Events_CloseEvent_internal)) - ICALL_TYPE(RUNTIME, "Mono.Runtime", RUNTIME_20) NOHANDLES(ICALL(RUNTIME_20, "AnnotateMicrosoftTelemetry_internal", ves_icall_Mono_Runtime_AnnotateMicrosoftTelemetry)) NOHANDLES(ICALL(RUNTIME_19, "CheckCrashReportLog_internal", ves_icall_Mono_Runtime_CheckCrashReportingLog)) @@ -447,11 +444,6 @@ HANDLES(STRING_9, "FastAllocateString", ves_icall_System_String_FastAllocateStri HANDLES(STRING_10, "InternalIntern", ves_icall_System_String_InternalIntern, MonoString, 1, (MonoString)) HANDLES(STRING_11, "InternalIsInterned", ves_icall_System_String_InternalIsInterned, MonoString, 1, (MonoString)) -ICALL_TYPE(NATIVEC, "System.Threading.EventWaitHandle", EWH_1) // && Unix -HANDLES(EWH_1, "CreateEventInternal", ves_icall_System_Threading_Events_CreateEvent_icall, gpointer, 5, (MonoBoolean, MonoBoolean, const_gunichar2_ptr, gint32, gint32_ref)) -NOHANDLES(ICALL(EWH_2, "ResetEventInternal", ves_icall_System_Threading_Events_ResetEvent_internal)) -NOHANDLES(ICALL(EWH_3, "SetEventInternal", ves_icall_System_Threading_Events_SetEvent_internal)) - ICALL_TYPE(ILOCK, "System.Threading.Interlocked", ILOCK_1) NOHANDLES(ICALL(ILOCK_1, "Add(int&,int)", ves_icall_System_Threading_Interlocked_Add_Int)) NOHANDLES(ICALL(ILOCK_2, "Add(long&,long)", ves_icall_System_Threading_Interlocked_Add_Long)) @@ -490,16 +482,6 @@ HANDLES(MONIT_7, "Monitor_wait", ves_icall_System_Threading_Monitor_Monitor_wait NOHANDLES(ICALL(MONIT_8, "get_LockContentionCount", ves_icall_System_Threading_Monitor_Monitor_LockContentionCount)) HANDLES(MONIT_9, "try_enter_with_atomic_var", ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var, void, 4, (MonoObject, guint32, MonoBoolean, MonoBoolean_ref)) -ICALL_TYPE(MUTEX, "System.Threading.Mutex", MUTEX_1) -HANDLES(MUTEX_1, "CreateMutex_icall", ves_icall_System_Threading_Mutex_CreateMutex_icall, gpointer, 4, (MonoBoolean, const_gunichar2_ptr, gint32, MonoBoolean_ref)) -HANDLES(MUTEX_2, "OpenMutex_icall", ves_icall_System_Threading_Mutex_OpenMutex_icall, gpointer, 4, (const_gunichar2_ptr, gint32, gint32, gint32_ref)) -NOHANDLES(ICALL(MUTEX_3, "ReleaseMutex_internal", ves_icall_System_Threading_Mutex_ReleaseMutex_internal)) - -ICALL_TYPE(SEMA, "System.Threading.Semaphore", SEMA_1) -NOHANDLES(ICALL(SEMA_1, "CreateSemaphore_icall", ves_icall_System_Threading_Semaphore_CreateSemaphore_icall)) -NOHANDLES(ICALL(SEMA_2, "OpenSemaphore_icall", ves_icall_System_Threading_Semaphore_OpenSemaphore_icall)) -NOHANDLES(ICALL(SEMA_3, "ReleaseSemaphore_internal", ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal)) - ICALL_TYPE(THREAD, "System.Threading.Thread", THREAD_1) HANDLES(THREAD_1, "ClrState", ves_icall_System_Threading_Thread_ClrState, void, 2, (MonoInternalThread, guint32)) HANDLES(ITHREAD_2, "FreeInternal", ves_icall_System_Threading_InternalThread_Thread_free_internal, void, 1, (MonoInternalThread)) @@ -514,13 +496,9 @@ HANDLES(THREAD_8, "SetName_icall", ves_icall_System_Threading_Thread_SetName_ica HANDLES(THREAD_9, "SetPriority", ves_icall_System_Threading_Thread_SetPriority, void, 2, (MonoThreadObject, int)) HANDLES(THREAD_10, "SetState", ves_icall_System_Threading_Thread_SetState, void, 2, (MonoInternalThread, guint32)) HANDLES(THREAD_11, "SleepInternal", ves_icall_System_Threading_Thread_Sleep_internal, void, 2, (gint32, MonoBoolean)) -HANDLES(THREAD_13, "StartInternal", ves_icall_System_Threading_Thread_StartInternal, void, 1, (MonoThreadObject)) +HANDLES(THREAD_13, "StartInternal", ves_icall_System_Threading_Thread_StartInternal, void, 2, (MonoThreadObject, gint32)) NOHANDLES(ICALL(THREAD_14, "YieldInternal", ves_icall_System_Threading_Thread_YieldInternal)) -ICALL_TYPE(WAITH, "System.Threading.WaitHandle", WAITH_1) -HANDLES(WAITH_1, "SignalAndWait_Internal", ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal, gint32, 3, (gpointer, gpointer, gint32)) -HANDLES(WAITH_2, "Wait_internal", ves_icall_System_Threading_WaitHandle_Wait_internal, gint32, 4, (gpointer_ptr, gint32, MonoBoolean, gint32)) - ICALL_TYPE(TYPE, "System.Type", TYPE_1) HANDLES(TYPE_1, "internal_from_handle", ves_icall_System_Type_internal_from_handle, MonoReflectionType, 1, (MonoType_ref)) diff --git a/src/mono/mono/metadata/icall-table.h b/src/mono/mono/metadata/icall-table.h index f34658581bc438..31aa3aba238a04 100644 --- a/src/mono/mono/metadata/icall-table.h +++ b/src/mono/mono/metadata/icall-table.h @@ -69,7 +69,6 @@ typedef MonoVTable *MonoVTable_ptr; typedef unsigned *unsigned_ptr; typedef mono_unichar2 *mono_unichar2_ptr; typedef mono_unichar4 *mono_unichar4_ptr; -typedef WSABUF *WSABUF_ptr; typedef char **char_ptr_ref; typedef gint32 *gint32_ref; @@ -151,7 +150,6 @@ typedef MonoStringHandle MonoStringOutHandle; #define MONO_HANDLE_TYPE_WRAP_MonoProperty_ptr ICALL_HANDLES_WRAP_NONE #define MONO_HANDLE_TYPE_WRAP_size_t ICALL_HANDLES_WRAP_NONE #define MONO_HANDLE_TYPE_WRAP_MonoVTable_ptr ICALL_HANDLES_WRAP_NONE -#define MONO_HANDLE_TYPE_WRAP_WSABUF_ptr ICALL_HANDLES_WRAP_NONE #define MONO_HANDLE_TYPE_WRAP_MonoAssemblyName_ref ICALL_HANDLES_WRAP_VALUETYPE_REF #define MONO_HANDLE_TYPE_WRAP_MonoBoolean_ref ICALL_HANDLES_WRAP_VALUETYPE_REF diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 4d2a5ad773dff4..7492f82d2a6815 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include @@ -82,8 +81,6 @@ #include #include #include -#include -#include #include #include #include @@ -6673,69 +6670,6 @@ mono_icall_get_windows_folder_path (int folder, MonoError *error) } #endif /* !HOST_WIN32 */ -static MonoArrayHandle -mono_icall_get_logical_drives (MonoError *error) -{ - gunichar2 buf [256], *ptr, *dname; - gunichar2 *u16; - guint initial_size = 127, size = 128; - gint ndrives; - MonoArrayHandle result = NULL_HANDLE_ARRAY; - MonoStringHandle drivestr; - gint len; - - buf [0] = '\0'; - ptr = buf; - - while (size > initial_size) { - size = (guint) mono_w32file_get_logical_drive (initial_size, ptr, error); - if (!is_ok (error)) - goto leave; - if (size > initial_size) { - if (ptr != buf) - g_free (ptr); - ptr = (gunichar2 *)g_malloc0 ((size + 1) * sizeof (gunichar2)); - initial_size = size; - size++; - } - } - - /* Count strings */ - dname = ptr; - ndrives = 0; - do { - while (*dname++); - ndrives++; - } while (*dname); - - dname = ptr; - result = mono_array_new_handle (mono_defaults.string_class, ndrives, error); - goto_if_nok (error, leave); - - drivestr = MONO_HANDLE_NEW (MonoString, NULL); - ndrives = 0; - do { - len = 0; - u16 = dname; - while (*u16) { - u16++; len ++; - } - MonoString *s = mono_string_new_utf16_checked (dname, len, error); - goto_if_nok (error, leave); - MONO_HANDLE_ASSIGN_RAW (drivestr, s); - - mono_array_handle_setref (result, ndrives, drivestr); - ndrives ++; - while (*dname++); - } while (*dname); - -leave: - if (ptr != buf) - g_free (ptr); - - return result; -} - MonoBoolean ves_icall_System_Environment_get_HasShutdownStarted (void) { @@ -6755,32 +6689,6 @@ ves_icall_System_Environment_get_TickCount64 (void) return mono_msec_boottime (); } -#ifndef PLATFORM_NO_DRIVEINFO -MonoBoolean -ves_icall_System_IO_DriveInfo_GetDiskFreeSpace (const gunichar2 *path_name, gint32 path_name_length, guint64 *free_bytes_avail, - guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes, - gint32 *error) -{ - g_assert (error); - g_assert (free_bytes_avail); - g_assert (total_number_of_bytes); - g_assert (total_number_of_free_bytes); - - // FIXME check for embedded nuls here or managed - - *error = ERROR_SUCCESS; - *free_bytes_avail = (guint64)-1; - *total_number_of_bytes = (guint64)-1; - *total_number_of_free_bytes = (guint64)-1; - - gboolean result = mono_w32file_get_disk_free_space (path_name, free_bytes_avail, total_number_of_bytes, total_number_of_free_bytes); - if (!result) - *error = mono_w32error_get_last (); - - return result; -} -#endif /* PLATFORM_NO_DRIVEINFO */ - gpointer ves_icall_RuntimeMethodHandle_GetFunctionPointer (MonoMethod *method, MonoError *error) { diff --git a/src/mono/mono/metadata/monitor.c b/src/mono/mono/metadata/monitor.c index 410f0d6103fed8..30cbe19e4300ef 100644 --- a/src/mono/mono/metadata/monitor.c +++ b/src/mono/mono/metadata/monitor.c @@ -1386,10 +1386,6 @@ mono_monitor_wait (MonoObjectHandle obj_handle, guint32 ms, MonoBoolean allow_in mon = lock_word_get_inflated_lock (lw); - /* Do this WaitSleepJoin check before creating the event handle */ - if (mono_thread_current_check_pending_interrupt ()) - return FALSE; - event = mono_w32event_create (FALSE, FALSE); if (event == NULL) { ERROR_DECL (error); @@ -1404,15 +1400,9 @@ mono_monitor_wait (MonoObjectHandle obj_handle, guint32 ms, MonoBoolean allow_in return FALSE; } #endif - + LOCK_DEBUG (g_message ("%s: (%d) queuing handle %p", __func__, id, event)); - /* This looks superfluous */ - if (allow_interruption && mono_thread_current_check_pending_interrupt ()) { - mono_w32event_close (event); - return FALSE; - } - mono_thread_set_state (thread, ThreadState_WaitSleepJoin); mon->wait_list = g_slist_append (mon->wait_list, event); diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 9f66f9ca8bec03..fdc2e31f97766f 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -568,8 +568,6 @@ struct _MonoInternalThread { * longer */ MonoLongLivedThreadData *longlived; MonoBoolean threadpool_thread; - MonoBoolean thread_interrupt_requested; - int stack_size; guint8 apartment_state; gint32 managed_id; guint32 small_id; diff --git a/src/mono/mono/metadata/threads-types.h b/src/mono/mono/metadata/threads-types.h index c53e735b80eb52..481ddf1cc60ade 100644 --- a/src/mono/mono/metadata/threads-types.h +++ b/src/mono/mono/metadata/threads-types.h @@ -206,7 +206,6 @@ void mono_thread_internal_reset_abort (MonoInternalThread *thread); void mono_thread_internal_unhandled_exception (MonoObject* exc); void mono_alloc_special_static_data_free (GHashTable *special_static_fields); -gboolean mono_thread_current_check_pending_interrupt (void); void mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state); void mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state); diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index 36fbfa86c9f750..98956c4a1d0d76 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include @@ -198,7 +197,6 @@ static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL; /* The default stack size for each thread */ static guint32 default_stacksize = 0; -#define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize) static void mono_free_static_data (gpointer* static_data); static void mono_init_static_data_info (StaticDataInfo *static_data); @@ -859,6 +857,43 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean return FALSE; } +#ifndef HOST_WIN32 +static GENERATE_GET_CLASS_WITH_CACHE (wait_subsystem, "System.Threading", "WaitSubsystem"); + +static void +abandon_mutexes (MonoInternalThread *internal) +{ + // TODO: delete me if we decide not to prejit +/* ERROR_DECL (error); + + MONO_STATIC_POINTER_INIT (MonoMethod, thread_exiting) + + MonoClass *wait_subsystem_class = mono_class_get_wait_subsystem_class (); + g_assert (wait_subsystem_class); + thread_exiting = mono_class_get_method_from_name_checked (wait_subsystem_class, "OnThreadExiting", -1, 0, error); + mono_error_assert_ok (error); + + MONO_STATIC_POINTER_INIT_END (MonoMethod, thread_exiting) + + g_assert (thread_exiting); + + if (mono_runtime_get_no_exec ()) + return; + + HANDLE_FUNCTION_ENTER (); + + ERROR_DECL (error); + + gpointer args [1]; + args [0] = internal; + mono_runtime_try_invoke_handle (thread_exiting, NULL_HANDLE, args, error); + + mono_error_cleanup (error); + + HANDLE_FUNCTION_RETURN ();*/ +} +#endif + static void mono_thread_detach_internal (MonoInternalThread *thread) { @@ -891,7 +926,7 @@ mono_thread_detach_internal (MonoInternalThread *thread) threads_add_pending_joinable_runtime_thread (info); #ifndef HOST_WIN32 - mono_w32mutex_abandon (thread); + abandon_mutexes (thread); #endif mono_gchandle_free_internal (thread->abort_state_handle); @@ -1228,7 +1263,7 @@ throw_thread_start_exception (guint32 error_code, MonoError *error) */ static gboolean create_thread (MonoThread *thread, MonoInternalThread *internal, MonoThreadStart start_func, gpointer start_func_arg, - MonoThreadCreateFlags flags, MonoError *error) + gint32 stack_size, MonoThreadCreateFlags flags, MonoError *error) { StartInfo *start_info = NULL; MonoNativeThreadId tid; @@ -1280,7 +1315,7 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoThreadStart mono_coop_sem_init (&start_info->registered, 0); if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK) - stack_set_size = default_stacksize_for_thread (internal); + stack_set_size = stack_size ? stack_size : default_stacksize; else stack_set_size = 0; @@ -1298,8 +1333,6 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoThreadStart goto done; } - internal->stack_size = (int) stack_set_size; - THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT ") Launching thread %p (%" G_GSIZE_FORMAT ")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid)); /* @@ -1373,7 +1406,7 @@ mono_thread_create_internal (MonoThreadStart func, gpointer arg, MonoThreadCreat LOCK_THREAD (internal); - res = create_thread (thread, internal, func, arg, flags, error); + res = create_thread (thread, internal, func, arg, 0, flags, error); (void)res; UNLOCK_THREAD (internal); @@ -1724,9 +1757,6 @@ mono_sleep_internal (gint32 ms, MonoBoolean allow_interruption, MonoError *error { THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms)); - if (mono_thread_current_check_pending_interrupt ()) - return; - MonoInternalThread * const thread = mono_thread_internal_current (); HANDLE_LOOP_PREPARE; @@ -1994,9 +2024,6 @@ mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError MonoBoolean ves_icall_System_Threading_Thread_Join_internal (MonoThreadObjectHandle thread_handle, int ms, MonoError *error) { - if (mono_thread_current_check_pending_interrupt ()) - return FALSE; - // Internal threads are pinned so shallow coop/handle. MonoInternalThread * const thread = thread_handle_to_internal_ptr (thread_handle); MonoThreadHandle *handle = thread->handle; @@ -2066,105 +2093,6 @@ map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects) } } -gint32 -ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer *handles, gint32 numhandles, MonoBoolean waitall, gint32 timeout, MonoError *error) -{ - /* Do this WaitSleepJoin check before creating objects */ - if (mono_thread_current_check_pending_interrupt ()) - return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0); - - MonoInternalThread * const thread = mono_thread_internal_current (); - - mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - - gint64 start = 0; - - if (timeout == -1) - timeout = MONO_INFINITE_WAIT; - if (timeout != MONO_INFINITE_WAIT) - start = mono_msec_ticks (); - - guint32 timeoutLeft = timeout; - - MonoW32HandleWaitRet ret; - -#ifdef DISABLE_THREADS - if (numhandles == 1 && timeout == MONO_INFINITE_WAIT) { - gboolean signalled = FALSE; - for (int i = 0; i < numhandles; ++i) { - if (mono_w32handle_handle_is_owned (handles [i]) || mono_w32handle_handle_is_signalled (handles [i])) { - signalled = TRUE; - break; - } - } - if (!signalled) { - mono_error_set_synchronization_lock (error, "Cannot wait on events on this runtime."); - return 0; - } - } -#endif - - HANDLE_LOOP_PREPARE; - - for (;;) { - - /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */ - ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE, error); - - if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED) - break; - - SETUP_ICALL_FRAME; - - MonoExceptionHandle exc = MONO_HANDLE_NEW (MonoException, NULL); - - const gboolean interrupt = mono_thread_execute_interruption (&exc); - - if (interrupt) - mono_error_set_exception_handle (error, exc); - - CLEAR_ICALL_FRAME; - - if (interrupt) - break; - - if (timeout != MONO_INFINITE_WAIT) { - gint64 const elapsed = mono_msec_ticks () - start; - if (elapsed >= timeout) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - break; - } - - timeoutLeft = timeout - elapsed; - } - } - - mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); - - return map_native_wait_result_to_managed (ret, numhandles); -} - -gint32 -ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal, gpointer toWait, gint32 ms, MonoError *error) -{ - MonoW32HandleWaitRet ret; - MonoInternalThread *thread = mono_thread_internal_current (); - - if (ms == -1) - ms = MONO_INFINITE_WAIT; - - if (mono_thread_current_check_pending_interrupt ()) - return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0); - - mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - - ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE); - - mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); - - return map_native_wait_result_to_managed (ret, 1); -} - gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location) { return mono_atomic_inc_i32 (location); @@ -2430,7 +2358,6 @@ ves_icall_System_Threading_Thread_Interrupt_internal (MonoThreadObjectHandle thr LOCK_THREAD (thread); - thread->thread_interrupt_requested = TRUE; gboolean const throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin); UNLOCK_THREAD (thread); @@ -2439,34 +2366,6 @@ ves_icall_System_Threading_Thread_Interrupt_internal (MonoThreadObjectHandle thr async_abort_internal (thread, FALSE); } -/** - * mono_thread_current_check_pending_interrupt: - * Checks if there's a interruption request and set the pending exception if so. - * \returns true if a pending exception was set - */ -gboolean -mono_thread_current_check_pending_interrupt (void) -{ - MonoInternalThread *thread = mono_thread_internal_current (); - gboolean throw_ = FALSE; - - LOCK_THREAD (thread); - - if (thread->thread_interrupt_requested) { - throw_ = TRUE; - thread->thread_interrupt_requested = FALSE; - } - - UNLOCK_THREAD (thread); - - if (throw_) { - ERROR_DECL (error); - mono_error_set_thread_interrupted (error); - mono_error_set_pending_exception (error); - } - return throw_; -} - // state is a pointer to a handle in order to be optional, // and be passed unspecified from functions not using handles. // When raw pointers is gone, it need not be a pointer, @@ -2819,7 +2718,7 @@ mono_thread_cleanup (void) * won't exit in time. */ if (!mono_runtime_get_no_exec ()) - mono_w32mutex_abandon (mono_thread_internal_current ()); + abandon_mutexes (mono_thread_internal_current ()); #endif #if 0 @@ -3806,15 +3705,6 @@ mono_thread_execute_interruption (MonoExceptionHandle *pexc) /* calls UNLOCK_THREAD (thread) */ self_suspend_internal (); unlock = FALSE; - } else if (MONO_HANDLE_GETVAL (thread, thread_interrupt_requested)) { - // thread->thread_interrupt_requested = FALSE - MONO_HANDLE_SETVAL (thread, thread_interrupt_requested, MonoBoolean, FALSE); - unlock_thread_handle (thread); - unlock = FALSE; - ERROR_DECL (error); - exc = mono_exception_new_thread_interrupted (error); - mono_error_assert_ok (error); // FIXME - fexc = TRUE; } exit: if (unlock) @@ -5496,7 +5386,7 @@ mono_threads_summarize (MonoContext *ctx, gchar **out, MonoStackHash *hashes, gb #endif void -ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_handle, MonoError *error) +ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_handle, gint32 stack_size, MonoError *error) { MonoThread *internal = MONO_HANDLE_RAW (thread_handle); gboolean res; @@ -5521,7 +5411,7 @@ ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_h return; } - res = create_thread (internal, internal, NULL, NULL, MONO_THREAD_CREATE_FLAGS_NONE, error); + res = create_thread (internal, internal, NULL, NULL, stack_size, MONO_THREAD_CREATE_FLAGS_NONE, error); if (!res) { UNLOCK_THREAD (internal); return; diff --git a/src/mono/mono/metadata/w32event-unix.c b/src/mono/mono/metadata/w32event-unix.c index e55051b991f91b..64ff8eea4e8782 100644 --- a/src/mono/mono/metadata/w32event-unix.c +++ b/src/mono/mono/metadata/w32event-unix.c @@ -170,12 +170,6 @@ mono_w32event_set (gpointer handle) ves_icall_System_Threading_Events_SetEvent_internal (handle); } -void -mono_w32event_reset (gpointer handle) -{ - ves_icall_System_Threading_Events_ResetEvent_internal (handle); -} - static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32Type type, gboolean manual, gboolean initial) { MonoW32Handle *handle_data; @@ -274,19 +268,6 @@ mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const char * return event; } -gpointer -ves_icall_System_Threading_Events_CreateEvent_icall (MonoBoolean manual, MonoBoolean initial, - const gunichar2* name, gint32 name_length, gint32 *win32error, MonoError *error) -{ - *win32error = ERROR_SUCCESS; - gsize utf8_name_length = 0; - char *utf8_name = mono_utf16_to_utf8len (name, name_length, &utf8_name_length, error); - return_val_if_nok (error, NULL); - gpointer result = mono_w32event_create_full (manual, initial, utf8_name, utf8_name_length, win32error); - g_free (utf8_name); - return result; -} - gboolean ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle) { @@ -326,58 +307,6 @@ ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle) return TRUE; } -gboolean -ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle) -{ - MonoW32Handle *handle_data; - MonoW32HandleEvent *event_handle; - - mono_w32error_set_last (ERROR_SUCCESS); - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { - g_warning ("%s: unkown handle %p", __func__, handle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (handle_data->type != MONO_W32TYPE_EVENT && handle_data->type != MONO_W32TYPE_NAMEDEVENT) { - g_warning ("%s: unkown event handle %p", __func__, handle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_w32handle_unref (handle_data); - return FALSE; - } - - event_handle = (MonoW32HandleEvent*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: resetting %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - mono_w32handle_lock (handle_data); - - if (!mono_w32handle_issignalled (handle_data)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: no need to reset %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: obtained write lock on %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); - } - - event_handle->set_count = 0; - - mono_w32handle_unlock (handle_data); - - mono_w32handle_unref (handle_data); - return TRUE; -} - -void -ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle) -{ - mono_w32handle_close (handle); -} - gpointer mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error) { diff --git a/src/mono/mono/metadata/w32event-win32.c b/src/mono/mono/metadata/w32event-win32.c index f51d75ba7ded04..c068a199b7839c 100644 --- a/src/mono/mono/metadata/w32event-win32.c +++ b/src/mono/mono/metadata/w32event-win32.c @@ -38,58 +38,3 @@ mono_w32event_set (gpointer handle) { SetEvent (handle); } - -void -mono_w32event_reset (gpointer handle) -{ - ResetEvent (handle); -} - -gpointer -ves_icall_System_Threading_Events_CreateEvent_icall (MonoBoolean manual, MonoBoolean initial, - const gunichar2 *name, gint32 name_length, gint32 *win32error, MonoError *error) -{ - gpointer event; - - MONO_ENTER_GC_SAFE; - event = CreateEventW (NULL, manual, initial, name); - *win32error = GetLastError (); - MONO_EXIT_GC_SAFE; - - return event; -} - -gboolean -ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle) -{ - return SetEvent (handle); -} - -gboolean -ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle) -{ - return ResetEvent (handle); -} - -void -ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle) -{ - CloseHandle (handle); -} - -gpointer -ves_icall_System_Threading_Events_OpenEvent_icall (const gunichar2 *name, gint32 name_length, - gint32 rights, gint32 *win32error, MonoError *error) -{ - gpointer handle; - - *win32error = ERROR_SUCCESS; - - MONO_ENTER_GC_SAFE; - handle = OpenEventW (rights, FALSE, name); - if (!handle) - *win32error = GetLastError (); - MONO_EXIT_GC_SAFE; - - return handle; -} diff --git a/src/mono/mono/metadata/w32event.h b/src/mono/mono/metadata/w32event.h index 7f6e92e28398bd..7bbbece7bf9be9 100644 --- a/src/mono/mono/metadata/w32event.h +++ b/src/mono/mono/metadata/w32event.h @@ -25,21 +25,10 @@ mono_w32event_close (gpointer handle); void mono_w32event_set (gpointer handle); -void -mono_w32event_reset (gpointer handle); - ICALL_EXPORT gboolean ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle); -ICALL_EXPORT -gboolean -ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle); - -ICALL_EXPORT -void -ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle); - typedef struct MonoW32HandleNamedEvent MonoW32HandleNamedEvent; MonoW32HandleNamespace* diff --git a/src/mono/mono/metadata/w32file-internals.h b/src/mono/mono/metadata/w32file-internals.h deleted file mode 100644 index 0f7876c9ddf3ef..00000000000000 --- a/src/mono/mono/metadata/w32file-internals.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - * \file - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#ifndef _MONO_METADATA_W32FILE_INTERNALS_H_ -#define _MONO_METADATA_W32FILE_INTERNALS_H_ - -#include -#include - -#endif /* _MONO_METADATA_W32FILE_INTERNALS_H_ */ diff --git a/src/mono/mono/metadata/w32file-unix-glob.c b/src/mono/mono/metadata/w32file-unix-glob.c deleted file mode 100644 index d07a7dc8297f22..00000000000000 --- a/src/mono/mono/metadata/w32file-unix-glob.c +++ /dev/null @@ -1,406 +0,0 @@ -/* $OpenBSD: glob.c,v 1.26 2005/11/28 17:50:12 deraadt Exp $ */ -/** - * \file - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * mono_w32file_unix_glob(3) -- a subset of the one defined in POSIX 1003.2. - * - * Optional extra services, controlled by flags not defined by POSIX: - * - * GLOB_MAGCHAR: - * Set in gl_flags if pattern contained a globbing character. - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "w32file-unix-glob.h" - -#define EOS '\0' -#define NOT '!' -#define QUESTION '?' -#define QUOTE '\\' -#define STAR '*' - -#ifndef DEBUG - -#define M_QUOTE 0x8000 -#define M_PROTECT 0x4000 -#define M_MASK 0xffff -#define M_ASCII 0x00ff - -typedef unsigned short Char; - -#else - -#define M_QUOTE 0x80 -#define M_PROTECT 0x40 -#define M_MASK 0xff -#define M_ASCII 0x7f - -typedef char Char; - -#endif - - -#define CHAR(c) ((gchar)((c)&M_ASCII)) -#define META(c) ((gchar)((c)|M_QUOTE)) -#define M_ALL META('*') -#define M_ONE META('?') -#define ismeta(c) (((c)&M_QUOTE) != 0) - - -static int -g_Ctoc(const gchar *, char *, unsigned int); - -static int -glob0(GDir *dir, const gchar *, mono_w32file_unix_glob_t *, gboolean, gboolean); -static int -glob1(GDir *dir, gchar *, gchar *, mono_w32file_unix_glob_t *, size_t *, gboolean, gboolean); - -static int -glob3(GDir *dir, gchar *, gchar *, mono_w32file_unix_glob_t *, size_t *, gboolean, gboolean); - -static int -globextend(const gchar *, mono_w32file_unix_glob_t *, size_t *); - -static int -match(const gchar *, gchar *, gchar *, gboolean); - -#ifdef DEBUG_ENABLED -static void qprintf(const char *, Char *); -#endif - -int -mono_w32file_unix_glob(GDir *dir, const char *pattern, int flags, mono_w32file_unix_glob_t *pglob) -{ - const unsigned char *patnext; - int c; - gchar *bufnext, *bufend, patbuf[PATH_MAX]; - - patnext = (unsigned char *) pattern; - if (!(flags & W32FILE_UNIX_GLOB_APPEND)) { - pglob->gl_pathc = 0; - pglob->gl_pathv = NULL; - pglob->gl_offs = 0; - } - pglob->gl_flags = flags & ~W32FILE_UNIX_GLOB_MAGCHAR; - - bufnext = patbuf; - bufend = bufnext + PATH_MAX - 1; - - /* Protect the quoted characters. */ - while (bufnext < bufend && (c = *patnext++) != EOS) - if (c == QUOTE) { - if ((c = *patnext++) == EOS) { - c = QUOTE; - --patnext; - } - *bufnext++ = c | M_PROTECT; - } else - *bufnext++ = c; - - *bufnext = EOS; - - return glob0(dir, patbuf, pglob, flags & W32FILE_UNIX_GLOB_IGNORECASE, - flags & W32FILE_UNIX_GLOB_UNIQUE); -} - -/* - * The main glob() routine: compiles the pattern (optionally processing - * quotes), calls glob1() to do the real pattern matching, and finally - * sorts the list (unless unsorted operation is requested). Returns 0 - * if things went well, nonzero if errors occurred. It is not an error - * to find no matches. - */ -static int -glob0(GDir *dir, const gchar *pattern, mono_w32file_unix_glob_t *pglob, gboolean ignorecase, - gboolean unique) -{ - const gchar *qpatnext; - int c, err, oldpathc; - gchar *bufnext, patbuf[PATH_MAX]; - size_t limit = 0; - - qpatnext = pattern; - oldpathc = pglob->gl_pathc; - bufnext = patbuf; - - /* We don't need to check for buffer overflow any more. */ - while ((c = *qpatnext++) != EOS) { - switch (c) { - case QUESTION: - pglob->gl_flags |= W32FILE_UNIX_GLOB_MAGCHAR; - *bufnext++ = M_ONE; - break; - case STAR: - pglob->gl_flags |= W32FILE_UNIX_GLOB_MAGCHAR; - /* collapse adjacent stars to one, - * to avoid exponential behavior - */ - if (bufnext == patbuf || bufnext[-1] != M_ALL) - *bufnext++ = M_ALL; - break; - default: - *bufnext++ = CHAR(c); - break; - } - } - *bufnext = EOS; -#ifdef DEBUG_ENABLED - qprintf("glob0:", patbuf); -#endif - - if ((err = glob1(dir, patbuf, patbuf+PATH_MAX-1, pglob, &limit, - ignorecase, unique)) != 0) - return(err); - - if (pglob->gl_pathc == oldpathc) { - return(W32FILE_UNIX_GLOB_NOMATCH); - } - - return(0); -} - -static int -glob1(GDir *dir, gchar *pattern, gchar *pattern_last, mono_w32file_unix_glob_t *pglob, - size_t *limitp, gboolean ignorecase, gboolean unique) -{ - /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ - if (*pattern == EOS) - return(0); - return(glob3(dir, pattern, pattern_last, pglob, limitp, ignorecase, - unique)); -} - -static gboolean contains (mono_w32file_unix_glob_t *pglob, const gchar *name) -{ - int i; - char **pp; - - if (pglob->gl_pathv != NULL) { - pp = pglob->gl_pathv + pglob->gl_offs; - for (i = pglob->gl_pathc; i--; ++pp) { - if (*pp) { - if (!strcmp (*pp, name)) { - return(TRUE); - } - } - } - } - - return(FALSE); -} - -static int -glob3(GDir *dir, gchar *pattern, gchar *pattern_last, mono_w32file_unix_glob_t *pglob, - size_t *limitp, gboolean ignorecase, gboolean unique) -{ - const gchar *name; - - /* Search directory for matching names. */ - while ((name = g_dir_read_name(dir))) { - if (!match(name, pattern, pattern + strlen (pattern), - ignorecase)) { - continue; - } - if (!unique || - !contains (pglob, name)) { - globextend (name, pglob, limitp); - } - } - - return(0); -} - - -/* - * Extend the gl_pathv member of a mono_w32file_unix_glob_t structure to accommodate a new item, - * add the new item, and update gl_pathc. - * - * This assumes the BSD realloc, which only copies the block when its size - * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic - * behavior. - * - * Return 0 if new item added, error code if memory couldn't be allocated. - * - * Invariant of the mono_w32file_unix_glob_t structure: - * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and - * gl_pathv points to (gl_offs + gl_pathc + 1) items. - */ -static int -globextend(const gchar *path, mono_w32file_unix_glob_t *pglob, size_t *limitp) -{ - char **pathv; - int i; - unsigned int newsize, len; - char *copy; - const gchar *p; - - newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); - /* FIXME: Can just use realloc(). */ - pathv = pglob->gl_pathv ? (char**)g_realloc (pglob->gl_pathv, newsize) : - (char**)g_malloc (newsize); - if (pathv == NULL) { - g_free (pglob->gl_pathv); - pglob->gl_pathv = NULL; - return(W32FILE_UNIX_GLOB_NOSPACE); - } - - if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { - /* first time around -- clear initial gl_offs items */ - pathv += pglob->gl_offs; - for (i = pglob->gl_offs; --i >= 0; ) - *--pathv = NULL; - } - pglob->gl_pathv = pathv; - - for (p = path; *p++;) - ; - len = (size_t)(p - path); - *limitp += len; - if ((copy = (char *)malloc(len)) != NULL) { - if (g_Ctoc(path, copy, len)) { - g_free (copy); - return(W32FILE_UNIX_GLOB_NOSPACE); - } - pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; - } - pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; - -#if 0 - /* Broken on opensuse 11 */ - if ((pglob->gl_flags & W32FILE_UNIX_GLOB_LIMIT) && - newsize + *limitp >= ARG_MAX) { - mono_set_errno (0); - return(W32FILE_UNIX_GLOB_NOSPACE); - } -#endif - - return(copy == NULL ? W32FILE_UNIX_GLOB_NOSPACE : 0); -} - - -/* - * pattern matching function for filenames. Each occurrence of the * - * pattern causes a recursion level. - */ -static int -match(const gchar *name, gchar *pat, gchar *patend, gboolean ignorecase) -{ - gchar c; - - while (pat < patend) { - c = *pat++; - switch (c & M_MASK) { - case M_ALL: - if (pat == patend) - return(1); - do { - if (match(name, pat, patend, ignorecase)) - return(1); - } while (*name++ != EOS); - return(0); - case M_ONE: - if (*name++ == EOS) - return(0); - break; - default: - if (ignorecase) { - if (g_ascii_tolower (*name++) != g_ascii_tolower (c)) - return(0); - } else { - if (*name++ != c) - return(0); - } - - break; - } - } - return(*name == EOS); -} - -/* Free allocated data belonging to a mono_w32file_unix_glob_t structure. */ -void -mono_w32file_unix_globfree(mono_w32file_unix_glob_t *pglob) -{ - int i; - char **pp; - - if (pglob->gl_pathv != NULL) { - pp = pglob->gl_pathv + pglob->gl_offs; - for (i = pglob->gl_pathc; i--; ++pp) - if (*pp) - g_free (*pp); - g_free (pglob->gl_pathv); - pglob->gl_pathv = NULL; - } -} - -static int -g_Ctoc(const gchar *str, char *buf, unsigned int len) -{ - - while (len--) { - if ((*buf++ = *str++) == EOS) - return (0); - } - return (1); -} - -#ifdef DEBUG_ENABLED -static void -qprintf(const char *str, Char *s) -{ - Char *p; - - (void)printf("%s:\n", str); - for (p = s; *p; p++) - (void)printf("%c", CHAR(*p)); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", *p & M_PROTECT ? '"' : ' '); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", ismeta(*p) ? '_' : ' '); - (void)printf("\n"); -} -#endif diff --git a/src/mono/mono/metadata/w32file-unix-glob.h b/src/mono/mono/metadata/w32file-unix-glob.h deleted file mode 100644 index e4d940ef189e6a..00000000000000 --- a/src/mono/mono/metadata/w32file-unix-glob.h +++ /dev/null @@ -1,70 +0,0 @@ -/* $OpenBSD: glob.h,v 1.10 2005/12/13 00:35:22 millert Exp $ */ -/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */ - -/** - * \file - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)glob.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef __MONO_METADATA_W32FILE_UNIX_GLOB_H__ -#define __MONO_METADATA_W32FILE_UNIX_GLOB_H__ - -#include - -struct stat; -typedef struct { - int gl_pathc; /* Count of total paths so far. */ - int gl_offs; /* Reserved at beginning of gl_pathv. */ - int gl_flags; /* Copy of flags parameter to glob. */ - char **gl_pathv; /* List of paths matching pattern. */ -} mono_w32file_unix_glob_t; - -#define W32FILE_UNIX_GLOB_APPEND 0x0001 /* Append to output from previous call. */ -#define W32FILE_UNIX_GLOB_UNIQUE 0x0040 /* When appending only add items that aren't already in the list */ -#define W32FILE_UNIX_GLOB_NOSPACE (-1) /* Malloc call failed. */ -#define W32FILE_UNIX_GLOB_ABORTED (-2) /* Unignored error. */ -#define W32FILE_UNIX_GLOB_NOMATCH (-3) /* No match and W32FILE_UNIX_GLOB_NOCHECK not set. */ -#define W32FILE_UNIX_GLOB_NOSYS (-4) /* Function not supported. */ - -#define W32FILE_UNIX_GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ -#define W32FILE_UNIX_GLOB_LIMIT 0x2000 /* Limit pattern match output to ARG_MAX */ -#define W32FILE_UNIX_GLOB_IGNORECASE 0x4000 /* Ignore case when matching */ -#define W32FILE_UNIX_GLOB_ABEND W32FILE_UNIX_GLOB_ABORTED /* backward compatibility */ - -int -mono_w32file_unix_glob (GDir *dir, const char *, int, mono_w32file_unix_glob_t *); - -void -mono_w32file_unix_globfree (mono_w32file_unix_glob_t *); - -#endif /* !__MONO_METADATA_W32FILE_UNIX_GLOB_H__ */ diff --git a/src/mono/mono/metadata/w32file-unix.c b/src/mono/mono/metadata/w32file-unix.c index 0d842853b876e9..306af8436d1dea 100644 --- a/src/mono/mono/metadata/w32file-unix.c +++ b/src/mono/mono/metadata/w32file-unix.c @@ -44,8 +44,6 @@ #endif #include "w32file.h" -#include "w32file-internals.h" -#include "w32file-unix-glob.h" #include "w32error.h" #include "fdhandle.h" #include "utils/mono-error-internals.h" @@ -60,17 +58,6 @@ #include "icall-decl.h" #include "utils/mono-errno.h" -#define NANOSECONDS_PER_MICROSECOND 1000LL -#define TICKS_PER_MICROSECOND 10L -#define TICKS_PER_MILLISECOND 10000L -#define TICKS_PER_SECOND 10000000LL -#define TICKS_PER_MINUTE 600000000LL -#define TICKS_PER_HOUR 36000000000LL -#define TICKS_PER_DAY 864000000000LL - -// Constants to convert Unix times to the API expected by .NET and Windows -#define CONVERT_BASE 116444736000000000ULL - #define INVALID_HANDLE_VALUE ((gpointer)-1) typedef struct { @@ -94,15 +81,6 @@ typedef struct { guint32 attrs; } FileHandle; -typedef struct { - MonoRefCount ref; - MonoCoopMutex mutex; - gchar **namelist; - gchar *dir_part; - gint num; - gsize count; -} FindHandle; - /* * If SHM is disabled, this will point to a hash of FileShare structures, otherwise * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a @@ -111,25 +89,6 @@ typedef struct { static GHashTable *file_share_table; static MonoCoopMutex file_share_mutex; -static GHashTable *finds; -static MonoCoopMutex finds_mutex; - -#if HOST_DARWIN -typedef int (*clonefile_fn) (const char *from, const char *to, int flags); -static MonoDl *libc_handle; -static clonefile_fn clonefile_ptr; -#endif - -static void -time_t_to_filetime (time_t timeval, FILETIME *filetime) -{ - guint64 ticks; - - ticks = ((guint64)timeval * 10000000) + CONVERT_BASE; - filetime->dwLowDateTime = ticks & 0xFFFFFFFF; - filetime->dwHighDateTime = ticks >> 32; -} - static FileHandle* file_data_create (MonoFDType type, gint fd) { @@ -340,18 +299,14 @@ _wapi_access (const gchar *pathname, gint mode) } static gint -_wapi_chmod (const gchar *pathname, mode_t mode) +_wapi_unlink (const gchar *pathname) { gint ret; MONO_ENTER_GC_SAFE; -#if defined(HAVE_CHMOD) - ret = chmod (pathname, mode); -#else - ret = -1; -#endif + ret = unlink (pathname); MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) { + if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) && IS_PORTABILITY_SET) { gint saved_errno = errno; gchar *located_filename = mono_portability_find_file (pathname, TRUE); @@ -360,4534 +315,394 @@ _wapi_chmod (const gchar *pathname, mode_t mode) return -1; } -#if defined(HAVE_CHMOD) MONO_ENTER_GC_SAFE; - ret = chmod (located_filename, mode); + ret = unlink (located_filename); MONO_EXIT_GC_SAFE; -#else - ret = -1; -#endif g_free (located_filename); } return ret; } -#ifndef HAVE_STRUCT_TIMEVAL -static gint -_wapi_utime (const gchar *filename, const struct utimbuf *buf) +static gchar* +_wapi_dirname (const gchar *filename) { - gint ret = -1; + gchar *new_filename = g_strdup (filename), *ret; -#ifdef HAVE_UTIME - MONO_ENTER_GC_SAFE; - ret = utime (filename, buf); - MONO_EXIT_GC_SAFE; - if (ret == -1 && errno == ENOENT && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (filename, TRUE); + if (IS_PORTABILITY_SET) + g_strdelimit (new_filename, '\\', '/'); - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } + if (IS_PORTABILITY_DRIVE && g_ascii_isalpha (new_filename[0]) && (new_filename[1] == ':')) { + gint len = strlen (new_filename); - MONO_ENTER_GC_SAFE; - ret = utime (located_filename, buf); - MONO_EXIT_GC_SAFE; - g_free (located_filename); + g_memmove (new_filename, new_filename + 2, len - 2); + new_filename[len - 2] = '\0'; } -#endif + + ret = g_path_get_dirname (new_filename); + g_free (new_filename); return ret; } -#else -static gint -_wapi_utimes (const gchar *filename, const struct timeval times[2]) +static gboolean +_wapi_lock_file_region (gint fd, off_t offset, off_t length) { - gint ret = -1; - -#ifdef HAVE_UTIMES - MONO_ENTER_GC_SAFE; - ret = utimes (filename, times); - MONO_EXIT_GC_SAFE; - if (ret == -1 && errno == ENOENT && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (filename, TRUE); - - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } + struct flock lock_data; + gint ret; - MONO_ENTER_GC_SAFE; - ret = utimes (located_filename, times); - MONO_EXIT_GC_SAFE; - g_free (located_filename); + if (offset < 0 || length < 0) { + mono_w32error_set_last (ERROR_INVALID_PARAMETER); + return FALSE; } -#endif - return ret; -} -#endif + lock_data.l_type = F_WRLCK; + lock_data.l_whence = SEEK_SET; + lock_data.l_start = offset; + lock_data.l_len = length; -static gint -_wapi_unlink (const gchar *pathname) -{ - gint ret; + do { + ret = fcntl (fd, F_SETLK, &lock_data); + } while(ret == -1 && errno == EINTR); - MONO_ENTER_GC_SAFE; - ret = unlink (pathname); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (pathname, TRUE); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; + if (ret == -1) { + /* + * if locks are not available (NFS for example), + * ignore the error + */ + if (errno == ENOLCK +#ifdef EOPNOTSUPP + || errno == EOPNOTSUPP +#endif +#ifdef ENOTSUP + || errno == ENOTSUP +#endif + ) { + return TRUE; } - MONO_ENTER_GC_SAFE; - ret = unlink (located_filename); - MONO_EXIT_GC_SAFE; - g_free (located_filename); + mono_w32error_set_last (ERROR_LOCK_VIOLATION); + return FALSE; } - return ret; + return TRUE; } -static gint -_wapi_rename (const gchar *oldpath, const gchar *newpath) +static gboolean +_wapi_unlock_file_region (gint fd, off_t offset, off_t length) { + struct flock lock_data; gint ret; - gchar *located_newpath = mono_portability_find_file (newpath, FALSE); - - if (located_newpath == NULL) { - MONO_ENTER_GC_SAFE; - ret = rename (oldpath, newpath); - MONO_EXIT_GC_SAFE; - } else { - MONO_ENTER_GC_SAFE; - ret = rename (oldpath, located_newpath); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == EISDIR || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EXDEV) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_oldpath = mono_portability_find_file (oldpath, TRUE); + lock_data.l_type = F_UNLCK; + lock_data.l_whence = SEEK_SET; + lock_data.l_start = offset; + lock_data.l_len = length; - if (located_oldpath == NULL) { - g_free (located_oldpath); - g_free (located_newpath); + do { + ret = fcntl (fd, F_SETLK, &lock_data); + } while(ret == -1 && errno == EINTR); - mono_set_errno (saved_errno); - return -1; - } + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); - MONO_ENTER_GC_SAFE; - ret = rename (located_oldpath, located_newpath); - MONO_EXIT_GC_SAFE; - g_free (located_oldpath); + if (ret == -1) { + /* + * if locks are not available (NFS for example), + * ignore the error + */ + if (errno == ENOLCK +#ifdef EOPNOTSUPP + || errno == EOPNOTSUPP +#endif +#ifdef ENOTSUP + || errno == ENOTSUP +#endif + ) { + return TRUE; } - g_free (located_newpath); + + mono_w32error_set_last (ERROR_LOCK_VIOLATION); + return FALSE; } - return ret; + return TRUE; } -static gint -_wapi_stat (const gchar *path, struct stat *buf) -{ - gint ret; - - MONO_ENTER_GC_SAFE; - ret = stat (path, buf); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (path, TRUE); - - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } - - MONO_ENTER_GC_SAFE; - ret = stat (located_filename, buf); - MONO_EXIT_GC_SAFE; - g_free (located_filename); - } +static gboolean lock_while_writing = FALSE; - return ret; +static void +_wapi_set_last_error_from_errno (void) +{ + mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); } -static gint -_wapi_lstat (const gchar *path, struct stat *buf) +static void _wapi_set_last_path_error_from_errno (const gchar *dir, + const gchar *path) { - gint ret; + if (errno == ENOENT) { + /* Check the path - if it's a missing directory then + * we need to set PATH_NOT_FOUND not FILE_NOT_FOUND + */ + gchar *dirname; -#ifdef HAVE_LSTAT - MONO_ENTER_GC_SAFE; - ret = lstat (path, buf); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (path, TRUE); - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; + if (dir == NULL) { + dirname = _wapi_dirname (path); + } else { + dirname = g_strdup (dir); + } + + if (_wapi_access (dirname, F_OK) == 0) { + mono_w32error_set_last (ERROR_FILE_NOT_FOUND); + } else { + mono_w32error_set_last (ERROR_PATH_NOT_FOUND); } - ret = lstat (located_filename, buf); - g_free (located_filename); + g_free (dirname); + } else { + _wapi_set_last_error_from_errno (); } -#else - ret = -1; -#endif - - return ret; } -static gint -_wapi_mkdir (const gchar *pathname, mode_t mode) +static gboolean +file_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) { gint ret; - gchar *located_filename = mono_portability_find_file (pathname, FALSE); + off_t current_pos = 0; + MonoThreadInfo *info = mono_thread_info_current (); + + if(byteswritten!=NULL) { + *byteswritten=0; + } + + if(!(filehandle->fileaccess & GENERIC_WRITE) && !(filehandle->fileaccess & GENERIC_ALL)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - if (located_filename == NULL) { + mono_w32error_set_last (ERROR_ACCESS_DENIED); + return(FALSE); + } + + if (lock_while_writing) { + /* Need to lock the region we're about to write to, + * because we only do advisory locking on POSIX + * systems + */ MONO_ENTER_GC_SAFE; - ret = mkdir (pathname, mode); + current_pos = lseek (((MonoFDHandle*) filehandle)->fd, (off_t)0, SEEK_CUR); MONO_EXIT_GC_SAFE; - } else { + if (current_pos == -1) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror (errno)); + _wapi_set_last_error_from_errno (); + return(FALSE); + } + + if (_wapi_lock_file_region (((MonoFDHandle*) filehandle)->fd, current_pos, numbytes) == FALSE) { + /* The error has already been set */ + return(FALSE); + } + } + + do { MONO_ENTER_GC_SAFE; - ret = mkdir (located_filename, mode); + ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); MONO_EXIT_GC_SAFE; - g_free (located_filename); + } while (ret == -1 && errno == EINTR && + !mono_thread_info_is_interrupt_state (info)); + + if (lock_while_writing) { + _wapi_unlock_file_region (((MonoFDHandle*) filehandle)->fd, current_pos, numbytes); } - return ret; -} - -static gint -_wapi_rmdir (const gchar *pathname) -{ - gint ret; - - MONO_ENTER_GC_SAFE; - ret = rmdir (pathname); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (pathname, TRUE); - - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } - - MONO_ENTER_GC_SAFE; - ret = rmdir (located_filename); - MONO_EXIT_GC_SAFE; - g_free (located_filename); - } - - return ret; -} - -static gint -_wapi_chdir (const gchar *path) -{ - gint ret; - - MONO_ENTER_GC_SAFE; - ret = chdir (path); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (path, TRUE); - - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } - - MONO_ENTER_GC_SAFE; - ret = chdir (located_filename); - MONO_EXIT_GC_SAFE; - g_free (located_filename); - } - - return ret; -} - -static gchar* -_wapi_basename (const gchar *filename) -{ - gchar *new_filename = g_strdup (filename), *ret; - - if (IS_PORTABILITY_SET) - g_strdelimit (new_filename, '\\', '/'); - - if (IS_PORTABILITY_DRIVE && g_ascii_isalpha (new_filename[0]) && (new_filename[1] == ':')) { - gint len = strlen (new_filename); - - g_memmove (new_filename, new_filename + 2, len - 2); - new_filename[len - 2] = '\0'; - } - - ret = g_path_get_basename (new_filename); - g_free (new_filename); - - return ret; -} - -static gchar* -_wapi_dirname (const gchar *filename) -{ - gchar *new_filename = g_strdup (filename), *ret; - - if (IS_PORTABILITY_SET) - g_strdelimit (new_filename, '\\', '/'); - - if (IS_PORTABILITY_DRIVE && g_ascii_isalpha (new_filename[0]) && (new_filename[1] == ':')) { - gint len = strlen (new_filename); - - g_memmove (new_filename, new_filename + 2, len - 2); - new_filename[len - 2] = '\0'; - } - - ret = g_path_get_dirname (new_filename); - g_free (new_filename); - - return ret; -} - -static GDir* -_wapi_g_dir_open (const gchar *path, guint flags, GError **gerror) -{ - GDir *ret; - - MONO_ENTER_GC_SAFE; - ret = g_dir_open (path, flags, gerror); - MONO_EXIT_GC_SAFE; - if (ret == NULL && ((*gerror)->code == G_FILE_ERROR_NOENT || (*gerror)->code == G_FILE_ERROR_NOTDIR || (*gerror)->code == G_FILE_ERROR_NAMETOOLONG) && IS_PORTABILITY_SET) { - gchar *located_filename = mono_portability_find_file (path, TRUE); - GError *tmp_error = NULL; - - if (located_filename == NULL) { - return(NULL); - } - - MONO_ENTER_GC_SAFE; - ret = g_dir_open (located_filename, flags, &tmp_error); - MONO_EXIT_GC_SAFE; - g_free (located_filename); - if (tmp_error == NULL) { - g_clear_error (gerror); - } - } - - return ret; -} - -static gint -get_errno_from_g_file_error (gint error) -{ - switch (error) { -#ifdef EACCES - case G_FILE_ERROR_ACCES: return EACCES; -#endif -#ifdef ENAMETOOLONG - case G_FILE_ERROR_NAMETOOLONG: return ENAMETOOLONG; -#endif -#ifdef ENOENT - case G_FILE_ERROR_NOENT: return ENOENT; -#endif -#ifdef ENOTDIR - case G_FILE_ERROR_NOTDIR: return ENOTDIR; -#endif -#ifdef ENXIO - case G_FILE_ERROR_NXIO: return ENXIO; -#endif -#ifdef ENODEV - case G_FILE_ERROR_NODEV: return ENODEV; -#endif -#ifdef EROFS - case G_FILE_ERROR_ROFS: return EROFS; -#endif -#ifdef ETXTBSY - case G_FILE_ERROR_TXTBSY: return ETXTBSY; -#endif -#ifdef EFAULT - case G_FILE_ERROR_FAULT: return EFAULT; -#endif -#ifdef ELOOP - case G_FILE_ERROR_LOOP: return ELOOP; -#endif -#ifdef ENOSPC - case G_FILE_ERROR_NOSPC: return ENOSPC; -#endif -#ifdef ENOMEM - case G_FILE_ERROR_NOMEM: return ENOMEM; -#endif -#ifdef EMFILE - case G_FILE_ERROR_MFILE: return EMFILE; -#endif -#ifdef ENFILE - case G_FILE_ERROR_NFILE: return ENFILE; -#endif -#ifdef EBADF - case G_FILE_ERROR_BADF: return EBADF; -#endif -#ifdef EINVAL - case G_FILE_ERROR_INVAL: return EINVAL; -#endif -#ifdef EPIPE - case G_FILE_ERROR_PIPE: return EPIPE; -#endif -#ifdef EAGAIN - case G_FILE_ERROR_AGAIN: return EAGAIN; -#endif -#ifdef EINTR - case G_FILE_ERROR_INTR: return EINTR; -#endif -#ifdef EIO - case G_FILE_ERROR_IO: return EIO; -#endif -#ifdef EPERM - case G_FILE_ERROR_PERM: return EPERM; -#endif - case G_FILE_ERROR_FAILED: return ERROR_INVALID_PARAMETER; - default: - g_assert_not_reached (); - } -} - -static gint -file_compare (gconstpointer a, gconstpointer b) -{ - gchar *astr = *(gchar **) a; - gchar *bstr = *(gchar **) b; - - return strcmp (astr, bstr); -} - -/* scandir using glib */ -static gint -_wapi_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist) -{ - GError *gerror = NULL; - GDir *dir; - GPtrArray *names; - gint result; - mono_w32file_unix_glob_t glob_buf; - gint flags = 0, i; - - dir = _wapi_g_dir_open (dirname, 0, &gerror); - if (dir == NULL) { - /* g_dir_open returns ENOENT on directories on which we don't - * have read/x permission */ - gint errnum = get_errno_from_g_file_error (gerror->code); - g_error_free (gerror); - if (errnum == ENOENT && - !_wapi_access (dirname, F_OK) && - _wapi_access (dirname, R_OK|X_OK)) { - errnum = EACCES; - } - - mono_set_errno (errnum); - return -1; - } - - if (IS_PORTABILITY_CASE) { - flags = W32FILE_UNIX_GLOB_IGNORECASE; - } - - result = mono_w32file_unix_glob (dir, pattern, flags, &glob_buf); - if (g_str_has_suffix (pattern, ".*")) { - /* Special-case the patterns ending in '.*', as - * windows also matches entries with no extension with - * this pattern. - * - * TODO: should this be a MONO_IOMAP option? - */ - gchar *pattern2 = g_strndup (pattern, strlen (pattern) - 2); - gint result2; - - MONO_ENTER_GC_SAFE; - g_dir_rewind (dir); - MONO_EXIT_GC_SAFE; - result2 = mono_w32file_unix_glob (dir, pattern2, flags | W32FILE_UNIX_GLOB_APPEND | W32FILE_UNIX_GLOB_UNIQUE, &glob_buf); - - g_free (pattern2); - - if (result != 0) { - result = result2; - } - } - - MONO_ENTER_GC_SAFE; - g_dir_close (dir); - MONO_EXIT_GC_SAFE; - if (glob_buf.gl_pathc == 0) { - return(0); - } else if (result != 0) { - return -1; - } - - names = g_ptr_array_new (); - for (i = 0; i < glob_buf.gl_pathc; i++) { - g_ptr_array_add (names, g_strdup (glob_buf.gl_pathv[i])); - } - - mono_w32file_unix_globfree (&glob_buf); - - result = names->len; - if (result > 0) { - g_ptr_array_sort (names, file_compare); - g_ptr_array_set_size (names, result + 1); - - *namelist = (gchar **) g_ptr_array_free (names, FALSE); - } else { - g_ptr_array_free (names, TRUE); - } - - return result; -} - -static gboolean -_wapi_lock_file_region (gint fd, off_t offset, off_t length) -{ - struct flock lock_data; - gint ret; - - if (offset < 0 || length < 0) { - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return FALSE; - } - - lock_data.l_type = F_WRLCK; - lock_data.l_whence = SEEK_SET; - lock_data.l_start = offset; - lock_data.l_len = length; - - do { - ret = fcntl (fd, F_SETLK, &lock_data); - } while(ret == -1 && errno == EINTR); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); - - if (ret == -1) { - /* - * if locks are not available (NFS for example), - * ignore the error - */ - if (errno == ENOLCK -#ifdef EOPNOTSUPP - || errno == EOPNOTSUPP -#endif -#ifdef ENOTSUP - || errno == ENOTSUP -#endif - ) { - return TRUE; - } - - mono_w32error_set_last (ERROR_LOCK_VIOLATION); - return FALSE; - } - - return TRUE; -} - -static gboolean -_wapi_unlock_file_region (gint fd, off_t offset, off_t length) -{ - struct flock lock_data; - gint ret; - - lock_data.l_type = F_UNLCK; - lock_data.l_whence = SEEK_SET; - lock_data.l_start = offset; - lock_data.l_len = length; - - do { - ret = fcntl (fd, F_SETLK, &lock_data); - } while(ret == -1 && errno == EINTR); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); - - if (ret == -1) { - /* - * if locks are not available (NFS for example), - * ignore the error - */ - if (errno == ENOLCK -#ifdef EOPNOTSUPP - || errno == EOPNOTSUPP -#endif -#ifdef ENOTSUP - || errno == ENOTSUP -#endif - ) { - return TRUE; - } - - mono_w32error_set_last (ERROR_LOCK_VIOLATION); - return FALSE; - } - - return TRUE; -} - -static gboolean lock_while_writing = FALSE; - -/* Some utility functions. - */ - -/* - * Check if a file is writable by the current user. - * - * This is is a best effort kind of thing. It assumes a reasonable sane set - * of permissions by the underlying OS. - * - * We generally assume that basic unix permission bits are authoritative. Which might not - * be the case under systems with extended permissions systems (posix ACLs, SELinux, OSX/iOS sandboxing, etc) - * - * The choice of access as the fallback is due to the expected lower overhead compared to trying to open the file. - * - * The only expected problem with using access are for root, setuid or setgid programs as access is not consistent - * under those situations. It's to be expected that this should not happen in practice as those bits are very dangerous - * and should not be used with a dynamic runtime. - */ -static gboolean -is_file_writable (struct stat *st, const gchar *path) -{ - gboolean ret; - gchar *located_path; - -#if __APPLE__ - // OS X Finder "locked" or `ls -lO` "uchg". - // This only covers one of several cases where an OS X file could be unwritable through special flags. - if (st->st_flags & (UF_IMMUTABLE|SF_IMMUTABLE)) - return 0; -#endif - - /* Is it globally writable? */ - if (st->st_mode & S_IWOTH) - return 1; - - /* Am I the owner? */ - if ((st->st_uid == geteuid ()) && (st->st_mode & S_IWUSR)) - return 1; - - /* Am I in the same group? */ - if ((st->st_gid == getegid ()) && (st->st_mode & S_IWGRP)) - return 1; - - located_path = mono_portability_find_file (path, FALSE); - - /* Fallback to using access(2). It's not ideal as it might not take into consideration euid/egid - * but it's the only sane option we have on unix. - */ - MONO_ENTER_GC_SAFE; - ret = access (located_path != NULL ? located_path : path, W_OK) == 0; - MONO_EXIT_GC_SAFE; - - g_free (located_path); - - return ret; -} - - -static guint32 _wapi_stat_to_file_attributes (const gchar *pathname, - struct stat *buf, - struct stat *lbuf) -{ - guint32 attrs = 0; - gchar *filename; - - /* FIXME: this could definitely be better, but there seems to - * be no pattern to the attributes that are set - */ - - /* Sockets (0140000) != Directory (040000) + Regular file (0100000) */ - if (S_ISSOCK (buf->st_mode)) - buf->st_mode &= ~S_IFSOCK; /* don't consider socket protection */ - - filename = _wapi_basename (pathname); - - if (S_ISDIR (buf->st_mode)) { - attrs = FILE_ATTRIBUTE_DIRECTORY; - if (!is_file_writable (buf, pathname)) { - attrs |= FILE_ATTRIBUTE_READONLY; - } - if (filename[0] == '.') { - attrs |= FILE_ATTRIBUTE_HIDDEN; - } - } else { - if (!is_file_writable (buf, pathname)) { - attrs = FILE_ATTRIBUTE_READONLY; - - if (filename[0] == '.') { - attrs |= FILE_ATTRIBUTE_HIDDEN; - } - } else if (filename[0] == '.') { - attrs = FILE_ATTRIBUTE_HIDDEN; - } else { - attrs = FILE_ATTRIBUTE_NORMAL; - } - } - - if (lbuf != NULL) { - if (S_ISLNK (lbuf->st_mode)) { - attrs |= FILE_ATTRIBUTE_REPARSE_POINT; - } - } - - g_free (filename); - - return attrs; -} - -static void -_wapi_set_last_error_from_errno (void) -{ - mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); -} - -static void _wapi_set_last_path_error_from_errno (const gchar *dir, - const gchar *path) -{ - if (errno == ENOENT) { - /* Check the path - if it's a missing directory then - * we need to set PATH_NOT_FOUND not FILE_NOT_FOUND - */ - gchar *dirname; - - - if (dir == NULL) { - dirname = _wapi_dirname (path); - } else { - dirname = g_strdup (dir); - } - - if (_wapi_access (dirname, F_OK) == 0) { - mono_w32error_set_last (ERROR_FILE_NOT_FOUND); - } else { - mono_w32error_set_last (ERROR_PATH_NOT_FOUND); - } - - g_free (dirname); - } else { - _wapi_set_last_error_from_errno (); - } -} - -static gboolean -file_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *bytesread) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(bytesread!=NULL) { - *bytesread=0; - } - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - do { - MONO_ENTER_GC_SAFE; - ret = read (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if(ret==-1) { - gint err = errno; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(err)); - mono_w32error_set_last (mono_w32error_unix_to_win32 (err)); - return(FALSE); - } - - if (bytesread != NULL) { - *bytesread = ret; - } - - return(TRUE); -} - -static gboolean -file_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) -{ - gint ret; - off_t current_pos = 0; - MonoThreadInfo *info = mono_thread_info_current (); - - if(byteswritten!=NULL) { - *byteswritten=0; - } - - if(!(filehandle->fileaccess & GENERIC_WRITE) && !(filehandle->fileaccess & GENERIC_ALL)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - if (lock_while_writing) { - /* Need to lock the region we're about to write to, - * because we only do advisory locking on POSIX - * systems - */ - MONO_ENTER_GC_SAFE; - current_pos = lseek (((MonoFDHandle*) filehandle)->fd, (off_t)0, SEEK_CUR); - MONO_EXIT_GC_SAFE; - if (current_pos == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror (errno)); - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - if (_wapi_lock_file_region (((MonoFDHandle*) filehandle)->fd, current_pos, numbytes) == FALSE) { - /* The error has already been set */ - return(FALSE); - } - } - - do { - MONO_ENTER_GC_SAFE; - ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if (lock_while_writing) { - _wapi_unlock_file_region (((MonoFDHandle*) filehandle)->fd, current_pos, numbytes); - } - - if (ret == -1) { - if (errno == EINTR) { - ret = 0; - } else { - _wapi_set_last_error_from_errno (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - return(FALSE); - } - } - if (byteswritten != NULL) { - *byteswritten = ret; - } - return(TRUE); -} - -static gboolean file_flush(FileHandle *filehandle) -{ - gint ret; - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - MONO_ENTER_GC_SAFE; - ret=fsync(((MonoFDHandle*) filehandle)->fd); - MONO_EXIT_GC_SAFE; - if (ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fsync of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - return(TRUE); -} - -static guint32 file_seek(FileHandle *filehandle, gint32 movedistance, - gint32 *highmovedistance, gint method) -{ - gint64 offset, newpos; - gint whence; - guint32 ret; - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(INVALID_SET_FILE_POINTER); - } - - switch(method) { - case FILE_BEGIN: - whence=SEEK_SET; - break; - case FILE_CURRENT: - whence=SEEK_CUR; - break; - case FILE_END: - whence=SEEK_END; - break; - default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: invalid seek type %d", __func__, method); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(INVALID_SET_FILE_POINTER); - } - -#ifdef HAVE_LARGE_FILE_SUPPORT - if(highmovedistance==NULL) { - offset=movedistance; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting offset to %" G_GINT64_FORMAT " (low %" G_GINT32_FORMAT ")", __func__, - offset, movedistance); - } else { - offset=((gint64) *highmovedistance << 32) | (guint32)movedistance; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting offset to %" G_GINT64_FORMAT " 0x%" PRIx64 " (high %" G_GINT32_FORMAT " 0x%" PRIx32 ", low %" G_GINT32_FORMAT " 0x%" PRIx32 ")", - __func__, offset, offset, *highmovedistance, *highmovedistance, movedistance, movedistance); - } -#else - offset=movedistance; -#endif - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: moving fd %d by %" G_GINT64_FORMAT " bytes from %d", __func__, ((MonoFDHandle*) filehandle)->fd, offset, whence); - -#ifdef HOST_ANDROID - /* bionic doesn't support -D_FILE_OFFSET_BITS=64 */ - MONO_ENTER_GC_SAFE; - newpos=lseek64(((MonoFDHandle*) filehandle)->fd, offset, whence); - MONO_EXIT_GC_SAFE; -#else - MONO_ENTER_GC_SAFE; - newpos=lseek(((MonoFDHandle*) filehandle)->fd, offset, whence); - MONO_EXIT_GC_SAFE; -#endif - if(newpos==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lseek on fd %d returned error %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(INVALID_SET_FILE_POINTER); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lseek returns %" G_GINT64_FORMAT, __func__, newpos); - -#ifdef HAVE_LARGE_FILE_SUPPORT - ret=newpos & 0xFFFFFFFF; - if(highmovedistance!=NULL) { - *highmovedistance=newpos>>32; - } -#else - ret=newpos; - if(highmovedistance!=NULL) { - /* Accurate, but potentially dodgy :-) */ - *highmovedistance=0; - } -#endif - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: move of fd %d returning %" G_GUINT32_FORMAT "/%" G_GINT32_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, ret, highmovedistance==NULL?0:*highmovedistance); - - return(ret); -} - -static gboolean file_setendoffile(FileHandle *filehandle) -{ - struct stat statbuf; - off_t pos; - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - /* Find the current file position, and the file length. If - * the file position is greater than the length, write to - * extend the file with a hole. If the file position is less - * than the length, truncate the file. - */ - - MONO_ENTER_GC_SAFE; - ret=fstat(((MonoFDHandle*) filehandle)->fd, &statbuf); - MONO_EXIT_GC_SAFE; - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - MONO_ENTER_GC_SAFE; - pos=lseek(((MonoFDHandle*) filehandle)->fd, (off_t)0, SEEK_CUR); - MONO_EXIT_GC_SAFE; - if(pos==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - -#ifdef FTRUNCATE_DOESNT_EXTEND - off_t size = statbuf.st_size; - /* I haven't bothered to write the configure.ac stuff for this - * because I don't know if any platform needs it. I'm leaving - * this code just in case though - */ - if(pos>size) { - /* Extend the file. Use write() here, because some - * manuals say that ftruncate() behaviour is undefined - * when the file needs extending. The POSIX spec says - * that on XSI-conformant systems it extends, so if - * every system we care about conforms, then we can - * drop this write. - */ - do { - MONO_ENTER_GC_SAFE; - ret = write (((MonoFDHandle*) filehandle)->fd, "", 1); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d extend write failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - /* And put the file position back after the write */ - MONO_ENTER_GC_SAFE; - ret = lseek (((MonoFDHandle*) filehandle)->fd, pos, SEEK_SET); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d second lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - } -#endif - - /* always truncate, because the extend write() adds an extra - * byte to the end of the file - */ - do { - MONO_ENTER_GC_SAFE; - ret=ftruncate(((MonoFDHandle*) filehandle)->fd, pos); - MONO_EXIT_GC_SAFE; - } - while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d ftruncate failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - return(TRUE); -} - -static guint32 file_getfilesize(FileHandle *filehandle, guint32 *highsize) -{ - struct stat statbuf; - guint32 size; - gint ret; - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(INVALID_FILE_SIZE); - } - - /* If the file has a size with the low bits 0xFFFFFFFF the - * caller can't tell if this is an error, so clear the error - * value - */ - mono_w32error_set_last (ERROR_SUCCESS); - - MONO_ENTER_GC_SAFE; - ret = fstat(((MonoFDHandle*) filehandle)->fd, &statbuf); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(INVALID_FILE_SIZE); - } - - /* fstat indicates block devices as zero-length, so go a different path */ -#ifdef BLKGETSIZE64 - if (S_ISBLK(statbuf.st_mode)) { - guint64 bigsize; - gint res; - MONO_ENTER_GC_SAFE; - res = ioctl (((MonoFDHandle*) filehandle)->fd, BLKGETSIZE64, &bigsize); - MONO_EXIT_GC_SAFE; - if (res < 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d ioctl BLKGETSIZE64 failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(INVALID_FILE_SIZE); - } - - size = bigsize & 0xFFFFFFFF; - if (highsize != NULL) { - *highsize = bigsize>>32; - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning block device size %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, - __func__, size, *highsize); - - return(size); - } -#endif - -#ifdef HAVE_LARGE_FILE_SUPPORT - size = statbuf.st_size & 0xFFFFFFFF; - if (highsize != NULL) { - *highsize = statbuf.st_size>>32; - } -#else - if (highsize != NULL) { - /* Accurate, but potentially dodgy :-) */ - *highsize = 0; - } - size = statbuf.st_size; -#endif - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning size %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, __func__, size, *highsize); - - return(size); -} - -static guint64 -convert_unix_filetime_ms (const FILETIME *file_time, const char *ttype) -{ - guint64 t = ((guint64) file_time->dwHighDateTime << 32) + file_time->dwLowDateTime; - - /* This is (time_t)0. We can actually go to INT_MIN, - * but this will do for now. - */ - if (t < CONVERT_BASE) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: attempt to set %s time too early", __func__, ttype); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return (FALSE); - } - - return t - CONVERT_BASE; -} - -#ifndef HAVE_STRUCT_TIMEVAL -static guint64 -convert_unix_filetime (const FILETIME *file_time, size_t field_size, const char *ttype) -{ - guint64 t = convert_unix_filetime_ms (file_time, ttype); - - if (field_size == 4 && (t / 10000000) > INT_MAX) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: attempt to set %s time that is too big for a 32bits time_t", __func__, ttype); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return (FALSE); - } - - return t / 10000000; -} -#endif - -static void convert_stattime_access_to_timeval (struct timeval *dest, struct stat *statbuf) -{ -#if HAVE_STRUCT_STAT_ST_ATIMESPEC - dest->tv_sec = statbuf->st_atimespec.tv_sec; - dest->tv_usec = statbuf->st_atimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND; -#else - dest->tv_sec = statbuf->st_atime; -#if HAVE_STRUCT_STAT_ST_ATIM - dest->tv_usec = statbuf->st_atim.tv_nsec / NANOSECONDS_PER_MICROSECOND; -#endif -#endif -} - -static void convert_stattime_mod_to_timeval (struct timeval *dest, struct stat *statbuf) -{ -#if HAVE_STRUCT_STAT_ST_ATIMESPEC - dest->tv_sec = statbuf->st_mtimespec.tv_sec; - dest->tv_usec = statbuf->st_mtimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND; -#else - dest->tv_sec = statbuf->st_mtime; -#if HAVE_STRUCT_STAT_ST_ATIM - dest->tv_usec = statbuf->st_mtim.tv_nsec / NANOSECONDS_PER_MICROSECOND; -#endif -#endif -} - -static gboolean file_setfiletime(FileHandle *filehandle, - const FILETIME *create_time G_GNUC_UNUSED, - const FILETIME *access_time, - const FILETIME *write_time) -{ - struct stat statbuf; - gint ret; - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - if(filehandle->filename == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d unknown filename", __func__, ((MonoFDHandle*) filehandle)->fd); - - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return(FALSE); - } - - /* Get the current times, so we can put the same times back in - * the event that one of the FileTime structs is NULL - */ - MONO_ENTER_GC_SAFE; - ret=fstat (((MonoFDHandle*) filehandle)->fd, &statbuf); - MONO_EXIT_GC_SAFE; - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - -#ifdef HAVE_STRUCT_TIMEVAL - struct timeval times [2]; - memset (times, 0, sizeof (times)); - - if (access_time) { - guint64 actime = convert_unix_filetime_ms (access_time, "access"); - times [0].tv_sec = actime / TICKS_PER_SECOND; - times [0].tv_usec = (actime % TICKS_PER_SECOND) / TICKS_PER_MICROSECOND; - } else { - convert_stattime_access_to_timeval (× [0], &statbuf); - } - - if (write_time) { - guint64 wtime = convert_unix_filetime_ms (write_time, "write"); - times [1].tv_sec = wtime / TICKS_PER_SECOND; - times [1].tv_usec = (wtime % TICKS_PER_SECOND) / TICKS_PER_MICROSECOND; - } else { - convert_stattime_mod_to_timeval (× [1], &statbuf); - } - - ret = _wapi_utimes (filehandle->filename, times); -#else - struct utimbuf utbuf; - utbuf.actime = access_time ? convert_unix_filetime (access_time, sizeof (utbuf.actime), "access") : statbuf.st_atime; - utbuf.modtime = write_time ? convert_unix_filetime (write_time, sizeof (utbuf.modtime), "write") : statbuf.st_mtime; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting fd %d access %ld write %ld", __func__, ((MonoFDHandle*) filehandle)->fd, utbuf.actime, utbuf.modtime); - - ret = _wapi_utime (filehandle->filename, &utbuf); -#endif - if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d [%s] utime failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->filename, g_strerror(errno)); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - return(TRUE); -} - -static gboolean -console_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *bytesread) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(bytesread!=NULL) { - *bytesread=0; - } - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - do { - MONO_ENTER_GC_SAFE; - ret=read(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); - - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - if(bytesread!=NULL) { - *bytesread=ret; - } - - return(TRUE); -} - -static gboolean -console_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(byteswritten!=NULL) { - *byteswritten=0; - } - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - do { - MONO_ENTER_GC_SAFE; - ret = write(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - if (errno == EINTR) { - ret = 0; - } else { - _wapi_set_last_error_from_errno (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - return(FALSE); - } - } - if(byteswritten!=NULL) { - *byteswritten=ret; - } - - return(TRUE); -} - -static gboolean -pipe_read (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *bytesread) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(bytesread!=NULL) { - *bytesread=0; - } - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: reading up to %" G_GUINT32_FORMAT " bytes from pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); - - do { - MONO_ENTER_GC_SAFE; - ret=read(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - if (errno == EINTR) { - ret = 0; - } else { - _wapi_set_last_error_from_errno (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - return(FALSE); - } - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read %d bytes from pipe %d", __func__, ret, ((MonoFDHandle*) filehandle)->fd); - - if(bytesread!=NULL) { - *bytesread=ret; - } - - return(TRUE); -} - -static gboolean -pipe_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(byteswritten!=NULL) { - *byteswritten=0; - } - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: writing up to %" G_GUINT32_FORMAT " bytes to pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); - - do { - MONO_ENTER_GC_SAFE; - ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - if (errno == EINTR) { - ret = 0; - } else { - _wapi_set_last_error_from_errno (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - return(FALSE); - } - } - if(byteswritten!=NULL) { - *byteswritten=ret; - } - - return(TRUE); -} - -static gint convert_flags(guint32 fileaccess, guint32 createmode) -{ - gint flags=0; - - switch(fileaccess) { - case GENERIC_READ: - flags=O_RDONLY; - break; - case GENERIC_WRITE: - flags=O_WRONLY; - break; - case GENERIC_READ|GENERIC_WRITE: - flags=O_RDWR; - break; - default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown access type 0x%" PRIx32, __func__, - fileaccess); - break; - } - - switch(createmode) { - case CREATE_NEW: - flags|=O_CREAT|O_EXCL; - break; - case CREATE_ALWAYS: - flags|=O_CREAT|O_TRUNC; - break; - case OPEN_EXISTING: - break; - case OPEN_ALWAYS: - flags|=O_CREAT; - break; - case TRUNCATE_EXISTING: - flags|=O_TRUNC; - break; - default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown create mode 0x%" PRIx32, __func__, - createmode); - break; - } - - return(flags); -} - -#if 0 /* unused */ -static mode_t convert_perms(guint32 sharemode) -{ - mode_t perms=0600; - - if(sharemode&FILE_SHARE_READ) { - perms|=044; - } - if(sharemode&FILE_SHARE_WRITE) { - perms|=022; - } - - return(perms); -} -#endif - -static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, - guint32 fileaccess, - FileShare **share_info) -{ - gboolean file_already_shared; - guint32 file_existing_share, file_existing_access; - - file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, sharemode, fileaccess, &file_existing_share, &file_existing_access, share_info); - - if (file_already_shared) { - /* The reference to this share info was incremented - * when we looked it up, so be careful to put it back - * if we conclude we can't use this file. - */ - if ((file_existing_share == FILE_SHARE_NONE) || (sharemode == FILE_SHARE_NONE)) { - /* Quick and easy, no possibility to share */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, fileaccess); - - file_share_release (*share_info); - *share_info = NULL; - - return(FALSE); - } - - if (((file_existing_share == FILE_SHARE_READ) && - (fileaccess != GENERIC_READ)) || - ((file_existing_share == FILE_SHARE_WRITE) && - (fileaccess != GENERIC_WRITE))) { - /* New access mode doesn't match up */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, fileaccess, file_existing_share); - - file_share_release (*share_info); - *share_info = NULL; - - return(FALSE); - } - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: New file!", __func__); - } - - return(TRUE); -} - - -static gboolean -share_allows_delete (struct stat *statbuf, FileShare **share_info) -{ - gboolean file_already_shared; - guint32 file_existing_share, file_existing_access; - - file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, FILE_SHARE_DELETE, GENERIC_READ, &file_existing_share, &file_existing_access, share_info); - - if (file_already_shared) { - /* The reference to this share info was incremented - * when we looked it up, so be careful to put it back - * if we conclude we can't use this file. - */ - if (file_existing_share == 0) { - /* Quick and easy, no possibility to share */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, (*share_info)->access); - - file_share_release (*share_info); - *share_info = NULL; - - return(FALSE); - } - - if (!(file_existing_share & FILE_SHARE_DELETE)) { - /* New access mode doesn't match up */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, (*share_info)->access, file_existing_share); - - file_share_release (*share_info); - *share_info = NULL; - - return(FALSE); - } - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: New file!", __func__); - } - - return(TRUE); -} - -gpointer -mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs) -{ - FileHandle *filehandle; - MonoFDType type; - gint flags=convert_flags(fileaccess, createmode); - /*mode_t perms=convert_perms(sharemode);*/ - /* we don't use sharemode, because that relates to sharing of - * the file when the file is open and is already handled by - * other code, perms instead are the on-disk permissions and - * this is a sane default. - */ - mode_t perms=0666; - gchar *filename; - gint fd, ret; - struct stat statbuf; - ERROR_DECL (error); - - if (attrs & FILE_ATTRIBUTE_TEMPORARY) - perms = 0600; - - if (attrs & FILE_ATTRIBUTE_ENCRYPTED){ - mono_w32error_set_last (ERROR_ENCRYPTION_FAILED); - return INVALID_HANDLE_VALUE; - } - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(INVALID_HANDLE_VALUE); - } - - filename = mono_unicode_to_external_checked (name, error); - if (filename == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(INVALID_HANDLE_VALUE); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Opening %s with share 0x%" PRIx32 " and access 0x%" PRIx32, __func__, - filename, sharemode, fileaccess); - - fd = _wapi_open (filename, flags, perms); - - /* If we were trying to open a directory with write permissions - * (e.g. O_WRONLY or O_RDWR), this call will fail with - * EISDIR. However, this is a bit bogus because calls to - * manipulate the directory (e.g. mono_w32file_set_times) will still work on - * the directory because they use other API calls - * (e.g. utime()). Hence, if we failed with the EISDIR error, try - * to open the directory again without write permission. - */ - if (fd == -1 && errno == EISDIR) - { - /* Try again but don't try to make it writable */ - fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms); - } - - if (fd == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error opening file %s: %s", __func__, filename, g_strerror(errno)); - _wapi_set_last_path_error_from_errno (NULL, filename); - g_free (filename); - - return(INVALID_HANDLE_VALUE); - } - - MONO_ENTER_GC_SAFE; - ret = fstat (fd, &statbuf); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fstat error of file %s: %s", __func__, filename, g_strerror (errno)); - _wapi_set_last_error_from_errno (); - MONO_ENTER_GC_SAFE; - close (fd); - MONO_EXIT_GC_SAFE; - - return(INVALID_HANDLE_VALUE); - } - -#ifndef S_ISFIFO -#define S_ISFIFO(m) ((m & S_IFIFO) != 0) -#endif - if (S_ISFIFO (statbuf.st_mode)) { - type = MONO_FDTYPE_PIPE; - /* maintain invariant that pipes have no filename */ - g_free (filename); - filename = NULL; - } else if (S_ISCHR (statbuf.st_mode)) { - type = MONO_FDTYPE_CONSOLE; - } else { - type = MONO_FDTYPE_FILE; - } - - filehandle = file_data_create (type, fd); - filehandle->filename = filename; - filehandle->fileaccess = fileaccess; - filehandle->sharemode = sharemode; - filehandle->attrs = attrs; - - if (!share_allows_open (&statbuf, filehandle->sharemode, filehandle->fileaccess, &filehandle->share_info)) { - mono_w32error_set_last (ERROR_SHARING_VIOLATION); - MONO_ENTER_GC_SAFE; - close (((MonoFDHandle*) filehandle)->fd); - MONO_EXIT_GC_SAFE; - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return (INVALID_HANDLE_VALUE); - } - if (!filehandle->share_info) { - /* No space, so no more files can be opened */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: No space in the share table", __func__); - - mono_w32error_set_last (ERROR_TOO_MANY_OPEN_FILES); - MONO_ENTER_GC_SAFE; - close (((MonoFDHandle*) filehandle)->fd); - MONO_EXIT_GC_SAFE; - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return(INVALID_HANDLE_VALUE); - } - -#ifdef HAVE_POSIX_FADVISE - if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) { - MONO_ENTER_GC_SAFE; - posix_fadvise (((MonoFDHandle*) filehandle)->fd, 0, 0, POSIX_FADV_SEQUENTIAL); - MONO_EXIT_GC_SAFE; - } - if (attrs & FILE_FLAG_RANDOM_ACCESS) { - MONO_ENTER_GC_SAFE; - posix_fadvise (((MonoFDHandle*) filehandle)->fd, 0, 0, POSIX_FADV_RANDOM); - MONO_EXIT_GC_SAFE; - } -#endif - -#ifdef F_RDAHEAD - if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) { - MONO_ENTER_GC_SAFE; - fcntl(((MonoFDHandle*) filehandle)->fd, F_RDAHEAD, 1); - MONO_EXIT_GC_SAFE; - } -#endif - - mono_fdhandle_insert ((MonoFDHandle*) filehandle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); - - return GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd); -} - -gboolean -mono_w32file_cancel (gpointer handle) -{ - mono_w32error_set_last (ERROR_NOT_SUPPORTED); - return FALSE; -} - -gboolean -mono_w32file_close (gpointer handle) -{ - if (!mono_fdhandle_close (GPOINTER_TO_INT (handle))) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - return TRUE; -} - -gboolean mono_w32file_delete(const gunichar2 *name) -{ - gchar *filename; - gint retval; - gboolean ret = FALSE; - ERROR_DECL (error); -#if 0 - struct stat statbuf; - FileShare *shareinfo; -#endif - - if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - filename = mono_unicode_to_external_checked (name, error); - if(filename==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - -#if 0 - /* Check to make sure sharing allows us to open the file for - * writing. See bug 323389. - * - * Do the checks that don't need an open file descriptor, for - * simplicity's sake. If we really have to do the full checks - * then we can implement that later. - */ - if (_wapi_stat (filename, &statbuf) < 0) { - _wapi_set_last_path_error_from_errno (NULL, filename); - g_free (filename); - return(FALSE); - } - - if (share_allows_open (&statbuf, 0, GENERIC_WRITE, - &shareinfo) == FALSE) { - mono_w32error_set_last (ERROR_SHARING_VIOLATION); - g_free (filename); - return FALSE; - } - if (shareinfo) - file_share_release (shareinfo); -#endif - - retval = _wapi_unlink (filename); - - if (retval == -1) { - /* On linux, calling unlink on an non-existing file in a read-only mount will fail with EROFS. - * The expected behavior is for this function to return FALSE and not trigger an exception. - * To work around this behavior, we stat the file on failure. - * - * This was supposedly fixed on kernel 3.0 [1] but we could reproduce it with Ubuntu 16.04 which has kernel 4.4. - * We can't remove this workaround until the early 2020's when most Android deviced will have a fix. - * [1] https://github.com/torvalds/linux/commit/50338b889dc504c69e0cb316ac92d1b9e51f3c8a - */ - if (errno == EROFS) { - MonoIOStat stat; - if (mono_w32file_get_attributes_ex (name, &stat)) //The file exists, so must be due the RO file system - mono_set_errno (EROFS); - } - _wapi_set_last_path_error_from_errno (NULL, filename); - } else { - ret = TRUE; - } - - g_free(filename); - - return(ret); -} - -static gboolean -MoveFile (const gunichar2 *name, const gunichar2 *dest_name) -{ - gchar *utf8_name, *utf8_dest_name; - gint result, errno_copy; - struct stat stat_src, stat_dest; - gboolean ret = FALSE; - FileShare *shareinfo; - ERROR_DECL (error); - - if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - if(dest_name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - g_free (utf8_name); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_dest_name = mono_unicode_to_external_checked (dest_name, error); - if (utf8_dest_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - g_free (utf8_name); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - /* - * In C# land we check for the existence of src, but not for dest. - * We check it here and return the failure if dest exists and is not - * the same file as src. - */ - if (_wapi_stat (utf8_name, &stat_src) < 0) { - if (errno != ENOENT || _wapi_lstat (utf8_name, &stat_src) < 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - g_free (utf8_dest_name); - return FALSE; - } - } - - if (!_wapi_stat (utf8_dest_name, &stat_dest)) { - if (stat_dest.st_dev != stat_src.st_dev || - stat_dest.st_ino != stat_src.st_ino) { - g_free (utf8_name); - g_free (utf8_dest_name); - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - return FALSE; - } - } - - /* Check to make that we have delete sharing permission. - * See https://bugzilla.xamarin.com/show_bug.cgi?id=17009 - * - * Do the checks that don't need an open file descriptor, for - * simplicity's sake. If we really have to do the full checks - * then we can implement that later. - */ - if (share_allows_delete (&stat_src, &shareinfo) == FALSE) { - mono_w32error_set_last (ERROR_SHARING_VIOLATION); - return FALSE; - } - if (shareinfo) { - file_share_release (shareinfo); - shareinfo = NULL; - } - - result = _wapi_rename (utf8_name, utf8_dest_name); - errno_copy = errno; - - if (result == -1) { - switch(errno_copy) { - case EEXIST: - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - break; - - case EXDEV: - /* Ignore here, it is dealt with below */ - break; - - case ENOENT: - /* We already know src exists. Must be dest that doesn't exist. */ - _wapi_set_last_path_error_from_errno (NULL, utf8_dest_name); - break; - - default: - _wapi_set_last_error_from_errno (); - } - } - - g_free (utf8_name); - g_free (utf8_dest_name); - - if (result != 0 && errno_copy == EXDEV) { - gint32 copy_error; - - if (S_ISDIR (stat_src.st_mode)) { - mono_w32error_set_last (ERROR_NOT_SAME_DEVICE); - return FALSE; - } - /* Try a copy to the new location, and delete the source */ - if (!mono_w32file_copy (name, dest_name, FALSE, ©_error)) { - /* mono_w32file_copy will set the error */ - return(FALSE); - } - - return(mono_w32file_delete (name)); - } - - if (result == 0) { - ret = TRUE; - } - - return(ret); -} - -static gboolean -write_file (gint src_fd, gint dest_fd, struct stat *st_src, gboolean report_errors) -{ - gint remain, n; - gchar *buf, *wbuf; - gint buf_size = st_src->st_blksize; - MonoThreadInfo *info = mono_thread_info_current (); - - buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : buf_size); - buf = (gchar *) g_malloc (buf_size); - - for (;;) { - MONO_ENTER_GC_SAFE; - remain = read (src_fd, buf, buf_size); - MONO_EXIT_GC_SAFE; - if (remain < 0) { - if (errno == EINTR && !mono_thread_info_is_interrupt_state (info)) - continue; - - if (report_errors) - _wapi_set_last_error_from_errno (); - - g_free (buf); - return FALSE; - } - if (remain == 0) { - break; - } - - wbuf = buf; - while (remain > 0) { - MONO_ENTER_GC_SAFE; - n = write (dest_fd, wbuf, remain); - MONO_EXIT_GC_SAFE; - if (n < 0) { - if (errno == EINTR && !mono_thread_info_is_interrupt_state (info)) - continue; - - if (report_errors) - _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write failed.", __func__); - g_free (buf); - return FALSE; - } - - remain -= n; - wbuf += n; - } - } - - g_free (buf); - return TRUE ; -} - -#if HOST_DARWIN -static int -_wapi_clonefile(const char *from, const char *to, int flags) -{ - gchar *located_from, *located_to; - int ret; - - g_assert (clonefile_ptr != NULL); - - located_from = mono_portability_find_file (from, FALSE); - located_to = mono_portability_find_file (to, FALSE); - - MONO_ENTER_GC_SAFE; - ret = clonefile_ptr ( - located_from == NULL ? from : located_from, - located_to == NULL ? to : located_to, - flags); - MONO_EXIT_GC_SAFE; - - g_free (located_from); - g_free (located_to); - - return ret; -} -#endif - -static gboolean -CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_exists) -{ - gchar *utf8_src, *utf8_dest; - struct stat st, dest_st; - gboolean ret = TRUE; - ERROR_DECL (error); - - if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_src = mono_unicode_to_external_checked (name, error); - if (utf8_src == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of source returned NULL; %s", - __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - if(dest_name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: dest is NULL", __func__); - - g_free (utf8_src); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_dest = mono_unicode_to_external_checked (dest_name, error); - if (utf8_dest == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of dest returned NULL; %s", - __func__, mono_error_get_message (error)); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - - mono_error_cleanup (error); - g_free (utf8_src); - - return(FALSE); - } - - gint src_fd, dest_fd; - gint ret_utime; - gint syscall_res; - - src_fd = _wapi_open (utf8_src, O_RDONLY, 0); - if (src_fd < 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_src); - - g_free (utf8_src); - g_free (utf8_dest); - - return(FALSE); - } - - MONO_ENTER_GC_SAFE; - syscall_res = fstat (src_fd, &st); - MONO_EXIT_GC_SAFE; - if (syscall_res < 0) { - _wapi_set_last_error_from_errno (); - - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - return(FALSE); - } - - if (!_wapi_stat (utf8_dest, &dest_st)) { - /* Before trying to open/create the dest, we need to report a 'file busy' - * error if src and dest are actually the same file. We do the check here to take - * advantage of the IOMAP capability */ - if (st.st_dev == dest_st.st_dev && st.st_ino == dest_st.st_ino) { - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - mono_w32error_set_last (ERROR_SHARING_VIOLATION); - return (FALSE); - } - - /* Take advantage of the fact that we already know the file exists and bail out - * early */ - if (fail_if_exists) { - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - return (FALSE); - } - -#if HOST_DARWIN - /* If we attempt to use clonefile API we need to unlink the destination file - * first */ - if (clonefile_ptr != NULL) { - - /* Bail out if the destination is read-only */ - if (!is_file_writable (&dest_st, utf8_dest)) { - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return (FALSE); - } - - _wapi_unlink (utf8_dest); - } -#endif - } - -#if HOST_DARWIN - if (clonefile_ptr != NULL) { - ret = _wapi_clonefile (utf8_src, utf8_dest, 0); - if (ret == 0 || (errno != ENOTSUP && errno != EXDEV)) { - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - if (ret == 0) { - return (TRUE); - } else { - _wapi_set_last_error_from_errno (); - return (FALSE); - } - } - } -#endif - - if (fail_if_exists) { - dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL, st.st_mode); - } else { - /* FIXME: it's bad that this code path potentially scans - * the directory twice due to the weird mono_w32error_set_last() - * behavior. */ - dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode); - if (dest_fd < 0) { - /* The file does not exist, try creating it */ - dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode); - } else { - /* Apparently this error is set if we - * overwrite the dest file - */ - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - } - } - if (dest_fd < 0) { - _wapi_set_last_error_from_errno (); - - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - return(FALSE); - } - - if (!write_file (src_fd, dest_fd, &st, TRUE)) - ret = FALSE; - - close (src_fd); - close (dest_fd); - -#ifdef HAVE_STRUCT_TIMEVAL - struct timeval times [2]; - memset (times, 0, sizeof (times)); - - convert_stattime_access_to_timeval (× [0], &st); - convert_stattime_mod_to_timeval (× [1], &st); - - ret_utime = _wapi_utimes (utf8_dest, times); -#else - struct utimbuf dest_time; - dest_time.modtime = st.st_mtime; - dest_time.actime = st.st_atime; - - ret_utime = _wapi_utime (utf8_dest, &dest_time); -#endif - if (ret_utime == -1) - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: file [%s] utime failed: %s", __func__, utf8_dest, g_strerror(errno)); - - g_free (utf8_src); - g_free (utf8_dest); - - return ret; -} - -static gchar* -convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name) -{ - gchar *utf8_ret; - ERROR_DECL (error); - - if (arg == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: %s is NULL", __func__, arg_name); - mono_w32error_set_last (ERROR_INVALID_NAME); - return NULL; - } - - utf8_ret = mono_unicode_to_external_checked (arg, error); - if (utf8_ret == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of %s returned NULL; %s", - __func__, arg_name, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return NULL; - } - - return utf8_ret; -} - -static gboolean -ReplaceFile (const gunichar2 *replacedFileName, const gunichar2 *replacementFileName, const gunichar2 *backupFileName, guint32 replaceFlags, gpointer exclude, gpointer reserved) -{ - gint result, backup_fd = -1,replaced_fd = -1; - gchar *utf8_replacedFileName, *utf8_replacementFileName = NULL, *utf8_backupFileName = NULL; - struct stat stBackup; - gboolean ret = FALSE; - - if (!(utf8_replacedFileName = convert_arg_to_utf8 (replacedFileName, "replacedFileName"))) - return FALSE; - if (!(utf8_replacementFileName = convert_arg_to_utf8 (replacementFileName, "replacementFileName"))) - goto replace_cleanup; - if (backupFileName != NULL) { - if (!(utf8_backupFileName = convert_arg_to_utf8 (backupFileName, "backupFileName"))) - goto replace_cleanup; - } - - if (utf8_backupFileName) { - // Open the backup file for read so we can restore the file if an error occurs. - backup_fd = _wapi_open (utf8_backupFileName, O_RDONLY, 0); - result = _wapi_rename (utf8_replacedFileName, utf8_backupFileName); - if (result == -1) - goto replace_cleanup; - } - - result = _wapi_rename (utf8_replacementFileName, utf8_replacedFileName); - if (result == -1) { - _wapi_set_last_path_error_from_errno (NULL, utf8_replacementFileName); - _wapi_rename (utf8_backupFileName, utf8_replacedFileName); - if (backup_fd != -1 && !fstat (backup_fd, &stBackup)) { - replaced_fd = _wapi_open (utf8_backupFileName, O_WRONLY | O_CREAT | O_TRUNC, - stBackup.st_mode); - - if (replaced_fd == -1) - goto replace_cleanup; - - write_file (backup_fd, replaced_fd, &stBackup, FALSE); - } - - goto replace_cleanup; - } - - ret = TRUE; - -replace_cleanup: - g_free (utf8_replacedFileName); - g_free (utf8_replacementFileName); - g_free (utf8_backupFileName); - if (backup_fd != -1) { - MONO_ENTER_GC_SAFE; - close (backup_fd); - MONO_EXIT_GC_SAFE; - } - if (replaced_fd != -1) { - MONO_ENTER_GC_SAFE; - close (replaced_fd); - MONO_EXIT_GC_SAFE; - } - return ret; -} - -static gpointer -_wapi_stdhandle_create (gint fd, const gchar *name) -{ - gint flags; - FileHandle *filehandle; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: creating standard handle type %s, fd %d", __func__, name, fd); - - /* Check if fd is valid */ - do { - flags = fcntl(fd, F_GETFL); - } while (flags == -1 && errno == EINTR); - - if (flags == -1) { - /* Invalid fd. Not really much point checking for EBADF - * specifically - */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl error on fd %d: %s", __func__, fd, g_strerror(errno)); - - mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); - return INVALID_HANDLE_VALUE; - } - - filehandle = file_data_create (MONO_FDTYPE_CONSOLE, fd); - filehandle->filename = g_strdup(name); - - switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) { - case O_RDONLY: - filehandle->fileaccess = GENERIC_READ; - break; - case O_WRONLY: - filehandle->fileaccess = GENERIC_WRITE; - break; - case O_RDWR: - filehandle->fileaccess = GENERIC_READ | GENERIC_WRITE; - break; - default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Can't figure out flags 0x%x", __func__, flags); - filehandle->fileaccess = 0; - break; - } - - /* some default security attributes might be needed */ - filehandle->security_attributes = 0; - - /* Apparently input handles can't be written to. (I don't - * know if output or error handles can't be read from.) - */ - if (fd == 0) - filehandle->fileaccess &= ~GENERIC_WRITE; - - filehandle->sharemode = 0; - filehandle->attrs = 0; - - if (!mono_fdhandle_try_insert ((MonoFDHandle*) filehandle)) { - /* we raced between 2 invocations of _wapi_stdhandle_create */ - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return GINT_TO_POINTER(fd); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); - - return GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd); -} - -enum { - STD_INPUT_HANDLE = -10, - STD_OUTPUT_HANDLE = -11, - STD_ERROR_HANDLE = -12, -}; - -static gpointer -mono_w32file_get_std_handle (gint stdhandle) -{ - FileHandle **filehandle; - gint fd; - const gchar *name; - - switch(stdhandle) { - case STD_INPUT_HANDLE: - fd = 0; - name = ""; - break; - - case STD_OUTPUT_HANDLE: - fd = 1; - name = ""; - break; - - case STD_ERROR_HANDLE: - fd = 2; - name = ""; - break; - - default: - g_assert_not_reached (); - } - - if (!mono_fdhandle_lookup_and_ref(fd, (MonoFDHandle**) &filehandle)) { - gpointer handle; - - handle = _wapi_stdhandle_create (fd, name); - if (handle == INVALID_HANDLE_VALUE) { - mono_w32error_set_last (ERROR_NO_MORE_FILES); - return INVALID_HANDLE_VALUE; - } - } - - return GINT_TO_POINTER (fd); -} - -static gboolean -mono_w32file_read_or_write (gboolean read, gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error) -{ - MONO_REQ_GC_UNSAFE_MODE; - - FileHandle *filehandle; - gboolean ret = FALSE; - - gboolean const ref = mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle); - if (!ref) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - goto exit; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = (read ? file_read : file_write) (filehandle, buffer, numbytes, bytesread); - break; - case MONO_FDTYPE_CONSOLE: - ret = (read ? console_read : console_write) (filehandle, buffer, numbytes, bytesread); - break; - case MONO_FDTYPE_PIPE: - ret = (read ? pipe_read : pipe_write) (filehandle, buffer, numbytes, bytesread); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - break; - } - -exit: - if (ref) - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - if (!ret) - *win32error = mono_w32error_get_last (); - return ret; -} - -gboolean -mono_w32file_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error) -{ - return mono_w32file_read_or_write (TRUE, handle, buffer, numbytes, bytesread, win32error); -} - -gboolean -mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) -{ - return mono_w32file_read_or_write (FALSE, handle, (gpointer)buffer, numbytes, byteswritten, win32error); -} - -gboolean -mono_w32file_flush (gpointer handle) -{ - FileHandle *filehandle; - gboolean ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_flush(filehandle); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -gboolean -mono_w32file_truncate (gpointer handle) -{ - FileHandle *filehandle; - gboolean ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_setendoffile(filehandle); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -guint32 -mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method) -{ - FileHandle *filehandle; - guint32 ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return INVALID_SET_FILE_POINTER; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_seek(filehandle, movedistance, highmovedistance, method); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return INVALID_SET_FILE_POINTER; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -gint -mono_w32file_get_type(gpointer handle) -{ - FileHandle *filehandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FILE_TYPE_UNKNOWN; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = FILE_TYPE_DISK; - break; - case MONO_FDTYPE_CONSOLE: - ret = FILE_TYPE_CHAR; - break; - case MONO_FDTYPE_PIPE: - ret = FILE_TYPE_PIPE; - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FILE_TYPE_UNKNOWN; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -static guint32 -GetFileSize(gpointer handle, guint32 *highsize) -{ - FileHandle *filehandle; - guint32 ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return INVALID_FILE_SIZE; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_getfilesize(filehandle, highsize); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return INVALID_FILE_SIZE; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -gboolean -mono_w32file_set_times(gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time) -{ - FileHandle *filehandle; - gboolean ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_setfiletime(filehandle, create_time, access_time, write_time); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -/* A tick is a 100-nanosecond interval. File time epoch is Midnight, - * January 1 1601 GMT - */ - -#define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0)) - -static const guint16 mon_yday[2][13]={ - {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, - {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}, -}; - -gboolean -mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *system_time) -{ - gint64 file_ticks, totaldays, rem, y; - const guint16 *ip; - - if(system_time==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: system_time NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - file_ticks=((gint64)file_time->dwHighDateTime << 32) + - file_time->dwLowDateTime; - - /* Really compares if file_ticks>=0x8000000000000000 - * (LLONG_MAX+1) but we're working with a signed value for the - * year and day calculation to work later - */ - if(file_ticks<0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: file_time too big", __func__); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - totaldays=(file_ticks / TICKS_PER_DAY); - rem = file_ticks % TICKS_PER_DAY; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT " rem: %" G_GINT64_FORMAT, __func__, - totaldays, rem); - - system_time->wHour=rem/TICKS_PER_HOUR; - rem %= TICKS_PER_HOUR; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Hour: %d rem: %" G_GINT64_FORMAT, __func__, - system_time->wHour, rem); - - system_time->wMinute = rem / TICKS_PER_MINUTE; - rem %= TICKS_PER_MINUTE; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Minute: %d rem: %" G_GINT64_FORMAT, __func__, - system_time->wMinute, rem); - - system_time->wSecond = rem / TICKS_PER_SECOND; - rem %= TICKS_PER_SECOND; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Second: %d rem: %" G_GINT64_FORMAT, __func__, - system_time->wSecond, rem); - - system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Milliseconds: %d", __func__, - system_time->wMilliseconds); - - /* January 1, 1601 was a Monday, according to Emacs calendar */ - system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Day of week: %d", __func__, system_time->wDayOfWeek); - - /* This algorithm to find year and month given days from epoch - * from glibc - */ - y=1601; - -#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) -#define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400)) - - while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) { - /* Guess a corrected year, assuming 365 days per year */ - gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT " yg: %" G_GINT64_FORMAT " y: %" G_GINT64_FORMAT, __func__, - totaldays, yg, y); - g_message("%s: LEAPS(yg): %li LEAPS(y): %li", __func__, - LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1)); - - /* Adjust days and y to match the guessed year. */ - totaldays -= ((yg - y) * 365 - + LEAPS_THRU_END_OF (yg - 1) - - LEAPS_THRU_END_OF (y - 1)); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT, - __func__, totaldays); - y = yg; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: y: %" G_GINT64_FORMAT, __func__, y); - } - - system_time->wYear = y; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Year: %d", __func__, system_time->wYear); - - ip = mon_yday[isleap(y)]; - - for(y=11; totaldays < ip[y]; --y) { - continue; - } - totaldays-=ip[y]; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT, __func__, totaldays); - - system_time->wMonth = y + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Month: %d", __func__, system_time->wMonth); - - system_time->wDay = totaldays + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Day: %d", __func__, system_time->wDay); - - return(TRUE); -} - -static void -findhandle_destroy (gpointer data) -{ - FindHandle *findhandle; - - findhandle = (FindHandle*) data; - g_assert (findhandle); - - mono_coop_mutex_destroy (&findhandle->mutex); - - if (findhandle->namelist) - g_strfreev (findhandle->namelist); - if (findhandle->dir_part) - g_free (findhandle->dir_part); - - g_free (findhandle); -} - -static FindHandle* -findhandle_create (void) -{ - FindHandle* findhandle; - - findhandle = g_new0 (FindHandle, 1); - mono_refcount_init (findhandle, findhandle_destroy); - - mono_coop_mutex_init (&findhandle->mutex); - - return findhandle; -} - -static void -findhandle_insert (FindHandle *findhandle) -{ - mono_coop_mutex_lock (&finds_mutex); - - if (g_hash_table_lookup_extended (finds, (gpointer) findhandle, NULL, NULL)) - g_error("%s: duplicate Find handle %p", __func__, (gpointer) findhandle); - - g_hash_table_insert (finds, (gpointer) findhandle, findhandle); - - mono_coop_mutex_unlock (&finds_mutex); -} - -static gboolean -findhandle_lookup_and_ref (gpointer handle, FindHandle **findhandle) -{ - mono_coop_mutex_lock (&finds_mutex); - - if (!g_hash_table_lookup_extended (finds, handle, NULL, (gpointer*) findhandle)) { - mono_coop_mutex_unlock (&finds_mutex); - return FALSE; - } - - mono_refcount_inc (*findhandle); - - mono_coop_mutex_unlock (&finds_mutex); - - return TRUE; -} - -static void -findhandle_unref (FindHandle *findhandle) -{ - mono_refcount_dec (findhandle); -} - -static gboolean -findhandle_close (gpointer handle) -{ - FindHandle *findhandle; - gboolean removed; - - mono_coop_mutex_lock (&finds_mutex); - - if (!g_hash_table_lookup_extended (finds, handle, NULL, (gpointer*) &findhandle)) { - mono_coop_mutex_unlock (&finds_mutex); - - return FALSE; - } - - removed = g_hash_table_remove (finds, (gpointer) findhandle); - g_assert (removed); - - mono_coop_mutex_unlock (&finds_mutex); - - return TRUE; -} - -static void -finds_remove (gpointer data) -{ - FindHandle* findhandle; - - findhandle = (FindHandle*) data; - g_assert (findhandle); - - mono_refcount_dec (findhandle); -} - -gpointer -mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data) -{ - FindHandle *findhandle; - gchar *utf8_pattern = NULL, *dir_part, *entry_part, **namelist; - gint result; - ERROR_DECL (error); - - if (pattern == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: pattern is NULL", __func__); - - mono_w32error_set_last (ERROR_PATH_NOT_FOUND); - return(INVALID_HANDLE_VALUE); - } - - utf8_pattern = mono_unicode_to_external_checked (pattern, error); - if (utf8_pattern == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(INVALID_HANDLE_VALUE); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: looking for [%s]", __func__, utf8_pattern); - - /* Figure out which bit of the pattern is the directory */ - dir_part = _wapi_dirname (utf8_pattern); - entry_part = _wapi_basename (utf8_pattern); - -#if 0 - /* Don't do this check for now, it breaks if directories - * really do have metachars in their names (see bug 58116). - * FIXME: Figure out a better solution to keep some checks... - */ - if (strchr (dir_part, '*') || strchr (dir_part, '?')) { - mono_w32error_set_last (ERROR_INVALID_NAME); - g_free (dir_part); - g_free (entry_part); - g_free (utf8_pattern); - return(INVALID_HANDLE_VALUE); - } -#endif - - /* The pattern can specify a directory or a set of files. - * - * The pattern can have wildcard characters ? and *, but only - * in the section after the last directory delimiter. (Return - * ERROR_INVALID_NAME if there are wildcards in earlier path - * sections.) "*" has the usual 0-or-more chars meaning. "?" - * means "match one character", "??" seems to mean "match one - * or two characters", "???" seems to mean "match one, two or - * three characters", etc. Windows will also try and match - * the mangled "short name" of files, so 8 character patterns - * with wildcards will show some surprising results. - * - * All the written documentation I can find says that '?' - * should only match one character, and doesn't mention '??', - * '???' etc. I'm going to assume that the strict behaviour - * (ie '???' means three and only three characters) is the - * correct one, because that lets me use fnmatch(3) rather - * than mess around with regexes. - */ - - namelist = NULL; - result = _wapi_io_scandir (dir_part, entry_part, - &namelist); - - if (result == 0) { - /* No files, which windows seems to call - * FILE_NOT_FOUND - */ - mono_w32error_set_last (ERROR_FILE_NOT_FOUND); - g_free (utf8_pattern); - g_free (entry_part); - g_free (dir_part); - g_strfreev (namelist); - return (INVALID_HANDLE_VALUE); - } - - if (result < 0) { - _wapi_set_last_path_error_from_errno (dir_part, NULL); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: scandir error: %s", __func__, g_strerror (errno)); - g_free (utf8_pattern); - g_free (entry_part); - g_free (dir_part); - g_strfreev (namelist); - return (INVALID_HANDLE_VALUE); - } - - g_free (utf8_pattern); - g_free (entry_part); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Got %d matches", __func__, result); - - findhandle = findhandle_create (); - findhandle->namelist = namelist; - findhandle->dir_part = dir_part; - findhandle->num = result; - findhandle->count = 0; - - findhandle_insert (findhandle); - - if (!mono_w32file_find_next ((gpointer) findhandle, find_data)) { - mono_w32file_find_close ((gpointer) findhandle); - mono_w32error_set_last (ERROR_NO_MORE_FILES); - return INVALID_HANDLE_VALUE; - } - - return (gpointer) findhandle; -} - -gboolean -mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) -{ - FindHandle *findhandle; - struct stat buf, linkbuf; - gint result; - gchar *filename; - gchar *utf8_filename, *utf8_basename; - gunichar2 *utf16_basename; - time_t create_time; - glong bytes; - gboolean ret = FALSE; - - if (!findhandle_lookup_and_ref (handle, &findhandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - mono_coop_mutex_lock (&findhandle->mutex); - -retry: - if (findhandle->count >= findhandle->num) { - mono_w32error_set_last (ERROR_NO_MORE_FILES); - goto cleanup; - } - - /* stat next match */ - - filename = g_build_filename (findhandle->dir_part, findhandle->namelist[findhandle->count ++], (const char*)NULL); - - result = _wapi_stat (filename, &buf); - if (result == -1 && errno == ENOENT) { - /* Might be a dangling symlink */ - result = _wapi_lstat (filename, &buf); - } - - if (result != 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: stat failed: %s", __func__, filename); - - g_free (filename); - goto retry; - } - - result = _wapi_lstat (filename, &linkbuf); - if (result != 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lstat failed: %s", __func__, filename); - - g_free (filename); - goto retry; - } - - utf8_filename = mono_utf8_from_external (filename); - if (utf8_filename == NULL) { - /* We couldn't turn this filename into utf8 (eg the - * encoding of the name wasn't convertible), so just - * ignore it. - */ - g_warning ("%s: Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODINGS\n", __func__, filename); - - g_free (filename); - goto retry; - } - g_free (filename); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Found [%s]", __func__, utf8_filename); - - /* fill data block */ - - if (buf.st_mtime < buf.st_ctime) - create_time = buf.st_mtime; - else - create_time = buf.st_ctime; - - find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, &linkbuf); - - time_t_to_filetime (create_time, &find_data->ftCreationTime); - time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime); - time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime); - - if (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - find_data->nFileSizeHigh = 0; - find_data->nFileSizeLow = 0; - } else { - find_data->nFileSizeHigh = buf.st_size >> 32; - find_data->nFileSizeLow = buf.st_size & 0xFFFFFFFF; - } - - find_data->dwReserved0 = 0; - find_data->dwReserved1 = 0; - - utf8_basename = _wapi_basename (utf8_filename); - utf16_basename = g_utf8_to_utf16 (utf8_basename, -1, NULL, &bytes, - NULL); - if(utf16_basename==NULL) { - g_free (utf8_basename); - g_free (utf8_filename); - goto retry; - } - ret = TRUE; - - /* utf16 is 2 * utf8 */ - bytes *= 2; - - memset (find_data->cFileName, '\0', (MAX_PATH*2)); - - /* Truncating a utf16 string like this might leave the last - * gchar incomplete - */ - memcpy (find_data->cFileName, utf16_basename, - bytes<(MAX_PATH*2)-2?bytes:(MAX_PATH*2)-2); - - find_data->cAlternateFileName [0] = 0; /* not used */ - - g_free (utf8_basename); - g_free (utf8_filename); - g_free (utf16_basename); - -cleanup: - mono_coop_mutex_unlock (&findhandle->mutex); - - findhandle_unref (findhandle); - - return(ret); -} - -gboolean -mono_w32file_find_close (gpointer handle) -{ - if (!findhandle_close (handle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - return TRUE; -} - -gboolean -mono_w32file_create_directory (const gunichar2 *name) -{ - gchar *utf8_name; - gint result; - ERROR_DECL (error); - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - result = _wapi_mkdir (utf8_name, 0777); - - if (result == 0) { - g_free (utf8_name); - return TRUE; - } - - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return FALSE; -} - -gboolean -mono_w32file_remove_directory (const gunichar2 *name) -{ - gchar *utf8_name; - gint result; - ERROR_DECL (error); - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - result = _wapi_rmdir (utf8_name); - if (result == -1) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - - return(FALSE); - } - g_free (utf8_name); - - return(TRUE); -} - -guint32 -mono_w32file_get_attributes (const gunichar2 *name) -{ - gchar *utf8_name; - struct stat buf, linkbuf; - gint result; - guint32 ret; - ERROR_DECL (error); - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return (INVALID_FILE_ATTRIBUTES); - } - - result = _wapi_stat (utf8_name, &buf); - if (result == -1 && (errno == ENOENT || errno == ELOOP)) { - /* Might be a dangling symlink... */ - result = _wapi_lstat (utf8_name, &buf); - } - - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return (INVALID_FILE_ATTRIBUTES); - } - - result = _wapi_lstat (utf8_name, &linkbuf); - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return (INVALID_FILE_ATTRIBUTES); - } - - ret = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf); - - g_free (utf8_name); - - return(ret); -} - -gboolean -mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat) -{ - gchar *utf8_name; - - struct stat buf, linkbuf; - gint result; - ERROR_DECL (error); - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return FALSE; - } - - result = _wapi_stat (utf8_name, &buf); - if (result == -1 && errno == ENOENT) { - /* Might be a dangling symlink... */ - result = _wapi_lstat (utf8_name, &buf); - } - - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return FALSE; - } - - result = _wapi_lstat (utf8_name, &linkbuf); - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return(FALSE); - } - - /* fill stat block */ - - stat->attributes = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf); - stat->length = (stat->attributes & FILE_ATTRIBUTE_DIRECTORY) ? 0 : buf.st_size; - -#if HAVE_STRUCT_STAT_ST_ATIMESPEC - if (linkbuf.st_mtimespec.tv_sec < linkbuf.st_ctimespec.tv_sec || (linkbuf.st_mtimespec.tv_sec == linkbuf.st_ctimespec.tv_sec && linkbuf.st_mtimespec.tv_nsec < linkbuf.st_ctimespec.tv_nsec)) - stat->creation_time = linkbuf.st_mtimespec.tv_sec * TICKS_PER_SECOND + (linkbuf.st_mtimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - else - stat->creation_time = linkbuf.st_ctimespec.tv_sec * TICKS_PER_SECOND + (linkbuf.st_ctimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - - stat->last_access_time = linkbuf.st_atimespec.tv_sec * TICKS_PER_SECOND + (linkbuf.st_atimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - stat->last_write_time = linkbuf.st_mtimespec.tv_sec * TICKS_PER_SECOND + (linkbuf.st_mtimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; -#elif HAVE_STRUCT_STAT_ST_ATIM - if (linkbuf.st_mtime < linkbuf.st_ctime || (linkbuf.st_mtime == linkbuf.st_ctime && linkbuf.st_mtim.tv_nsec < linkbuf.st_ctim.tv_nsec)) - stat->creation_time = linkbuf.st_mtime * TICKS_PER_SECOND + (linkbuf.st_mtim.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - else - stat->creation_time = linkbuf.st_ctime * TICKS_PER_SECOND + (linkbuf.st_ctim.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - - stat->last_access_time = linkbuf.st_atime * TICKS_PER_SECOND + (linkbuf.st_atim.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - stat->last_write_time = linkbuf.st_mtime * TICKS_PER_SECOND + (linkbuf.st_mtim.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; -#else - stat->creation_time = (((guint64) (linkbuf.st_mtime < linkbuf.st_ctime ? linkbuf.st_mtime : linkbuf.st_ctime)) * TICKS_PER_SECOND) + CONVERT_BASE; - stat->last_access_time = (((guint64) (linkbuf.st_atime)) * TICKS_PER_SECOND) + CONVERT_BASE; - stat->last_write_time = (((guint64) (linkbuf.st_mtime)) * TICKS_PER_SECOND) + CONVERT_BASE; -#endif - - g_free (utf8_name); - return TRUE; -} - -gboolean -mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs) -{ - /* FIXME: think of something clever to do on unix */ - gchar *utf8_name; - struct stat buf; - gint result; - ERROR_DECL (error); - - /* - * Currently we only handle one *internal* case, with a value that is - * not standard: 0x80000000, which means `set executable bit' - */ - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - result = _wapi_stat (utf8_name, &buf); - if (result == -1 && errno == ENOENT) { - /* Might be a dangling symlink... */ - result = _wapi_lstat (utf8_name, &buf); - } - - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return FALSE; - } - - /* Contrary to the documentation, ms allows NORMAL to be - * specified along with other attributes, so dont bother to - * catch that case here. - */ - if (attrs & FILE_ATTRIBUTE_READONLY) { - result = _wapi_chmod (utf8_name, buf.st_mode & ~(S_IWUSR | S_IWOTH | S_IWGRP)); - } else { - result = _wapi_chmod (utf8_name, buf.st_mode | S_IWUSR); - } - - /* Ignore the other attributes for now */ - - if (attrs & 0x80000000){ - mode_t exec_mask = 0; - - if ((buf.st_mode & S_IRUSR) != 0) - exec_mask |= S_IXUSR; - - if ((buf.st_mode & S_IRGRP) != 0) - exec_mask |= S_IXGRP; - - if ((buf.st_mode & S_IROTH) != 0) - exec_mask |= S_IXOTH; - -#if defined(HAVE_CHMOD) - MONO_ENTER_GC_SAFE; - result = chmod (utf8_name, buf.st_mode | exec_mask); - MONO_EXIT_GC_SAFE; -#else - result = -1; -#endif - } - /* Don't bother to reset executable (might need to change this - * policy) - */ - - g_free (utf8_name); - - return(TRUE); -} - -guint32 -mono_w32file_get_cwd (guint32 length, gunichar2 *buffer) -{ - gunichar2 *utf16_path; - glong count; - gsize bytes; - - if (getcwd ((gchar*)buffer, length) == NULL) { - if (errno == ERANGE) { /*buffer length is not big enough */ - gchar *path = g_get_current_dir (); /*FIXME g_get_current_dir doesn't work with broken paths and calling it just to know the path length is silly*/ - if (path == NULL) - return 0; - utf16_path = mono_unicode_from_external (path, &bytes); - g_free (utf16_path); - g_free (path); - return (bytes/2)+1; - } - _wapi_set_last_error_from_errno (); - return 0; - } - - utf16_path = mono_unicode_from_external ((gchar*)buffer, &bytes); - count = (bytes/2)+1; - g_assert (count <= length); /*getcwd must have failed before with ERANGE*/ - - /* Add the terminator */ - memset (buffer, '\0', bytes+2); - memcpy (buffer, utf16_path, bytes); - - g_free (utf16_path); - - return count; -} - -gboolean -mono_w32file_set_cwd (const gunichar2 *path) -{ - gchar *utf8_path; - gboolean result; - ERROR_DECL (error); - - if (path == NULL) { - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - utf8_path = mono_unicode_to_external_checked (path, error); - if (utf8_path == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (_wapi_chdir (utf8_path) != 0) { - _wapi_set_last_error_from_errno (); - result = FALSE; - } - else - result = TRUE; - - g_free (utf8_path); - return result; -} - -gboolean -mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size) -{ - FileHandle *read_filehandle, *write_filehandle; - gint filedes[2]; - gint ret; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Creating pipe", __func__); - - MONO_ENTER_GC_SAFE; - ret=pipe (filedes); - MONO_EXIT_GC_SAFE; - if (ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error creating pipe: (%d) %s", - __func__, errno, g_strerror (errno)); - - _wapi_set_last_error_from_errno (); - return FALSE; - } - - /* filedes[0] is open for reading, filedes[1] for writing */ - - read_filehandle = file_data_create (MONO_FDTYPE_PIPE, filedes[0]); - read_filehandle->fileaccess = GENERIC_READ; - - write_filehandle = file_data_create (MONO_FDTYPE_PIPE, filedes[1]); - write_filehandle->fileaccess = GENERIC_WRITE; - - mono_fdhandle_insert ((MonoFDHandle*) read_filehandle); - mono_fdhandle_insert ((MonoFDHandle*) write_filehandle); - - *readpipe = GINT_TO_POINTER(((MonoFDHandle*) read_filehandle)->fd); - *writepipe = GINT_TO_POINTER(((MonoFDHandle*) write_filehandle)->fd); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning pipe: read handle %p, write handle %p", - __func__, GINT_TO_POINTER(((MonoFDHandle*) read_filehandle)->fd), GINT_TO_POINTER(((MonoFDHandle*) write_filehandle)->fd)); - - return(TRUE); -} - -#ifdef HAVE_GETFSSTAT -/* Darwin has getfsstat */ -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - struct statfs *stats; - gint size, n, i; - gunichar2 *dir; - glong length, total = 0; - gint syscall_res; - - MONO_ENTER_GC_SAFE; - n = getfsstat (NULL, 0, MNT_NOWAIT); - MONO_EXIT_GC_SAFE; - if (n == -1) - return 0; - size = n * sizeof (struct statfs); - stats = (struct statfs *) g_malloc (size); - if (stats == NULL) - return 0; - MONO_ENTER_GC_SAFE; - syscall_res = getfsstat (stats, size, MNT_NOWAIT); - MONO_EXIT_GC_SAFE; - if (syscall_res == -1){ - g_free (stats); - return 0; - } - for (i = 0; i < n; i++){ - dir = g_utf8_to_utf16 (stats [i].f_mntonname, -1, NULL, &length, NULL); - if (total + length < len){ - memcpy (buf + total, dir, sizeof (gunichar2) * length); - buf [total+length] = 0; - } - g_free (dir); - total += length + 1; - } - if (total < len) - buf [total] = 0; - total++; - g_free (stats); - return total; -} -#elif _AIX -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - struct vmount *mounts; - // ret will first be the errno cond, then no of structs - int needsize, ret, total; - gunichar2 *dir; - glong length; - total = 0; - - MONO_ENTER_GC_SAFE; - ret = mntctl (MCTL_QUERY, sizeof(needsize), (char*)&needsize); - MONO_EXIT_GC_SAFE; - if (ret == -1) - return 0; - mounts = (struct vmount *) g_malloc (needsize); - if (mounts == NULL) - return 0; - MONO_ENTER_GC_SAFE; - ret = mntctl (MCTL_QUERY, needsize, (char*)mounts); - MONO_EXIT_GC_SAFE; if (ret == -1) { - g_free (mounts); - return 0; - } - - for (int i = 0; i < ret; i++) { - dir = g_utf8_to_utf16 (vmt2dataptr(mounts, VMT_STUB), -1, NULL, &length, NULL); - if (total + length < len){ - memcpy (buf + total, dir, sizeof (gunichar2) * length); - buf [total+length] = 0; - } - g_free (dir); - total += length + 1; - mounts = (struct vmount *)((char*)mounts + mounts->vmt_length); // next! - } - if (total < len) - buf [total] = 0; - total++; - g_free (mounts); - return total; -} -#else -/* In-place octal sequence replacement */ -static void -unescape_octal (gchar *str) -{ - gchar *rptr; - gchar *wptr; - - if (str == NULL) - return; - - rptr = wptr = str; - while (*rptr != '\0') { - if (*rptr == '\\') { - gchar c; - rptr++; - c = (*(rptr++) - '0') << 6; - c += (*(rptr++) - '0') << 3; - c += *(rptr++) - '0'; - *wptr++ = c; - } else if (wptr != rptr) { - *wptr++ = *rptr++; + if (errno == EINTR) { + ret = 0; } else { - rptr++; wptr++; - } - } - *wptr = '\0'; -} -static gint32 GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf); - -#if __linux__ -#define GET_LOGICAL_DRIVE_STRINGS_BUFFER 512 -#define GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER 512 -#define GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER 64 - -typedef struct -{ - glong total; - guint32 buffer_index; - guint32 mountpoint_index; - guint32 field_number; - guint32 allocated_size; - guint32 fsname_index; - guint32 fstype_index; - gchar mountpoint [GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER + 1]; - gchar *mountpoint_allocated; - gchar buffer [GET_LOGICAL_DRIVE_STRINGS_BUFFER]; - gchar fsname [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1]; - gchar fstype [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1]; - ssize_t nbytes; - gchar delimiter; - gboolean check_mount_source; -} LinuxMountInfoParseState; - -static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state); -static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state); -static void append_to_mountpoint (LinuxMountInfoParseState *state); -static gboolean add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state); - -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - gint fd; - gint32 ret = 0; - LinuxMountInfoParseState state; - gboolean (*parser)(guint32, gunichar2*, LinuxMountInfoParseState*) = NULL; - - memset (buf, 0, len * sizeof (gunichar2)); - MONO_ENTER_GC_SAFE; - fd = open ("/proc/self/mountinfo", O_RDONLY); - MONO_EXIT_GC_SAFE; - if (fd != -1) - parser = GetLogicalDriveStrings_MountInfo; - else { - MONO_ENTER_GC_SAFE; - fd = open ("/proc/mounts", O_RDONLY); - MONO_EXIT_GC_SAFE; - if (fd != -1) - parser = GetLogicalDriveStrings_Mounts; - } - - if (!parser) { - ret = GetLogicalDriveStrings_Mtab (len, buf); - goto done_and_out; - } - - memset (&state, 0, sizeof (LinuxMountInfoParseState)); - state.field_number = 1; - state.delimiter = ' '; - - while (1) { - MONO_ENTER_GC_SAFE; - state.nbytes = read (fd, state.buffer, GET_LOGICAL_DRIVE_STRINGS_BUFFER); - MONO_EXIT_GC_SAFE; - if (!(state.nbytes > 0)) - break; - state.buffer_index = 0; - - while ((*parser)(len, buf, &state)) { - if (state.buffer [state.buffer_index] == '\n') { - gboolean quit = add_drive_string (len, buf, &state); - state.field_number = 1; - state.buffer_index++; - if (state.mountpoint_allocated) { - g_free (state.mountpoint_allocated); - state.mountpoint_allocated = NULL; - } - if (quit) { - ret = state.total; - goto done_and_out; - } - } - } - }; - ret = state.total; - - done_and_out: - if (fd != -1) { - MONO_ENTER_GC_SAFE; - close (fd); - MONO_EXIT_GC_SAFE; - } - return ret; -} - -static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state) -{ - gchar *ptr; - - if (state->field_number == 1) - state->check_mount_source = TRUE; - - while (state->buffer_index < (guint32)state->nbytes) { - if (state->buffer [state->buffer_index] == state->delimiter) { - state->field_number++; - switch (state->field_number) { - case 2: - state->mountpoint_index = 0; - break; - - case 3: - if (state->mountpoint_allocated) - state->mountpoint_allocated [state->mountpoint_index] = 0; - else - state->mountpoint [state->mountpoint_index] = 0; - break; - - default: - ptr = (gchar*)memchr (state->buffer + state->buffer_index, '\n', GET_LOGICAL_DRIVE_STRINGS_BUFFER - state->buffer_index); - if (ptr) - state->buffer_index = (ptr - (gchar*)state->buffer) - 1; - else - state->buffer_index = state->nbytes; - return TRUE; - } - state->buffer_index++; - continue; - } else if (state->buffer [state->buffer_index] == '\n') - return TRUE; - - switch (state->field_number) { - case 1: - if (state->check_mount_source) { - if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') { - /* We can ignore the rest, it's a device - * path */ - state->check_mount_source = FALSE; - state->fsname [state->fsname_index++] = '/'; - break; - } - if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER) - state->fsname [state->fsname_index++] = state->buffer [state->buffer_index]; - } - break; - - case 2: - append_to_mountpoint (state); - break; - - case 3: - if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER) - state->fstype [state->fstype_index++] = state->buffer [state->buffer_index]; - break; - } - - state->buffer_index++; - } - - return FALSE; -} - -static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state) -{ - while (state->buffer_index < (guint32)state->nbytes) { - if (state->buffer [state->buffer_index] == state->delimiter) { - state->field_number++; - switch (state->field_number) { - case 5: - state->mountpoint_index = 0; - break; - - case 6: - if (state->mountpoint_allocated) - state->mountpoint_allocated [state->mountpoint_index] = 0; - else - state->mountpoint [state->mountpoint_index] = 0; - break; - - case 7: - state->delimiter = '-'; - break; - - case 8: - state->delimiter = ' '; - break; - - case 10: - state->check_mount_source = TRUE; - break; - } - state->buffer_index++; - continue; - } else if (state->buffer [state->buffer_index] == '\n') - return TRUE; - - switch (state->field_number) { - case 5: - append_to_mountpoint (state); - break; - - case 9: - if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER) - state->fstype [state->fstype_index++] = state->buffer [state->buffer_index]; - break; - - case 10: - if (state->check_mount_source) { - if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') { - /* We can ignore the rest, it's a device - * path */ - state->check_mount_source = FALSE; - state->fsname [state->fsname_index++] = '/'; - break; - } - if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER) - state->fsname [state->fsname_index++] = state->buffer [state->buffer_index]; - } - break; - } - - state->buffer_index++; - } - - return FALSE; -} + _wapi_set_last_error_from_errno (); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); -static void -append_to_mountpoint (LinuxMountInfoParseState *state) -{ - gchar ch = state->buffer [state->buffer_index]; - if (state->mountpoint_allocated) { - if (state->mountpoint_index >= state->allocated_size) { - guint32 newsize = (state->allocated_size << 1) + 1; - gchar *newbuf = (gchar *)g_malloc0 (newsize * sizeof (gchar)); - - memcpy (newbuf, state->mountpoint_allocated, state->mountpoint_index); - g_free (state->mountpoint_allocated); - state->mountpoint_allocated = newbuf; - state->allocated_size = newsize; + return(FALSE); } - state->mountpoint_allocated [state->mountpoint_index++] = ch; - } else { - if (state->mountpoint_index >= GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER) { - state->allocated_size = (state->mountpoint_index << 1) + 1; - state->mountpoint_allocated = (gchar *)g_malloc0 (state->allocated_size * sizeof (gchar)); - memcpy (state->mountpoint_allocated, state->mountpoint, state->mountpoint_index); - state->mountpoint_allocated [state->mountpoint_index++] = ch; - } else - state->mountpoint [state->mountpoint_index++] = ch; } + if (byteswritten != NULL) { + *byteswritten = ret; + } + return(TRUE); } static gboolean -add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state) -{ - gboolean quit = FALSE; - gboolean ignore_entry; - - if (state->fsname_index == 1 && state->fsname [0] == '/') - ignore_entry = FALSE; - else if (memcmp ("overlay", state->fsname, state->fsname_index) == 0 || - memcmp ("aufs", state->fstype, state->fstype_index) == 0) { - /* Don't ignore overlayfs and aufs - these might be used on Docker - * (https://bugzilla.xamarin.com/show_bug.cgi?id=31021) */ - ignore_entry = FALSE; - } else if (state->fsname_index == 0 || memcmp ("none", state->fsname, state->fsname_index) == 0) { - ignore_entry = TRUE; - } else if (state->fstype_index >= 5 && memcmp ("fuse.", state->fstype, 5) == 0) { - /* Ignore GNOME's gvfs */ - if (state->fstype_index == 21 && memcmp ("fuse.gvfs-fuse-daemon", state->fstype, state->fstype_index) == 0) - ignore_entry = TRUE; - else - ignore_entry = FALSE; - } else if (state->fstype_index == 3 && memcmp ("nfs", state->fstype, state->fstype_index) == 0) - ignore_entry = FALSE; - else - ignore_entry = TRUE; - - if (!ignore_entry) { - gunichar2 *dir; - glong length; - gchar *mountpoint = state->mountpoint_allocated ? state->mountpoint_allocated : state->mountpoint; - - unescape_octal (mountpoint); - dir = g_utf8_to_utf16 (mountpoint, -1, NULL, &length, NULL); - if (state->total + length + 1 > len) { - quit = TRUE; - state->total = len * 2; - } else { - length++; - memcpy (buf + state->total, dir, sizeof (gunichar2) * length); - state->total += length; - } - g_free (dir); - } - state->fsname_index = 0; - state->fstype_index = 0; - - return quit; -} -#else -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - return GetLogicalDriveStrings_Mtab (len, buf); -} -#endif -static gint32 -GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf) +console_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) { - FILE *fp; - gunichar2 *ptr, *dir; - glong length, total = 0; - gchar buffer [512]; - gchar **splitted; - - memset (buf, 0, sizeof (gunichar2) * (len + 1)); - buf [0] = '/'; - buf [1] = 0; - buf [2] = 0; - - /* Sigh, mntent and friends don't work well. - * It stops on the first line that doesn't begin with a '/'. - * (linux 2.6.5, libc 2.3.2.ds1-12) - Gonz */ - MONO_ENTER_GC_SAFE; - fp = fopen ("/etc/mtab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) { - MONO_ENTER_GC_SAFE; - fp = fopen ("/etc/mnttab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) - return 1; - } - - ptr = buf; - while (1) { - gchar *fgets_res; - MONO_ENTER_GC_SAFE; - fgets_res = fgets (buffer, 512, fp); - MONO_EXIT_GC_SAFE; - if (!fgets_res) - break; - if (*buffer != '/') - continue; - - splitted = g_strsplit (buffer, " ", 0); - if (!*splitted || !*(splitted + 1)) { - g_strfreev (splitted); - continue; - } - - unescape_octal (*(splitted + 1)); - dir = g_utf8_to_utf16 (*(splitted + 1), -1, NULL, &length, NULL); - g_strfreev (splitted); - if (total + length + 1 > len) { - MONO_ENTER_GC_SAFE; - fclose (fp); - MONO_EXIT_GC_SAFE; - g_free (dir); - return len * 2; /* guess */ - } - - memcpy (ptr + total, dir, sizeof (gunichar2) * length); - g_free (dir); - total += length + 1; + gint ret; + MonoThreadInfo *info = mono_thread_info_current (); + + if(byteswritten!=NULL) { + *byteswritten=0; } - - MONO_ENTER_GC_SAFE; - fclose (fp); - MONO_EXIT_GC_SAFE; - return total; -/* Commented out, does not work with my mtab!!! - Gonz */ -#ifdef NOTENABLED /* HAVE_MNTENT_H */ -{ - FILE *fp; - struct mntent *mnt; - gunichar2 *ptr, *dir; - glong len, total = 0; + if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - MONO_ENTER_GC_SAFE; - fp = setmntent ("/etc/mtab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) { - MONO_ENTER_GC_SAFE; - fp = setmntent ("/etc/mnttab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) - return; + mono_w32error_set_last (ERROR_ACCESS_DENIED); + return(FALSE); } - - ptr = buf; - while (1) { + + do { MONO_ENTER_GC_SAFE; - mnt = getmntent (fp); + ret = write(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); MONO_EXIT_GC_SAFE; - if (mnt == NULL) - break; - g_print ("GOT %s\n", mnt->mnt_dir); - dir = g_utf8_to_utf16 (mnt->mnt_dir, &len, NULL, NULL, NULL); - if (total + len + 1 > len) { - MONO_ENTER_GC_SAFE; - endmntent (fp); - MONO_EXIT_GC_SAFE; - return len * 2; /* guess */ - } - - memcpy (ptr + total, dir, sizeof (gunichar2) * len); - g_free (dir); - total += len + 1; - } - - MONO_ENTER_GC_SAFE; - endmntent (fp); - MONO_EXIT_GC_SAFE; - return total; -} -#endif -} -#endif - -#ifndef PLATFORM_NO_DRIVEINFO -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) -{ - g_assert (free_bytes_avail); - g_assert (total_number_of_bytes); - g_assert (total_number_of_free_bytes); - -#if defined(HAVE_STATVFS) || defined(HAVE_STATFS) -#ifdef HAVE_STATVFS - struct statvfs fsstat; -#elif defined(HAVE_STATFS) - struct statfs fsstat; -#endif - gchar *utf8_path_name; - gint ret; - unsigned long block_size; - ERROR_DECL (error); + } while (ret == -1 && errno == EINTR && + !mono_thread_info_is_interrupt_state (info)); - if (path_name == NULL) { - utf8_path_name = g_strdup (g_get_current_dir()); - if (utf8_path_name == NULL) { - mono_w32error_set_last (ERROR_DIRECTORY); - return(FALSE); - } - } - else { - utf8_path_name = mono_unicode_to_external_checked (path_name, error); - if (utf8_path_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); + if (ret == -1) { + if (errno == EINTR) { + ret = 0; + } else { + _wapi_set_last_error_from_errno (); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); } } - - do { -#ifdef HAVE_STATVFS - MONO_ENTER_GC_SAFE; - ret = statvfs (utf8_path_name, &fsstat); - MONO_EXIT_GC_SAFE; - block_size = fsstat.f_frsize; -#elif defined(HAVE_STATFS) - MONO_ENTER_GC_SAFE; - ret = statfs (utf8_path_name, &fsstat); - MONO_EXIT_GC_SAFE; - block_size = fsstat.f_bsize; -#endif - } while(ret == -1 && errno == EINTR); - - g_free(utf8_path_name); - - if (ret == -1) { - _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: statvfs failed: %s", __func__, g_strerror (errno)); - return(FALSE); + if(byteswritten!=NULL) { + *byteswritten=ret; } - - /* total number of free bytes for non-root */ - *free_bytes_avail = block_size * (guint64)fsstat.f_bavail; - - /* total number of bytes available for non-root */ - *total_number_of_bytes = block_size * (guint64)fsstat.f_blocks; - - /* total number of bytes available for root */ - *total_number_of_free_bytes = block_size * (guint64)fsstat.f_bfree; -#endif + return(TRUE); } -#endif // PLATFORM_NO_DRIVEINFO - -/* - * General Unix support - */ -typedef struct { - guint32 drive_type; -#if __linux__ - // http://man7.org/linux/man-pages/man2/statfs.2.html - // - // The __fsword_t type used for various fields in the statfs structure - // definition is a glibc internal type, not intended for public use. - // This leaves the programmer in a bit of a conundrum when trying to - // copy or compare these fields to local variables in a program. Using - // unsigned int for such variables suffices on most systems. - // - // Let's hope "most" is enough, and that it works with other libc. - unsigned fstypeid; -#endif - const gchar* fstype; -} _wapi_drive_type; - -static const _wapi_drive_type _wapi_drive_types[] = { -#if HOST_DARWIN - { DRIVE_REMOTE, "afp" }, - { DRIVE_REMOTE, "afpfs" }, - { DRIVE_REMOTE, "autofs" }, - { DRIVE_CDROM, "cddafs" }, - { DRIVE_CDROM, "cd9660" }, - { DRIVE_RAMDISK, "devfs" }, - { DRIVE_RAMDISK, "nullfs" }, - { DRIVE_FIXED, "exfat" }, - { DRIVE_RAMDISK, "fdesc" }, - { DRIVE_REMOTE, "ftp" }, - { DRIVE_FIXED, "hfs" }, - { DRIVE_FIXED, "apfs" }, - { DRIVE_REMOTE, "kbfuse" }, - { DRIVE_FIXED, "msdos" }, - { DRIVE_REMOTE, "nfs" }, - { DRIVE_FIXED, "ntfs" }, - { DRIVE_REMOTE, "smbfs" }, - { DRIVE_FIXED, "udf" }, - { DRIVE_REMOTE, "webdav" }, - { DRIVE_FIXED, "ufsd_NTFS"}, - { DRIVE_UNKNOWN, NULL } -#elif __linux__ - { DRIVE_FIXED, ADFS_SUPER_MAGIC, "adfs"}, - { DRIVE_FIXED, AFFS_SUPER_MAGIC, "affs"}, - { DRIVE_REMOTE, AFS_SUPER_MAGIC, "afs"}, - { DRIVE_RAMDISK, AUTOFS_SUPER_MAGIC, "autofs"}, - { DRIVE_RAMDISK, AUTOFS_SBI_MAGIC, "autofs4"}, - { DRIVE_REMOTE, CODA_SUPER_MAGIC, "coda" }, - { DRIVE_RAMDISK, CRAMFS_MAGIC, "cramfs"}, - { DRIVE_RAMDISK, CRAMFS_MAGIC_WEND, "cramfs"}, - { DRIVE_REMOTE, CIFS_MAGIC_NUMBER, "cifs"}, - { DRIVE_RAMDISK, DEBUGFS_MAGIC, "debugfs"}, - { DRIVE_RAMDISK, SYSFS_MAGIC, "sysfs"}, - { DRIVE_RAMDISK, SECURITYFS_MAGIC, "securityfs"}, - { DRIVE_RAMDISK, SELINUX_MAGIC, "selinuxfs"}, - { DRIVE_RAMDISK, RAMFS_MAGIC, "ramfs"}, - { DRIVE_FIXED, SQUASHFS_MAGIC, "squashfs"}, - { DRIVE_FIXED, EFS_SUPER_MAGIC, "efs"}, - { DRIVE_FIXED, EXT2_SUPER_MAGIC, "ext"}, - { DRIVE_FIXED, EXT3_SUPER_MAGIC, "ext"}, - { DRIVE_FIXED, EXT4_SUPER_MAGIC, "ext"}, - { DRIVE_REMOTE, XENFS_SUPER_MAGIC, "xenfs"}, - { DRIVE_FIXED, BTRFS_SUPER_MAGIC, "btrfs"}, - { DRIVE_FIXED, HFS_SUPER_MAGIC, "hfs"}, - { DRIVE_FIXED, HFSPLUS_SUPER_MAGIC, "hfsplus"}, - { DRIVE_FIXED, HPFS_SUPER_MAGIC, "hpfs"}, - { DRIVE_RAMDISK, HUGETLBFS_MAGIC, "hugetlbfs"}, - { DRIVE_CDROM, ISOFS_SUPER_MAGIC, "iso"}, - { DRIVE_FIXED, JFFS2_SUPER_MAGIC, "jffs2"}, - { DRIVE_RAMDISK, ANON_INODE_FS_MAGIC, "anon_inode"}, - { DRIVE_FIXED, JFS_SUPER_MAGIC, "jfs"}, - { DRIVE_FIXED, MINIX_SUPER_MAGIC, "minix"}, - { DRIVE_FIXED, MINIX_SUPER_MAGIC2, "minix v2"}, - { DRIVE_FIXED, MINIX2_SUPER_MAGIC, "minix2"}, - { DRIVE_FIXED, MINIX2_SUPER_MAGIC2, "minix2 v2"}, - { DRIVE_FIXED, MINIX3_SUPER_MAGIC, "minix3"}, - { DRIVE_FIXED, MSDOS_SUPER_MAGIC, "msdos"}, - { DRIVE_REMOTE, NCP_SUPER_MAGIC, "ncp"}, - { DRIVE_REMOTE, NFS_SUPER_MAGIC, "nfs"}, - { DRIVE_FIXED, NTFS_SB_MAGIC, "ntfs"}, - { DRIVE_RAMDISK, OPENPROM_SUPER_MAGIC, "openpromfs"}, - { DRIVE_RAMDISK, PROC_SUPER_MAGIC, "proc"}, - { DRIVE_FIXED, QNX4_SUPER_MAGIC, "qnx4"}, - { DRIVE_FIXED, REISERFS_SUPER_MAGIC, "reiserfs"}, - { DRIVE_RAMDISK, ROMFS_MAGIC, "romfs"}, - { DRIVE_REMOTE, SMB_SUPER_MAGIC, "samba"}, - { DRIVE_RAMDISK, CGROUP_SUPER_MAGIC, "cgroupfs"}, - { DRIVE_RAMDISK, FUTEXFS_SUPER_MAGIC, "futexfs"}, - { DRIVE_FIXED, SYSV2_SUPER_MAGIC, "sysv2"}, - { DRIVE_FIXED, SYSV4_SUPER_MAGIC, "sysv4"}, - { DRIVE_RAMDISK, TMPFS_MAGIC, "tmpfs"}, - { DRIVE_RAMDISK, DEVPTS_SUPER_MAGIC, "devpts"}, - { DRIVE_CDROM, UDF_SUPER_MAGIC, "udf"}, - { DRIVE_FIXED, UFS_MAGIC, "ufs"}, - { DRIVE_FIXED, UFS_MAGIC_BW, "ufs"}, - { DRIVE_FIXED, UFS2_MAGIC, "ufs2"}, - { DRIVE_FIXED, UFS_CIGAM, "ufs"}, - { DRIVE_RAMDISK, USBDEVICE_SUPER_MAGIC, "usbdev"}, - { DRIVE_FIXED, XENIX_SUPER_MAGIC, "xenix"}, - { DRIVE_FIXED, XFS_SB_MAGIC, "xfs"}, - { DRIVE_RAMDISK, FUSE_SUPER_MAGIC, "fuse"}, - { DRIVE_FIXED, V9FS_MAGIC, "9p"}, - { DRIVE_REMOTE, CEPH_SUPER_MAGIC, "ceph"}, - { DRIVE_RAMDISK, CONFIGFS_MAGIC, "configfs"}, - { DRIVE_RAMDISK, ECRYPTFS_SUPER_MAGIC, "eCryptfs"}, - { DRIVE_FIXED, EXOFS_SUPER_MAGIC, "exofs"}, - { DRIVE_FIXED, VXFS_SUPER_MAGIC, "vxfs"}, - { DRIVE_FIXED, VXFS_OLT_MAGIC, "vxfs_olt"}, - { DRIVE_REMOTE, GFS2_MAGIC, "gfs2"}, - { DRIVE_FIXED, LOGFS_MAGIC_U32, "logfs"}, - { DRIVE_FIXED, OCFS2_SUPER_MAGIC, "ocfs2"}, - { DRIVE_FIXED, OMFS_MAGIC, "omfs"}, - { DRIVE_FIXED, UBIFS_SUPER_MAGIC, "ubifs"}, - { DRIVE_UNKNOWN, 0, NULL} -#else - { DRIVE_RAMDISK, "ramfs" }, - { DRIVE_RAMDISK, "tmpfs" }, - { DRIVE_RAMDISK, "proc" }, - { DRIVE_RAMDISK, "sysfs" }, - { DRIVE_RAMDISK, "debugfs" }, - { DRIVE_RAMDISK, "devpts" }, - { DRIVE_RAMDISK, "securityfs" }, - { DRIVE_RAMDISK, "procfs" }, // AIX procfs - { DRIVE_RAMDISK, "namefs" }, // AIX soft mounts - { DRIVE_RAMDISK, "nullfs" }, - { DRIVE_CDROM, "iso9660" }, - { DRIVE_CDROM, "cdrfs" }, // AIX ISO9660 CDs - { DRIVE_CDROM, "udfs" }, // AIX UDF CDs - { DRIVE_CDROM, "QOPT" }, // IBM i CD mount - { DRIVE_FIXED, "ext2" }, - { DRIVE_FIXED, "ext3" }, - { DRIVE_FIXED, "ext4" }, - { DRIVE_FIXED, "sysv" }, - { DRIVE_FIXED, "reiserfs" }, - { DRIVE_FIXED, "ufs" }, - { DRIVE_FIXED, "vfat" }, - { DRIVE_FIXED, "msdos" }, - { DRIVE_FIXED, "udf" }, - { DRIVE_FIXED, "hfs" }, - { DRIVE_FIXED, "hpfs" }, - { DRIVE_FIXED, "qnx4" }, - { DRIVE_FIXED, "ntfs" }, - { DRIVE_FIXED, "ntfs-3g" }, - { DRIVE_FIXED, "jfs" }, // IBM JFS - { DRIVE_FIXED, "jfs2" }, // IBM JFS (AIX defalt filesystem) - { DRIVE_FIXED, "EPFS" }, // IBM i IFS (root and QOpenSys) - { DRIVE_FIXED, "EPFSP" }, // IBM i auxiliary storage pool FS - { DRIVE_FIXED, "QSYS" }, // IBM i native system libraries - { DRIVE_FIXED, "QDLS" }, // IBM i legacy S/36 directories - { DRIVE_REMOTE, "smbfs" }, - { DRIVE_REMOTE, "fuse" }, - { DRIVE_REMOTE, "nfs" }, - { DRIVE_REMOTE, "nfs4" }, - { DRIVE_REMOTE, "cifs" }, - { DRIVE_REMOTE, "ncpfs" }, - { DRIVE_REMOTE, "coda" }, - { DRIVE_REMOTE, "afs" }, - { DRIVE_REMOTE, "nfs3" }, - { DRIVE_REMOTE, "stnfs" }, // AIX "short-term" NFS - { DRIVE_REMOTE, "autofs" }, // AIX automounter NFS - { DRIVE_REMOTE, "cachefs" }, // AIX cached NFS - { DRIVE_REMOTE, "NFS" }, // IBM i NFS - { DRIVE_REMOTE, "QNETC" }, // IBM i CIFS - { DRIVE_REMOTE, "QRFS" }, // IBM i native remote FS - { DRIVE_UNKNOWN, NULL } -#endif -}; -#if __linux__ -static guint32 _wapi_get_drive_type(unsigned f_type) +static gboolean +pipe_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) { - const _wapi_drive_type *current; - - current = &_wapi_drive_types[0]; - while (current->drive_type != DRIVE_UNKNOWN) { - if (current->fstypeid == f_type) - return current->drive_type; - current++; + gint ret; + MonoThreadInfo *info = mono_thread_info_current (); + + if(byteswritten!=NULL) { + *byteswritten=0; } + + if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - return DRIVE_UNKNOWN; -} -#else -static guint32 _wapi_get_drive_type(const gchar* fstype) -{ - const _wapi_drive_type *current; - - current = &_wapi_drive_types[0]; - while (current->drive_type != DRIVE_UNKNOWN) { - if (strcmp (current->fstype, fstype) == 0) - return current->drive_type; - - current++; + mono_w32error_set_last (ERROR_ACCESS_DENIED); + return(FALSE); } - return DRIVE_UNKNOWN; -} -#endif - -#if defined (HOST_DARWIN) || defined (__linux__) || defined (_AIX) -static guint32 -GetDriveTypeFromPath (const gchar *utf8_root_path_name) -{ -#if defined (_AIX) - struct statvfs buf; -#else - struct statfs buf; -#endif - gint res; - - MONO_ENTER_GC_SAFE; -#if defined (_AIX) - res = statvfs (utf8_root_path_name, &buf); -#else - res = statfs (utf8_root_path_name, &buf); -#endif - MONO_EXIT_GC_SAFE; - if (res == -1) - return DRIVE_UNKNOWN; -#if HOST_DARWIN - return _wapi_get_drive_type (buf.f_fstypename); -#elif defined (_AIX) - return _wapi_get_drive_type (buf.f_basetype); -#else - return _wapi_get_drive_type (buf.f_type); -#endif -} -#else -static guint32 -GetDriveTypeFromPath (const gchar *utf8_root_path_name) -{ - guint32 drive_type; - FILE *fp; - gchar buffer [512]; - gchar **splitted; + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: writing up to %" G_GUINT32_FORMAT " bytes to pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); - MONO_ENTER_GC_SAFE; - fp = fopen ("/etc/mtab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) { + do { MONO_ENTER_GC_SAFE; - fp = fopen ("/etc/mnttab", "rt"); + ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); MONO_EXIT_GC_SAFE; - if (fp == NULL) - return(DRIVE_UNKNOWN); - } + } while (ret == -1 && errno == EINTR && + !mono_thread_info_is_interrupt_state (info)); - drive_type = DRIVE_NO_ROOT_DIR; - while (1) { - gchar *fgets_res; - MONO_ENTER_GC_SAFE; - fgets_res = fgets (buffer, 512, fp); - MONO_EXIT_GC_SAFE; - if (fgets_res == NULL) - break; - splitted = g_strsplit (buffer, " ", 0); - if (!*splitted || !*(splitted + 1) || !*(splitted + 2)) { - g_strfreev (splitted); - continue; - } + if (ret == -1) { + if (errno == EINTR) { + ret = 0; + } else { + _wapi_set_last_error_from_errno (); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - /* compare given root_path_name with the one from mtab, - if length of utf8_root_path_name is zero it must be the root dir */ - if (strcmp (*(splitted + 1), utf8_root_path_name) == 0 || - (strcmp (*(splitted + 1), "/") == 0 && strlen (utf8_root_path_name) == 0)) { - drive_type = _wapi_get_drive_type (*(splitted + 2)); - /* it is possible this path might be mounted again with - a known type...keep looking */ - if (drive_type != DRIVE_UNKNOWN) { - g_strfreev (splitted); - break; - } + return(FALSE); } - - g_strfreev (splitted); - } - - MONO_ENTER_GC_SAFE; - fclose (fp); - MONO_EXIT_GC_SAFE; - return drive_type; -} -#endif - -#if defined (HOST_DARWIN) || defined (__linux__) || defined(HOST_BSD) || defined(__FreeBSD_kernel__) || defined(__HAIKU__) || defined(_AIX) -static gchar* -get_fstypename (gchar *utfpath) -{ -#if defined (_AIX) - /* statvfs offers the FS type name, easily, no need to iterate */ - struct statvfs stat; - gint statvfs_res; - - MONO_ENTER_GC_SAFE; - statvfs_res = statvfs (utfpath, &stat); - MONO_EXIT_GC_SAFE; - - if (statvfs_res != -1) { - return g_strdup (stat.f_basetype); } - - return NULL; -#elif defined (HOST_DARWIN) || defined (__linux__) - struct statfs stat; -#if __linux__ - const _wapi_drive_type *current; -#endif - gint statfs_res; - MONO_ENTER_GC_SAFE; - statfs_res = statfs (utfpath, &stat); - MONO_EXIT_GC_SAFE; - if (statfs_res == -1) - return NULL; -#if HOST_DARWIN - return g_strdup (stat.f_fstypename); -#else - current = &_wapi_drive_types[0]; - while (current->drive_type != DRIVE_UNKNOWN) { - if (stat.f_type == current->fstypeid) - return g_strdup (current->fstype); - current++; + if(byteswritten!=NULL) { + *byteswritten=ret; } - return NULL; -#endif -#else - return NULL; -#endif -} - -/* Linux has struct statfs which has a different layout */ -gboolean -mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize) -{ - gchar *utfpath; - gchar *fstypename; - gboolean status = FALSE; - glong len; - - // We only support getting the file system type - if (fsbuffer == NULL) - return 0; - utfpath = mono_unicode_to_external (path); - if ((fstypename = get_fstypename (utfpath)) != NULL){ - gunichar2 *ret = g_utf8_to_utf16 (fstypename, -1, NULL, &len, NULL); - if (ret != NULL && len < fsbuffersize){ - memcpy (fsbuffer, ret, len * sizeof (gunichar2)); - fsbuffer [len] = 0; - status = TRUE; - } - if (ret != NULL) - g_free (ret); - g_free (fstypename); - } - g_free (utfpath); - return status; + return(TRUE); } -#endif -static gboolean -LockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 length_low, guint32 length_high) +static gint convert_flags(guint32 fileaccess, guint32 createmode) { - FileHandle *filehandle; - gboolean ret; - off_t offset, length; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (((MonoFDHandle*) filehandle)->type != MONO_FDTYPE_FILE) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - - if (!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - mono_w32error_set_last (ERROR_ACCESS_DENIED); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - -#ifdef HAVE_LARGE_FILE_SUPPORT - offset = ((gint64)offset_high << 32) | offset_low; - length = ((gint64)length_high << 32) | length_low; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Locking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); -#else - if (offset_high > 0 || length_high > 0) { - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; + gint flags=0; + + switch(fileaccess) { + case GENERIC_READ: + flags=O_RDONLY; + break; + case GENERIC_WRITE: + flags=O_WRONLY; + break; + case GENERIC_READ|GENERIC_WRITE: + flags=O_RDWR; + break; + default: + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown access type 0x%" PRIx32, __func__, + fileaccess); + break; } - offset = offset_low; - length = length_low; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Locking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); -#endif - - ret = _wapi_lock_file_region (((MonoFDHandle*) filehandle)->fd, offset, length); - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; + switch(createmode) { + case CREATE_NEW: + flags|=O_CREAT|O_EXCL; + break; + case CREATE_ALWAYS: + flags|=O_CREAT|O_TRUNC; + break; + case OPEN_EXISTING: + break; + case OPEN_ALWAYS: + flags|=O_CREAT; + break; + case TRUNCATE_EXISTING: + flags|=O_TRUNC; + break; + default: + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown create mode 0x%" PRIx32, __func__, + createmode); + break; + } + + return(flags); } -static gboolean -UnlockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 length_low, guint32 length_high) +static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, + guint32 fileaccess, + FileShare **share_info) { - FileHandle *filehandle; - gboolean ret; - off_t offset, length; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } + gboolean file_already_shared; + guint32 file_existing_share, file_existing_access; - if (((MonoFDHandle*) filehandle)->type != MONO_FDTYPE_FILE) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } + file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, sharemode, fileaccess, &file_existing_share, &file_existing_access, share_info); + + if (file_already_shared) { + /* The reference to this share info was incremented + * when we looked it up, so be careful to put it back + * if we conclude we can't use this file. + */ + if ((file_existing_share == FILE_SHARE_NONE) || (sharemode == FILE_SHARE_NONE)) { + /* Quick and easy, no possibility to share */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, fileaccess); - if (!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - mono_w32error_set_last (ERROR_ACCESS_DENIED); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } + file_share_release (*share_info); + *share_info = NULL; + + return(FALSE); + } -#ifdef HAVE_LARGE_FILE_SUPPORT - offset = ((gint64)offset_high << 32) | offset_low; - length = ((gint64)length_high << 32) | length_low; -#else - offset = offset_low; - length = length_low; -#endif - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unlocking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); + if (((file_existing_share == FILE_SHARE_READ) && + (fileaccess != GENERIC_READ)) || + ((file_existing_share == FILE_SHARE_WRITE) && + (fileaccess != GENERIC_WRITE))) { + /* New access mode doesn't match up */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, fileaccess, file_existing_share); - ret = _wapi_unlock_file_region (((MonoFDHandle*) filehandle)->fd, offset, length); + file_share_release (*share_info); + *share_info = NULL; + + return(FALSE); + } + } else { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: New file!", __func__); + } - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; + return(TRUE); } void @@ -4904,15 +719,6 @@ mono_w32file_init (void) mono_coop_mutex_init (&file_share_mutex); - finds = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, finds_remove); - mono_coop_mutex_init (&finds_mutex); - -#if HOST_DARWIN - libc_handle = mono_dl_open ("/usr/lib/libc.dylib", 0, NULL); - g_assert (libc_handle); - g_free (mono_dl_symbol (libc_handle, "clonefile", (void**)&clonefile_ptr)); -#endif - if (g_hasenv ("MONO_STRICT_IO_EMULATION")) lock_while_writing = TRUE; } @@ -4924,99 +730,211 @@ mono_w32file_cleanup (void) if (file_share_table) g_hash_table_destroy (file_share_table); - - g_hash_table_destroy (finds); - mono_coop_mutex_destroy (&finds_mutex); - -#if HOST_DARWIN - mono_dl_close (libc_handle); -#endif } -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error) +gpointer +mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs) { - gboolean result; + FileHandle *filehandle; + MonoFDType type; + gint flags=convert_flags(fileaccess, createmode); + /*mode_t perms=convert_perms(sharemode);*/ + /* we don't use sharemode, because that relates to sharing of + * the file when the file is open and is already handled by + * other code, perms instead are the on-disk permissions and + * this is a sane default. + */ + mode_t perms=0666; + gchar *filename; + gint fd, ret; + struct stat statbuf; + ERROR_DECL (error); - result = MoveFile (path, dest); - if (!result) - *error = mono_w32error_get_last (); - return result; -} + if (attrs & FILE_ATTRIBUTE_TEMPORARY) + perms = 0600; + + if (attrs & FILE_ATTRIBUTE_ENCRYPTED){ + mono_w32error_set_last (ERROR_ENCRYPTION_FAILED); + return INVALID_HANDLE_VALUE; + } + + if (name == NULL) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error) -{ - gboolean result; + mono_w32error_set_last (ERROR_INVALID_NAME); + return(INVALID_HANDLE_VALUE); + } - result = CopyFile (path, dest, !overwrite); - if (!result) - *error = mono_w32error_get_last (); + filename = mono_unicode_to_external_checked (name, error); + if (filename == NULL) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - return result; -} + mono_error_cleanup (error); + mono_w32error_set_last (ERROR_INVALID_NAME); + return(INVALID_HANDLE_VALUE); + } + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Opening %s with share 0x%" PRIx32 " and access 0x%" PRIx32, __func__, + filename, sharemode, fileaccess); + + fd = _wapi_open (filename, flags, perms); + + /* If we were trying to open a directory with write permissions + * (e.g. O_WRONLY or O_RDWR), this call will fail with + * EISDIR. However, this is a bit bogus because calls to + * manipulate the directory (e.g. mono_w32file_set_times) will still work on + * the directory because they use other API calls + * (e.g. utime()). Hence, if we failed with the EISDIR error, try + * to open the directory again without write permission. + */ + if (fd == -1 && errno == EISDIR) + { + /* Try again but don't try to make it writable */ + fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms); + } + + if (fd == -1) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error opening file %s: %s", __func__, filename, g_strerror(errno)); + _wapi_set_last_path_error_from_errno (NULL, filename); + g_free (filename); -gboolean -mono_w32file_replace (const gunichar2 *destination_file_name, const gunichar2 *source_file_name, const gunichar2 *destination_backup_file_name, guint32 flags, gint32 *error) -{ - gboolean result; + return(INVALID_HANDLE_VALUE); + } - result = ReplaceFile (destination_file_name, source_file_name, destination_backup_file_name, flags, NULL, NULL); - if (!result) - *error = mono_w32error_get_last (); - return result; -} + MONO_ENTER_GC_SAFE; + ret = fstat (fd, &statbuf); + MONO_EXIT_GC_SAFE; + if (ret == -1) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fstat error of file %s: %s", __func__, filename, g_strerror (errno)); + _wapi_set_last_error_from_errno (); + MONO_ENTER_GC_SAFE; + close (fd); + MONO_EXIT_GC_SAFE; -gint64 -mono_w32file_get_file_size (gpointer handle, gint32 *error) -{ - gint64 length; - guint32 length_hi = 0; + return(INVALID_HANDLE_VALUE); + } - length = GetFileSize (handle, &length_hi); - if(length==INVALID_FILE_SIZE) { - *error=mono_w32error_get_last (); +#ifndef S_ISFIFO +#define S_ISFIFO(m) ((m & S_IFIFO) != 0) +#endif + if (S_ISFIFO (statbuf.st_mode)) { + type = MONO_FDTYPE_PIPE; + /* maintain invariant that pipes have no filename */ + g_free (filename); + filename = NULL; + } else if (S_ISCHR (statbuf.st_mode)) { + type = MONO_FDTYPE_CONSOLE; + } else { + type = MONO_FDTYPE_FILE; } - return length | ((gint64)length_hi << 32); -} + filehandle = file_data_create (type, fd); + filehandle->filename = filename; + filehandle->fileaccess = fileaccess; + filehandle->sharemode = sharemode; + filehandle->attrs = attrs; -gboolean -mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - gboolean result; + if (!share_allows_open (&statbuf, filehandle->sharemode, filehandle->fileaccess, &filehandle->share_info)) { + mono_w32error_set_last (ERROR_SHARING_VIOLATION); + MONO_ENTER_GC_SAFE; + close (((MonoFDHandle*) filehandle)->fd); + MONO_EXIT_GC_SAFE; + + mono_fdhandle_unref ((MonoFDHandle*) filehandle); + return (INVALID_HANDLE_VALUE); + } + if (!filehandle->share_info) { + /* No space, so no more files can be opened */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: No space in the share table", __func__); + + mono_w32error_set_last (ERROR_TOO_MANY_OPEN_FILES); + MONO_ENTER_GC_SAFE; + close (((MonoFDHandle*) filehandle)->fd); + MONO_EXIT_GC_SAFE; + + mono_fdhandle_unref ((MonoFDHandle*) filehandle); + return(INVALID_HANDLE_VALUE); + } + +#ifdef HAVE_POSIX_FADVISE + if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) { + MONO_ENTER_GC_SAFE; + posix_fadvise (((MonoFDHandle*) filehandle)->fd, 0, 0, POSIX_FADV_SEQUENTIAL); + MONO_EXIT_GC_SAFE; + } + if (attrs & FILE_FLAG_RANDOM_ACCESS) { + MONO_ENTER_GC_SAFE; + posix_fadvise (((MonoFDHandle*) filehandle)->fd, 0, 0, POSIX_FADV_RANDOM); + MONO_EXIT_GC_SAFE; + } +#endif + +#ifdef F_RDAHEAD + if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) { + MONO_ENTER_GC_SAFE; + fcntl(((MonoFDHandle*) filehandle)->fd, F_RDAHEAD, 1); + MONO_EXIT_GC_SAFE; + } +#endif - result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32); - if (!result) - *error = mono_w32error_get_last (); - return result; + mono_fdhandle_insert ((MonoFDHandle*) filehandle); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); + + return GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd); } + gboolean -mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error) +mono_w32file_close (gpointer handle) { - gboolean result; + if (!mono_fdhandle_close (GPOINTER_TO_INT (handle))) { + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } - result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32); - if (!result) - *error = mono_w32error_get_last (); - return result; + return TRUE; } -gpointer -mono_w32file_get_console_input (void) +static gboolean +mono_w32file_read_or_write (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error) { - return mono_w32file_get_std_handle (STD_INPUT_HANDLE); -} + MONO_REQ_GC_UNSAFE_MODE; -gpointer -mono_w32file_get_console_output (void) -{ - return mono_w32file_get_std_handle (STD_OUTPUT_HANDLE); + FileHandle *filehandle; + gboolean ret = FALSE; + + gboolean const ref = mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle); + if (!ref) { + mono_w32error_set_last (ERROR_INVALID_HANDLE); + goto exit; + } + + switch (((MonoFDHandle*) filehandle)->type) { + case MONO_FDTYPE_FILE: + ret = (file_write) (filehandle, buffer, numbytes, bytesread); + break; + case MONO_FDTYPE_CONSOLE: + ret = (console_write) (filehandle, buffer, numbytes, bytesread); + break; + case MONO_FDTYPE_PIPE: + ret = (pipe_write) (filehandle, buffer, numbytes, bytesread); + break; + default: + mono_w32error_set_last (ERROR_INVALID_HANDLE); + break; + } + +exit: + if (ref) + mono_fdhandle_unref ((MonoFDHandle*) filehandle); + if (!ret) + *win32error = mono_w32error_get_last (); + return ret; } -gpointer -mono_w32file_get_console_error (void) +gboolean +mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) { - return mono_w32file_get_std_handle (STD_ERROR_HANDLE); + return mono_w32file_read_or_write (handle, (gpointer)buffer, numbytes, byteswritten, win32error); } diff --git a/src/mono/mono/metadata/w32file-win32.c b/src/mono/mono/metadata/w32file-win32.c index ab6efc56f6a6fe..124b2bbbd5f6f6 100644 --- a/src/mono/mono/metadata/w32file-win32.c +++ b/src/mono/mono/metadata/w32file-win32.c @@ -23,35 +23,6 @@ mono_w32file_cleanup (void) { } -gunichar2 -ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar () -{ - return (gunichar2) ':'; /* colon */ -} - -gunichar2 -ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar () -{ - return (gunichar2) '\\'; /* backslash */ -} - -gunichar2 -ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar () -{ - return (gunichar2) '/'; /* forward slash */ -} - -gunichar2 -ves_icall_System_IO_MonoIO_get_PathSeparator () -{ - return (gunichar2) ';'; /* semicolon */ -} - -void ves_icall_System_IO_MonoIO_DumpHandles (void) -{ - return; -} - gpointer mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs) { @@ -62,12 +33,6 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode return res; } -gboolean -mono_w32file_cancel (gpointer handle) -{ - return CancelIoEx (handle, NULL); -} - gboolean mono_w32file_close (gpointer handle) { @@ -78,58 +43,11 @@ mono_w32file_close (gpointer handle) return res; } -gboolean -mono_w32file_delete (const gunichar2 *name) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = DeleteFileW (name); - MONO_EXIT_GC_SAFE; - return res; -} - -// See win32_wait_interrupt_handler for details. static void win32_io_interrupt_handler (gpointer ignored) { } -gboolean -mono_w32file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error) -{ - gboolean res; - MonoThreadInfo *info = mono_thread_info_current (); - gboolean alerted = FALSE; - - if (info) { - mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted); - if (alerted) { - SetLastError (ERROR_OPERATION_ABORTED); - *win32error = ERROR_OPERATION_ABORTED; - return FALSE; - } - mono_win32_enter_blocking_io_call (info, handle); - } - - MONO_ENTER_GC_SAFE; - if (info && mono_thread_info_is_interrupt_state (info)) { - res = FALSE; - SetLastError (ERROR_OPERATION_ABORTED); - } else { - res = ReadFile (handle, buffer, numbytes, (PDWORD)bytesread, NULL); - } - if (!res) - *win32error = GetLastError (); - MONO_EXIT_GC_SAFE; - - if (info) { - mono_win32_leave_blocking_io_call (info, handle); - mono_thread_info_uninstall_interrupt (&alerted); - } - - return res; -} - gboolean mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) { @@ -165,552 +83,3 @@ mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, gui return res; } - -gboolean -mono_w32file_flush (gpointer handle) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = FlushFileBuffers (handle); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_truncate (gpointer 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) -{ - guint32 res; - MONO_ENTER_GC_SAFE; - res = SetFilePointer (handle, movedistance, (PLONG)highmovedistance, method); - MONO_EXIT_GC_SAFE; - return res; -} - -gint -mono_w32file_get_type (gpointer handle) -{ - gint res; - MONO_ENTER_GC_SAFE; - res = GetFileType (handle); - 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) -{ - 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) -{ - 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_DATAW *find_data) -{ - gpointer res; - MONO_ENTER_GC_SAFE; - res = FindFirstFileW (pattern, find_data); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_find_next (gpointer handle, WIN32_FIND_DATAW *find_data) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = FindNextFileW (handle, find_data); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_find_close (gpointer handle) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = FindClose (handle); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_create_directory (const gunichar2 *name) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = CreateDirectoryW (name, NULL); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_remove_directory (const gunichar2 *name) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = RemoveDirectoryW (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) -{ - guint32 res; - HANDLE find_handle; - WIN32_FIND_DATAW find_data; - - MONO_ENTER_GC_SAFE; - - res = GetFileAttributesW (name); - if (res == INVALID_FILE_ATTRIBUTES && GetLastError () == ERROR_SHARING_VIOLATION) { - find_handle = FindFirstFileW (name, &find_data); - if (find_handle != INVALID_HANDLE_VALUE) { - FindClose (find_handle); - res = find_data.dwFileAttributes; - } else { - res = INVALID_FILE_ATTRIBUTES; - } - } - - MONO_EXIT_GC_SAFE; - - return res; -} - -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 res; - HANDLE find_handle; - WIN32_FIND_DATAW find_data; - WIN32_FILE_ATTRIBUTE_DATA file_attribute_data; - - MONO_ENTER_GC_SAFE; - - res = GetFileAttributesExW (name, GetFileExInfoStandard, &file_attribute_data); - 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; - } else if (!res && GetLastError () == ERROR_SHARING_VIOLATION) { - find_handle = FindFirstFileW (name, &find_data); - if (find_handle != INVALID_HANDLE_VALUE) { - FindClose (find_handle); - 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; - res = TRUE; - } - } - - MONO_EXIT_GC_SAFE; - - return res; -} - -gboolean -mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = SetFileAttributesW (name, attrs); - MONO_EXIT_GC_SAFE; - return res; -} - -guint32 -mono_w32file_get_cwd (guint32 length, gunichar2 *buffer) -{ - guint32 res; - MONO_ENTER_GC_SAFE; - res = GetCurrentDirectoryW (length, buffer); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_set_cwd (const gunichar2 *path) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = SetCurrentDirectoryW (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; - MONO_ENTER_GC_SAFE; - res = CreatePipe (readpipe, writepipe, &attr, size); - MONO_EXIT_GC_SAFE; - return res; -} - -#ifndef PLATFORM_NO_DRIVEINFO -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 = { 0 }; - ULARGE_INTEGER wapi_total_number_of_bytes = { 0 }; - ULARGE_INTEGER wapi_total_number_of_free_bytes = { 0 }; - - g_assert (free_bytes_avail); - g_assert (total_number_of_bytes); - g_assert (total_number_of_free_bytes); - - MONO_ENTER_GC_SAFE; - result = GetDiskFreeSpaceExW (path_name, &wapi_free_bytes_avail, &wapi_total_number_of_bytes, &wapi_total_number_of_free_bytes); - MONO_EXIT_GC_SAFE; - - *free_bytes_avail = wapi_free_bytes_avail.QuadPart; - *total_number_of_bytes = wapi_total_number_of_bytes.QuadPart; - *total_number_of_free_bytes = wapi_total_number_of_free_bytes.QuadPart; - - return result; -} -#endif // PLATFORM_NO_DRIVEINFO - -gboolean -mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = GetVolumeInformationW (path, NULL, 0, NULL, NULL, NULL, fsbuffer, fsbuffersize); - MONO_EXIT_GC_SAFE; - return res; -} - -#if HAVE_API_SUPPORT_WIN32_MOVE_FILE -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error) -{ - gboolean result = FALSE; - MONO_ENTER_GC_SAFE; - - result = MoveFileW (path, dest); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - return result; -} -#elif HAVE_API_SUPPORT_WIN32_MOVE_FILE_EX -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error) -{ - gboolean result = FALSE; - MONO_ENTER_GC_SAFE; - - result = MoveFileExW (path, dest, MOVEFILE_COPY_ALLOWED); - if (!result) { - *error = GetLastError (); - } - - MONO_EXIT_GC_SAFE; - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_MOVE_FILE && !HAVE_EXTERN_DEFINED_WIN32_MOVE_FILE_EX -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error) -{ - g_unsupported_api ("MoveFile, MoveFileEx"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_REPLACE_FILE -gboolean -mono_w32file_replace (const gunichar2 *destination_file_name, const gunichar2 *source_file_name, const gunichar2 *destination_backup_file_name, guint32 flags, gint32 *error) -{ - gboolean result = FALSE; - MONO_ENTER_GC_SAFE; - - result = ReplaceFileW (destination_file_name, source_file_name, destination_backup_file_name, flags, NULL, NULL); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_REPLACE_FILE -gboolean -mono_w32file_replace (const gunichar2 *destination_file_name, const gunichar2 *source_file_name, const gunichar2 *destination_backup_file_name, guint32 flags, gint32 *error) -{ - g_unsupported_api ("ReplaceFile"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_COPY_FILE - -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error) -{ - gboolean result = FALSE; - MONO_ENTER_GC_SAFE; - - result = CopyFileW (path, dest, !overwrite); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - return result; -} -#elif HAVE_API_SUPPORT_WIN32_COPY_FILE2 -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error) -{ - gboolean result = FALSE; - COPYFILE2_EXTENDED_PARAMETERS copy_param = {0}; - - copy_param.dwSize = sizeof (COPYFILE2_EXTENDED_PARAMETERS); - copy_param.dwCopyFlags = (!overwrite) ? COPY_FILE_FAIL_IF_EXISTS : 0; - - MONO_ENTER_GC_SAFE; - - result = SUCCEEDED (CopyFile2 (path, dest, ©_param)); - if (result == FALSE) { - *error=GetLastError (); - } - - MONO_EXIT_GC_SAFE; - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_COPY_FILE && !HAVE_EXTERN_DEFINED_WIN32_COPY_FILE2 -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error) -{ - g_unsupported_api ("CopyFile, CopyFile2"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_LOCK_FILE -gboolean -mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - gboolean result; - - MONO_ENTER_GC_SAFE; - - result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_LOCK_FILE -gboolean -mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - g_unsupported_api ("LockFile"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_UNLOCK_FILE -gboolean -mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - gboolean result; - - MONO_ENTER_GC_SAFE; - - result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_UNLOCK_FILE -gboolean -mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - g_unsupported_api ("UnlockFile"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE -gpointer -mono_w32file_get_console_input (void) -{ - HANDLE res; - MONO_ENTER_GC_SAFE; - res = GetStdHandle (STD_INPUT_HANDLE); - MONO_EXIT_GC_SAFE; - return res; -} - -gpointer -mono_w32file_get_console_output (void) -{ - HANDLE res; - MONO_ENTER_GC_SAFE; - res = GetStdHandle (STD_OUTPUT_HANDLE); - MONO_EXIT_GC_SAFE; - return res; -} - -gpointer -mono_w32file_get_console_error (void) -{ - HANDLE res; - MONO_ENTER_GC_SAFE; - res = GetStdHandle (STD_ERROR_HANDLE); - MONO_EXIT_GC_SAFE; - return res; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_GET_STD_HANDLE -gpointer -mono_w32file_get_console_input (void) -{ - g_unsupported_api ("GetStdHandle (STD_INPUT_HANDLE)"); - SetLastError (ERROR_NOT_SUPPORTED); - return INVALID_HANDLE_VALUE; -} - -gpointer -mono_w32file_get_console_output (void) -{ - g_unsupported_api ("GetStdHandle (STD_OUTPUT_HANDLE)"); - SetLastError (ERROR_NOT_SUPPORTED); - return INVALID_HANDLE_VALUE; -} - -gpointer -mono_w32file_get_console_error (void) -{ - g_unsupported_api ("GetStdHandle (STD_ERROR_HANDLE)"); - SetLastError (ERROR_NOT_SUPPORTED); - return INVALID_HANDLE_VALUE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX -gint64 -mono_w32file_get_file_size (HANDLE handle, gint32 *error) -{ - LARGE_INTEGER length; - - MONO_ENTER_GC_SAFE; - - if (!GetFileSizeEx (handle, &length)) { - *error=GetLastError (); - length.QuadPart = INVALID_FILE_SIZE; - } - - MONO_EXIT_GC_SAFE; - return length.QuadPart; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_GET_FILE_SIZE_EX -gint64 -mono_w32file_get_file_size (HANDLE handle, gint32 *error) -{ - g_unsupported_api ("GetFileSizeEx"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return 0; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_GET_DRIVE_TYPE -guint32 -mono_w32file_get_drive_type (const gunichar2 *root_path_name, gint32 root_path_name_length, MonoError *error) -{ - guint32 res; - MONO_ENTER_GC_SAFE; - res = GetDriveTypeW (root_path_name); - MONO_EXIT_GC_SAFE; - return res; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_GET_DRIVE_TYPE -guint32 -mono_w32file_get_drive_type (const gunichar2 *root_path_name, gint32 root_path_name_length, MonoError *error) -{ - g_unsupported_api ("GetDriveType"); - mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetDriveType"); - SetLastError (ERROR_NOT_SUPPORTED); - return DRIVE_UNKNOWN; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_GET_LOGICAL_DRIVE_STRINGS -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - gint32 res; - MONO_ENTER_GC_SAFE; - res = GetLogicalDriveStringsW (len, buf); - MONO_EXIT_GC_SAFE; - return res; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_GET_LOGICAL_DRIVE_STRINGS -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - g_unsupported_api ("GetLogicalDriveStrings"); - mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetLogicalDriveStrings"); - SetLastError (ERROR_NOT_SUPPORTED); - return 0; -} -#endif diff --git a/src/mono/mono/metadata/w32file.h b/src/mono/mono/metadata/w32file.h index c69554fe4db325..26bc897e5d0620 100644 --- a/src/mono/mono/metadata/w32file.h +++ b/src/mono/mono/metadata/w32file.h @@ -21,60 +21,6 @@ #include #include -/* This is a copy of System.IO.FileAccess */ -typedef enum { - FileAccess_Read=0x01, - FileAccess_Write=0x02, - FileAccess_ReadWrite=FileAccess_Read|FileAccess_Write -} MonoFileAccess; - -/* This is a copy of System.IO.FileMode */ -typedef enum { - FileMode_CreateNew=1, - FileMode_Create=2, - FileMode_Open=3, - FileMode_OpenOrCreate=4, - FileMode_Truncate=5, - FileMode_Append=6 -} MonoFileMode; - -/* This is a copy of System.IO.FileShare */ -typedef enum { - FileShare_None=0x0, - FileShare_Read=0x01, - FileShare_Write=0x02, - FileShare_ReadWrite=FileShare_Read|FileShare_Write, - FileShare_Delete=0x04 -} MonoFileShare; - -/* This is a copy of System.IO.FileOptions */ -typedef enum { - FileOptions_None = 0, - FileOptions_Temporary = 1, // Internal. See note in System.IO.FileOptions - FileOptions_Encrypted = 0x4000, - FileOptions_DeleteOnClose = 0x4000000, - FileOptions_SequentialScan = 0x8000000, - FileOptions_RandomAccess = 0x10000000, - FileOptions_Asynchronous = 0x40000000, - FileOptions_WriteThrough = 0x80000000 -} MonoFileOptions; - -/* This is a copy of System.IO.SeekOrigin */ -typedef enum { - SeekOrigin_Begin=0, - SeekOrigin_Current=1, - SeekOrigin_End=2 -} MonoSeekOrigin; - -/* This is a copy of System.IO.MonoIOStat */ -typedef struct _MonoIOStat { - gint32 attributes; - gint64 length; - gint64 creation_time; - gint64 last_access_time; - gint64 last_write_time; -} MonoIOStat; - /* This is a copy of System.IO.FileAttributes */ typedef enum { FileAttributes_ReadOnly=0x00001, @@ -93,25 +39,6 @@ typedef enum { FileAttributes_Encrypted=0x04000, FileAttributes_MonoExecutable= (int) 0x80000000 } MonoFileAttributes; -/* This is not used anymore -typedef struct _MonoFSAsyncResult { - MonoObject obj; - MonoObject *state; - MonoBoolean completed; - MonoBoolean done; - MonoException *exc; - MonoWaitHandle *wait_handle; - MonoDelegate *async_callback; - MonoBoolean completed_synch; - MonoArray *buffer; - gint offset; - gint count; - gint original_count; - gint bytes_read; - MonoDelegate *real_cb; -} MonoFSAsyncResult; -*/ -/* System.IO.MonoIO */ #if defined (TARGET_IOS) || defined (TARGET_ANDROID) @@ -213,19 +140,6 @@ typedef struct { #endif } FILETIME; -typedef struct { - guint32 dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - guint32 nFileSizeHigh; - guint32 nFileSizeLow; - guint32 dwReserved0; - guint32 dwReserved1; - gunichar2 cFileName [MAX_PATH]; - gunichar2 cAlternateFileName [14]; -} WIN32_FIND_DATA; - #endif /* !defined(HOST_WIN32) */ void @@ -237,111 +151,10 @@ mono_w32file_cleanup (void); gpointer mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs); -gboolean -mono_w32file_cancel (gpointer handle); - gboolean mono_w32file_close (gpointer handle); -gboolean -mono_w32file_delete (const gunichar2 *name); - -gboolean -mono_w32file_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error); - gboolean mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error); -gboolean -mono_w32file_flush (gpointer handle); - -gboolean -mono_w32file_truncate (gpointer handle); - -guint32 -mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method); - -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error); - -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error); - -gboolean -mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error); - -gboolean -mono_w32file_replace (const gunichar2 *destination_file_name, const gunichar2 *source_file_name, const gunichar2 *destination_backup_file_name, guint32 flags, gint32 *error); - -gboolean -mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error); - -gpointer -mono_w32file_get_console_output (void); - -gpointer -mono_w32file_get_console_error (void); - -gpointer -mono_w32file_get_console_input (void); - -gint64 -mono_w32file_get_file_size (gpointer handle, gint32 *error); - -gint -mono_w32file_get_type (gpointer handle); - -gboolean -mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time); - -gboolean -mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time); - -gpointer -mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data); - -gboolean -mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data); - -gboolean -mono_w32file_find_close (gpointer handle); - -gboolean -mono_w32file_create_directory (const gunichar2 *name); - -gboolean -mono_w32file_remove_directory (const gunichar2 *name); - -guint32 -mono_w32file_get_attributes (const gunichar2 *name); - -gboolean -mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat); - -gboolean -mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs); - -guint32 -mono_w32file_get_cwd (guint32 length, gunichar2 *buffer); - -gboolean -mono_w32file_set_cwd (const gunichar2 *path); - -gboolean -mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size); - -guint32 -mono_w32file_get_drive_type (const gunichar2 *root_path_name, gint32 root_path_name_length, MonoError *error); - -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error); - -#ifndef PLATFORM_NO_DRIVEINFO -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); -#endif // PLATFORM_NO_DRIVEINFO - -gboolean -mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize); - #endif /* _MONO_METADATA_W32FILE_H_ */ diff --git a/src/mono/mono/metadata/w32handle-namespace.c b/src/mono/mono/metadata/w32handle-namespace.c index c141b28909fd63..490ea43eca5bca 100644 --- a/src/mono/mono/metadata/w32handle-namespace.c +++ b/src/mono/mono/metadata/w32handle-namespace.c @@ -14,8 +14,6 @@ #include "w32handle-namespace.h" -#include "w32mutex.h" -#include "w32semaphore.h" #include "w32event.h" #include "mono/utils/mono-logger-internals.h" #include "mono/utils/mono-coop-mutex.h" @@ -44,8 +42,6 @@ static gboolean has_namespace (MonoW32Type type) { switch (type) { - case MONO_W32TYPE_NAMEDMUTEX: - case MONO_W32TYPE_NAMEDSEM: case MONO_W32TYPE_NAMEDEVENT: return TRUE; default: @@ -71,8 +67,6 @@ mono_w32handle_namespace_search_handle_callback (MonoW32Handle *handle_data, gpo search_data = (NamespaceSearchHandleData*) user_data; switch (handle_data->type) { - case MONO_W32TYPE_NAMEDMUTEX: sharedns = mono_w32mutex_get_namespace ((MonoW32HandleNamedMutex*) handle_data->specific); break; - case MONO_W32TYPE_NAMEDSEM: sharedns = mono_w32semaphore_get_namespace ((MonoW32HandleNamedSemaphore*) handle_data->specific); break; case MONO_W32TYPE_NAMEDEVENT: sharedns = mono_w32event_get_namespace ((MonoW32HandleNamedEvent*) handle_data->specific); break; default: g_assert_not_reached (); diff --git a/src/mono/mono/metadata/w32handle.c b/src/mono/mono/metadata/w32handle.c index 6de478863912b7..0aa023141ad585 100644 --- a/src/mono/mono/metadata/w32handle.c +++ b/src/mono/mono/metadata/w32handle.c @@ -133,12 +133,6 @@ mono_w32handle_lock (MonoW32Handle *handle_data) mono_coop_mutex_lock (&handle_data->signal_mutex); } -gboolean -mono_w32handle_trylock (MonoW32Handle *handle_data) -{ - return mono_coop_mutex_trylock (&handle_data->signal_mutex) == 0; -} - void mono_w32handle_unlock (MonoW32Handle *handle_data) { @@ -583,53 +577,6 @@ mono_w32handle_ops_prewait (MonoW32Handle *handle_data) handle_ops [handle_data->type]->prewait (handle_data); } -static void -mono_w32handle_lock_handles (MonoW32Handle **handles_data, gsize nhandles) -{ - gint i, j, iter = 0; -#ifndef HOST_WIN32 - struct timespec sleepytime; -#endif - - /* Lock all the handles, with backoff */ -again: - for (i = 0; i < nhandles; i++) { - if (!handles_data [i]) - continue; - if (!mono_w32handle_trylock (handles_data [i])) { - - for (j = i - 1; j >= 0; j--) { - if (!handles_data [j]) - continue; - mono_w32handle_unlock (handles_data [j]); - } - - iter += 10; - if (iter == 1000) - iter = 10; - - MONO_ENTER_GC_SAFE; -#ifdef HOST_WIN32 - SleepEx (iter, TRUE); -#else - /* If iter ever reaches 1000 the nanosleep will - * return EINVAL immediately, but we have a - * design flaw if that happens. */ - g_assert (iter < 1000); - - sleepytime.tv_sec = 0; - sleepytime.tv_nsec = iter * 1000000; - nanosleep (&sleepytime, NULL); -#endif /* HOST_WIN32 */ - MONO_EXIT_GC_SAFE; - - goto again; - } - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: Locked all handles", __func__); -} - static void mono_w32handle_unlock_handles (MonoW32Handle **handles_data, gsize nhandles) { @@ -776,22 +723,6 @@ mono_w32handle_timedwait_signal_handle (MonoW32Handle *handle_data, guint32 time return res; } -static gboolean -dump_callback (MonoW32Handle *handle_data, gpointer user_data) -{ - g_print ("%p [%7s] signalled: %5s ref: %3d ", - handle_data, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref - 1 /* foreach increase ref by 1 */); - mono_w32handle_ops_details (handle_data); - g_print ("\n"); - - return FALSE; -} - -void mono_w32handle_dump (void) -{ - mono_w32handle_foreach (dump_callback, NULL); -} - static gboolean own_if_signalled (MonoW32Handle *handle_data, gboolean *abandoned) { @@ -814,34 +745,6 @@ own_if_owned (MonoW32Handle *handle_data, gboolean *abandoned) return TRUE; } -gboolean -mono_w32handle_handle_is_signalled (gpointer handle) -{ - MonoW32Handle *handle_data; - gboolean res; - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - return FALSE; - - res = mono_w32handle_issignalled (handle_data); - mono_w32handle_unref (handle_data); - return res; -} - -gboolean -mono_w32handle_handle_is_owned (gpointer handle) -{ - MonoW32Handle *handle_data; - gboolean res; - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - return FALSE; - - res = mono_w32handle_ops_isowned (handle_data); - mono_w32handle_unref (handle_data); - return res; -} - #ifdef HOST_WIN32 MonoW32HandleWaitRet mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) @@ -1001,327 +904,3 @@ mono_w32handle_check_duplicates (MonoW32Handle *handles [ ], gsize nhandles, gbo mono_w32handle_clear_duplicates (handles, nhandles); } - -#ifdef HOST_WIN32 -MonoW32HandleWaitRet -mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable, MonoError *error) -{ - DWORD const wait_result = (nhandles != 1) - ? mono_coop_win32_wait_for_multiple_objects_ex (nhandles, handles, waitall, timeout, alertable, error) - : mono_coop_win32_wait_for_single_object_ex (handles [0], timeout, alertable); - return mono_w32handle_convert_wait_ret (wait_result, nhandles); -} -#else -MonoW32HandleWaitRet -mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable, MonoError *error) -{ - MonoW32HandleWaitRet ret; - gboolean alerted, poll; - gint i; - gint64 start = 0; - MonoW32Handle *handles_data [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; - gboolean abandoned [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0}; - - if (nhandles == 0) - return MONO_W32HANDLE_WAIT_RET_FAILED; - - if (nhandles == 1) - return mono_w32handle_wait_one (handles [0], timeout, alertable); - - alerted = FALSE; - - if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: too many handles: %" G_GSIZE_FORMAT "d", - __func__, nhandles); - - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - for (i = 0; i < nhandles; ++i) { - if (!mono_w32handle_lookup_and_ref (handles [i], &handles_data [i])) { - for (; i >= 0; --i) - mono_w32handle_unref (handles_data [i]); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - } - - for (i = 0; i < nhandles; ++i) { - if (!mono_w32handle_test_capabilities (handles_data[i], MONO_W32HANDLE_CAP_WAIT) - && !mono_w32handle_test_capabilities (handles_data[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)) - { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p can't be waited for", __func__, handles_data [i]); - - ret = MONO_W32HANDLE_WAIT_RET_FAILED; - goto done; - } - } - - mono_w32handle_check_duplicates (handles_data, nhandles, waitall, error); - if (!is_ok (error)) { - ret = MONO_W32HANDLE_WAIT_RET_FAILED; - goto done; - } - - poll = FALSE; - for (i = 0; i < nhandles; ++i) { - if (!handles_data [i]) - continue; - if (handles_data [i]->type == MONO_W32TYPE_PROCESS) { - /* Can't wait for a process handle + another handle without polling */ - poll = TRUE; - } - } - - if (timeout != MONO_INFINITE_WAIT) - start = mono_msec_ticks (); - - for (;;) { - gsize count, lowest; - gboolean signalled; - gint waited; - - count = 0; - lowest = nhandles; - - mono_w32handle_lock_handles (handles_data, nhandles); - - for (i = 0; i < nhandles; i++) { - if (!handles_data [i]) - continue; - if ((mono_w32handle_test_capabilities (handles_data [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles_data [i])) - || mono_w32handle_issignalled (handles_data [i])) - { - count ++; - - if (i < lowest) - lowest = i; - } - } - - signalled = (waitall && count == nhandles) || (!waitall && count > 0); - - if (signalled) { - for (i = 0; i < nhandles; i++) { - if (!handles_data [i]) - continue; - if (own_if_signalled (handles_data [i], &abandoned [i]) && !waitall) { - /* if we are calling WaitHandle.WaitAny, .NET only owns the first one; it matters for Mutex which - * throw AbandonedMutexException in case we owned it but didn't release it */ - break; - } - } - } - - mono_w32handle_unlock_handles (handles_data, nhandles); - - if (signalled) { - ret = (MonoW32HandleWaitRet)(MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest); - for (i = lowest; i < nhandles; i++) { - if (abandoned [i]) { - ret = (MonoW32HandleWaitRet)(MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest); - break; - } - } - goto done; - } - - for (i = 0; i < nhandles; i++) { - if (!handles_data [i]) - continue; - mono_w32handle_ops_prewait (handles_data [i]); - - if (mono_w32handle_test_capabilities (handles_data [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT) - && !mono_w32handle_issignalled (handles_data [i])) - { - mono_w32handle_ops_specialwait (handles_data [i], 0, alertable ? &alerted : NULL); - } - } - - mono_w32handle_lock_signal_mutex (); - - // FIXME These two loops can be just one. - if (waitall) { - signalled = TRUE; - for (i = 0; i < nhandles; ++i) { - if (!handles_data [i]) - continue; - if (!mono_w32handle_issignalled (handles_data [i])) { - signalled = FALSE; - break; - } - } - } else { - signalled = FALSE; - for (i = 0; i < nhandles; ++i) { - if (!handles_data [i]) - continue; - if (mono_w32handle_issignalled (handles_data [i])) { - signalled = TRUE; - break; - } - } - } - - waited = 0; - - if (!signalled) { - if (timeout == MONO_INFINITE_WAIT) { - waited = mono_w32handle_timedwait_signal (MONO_INFINITE_WAIT, poll, alertable ? &alerted : NULL); - } else { - gint64 elapsed; - - elapsed = mono_msec_ticks () - start; - if (elapsed > timeout) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - - mono_w32handle_unlock_signal_mutex (); - - goto done; - } - - waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL); - } - } - - mono_w32handle_unlock_signal_mutex (); - - if (alerted) { - ret = MONO_W32HANDLE_WAIT_RET_ALERTED; - goto done; - } - - if (waited != 0) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - } - -done: - for (i = nhandles - 1; i >= 0; i--) { - /* Unref everything we reffed above */ - if (!handles_data [i]) - continue; - mono_w32handle_unref (handles_data [i]); - } - - return ret; -} -#endif /* HOST_WIN32 */ - -#ifdef HOST_WIN32 -MonoW32HandleWaitRet -mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable) -{ - return mono_w32handle_convert_wait_ret (mono_coop_win32_signal_object_and_wait (signal_handle, wait_handle, timeout, alertable), 1); -} -#else -MonoW32HandleWaitRet -mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable) -{ - MonoW32Handle *signal_handle_data, *wait_handle_data, *handles_data [2]; - MonoW32HandleWaitRet ret; - gint64 start = 0; - gboolean alerted; - gboolean abandoned = FALSE; - - alerted = FALSE; - - if (!mono_w32handle_lookup_and_ref (signal_handle, &signal_handle_data)) { - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - if (!mono_w32handle_lookup_and_ref (wait_handle, &wait_handle_data)) { - mono_w32handle_unref (signal_handle_data); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - if (!mono_w32handle_test_capabilities (signal_handle_data, MONO_W32HANDLE_CAP_SIGNAL)) { - mono_w32handle_unref (wait_handle_data); - mono_w32handle_unref (signal_handle_data); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - if (!mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_WAIT)) { - mono_w32handle_unref (wait_handle_data); - mono_w32handle_unref (signal_handle_data); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - if (mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { - g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle_data); - mono_w32handle_unref (wait_handle_data); - mono_w32handle_unref (signal_handle_data); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - handles_data [0] = wait_handle_data; - handles_data [1] = signal_handle_data; - - mono_w32handle_lock_handles (handles_data, 2); - - gint32 signal_ret = mono_w32handle_ops_signal (signal_handle_data); - - mono_w32handle_unlock (signal_handle_data); - - if (signal_ret == MONO_W32HANDLE_WAIT_RET_TOO_MANY_POSTS || - signal_ret == MONO_W32HANDLE_WAIT_RET_NOT_OWNED_BY_CALLER) { - ret = (MonoW32HandleWaitRet) signal_ret; - goto done; - } - - if (mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_OWN)) { - if (own_if_owned (wait_handle_data, &abandoned)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p already owned", __func__, wait_handle_data); - - ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - goto done; - } - } - - if (timeout != MONO_INFINITE_WAIT) - start = mono_msec_ticks (); - - for (;;) { - gint waited; - - if (own_if_signalled (wait_handle_data, &abandoned)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p signalled", __func__, wait_handle_data); - - ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - goto done; - } - - mono_w32handle_ops_prewait (wait_handle_data); - - if (timeout == MONO_INFINITE_WAIT) { - waited = mono_w32handle_timedwait_signal_handle (wait_handle_data, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL); - } else { - gint64 elapsed; - - elapsed = mono_msec_ticks () - start; - if (elapsed > timeout) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - - waited = mono_w32handle_timedwait_signal_handle (wait_handle_data, timeout - elapsed, FALSE, alertable ? &alerted : NULL); - } - - if (alerted) { - ret = MONO_W32HANDLE_WAIT_RET_ALERTED; - goto done; - } - - if (waited != 0) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - } - -done: - mono_w32handle_unlock (wait_handle_data); - - mono_w32handle_unref (wait_handle_data); - mono_w32handle_unref (signal_handle_data); - - return ret; -} -#endif /* HOST_WIN32 */ diff --git a/src/mono/mono/metadata/w32handle.h b/src/mono/mono/metadata/w32handle.h index d0c50a9357b34e..f70fb140e6c270 100644 --- a/src/mono/mono/metadata/w32handle.h +++ b/src/mono/mono/metadata/w32handle.h @@ -22,12 +22,8 @@ typedef enum { MONO_W32TYPE_UNUSED = 0, - MONO_W32TYPE_SEM, - MONO_W32TYPE_MUTEX, MONO_W32TYPE_EVENT, MONO_W32TYPE_PROCESS, - MONO_W32TYPE_NAMEDMUTEX, - MONO_W32TYPE_NAMEDSEM, MONO_W32TYPE_NAMEDEVENT, MONO_W32TYPE_COUNT } MonoW32Type; @@ -133,9 +129,6 @@ mono_w32handle_unref (MonoW32Handle *handle_data); void mono_w32handle_foreach (gboolean (*on_each)(MonoW32Handle *handle_data, gpointer user_data), gpointer user_data); -void -mono_w32handle_dump (void); - void mono_w32handle_register_capabilities (MonoW32Type type, MonoW32HandleCapability caps); @@ -148,27 +141,12 @@ mono_w32handle_issignalled (MonoW32Handle *handle_data); void mono_w32handle_lock (MonoW32Handle *handle_data); -gboolean -mono_w32handle_trylock (MonoW32Handle *handle_data); - void mono_w32handle_unlock (MonoW32Handle *handle_data); -gboolean -mono_w32handle_handle_is_signalled (gpointer handle); - -gboolean -mono_w32handle_handle_is_owned (gpointer handle); - MonoW32HandleWaitRet mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable); -MonoW32HandleWaitRet -mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable, MonoError *error); - -MonoW32HandleWaitRet -mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable); - #ifdef HOST_WIN32 static inline MonoW32HandleWaitRet mono_w32handle_convert_wait_ret (guint32 res, guint32 numobjects) diff --git a/src/mono/mono/metadata/w32mutex-unix.c b/src/mono/mono/metadata/w32mutex-unix.c deleted file mode 100644 index 0e1da775ff9612..00000000000000 --- a/src/mono/mono/metadata/w32mutex-unix.c +++ /dev/null @@ -1,537 +0,0 @@ -/** - * \file - * Runtime support for managed Mutex on Unix - * - * Author: - * Ludovic Henry (luhenry@microsoft.com) - * - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include "w32mutex.h" - -#include - -#include "w32error.h" -#include "w32handle-namespace.h" -#include "mono/metadata/object-internals.h" -#include "mono/utils/mono-logger-internals.h" -#include "mono/utils/mono-threads.h" -#include "mono/metadata/w32handle.h" -#include "icall-decl.h" - -#define MAX_PATH 260 - -typedef struct { - MonoNativeThreadId tid; - guint32 recursion; - gboolean abandoned; -} MonoW32HandleMutex; - -struct MonoW32HandleNamedMutex { - MonoW32HandleMutex m; - MonoW32HandleNamespace sharedns; -}; - -static gpointer -mono_w32mutex_open (const char* utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error); - -static void -thread_own_mutex (MonoInternalThread *internal, gpointer handle, MonoW32Handle *handle_data) -{ - // Thread and InternalThread are pinned/mature. - // Take advantage of that and do not use handles here. - - /* if we are not on the current thread, there is a - * race condition when allocating internal->owned_mutexes */ - g_assert (mono_thread_internal_is_current (internal)); - - if (!internal->owned_mutexes) - internal->owned_mutexes = g_ptr_array_new (); - - g_ptr_array_add (internal->owned_mutexes, mono_w32handle_duplicate (handle_data)); -} - -static void -thread_disown_mutex (MonoInternalThread *internal, gpointer handle) -{ - // Thread and InternalThread are pinned/mature. - // Take advantage of that and do not use handles here. - gboolean removed; - - g_assert (mono_thread_internal_is_current (internal)); - - g_assert (internal->owned_mutexes); - removed = g_ptr_array_remove (internal->owned_mutexes, handle); - g_assert (removed); - - mono_w32handle_close (handle); -} - -static gint32 -mutex_handle_signal (MonoW32Handle *handle_data) -{ - MonoW32HandleMutex *mutex_handle; - pthread_t tid; - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: signalling %s handle %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion); - - tid = pthread_self (); - - if (mutex_handle->abandoned) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p is abandoned", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data); - } else if (!pthread_equal (mutex_handle->tid, tid)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (long)mutex_handle->tid, (long)tid); - return MONO_W32HANDLE_WAIT_RET_NOT_OWNED_BY_CALLER; - } else { - /* OK, we own this mutex */ - mutex_handle->recursion--; - - if (mutex_handle->recursion == 0) { - thread_disown_mutex (mono_thread_internal_current (), handle_data); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion); - - mutex_handle->tid = 0; - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - } - } - return MONO_W32HANDLE_WAIT_RET_SUCCESS_0; -} - -static gboolean -mutex_handle_own (MonoW32Handle *handle_data, gboolean *abandoned) -{ - MonoW32HandleMutex *mutex_handle; - - *abandoned = FALSE; - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: owning %s handle %p, before: [tid: %p, recursion: %d], after: [tid: %p, recursion: %d], abandoned: %s", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion, (gpointer) pthread_self (), mutex_handle->recursion + 1, mutex_handle->abandoned ? "true" : "false"); - - if (mutex_handle->recursion != 0) { - g_assert (pthread_equal (pthread_self (), mutex_handle->tid)); - mutex_handle->recursion++; - } else { - mutex_handle->tid = pthread_self (); - mutex_handle->recursion = 1; - - thread_own_mutex (mono_thread_internal_current (), handle_data, handle_data); - } - - if (mutex_handle->abandoned) { - mutex_handle->abandoned = FALSE; - *abandoned = TRUE; - } - - mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); - return TRUE; -} - -static gboolean -mutex_handle_is_owned (MonoW32Handle *handle_data) -{ - MonoW32HandleMutex *mutex_handle; - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: testing ownership %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data); - - if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p owned by %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) pthread_self ()); - return TRUE; - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p not owned by %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) pthread_self (), (gpointer) mutex_handle->tid, mutex_handle->recursion); - return FALSE; - } -} - -static void mutex_handle_prewait (MonoW32Handle *handle_data) -{ - /* If the mutex is not currently owned, do nothing and let the - * usual wait carry on. If it is owned, check that the owner - * is still alive; if it isn't we override the previous owner - * and assume that process exited abnormally and failed to - * clean up. - */ - MonoW32HandleMutex *mutex_handle; - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: pre-waiting %s handle %p, owned? %s", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, mutex_handle->recursion != 0 ? "true" : "false"); -} - -static void mutex_details (MonoW32Handle *handle_data) -{ - MonoW32HandleMutex *mut = (MonoW32HandleMutex *)handle_data->specific; - -#ifdef PTHREAD_POINTER_ID - g_print ("own: %5p, count: %5u", mut->tid, mut->recursion); -#else - g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion); -#endif -} - -static void namedmutex_details (MonoW32Handle *handle_data) -{ - MonoW32HandleNamedMutex *namedmut = (MonoW32HandleNamedMutex *)handle_data->specific; - -#ifdef PTHREAD_POINTER_ID - g_print ("own: %5p, count: %5u, name: \"%s\"", - namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name); -#else - g_print ("own: %5ld, count: %5u, name: \"%s\"", - namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name); -#endif -} - -static const gchar* mutex_typename (void) -{ - return "Mutex"; -} - -static gsize mutex_typesize (void) -{ - return sizeof (MonoW32HandleMutex); -} - -static const gchar* namedmutex_typename (void) -{ - return "N.Mutex"; -} - -static gsize namedmutex_typesize (void) -{ - return sizeof (MonoW32HandleNamedMutex); -} - -void -mono_w32mutex_init (void) -{ - static const MonoW32HandleOps mutex_ops = { - NULL, /* close */ - mutex_handle_signal, /* signal */ - mutex_handle_own, /* own */ - mutex_handle_is_owned, /* is_owned */ - NULL, /* special_wait */ - mutex_handle_prewait, /* prewait */ - mutex_details, /* details */ - mutex_typename, /* typename */ - mutex_typesize, /* typesize */ - }; - - static const MonoW32HandleOps namedmutex_ops = { - NULL, /* close */ - mutex_handle_signal, /* signal */ - mutex_handle_own, /* own */ - mutex_handle_is_owned, /* is_owned */ - NULL, /* special_wait */ - mutex_handle_prewait, /* prewait */ - namedmutex_details, /* details */ - namedmutex_typename, /* typename */ - namedmutex_typesize, /* typesize */ - }; - - mono_w32handle_register_ops (MONO_W32TYPE_MUTEX, &mutex_ops); - mono_w32handle_register_ops (MONO_W32TYPE_NAMEDMUTEX, &namedmutex_ops); - - mono_w32handle_register_capabilities (MONO_W32TYPE_MUTEX, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN)); - mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDMUTEX, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN)); -} - -static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32Type type, gboolean owned) -{ - MonoW32Handle *handle_data; - gpointer handle; - gboolean abandoned; - - mutex_handle->tid = 0; - mutex_handle->recursion = 0; - mutex_handle->abandoned = FALSE; - - handle = mono_w32handle_new (type, mutex_handle); - if (handle == INVALID_HANDLE_VALUE) { - g_warning ("%s: error creating %s handle", - __func__, mono_w32handle_get_typename (type)); - mono_w32error_set_last (ERROR_GEN_FAILURE); - return NULL; - } - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - g_error ("%s: unkown handle %p", __func__, handle); - - if (handle_data->type != type) - g_error ("%s: unknown mutex handle %p", __func__, handle); - - mono_w32handle_lock (handle_data); - - if (owned) - mutex_handle_own (handle_data, &abandoned); - else - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - - mono_w32handle_unlock (handle_data); - - /* Balance mono_w32handle_lookup_and_ref */ - mono_w32handle_unref (handle_data); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: created %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - - return handle; -} - -static gpointer mutex_create (gboolean owned) -{ - MonoW32HandleMutex mutex_handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: creating %s handle", - __func__, mono_w32handle_get_typename (MONO_W32TYPE_MUTEX)); - return mutex_handle_create (&mutex_handle, MONO_W32TYPE_MUTEX, owned); -} - -static gpointer -namedmutex_create (gboolean owned, const char *utf8_name, gsize utf8_len) -{ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: creating %s handle", - __func__, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDMUTEX)); - - // Opening named objects does not race. - mono_w32handle_namespace_lock (); - - gpointer handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDMUTEX, utf8_name); - - if (handle == INVALID_HANDLE_VALUE) { - /* The name has already been used for a different object. */ - handle = NULL; - mono_w32error_set_last (ERROR_INVALID_HANDLE); - } else if (handle) { - /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */ - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - - /* mono_w32handle_namespace_search_handle already adds a ref to the handle */ - } else { - /* A new named mutex */ - MonoW32HandleNamedMutex namedmutex_handle; - - // FIXME Silent truncation. - - size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH; - memcpy (&namedmutex_handle.sharedns.name [0], utf8_name, len); - namedmutex_handle.sharedns.name [len] = '\0'; - - handle = mutex_handle_create ((MonoW32HandleMutex*) &namedmutex_handle, MONO_W32TYPE_NAMEDMUTEX, owned); - } - - mono_w32handle_namespace_unlock (); - - return handle; -} - -gpointer -ves_icall_System_Threading_Mutex_CreateMutex_icall (MonoBoolean owned, const gunichar2 *name, - gint32 name_length, MonoBoolean *created, MonoError *error) -{ - gpointer mutex; - - *created = TRUE; - - /* Need to blow away any old errors here, because code tests - * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex - * was freshly created */ - mono_w32error_set_last (ERROR_SUCCESS); - - if (!name) { - mutex = mutex_create (owned); - } else { - gsize utf8_name_length = 0; - char *utf8_name = mono_utf16_to_utf8len (name, name_length, &utf8_name_length, error); - return_val_if_nok (error, NULL); - - mutex = namedmutex_create (owned, utf8_name, utf8_name_length); - - if (mono_w32error_get_last () == ERROR_ALREADY_EXISTS) - *created = FALSE; - g_free (utf8_name); - } - - return mutex; -} - -MonoBoolean -ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) -{ - MonoW32Handle *handle_data; - MonoW32HandleMutex *mutex_handle; - pthread_t tid; - gboolean ret; - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { - g_warning ("%s: unkown handle %p", __func__, handle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) { - g_warning ("%s: unknown mutex handle %p", __func__, handle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_w32handle_unref (handle_data); - return FALSE; - } - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: releasing %s handle %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); - - mono_w32handle_lock (handle_data); - - tid = pthread_self (); - - if (mutex_handle->abandoned) { - // The Win32 ReleaseMutex() function returns TRUE for abandoned mutexes - ret = TRUE; - } else if (!pthread_equal (mutex_handle->tid, tid)) { - ret = FALSE; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)", - __func__, mono_w32handle_get_typename (handle_data->type), handle, (long)mutex_handle->tid, (long)tid); - } else { - ret = TRUE; - - /* OK, we own this mutex */ - mutex_handle->recursion--; - - if (mutex_handle->recursion == 0) { - thread_disown_mutex (mono_thread_internal_current (), handle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); - - mutex_handle->tid = 0; - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - } - } - - mono_w32handle_unlock (handle_data); - mono_w32handle_unref (handle_data); - - return ret; -} - -gpointer -ves_icall_System_Threading_Mutex_OpenMutex_icall (const gunichar2 *name, gint32 name_length, gint32 rights G_GNUC_UNUSED, gint32 *win32error, MonoError *error) -{ - *win32error = ERROR_SUCCESS; - char *utf8_name = mono_utf16_to_utf8 (name, name_length, error); - return_val_if_nok (error, NULL); - gpointer handle = mono_w32mutex_open (utf8_name, rights, win32error); - g_free (utf8_name); - return handle; -} - -gpointer -mono_w32mutex_open (const char* utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error) -{ - *win32error = ERROR_SUCCESS; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: Opening named mutex [%s]", - __func__, utf8_name); - - // Opening named objects does not race. - mono_w32handle_namespace_lock (); - - gpointer handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDMUTEX, utf8_name); - - mono_w32handle_namespace_unlock (); - - if (handle == INVALID_HANDLE_VALUE) { - /* The name has already been used for a different object. */ - *win32error = ERROR_INVALID_HANDLE; - return handle; - } else if (!handle) { - /* This name doesn't exist */ - *win32error = ERROR_FILE_NOT_FOUND; - return handle; - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: returning named mutex handle %p", - __func__, handle); - - return handle; -} - -void -mono_w32mutex_abandon (MonoInternalThread *internal) -{ - // Thread and InternalThread are pinned/mature. - // Take advantage of that and do not use handles here. - g_assert (mono_thread_internal_is_current (internal)); - - if (!internal->owned_mutexes) - return; - - while (internal->owned_mutexes->len) { - MonoW32Handle *handle_data; - MonoW32HandleMutex *mutex_handle; - MonoNativeThreadId tid; - gpointer handle; - - handle = g_ptr_array_index (internal->owned_mutexes, 0); - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - g_error ("%s: unkown handle %p", __func__, handle); - - if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) - g_error ("%s: unkown mutex handle %p", __func__, handle); - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoning %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - tid = MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid); - - if (!pthread_equal (mutex_handle->tid, tid)) - g_error ("%s: trying to release mutex %p acquired by thread %p from thread %p", - __func__, handle, (gpointer) mutex_handle->tid, (gpointer) tid); - - mono_w32handle_lock (handle_data); - - mutex_handle->recursion = 0; - mutex_handle->tid = 0; - mutex_handle->abandoned = TRUE; - - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - - thread_disown_mutex (internal, handle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoned %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - mono_w32handle_unlock (handle_data); - mono_w32handle_unref (handle_data); - } - - g_ptr_array_free (internal->owned_mutexes, TRUE); - internal->owned_mutexes = NULL; -} - -MonoW32HandleNamespace* -mono_w32mutex_get_namespace (MonoW32HandleNamedMutex *mutex) -{ - return &mutex->sharedns; -} diff --git a/src/mono/mono/metadata/w32mutex-win32.c b/src/mono/mono/metadata/w32mutex-win32.c deleted file mode 100644 index 879bfeaa9c131a..00000000000000 --- a/src/mono/mono/metadata/w32mutex-win32.c +++ /dev/null @@ -1,67 +0,0 @@ -/** - * \file - * Runtime support for managed Mutex on Win32 - * - * Author: - * Ludovic Henry (luhenry@microsoft.com) - * - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include "w32mutex.h" - -#include -#include -#include -#include -#include "icall-decl.h" - -void -mono_w32mutex_init (void) -{ -} - -gpointer -ves_icall_System_Threading_Mutex_CreateMutex_icall (MonoBoolean owned, const gunichar2 *name, - gint32 name_length, MonoBoolean *created, MonoError *error) -{ - HANDLE mutex; - - *created = TRUE; - - /* Need to blow away any old errors here, because code tests - * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex - * was freshly created */ - SetLastError (ERROR_SUCCESS); - - MONO_ENTER_GC_SAFE; - mutex = CreateMutexW (NULL, owned, name); - if (name && GetLastError () == ERROR_ALREADY_EXISTS) - *created = FALSE; - MONO_EXIT_GC_SAFE; - - return mutex; -} - -MonoBoolean -ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) -{ - return ReleaseMutex (handle); -} - -gpointer -ves_icall_System_Threading_Mutex_OpenMutex_icall (const gunichar2 *name, gint32 name_length, - gint32 rights, gint32 *win32error, MonoError *error) -{ - HANDLE ret; - - *win32error = ERROR_SUCCESS; - - MONO_ENTER_GC_SAFE; - ret = OpenMutexW (rights, FALSE, name); - if (!ret) - *win32error = GetLastError (); - MONO_EXIT_GC_SAFE; - - return ret; -} diff --git a/src/mono/mono/metadata/w32mutex.h b/src/mono/mono/metadata/w32mutex.h deleted file mode 100644 index 264a22b7fee9fe..00000000000000 --- a/src/mono/mono/metadata/w32mutex.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * \file - */ - -#ifndef _MONO_METADATA_W32MUTEX_H_ -#define _MONO_METADATA_W32MUTEX_H_ - -#include -#include - -#include "object.h" -#include "object-internals.h" -#include "w32handle-namespace.h" -#include - -void -mono_w32mutex_init (void); - -ICALL_EXPORT -MonoBoolean -ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle); - -typedef struct MonoW32HandleNamedMutex MonoW32HandleNamedMutex; - -MonoW32HandleNamespace* -mono_w32mutex_get_namespace (MonoW32HandleNamedMutex *mutex); - -#ifndef HOST_WIN32 -void -mono_w32mutex_abandon (MonoInternalThread *internal); -#endif - -#endif /* _MONO_METADATA_W32MUTEX_H_ */ diff --git a/src/mono/mono/metadata/w32semaphore-unix.c b/src/mono/mono/metadata/w32semaphore-unix.c deleted file mode 100644 index fd1138b2b01538..00000000000000 --- a/src/mono/mono/metadata/w32semaphore-unix.c +++ /dev/null @@ -1,367 +0,0 @@ -/** - * \file - * Runtime support for managed Semaphore on Unix - * - * Author: - * Ludovic Henry (luhenry@microsoft.com) - * - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include "w32semaphore.h" -#include "w32error.h" -#include "w32handle-namespace.h" -#include "mono/utils/mono-logger-internals.h" -#include "mono/metadata/w32handle.h" -#include "object-internals.h" -#include "icall-decl.h" - -#define MAX_PATH 260 - -typedef struct { - guint32 val; - gint32 max; -} MonoW32HandleSemaphore; - -struct MonoW32HandleNamedSemaphore { - MonoW32HandleSemaphore s; - MonoW32HandleNamespace sharedns; -}; - -static gint32 sem_handle_signal (MonoW32Handle *handle_data) -{ - MonoW32HandleSemaphore *sem_handle; - - sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: signalling %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data); - - /* No idea why max is signed, but thats the spec :-( */ - if (sem_handle->val + 1 > (guint32)sem_handle->max) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, sem_handle->val, 1, sem_handle->max); - return MONO_W32HANDLE_WAIT_RET_TOO_MANY_POSTS; - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, sem_handle->val, 1, sem_handle->max); - - sem_handle->val += 1; - mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); - } - return MONO_W32HANDLE_WAIT_RET_SUCCESS_0; -} - -static gboolean sem_handle_own (MonoW32Handle *handle_data, gboolean *abandoned) -{ - MonoW32HandleSemaphore *sem_handle; - - *abandoned = FALSE; - - sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: owning %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data); - - sem_handle->val--; - - if (sem_handle->val == 0) - mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); - - return TRUE; -} - -static void sema_details (MonoW32Handle *handle_data) -{ - MonoW32HandleSemaphore *sem = (MonoW32HandleSemaphore *)handle_data->specific; - g_print ("val: %5u, max: %5d", sem->val, sem->max); -} - -static void namedsema_details (MonoW32Handle *handle_data) -{ - MonoW32HandleNamedSemaphore *namedsem = (MonoW32HandleNamedSemaphore *)handle_data->specific; - g_print ("val: %5u, max: %5d, name: \"%s\"", namedsem->s.val, namedsem->s.max, namedsem->sharedns.name); -} - -static const gchar* sema_typename (void) -{ - return "Semaphore"; -} - -static gsize sema_typesize (void) -{ - return sizeof (MonoW32HandleSemaphore); -} - -static const gchar* namedsema_typename (void) -{ - return "N.Semaphore"; -} - -static gsize namedsema_typesize (void) -{ - return sizeof (MonoW32HandleNamedSemaphore); -} - -void -mono_w32semaphore_init (void) -{ - static const MonoW32HandleOps sem_ops = { - NULL, /* close */ - sem_handle_signal, /* signal */ - sem_handle_own, /* own */ - NULL, /* is_owned */ - NULL, /* special_wait */ - NULL, /* prewait */ - sema_details, /* details */ - sema_typename, /* typename */ - sema_typesize, /* typesize */ - }; - - static const MonoW32HandleOps namedsem_ops = { - NULL, /* close */ - sem_handle_signal, /* signal */ - sem_handle_own, /* own */ - NULL, /* is_owned */ - NULL, /* special_wait */ - NULL, /* prewait */ - namedsema_details, /* details */ - namedsema_typename, /* typename */ - namedsema_typesize, /* typesize */ - }; - - mono_w32handle_register_ops (MONO_W32TYPE_SEM, &sem_ops); - mono_w32handle_register_ops (MONO_W32TYPE_NAMEDSEM, &namedsem_ops); - - mono_w32handle_register_capabilities (MONO_W32TYPE_SEM, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL)); - mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDSEM, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL)); -} - -static gpointer -sem_handle_create (MonoW32HandleSemaphore *sem_handle, MonoW32Type type, gint32 initial, gint32 max) -{ - MonoW32Handle *handle_data; - gpointer handle; - - sem_handle->val = initial; - sem_handle->max = max; - - handle = mono_w32handle_new (type, sem_handle); - if (handle == INVALID_HANDLE_VALUE) { - g_warning ("%s: error creating %s handle", - __func__, mono_w32handle_get_typename (type)); - mono_w32error_set_last (ERROR_GEN_FAILURE); - return NULL; - } - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - g_error ("%s: unkown handle %p", __func__, handle); - - if (handle_data->type != type) - g_error ("%s: unknown semaphore handle %p", __func__, handle); - - mono_w32handle_lock (handle_data); - - if (initial != 0) - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - - mono_w32handle_unlock (handle_data); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: created %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - - mono_w32handle_unref (handle_data); - - return handle; -} - -static gpointer -sem_create (gint32 initial, gint32 max) -{ - MonoW32HandleSemaphore sem_handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: creating %s handle, initial %d max %d", - __func__, mono_w32handle_get_typename (MONO_W32TYPE_SEM), initial, max); - return sem_handle_create (&sem_handle, MONO_W32TYPE_SEM, initial, max); -} - -static gpointer -namedsem_create (gint32 initial, gint32 max, const gunichar2 *name, gint32 name_length, MonoError *error) -{ - g_assert (name); - - gpointer handle = NULL; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: creating %s handle, initial %d max %d name \"%s\"", - __func__, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDSEM), initial, max, (const char*)name); - - gsize utf8_len = 0; - char *utf8_name = mono_utf16_to_utf8len (name, name_length, &utf8_len, error); - goto_if_nok (error, exit); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: Creating named sem name [%s] initial %d max %d", __func__, utf8_name, initial, max); - - // Opening named objects does not race. - mono_w32handle_namespace_lock (); - - handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDSEM, utf8_name); - if (handle == INVALID_HANDLE_VALUE) { - /* The name has already been used for a different object. */ - handle = NULL; - mono_w32error_set_last (ERROR_INVALID_HANDLE); - } else if (handle) { - /* Not an error, but this is how the caller is informed that the semaphore wasn't freshly created */ - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - - /* mono_w32handle_namespace_search_handle already adds a ref to the handle */ - } else { - /* A new named semaphore */ - MonoW32HandleNamedSemaphore namedsem_handle; - - // FIXME Silent truncation. - size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH; - memcpy (&namedsem_handle.sharedns.name [0], utf8_name, len); - namedsem_handle.sharedns.name [len] = '\0'; - - handle = sem_handle_create ((MonoW32HandleSemaphore*) &namedsem_handle, MONO_W32TYPE_NAMEDSEM, initial, max); - } - - mono_w32handle_namespace_unlock (); -exit: - g_free (utf8_name); - return handle; -} - -// These functions appear to be using coop-aware locking functions, and so this file does not include explicit -// GC-safe transitions like its corresponding Windows version - -gpointer -ves_icall_System_Threading_Semaphore_CreateSemaphore_icall (gint32 initialCount, gint32 maximumCount, - const gunichar2 *name, gint32 name_length, gint32 *win32error) -{ - if (maximumCount <= 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: maximumCount <= 0", __func__); -invalid_parameter: - *win32error = ERROR_INVALID_PARAMETER; - return NULL; - } - - if (initialCount > maximumCount || initialCount < 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: initialCount > maximumCount or < 0", __func__); - goto invalid_parameter; - } - - /* Need to blow away any old errors here, because code tests - * for ERROR_ALREADY_EXISTS on success (!) to see if a - * semaphore was freshly created - */ - mono_w32error_set_last (ERROR_SUCCESS); - - ERROR_DECL (error); - - gpointer sem = name ? namedsem_create (initialCount, maximumCount, name, name_length, error) - : sem_create (initialCount, maximumCount); - *win32error = mono_w32error_get_last (); - mono_error_set_pending_exception (error); \ - return sem; -} - -MonoBoolean -ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount) -{ - MonoW32Handle *handle_data = NULL; - MonoW32HandleSemaphore *sem_handle; - MonoBoolean ret = FALSE; - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { - g_warning ("%s: unkown handle %p", __func__, handle); -invalid_handle: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - goto exit; - } - - if (handle_data->type != MONO_W32TYPE_SEM && handle_data->type != MONO_W32TYPE_NAMEDSEM) { - g_warning ("%s: unknown sem handle %p", __func__, handle); - goto invalid_handle; - } - - sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: releasing %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - mono_w32handle_lock (handle_data); - - /* Do this before checking for count overflow, because overflowing - * max is a listed technique for finding the current value */ - if (prevcount) - *prevcount = sem_handle->val; - - /* No idea why max is signed, but thats the spec :-( */ - if (sem_handle->val + releaseCount > (guint32)sem_handle->max) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", - __func__, mono_w32handle_get_typename (handle_data->type), handle, sem_handle->val, releaseCount, sem_handle->max); - - ret = FALSE; - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle, sem_handle->val, releaseCount, sem_handle->max); - - sem_handle->val += releaseCount; - mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); - ret = TRUE; - } - - mono_w32handle_unlock (handle_data); -exit: - if (handle_data) - mono_w32handle_unref (handle_data); - return ret; -} - -gpointer -ves_icall_System_Threading_Semaphore_OpenSemaphore_icall (const gunichar2 *name, gint32 name_length, - gint32 rights, gint32 *win32error) -{ - g_assert (name); - gpointer handle = NULL; - ERROR_DECL (error); - - *win32error = ERROR_SUCCESS; - - char *utf8_name = mono_utf16_to_utf8 (name, name_length, error); - goto_if_nok (error, exit); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: Opening named sem [%s]", __func__, utf8_name); - - // Opening named objects does not race. - mono_w32handle_namespace_lock (); - - handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDSEM, utf8_name); - - mono_w32handle_namespace_unlock (); - - if (handle == INVALID_HANDLE_VALUE) { - /* The name has already been used for a different object. */ - *win32error = ERROR_INVALID_HANDLE; - goto exit; - } else if (!handle) { - /* This name doesn't exist */ - *win32error = ERROR_FILE_NOT_FOUND; - goto exit; - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: returning named sem handle %p", __func__, handle); - -exit: - g_free (utf8_name); - mono_error_set_pending_exception (error); \ - return handle; -} - -MonoW32HandleNamespace* -mono_w32semaphore_get_namespace (MonoW32HandleNamedSemaphore *semaphore) -{ - return &semaphore->sharedns; -} diff --git a/src/mono/mono/metadata/w32semaphore-win32.c b/src/mono/mono/metadata/w32semaphore-win32.c deleted file mode 100644 index 3856be46aea9f5..00000000000000 --- a/src/mono/mono/metadata/w32semaphore-win32.c +++ /dev/null @@ -1,67 +0,0 @@ -/** - * \file - * Runtime support for managed Semaphore on Win32 - * - * Author: - * Ludovic Henry (luhenry@microsoft.com) - * - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include "w32semaphore.h" - -#include -#include -#include -#include -#include "icall-decl.h" - -void -mono_w32semaphore_init (void) -{ -} - -#if HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE || HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX -gpointer -ves_icall_System_Threading_Semaphore_CreateSemaphore_icall (gint32 initialCount, gint32 maximumCount, - const gunichar2 *name, gint32 name_length, gint32 *win32error) -{ - HANDLE sem; - MONO_ENTER_GC_SAFE; -#if HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE - sem = CreateSemaphoreW (NULL, initialCount, maximumCount, name); -#elif HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX - sem = CreateSemaphoreExW (NULL, initialCount, maximumCount, name, 0, SEMAPHORE_ALL_ACCESS); -#endif - MONO_EXIT_GC_SAFE; - *win32error = GetLastError (); - return sem; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_CREATE_SEMAPHORE && !HAVE_EXTERN_DEFINED_WIN32_CREATE_SEMAPHORE_EX -gpointer -ves_icall_System_Threading_Semaphore_CreateSemaphore_icall (gint32 initialCount, gint32 maximumCount, - const gunichar2 *name, gint32 name_length, gint32 *win32error) -{ - g_unsupported_api ("CreateSemaphore, CreateSemaphoreEx"); - SetLastError (ERROR_NOT_SUPPORTED); - return NULL; -} -#endif /* HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE || HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX) */ - -MonoBoolean -ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount) -{ - return ReleaseSemaphore (handle, releaseCount, (PLONG)prevcount); -} - -gpointer -ves_icall_System_Threading_Semaphore_OpenSemaphore_icall (const gunichar2 *name, gint32 name_length, - gint32 rights, gint32 *win32error) -{ - HANDLE sem; - MONO_ENTER_GC_SAFE; - sem = OpenSemaphoreW (rights, FALSE, name); - MONO_EXIT_GC_SAFE; - *win32error = GetLastError (); - return sem; -} diff --git a/src/mono/mono/metadata/w32semaphore.h b/src/mono/mono/metadata/w32semaphore.h deleted file mode 100644 index adfa228e2c8f92..00000000000000 --- a/src/mono/mono/metadata/w32semaphore.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * \file - */ - -#ifndef _MONO_METADATA_W32SEMAPHORE_H_ -#define _MONO_METADATA_W32SEMAPHORE_H_ - -#include -#include -#include "object.h" -#include "w32handle-namespace.h" -#include - -void -mono_w32semaphore_init (void); - -typedef struct MonoW32HandleNamedSemaphore MonoW32HandleNamedSemaphore; - -MonoW32HandleNamespace* -mono_w32semaphore_get_namespace (MonoW32HandleNamedSemaphore *semaphore); - -#endif /* _MONO_METADATA_W32SEMAPHORE_H_ */ diff --git a/src/mono/mono/metadata/w32socket-internals.h b/src/mono/mono/metadata/w32socket-internals.h deleted file mode 100644 index 6e4785db5d6a5f..00000000000000 --- a/src/mono/mono/metadata/w32socket-internals.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * \file - * - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#ifndef __MONO_METADATA_W32SOCKET_INTERNALS_H__ -#define __MONO_METADATA_W32SOCKET_INTERNALS_H__ - -#include -#include - -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include - -#ifndef HAVE_SOCKLEN_T -#define socklen_t int -#endif - -#include - -#if defined(HOST_WIN32) && (HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE || HAVE_API_SUPPORT_WIN32_DISCONNECT_EX) -#include -#else -typedef struct { - gpointer Head; - guint32 HeadLength; - gpointer Tail; - guint32 TailLength; -} TRANSMIT_FILE_BUFFERS, *LPTRANSMIT_FILE_BUFFERS; -#endif - -#ifndef HOST_WIN32 -#define TF_DISCONNECT 0x01 -#define TF_REUSE_SOCKET 0x02 - -typedef struct { - guint32 Data1; - guint16 Data2; - guint16 Data3; - guint8 Data4[8]; -} GUID; - -typedef struct { - guint32 Internal; - guint32 InternalHigh; - guint32 Offset; - guint32 OffsetHigh; - gpointer hEvent; - gpointer handle1; - gpointer handle2; -} OVERLAPPED; -#endif - -void -mono_w32socket_initialize (void); - -void -mono_w32socket_cleanup (void); - -SOCKET -mono_w32socket_accept (SOCKET s, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking); - -int -mono_w32socket_connect (SOCKET s, const struct sockaddr *name, socklen_t namelen, gboolean blocking); - -int -mono_w32socket_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking); - -int -mono_w32socket_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking); - -int -mono_w32socket_recvbuffers (SOCKET s, LPWSABUF lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 *lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking); - -int -mono_w32socket_send (SOCKET s, void *buf, int len, int flags, gboolean blocking); - -int -mono_w32socket_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking); - -int -mono_w32socket_sendbuffers (SOCKET s, LPWSABUF lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking); - -BOOL -mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, gpointer lpTransmitBuffers, guint32 dwReserved, gboolean blocking); - - -#ifndef HOST_WIN32 - -SOCKET -mono_w32socket_socket (int domain, int type, int protocol); - -gint -mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen); - -gint -mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen); - -gint -mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen); - -gint -mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen); - -gint -mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen); - -gint -mono_w32socket_listen (SOCKET sock, gint backlog); - -gint -mono_w32socket_shutdown (SOCKET sock, gint how); - -gint -mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written); - -gboolean -mono_w32socket_close (SOCKET sock); - -#endif /* HOST_WIN32 */ - -gint -mono_w32socket_disconnect (SOCKET sock, gboolean reuse); - -gint -mono_w32socket_set_blocking (SOCKET socket, gboolean blocking); - -gint -mono_w32socket_get_available (SOCKET socket, guint64 *amount); - -void -mono_w32socket_set_last_error (gint32 error); - -gint32 -mono_w32socket_get_last_error (void); - -gint32 -mono_w32socket_convert_error (gint error); - -gboolean -mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle); - -#endif // __MONO_METADATA_W32SOCKET_INTERNALS_H__ diff --git a/src/mono/mono/metadata/w32socket-unix.c b/src/mono/mono/metadata/w32socket-unix.c deleted file mode 100644 index 2c19b035678764..00000000000000 --- a/src/mono/mono/metadata/w32socket-unix.c +++ /dev/null @@ -1,1578 +0,0 @@ -/** - * \file - * Unix specific socket code. - * - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include -#include - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#include -#include -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -#ifdef HAVE_SYS_UIO_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_SYS_FILIO_H -#include /* defines FIONBIO and FIONREAD */ -#endif -#ifdef HAVE_SYS_SOCKIO_H -#include /* defines SIOCATMARK */ -#endif -#include -#ifdef HAVE_SYS_SENDFILE_H -#include -#endif -#include - -#include "w32socket.h" -#include "w32socket-internals.h" -#include "w32error.h" -#include "fdhandle.h" -#include "utils/mono-logger-internals.h" -#include "utils/mono-poll.h" -#include "utils/mono-compiler.h" -#include "icall-decl.h" -#include "utils/mono-errno.h" - -typedef struct { - MonoFDHandle fdhandle; - gint domain; - gint type; - gint protocol; - gint saved_error; - gint still_readable; -} SocketHandle; - -static SocketHandle* -socket_data_create (MonoFDType type, gint fd) -{ - SocketHandle *sockethandle; - - sockethandle = g_new0 (SocketHandle, 1); - mono_fdhandle_init ((MonoFDHandle*) sockethandle, type, fd); - - return sockethandle; -} - -static void -socket_data_close (MonoFDHandle *fdhandle) -{ - MonoThreadInfo *info; - SocketHandle* sockethandle; - gint ret; - - sockethandle = (SocketHandle*) fdhandle; - g_assert (sockethandle); - - info = mono_thread_info_current (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: closing fd %d", __func__, ((MonoFDHandle*) sockethandle)->fd); - - /* Shutdown the socket for reading, to interrupt any potential - * receives that may be blocking for data. See bug 75705. */ - MONO_ENTER_GC_SAFE; - shutdown (((MonoFDHandle*) sockethandle)->fd, SHUT_RD); - MONO_EXIT_GC_SAFE; - -retry_close: - MONO_ENTER_GC_SAFE; - ret = close (((MonoFDHandle*) sockethandle)->fd); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - if (errno == EINTR && !mono_thread_info_is_interrupt_state (info)) - goto retry_close; - } - - sockethandle->saved_error = 0; -} - -static void -socket_data_destroy (MonoFDHandle *fdhandle) -{ - SocketHandle *sockethandle; - - sockethandle = (SocketHandle*) fdhandle; - g_assert (sockethandle); - - g_free (sockethandle); -} - -void -mono_w32socket_initialize (void) -{ - MonoFDHandleCallback socket_data_callbacks; - memset (&socket_data_callbacks, 0, sizeof (socket_data_callbacks)); - socket_data_callbacks.close = socket_data_close; - socket_data_callbacks.destroy = socket_data_destroy; - - mono_fdhandle_register (MONO_FDTYPE_SOCKET, &socket_data_callbacks); -} - -void -mono_w32socket_cleanup (void) -{ -} - -SOCKET -mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking) -{ - SocketHandle *sockethandle, *accepted_socket_data; - MonoThreadInfo *info; - gint accepted_fd; - - if (addr != NULL && *addrlen < sizeof(struct sockaddr)) { - mono_w32socket_set_last_error (WSAEFAULT); - return INVALID_SOCKET; - } - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return INVALID_SOCKET; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return INVALID_SOCKET; - } - - info = mono_thread_info_current (); - - do { - MONO_ENTER_GC_SAFE; - accepted_fd = accept (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); - MONO_EXIT_GC_SAFE; - } while (accepted_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (accepted_fd == -1) { - gint error = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: accept error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (error); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return INVALID_SOCKET; - } - - accepted_socket_data = socket_data_create (MONO_FDTYPE_SOCKET, accepted_fd); - accepted_socket_data->domain = sockethandle->domain; - accepted_socket_data->type = sockethandle->type; - accepted_socket_data->protocol = sockethandle->protocol; - accepted_socket_data->still_readable = 1; - - mono_fdhandle_insert ((MonoFDHandle*) accepted_socket_data); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning accepted handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) accepted_socket_data)->fd)); - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ((MonoFDHandle*) accepted_socket_data)->fd; -} - -int -mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, socklen_t addrlen, gboolean blocking) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = connect (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - MonoThreadInfo *info; - mono_pollfd fds; - gint errnum, so_error; - socklen_t len; - - errnum = errno; - - if (errno != EINTR) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect error: %s", __func__, - g_strerror (errnum)); - - errnum = mono_w32socket_convert_error (errnum); - if (errnum == WSAEINPROGRESS) - errnum = WSAEWOULDBLOCK; /* see bug #73053 */ - - mono_w32socket_set_last_error (errnum); - - /* - * On solaris x86 getsockopt (SO_ERROR) is not set after - * connect () fails so we need to save this error. - * - * But don't do this for EWOULDBLOCK (bug 317315) - */ - if (errnum != WSAEWOULDBLOCK) { - /* ECONNRESET means the socket was closed by another thread */ - /* Async close on mac raises ECONNABORTED. */ - sockethandle->saved_error = errnum; - } - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - fds.fd = ((MonoFDHandle*) sockethandle)->fd; - fds.events = MONO_POLLOUT; - for (;;) { - MONO_ENTER_GC_SAFE; - ret = mono_poll (&fds, 1, -1); - MONO_EXIT_GC_SAFE; - if (ret != -1 || mono_thread_info_is_interrupt_state (info)) - break; - - if (errno != EINTR) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect poll error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - } - - len = sizeof(so_error); - MONO_ENTER_GC_SAFE; - ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_ERROR, &so_error, &len); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (so_error != 0) { - gint errnum = mono_w32socket_convert_error (so_error); - - /* Need to save this socket error */ - sockethandle->saved_error = errnum; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt returned error: %s", - __func__, g_strerror (so_error)); - - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -int -mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking) -{ - return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking); -} - -int -mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking) -{ - SocketHandle *sockethandle; - int ret; - MonoThreadInfo *info; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - do { - MONO_ENTER_GC_SAFE; - ret = recvfrom (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, from, fromlen); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == 0 && len > 0) { - /* According to the Linux man page, recvfrom only - * returns 0 when the socket has been shut down - * cleanly. Turn this into an EINTR to simulate win32 - * behaviour of returning EINTR when a socket is - * closed while the recvfrom is blocking (we use a - * shutdown() in socket_close() to trigger this.) See - * bug 75705. - */ - /* Distinguish between the socket being shut down at - * the local or remote ends, and reads that request 0 - * bytes to be read - */ - - /* If this returns FALSE, it means the socket has been - * closed locally. If it returns TRUE, but - * still_readable != 1 then shutdown - * (SHUT_RD|SHUT_RDWR) has been called locally. - */ - if (sockethandle->still_readable != 1) { - ret = -1; - mono_set_errno (EINTR); - } - } - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recv error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -static void -wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr) -{ - guint32 i; - - memset (hdr, 0, sizeof (struct msghdr)); - hdr->msg_iovlen = count; - hdr->msg_iov = g_new0 (struct iovec, count); - for (i = 0; i < count; i++) { - hdr->msg_iov [i].iov_base = buffers [i].buf; - hdr->msg_iov [i].iov_len = buffers [i].len; - } -} - -static void -msghdr_iov_free (struct msghdr *hdr) -{ - g_free (hdr->msg_iov); -} - -int -mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking) -{ - SocketHandle *sockethandle; - MonoThreadInfo *info; - gint ret; - struct msghdr hdr; - - g_assert (overlapped == NULL); - g_assert (complete == NULL); - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - wsabuf_to_msghdr (buffers, count, &hdr); - - do { - MONO_ENTER_GC_SAFE; - ret = recvmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, *flags); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - msghdr_iov_free (&hdr); - - if (ret == 0) { - /* see mono_w32socket_recvfrom */ - if (sockethandle->still_readable != 1) { - ret = -1; - mono_set_errno (EINTR); - } - } - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recvmsg error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - *received = ret; - *flags = hdr.msg_flags; - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -int -mono_w32socket_send (SOCKET sock, void *buf, int len, int flags, gboolean blocking) -{ - SocketHandle *sockethandle; - int ret; - MonoThreadInfo *info; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - do { - MONO_ENTER_GC_SAFE; - ret = send (((MonoFDHandle*) sockethandle)->fd, buf, len, flags); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno)); - -#ifdef O_NONBLOCK - /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on - * a blocking socket. See bug #599488 */ - if (errnum == EAGAIN) { - MONO_ENTER_GC_SAFE; - ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0); - MONO_EXIT_GC_SAFE; - if (ret != -1 && (ret & O_NONBLOCK) == 0) - errnum = ETIMEDOUT; - } -#endif /* O_NONBLOCK */ - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -int -mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking) -{ - SocketHandle *sockethandle; - int ret; - MonoThreadInfo *info; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - do { - MONO_ENTER_GC_SAFE; - ret = sendto (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, to, tolen); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -int -mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking) -{ - struct msghdr hdr; - MonoThreadInfo *info; - SocketHandle *sockethandle; - gint ret; - - g_assert (overlapped == NULL); - g_assert (complete == NULL); - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - wsabuf_to_msghdr (buffers, count, &hdr); - - do { - MONO_ENTER_GC_SAFE; - ret = sendmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, flags); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - msghdr_iov_free (&hdr); - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: sendmsg error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - *sent = ret; - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -#define SF_BUFFER_SIZE 16384 - -BOOL -mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, gpointer lpTransmitBuffers, guint32 flags, gboolean blocking) -{ - MonoThreadInfo *info; - SocketHandle *sockethandle; - gint file; - gssize ret; -#if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) - struct stat statbuf; -#else - gpointer buffer; -#endif - TRANSMIT_FILE_BUFFERS *buffers = (TRANSMIT_FILE_BUFFERS *)lpTransmitBuffers; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return FALSE; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return FALSE; - } - - /* Write the header */ - if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) { - ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Head, buffers->HeadLength, 0, FALSE); - if (ret == SOCKET_ERROR) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return FALSE; - } - } - - info = mono_thread_info_current (); - - file = GPOINTER_TO_INT (file_handle); - -#if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) - MONO_ENTER_GC_SAFE; - ret = fstat (file, &statbuf); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return FALSE; - } - - do { - MONO_ENTER_GC_SAFE; -#ifdef __linux__ - ret = sendfile (((MonoFDHandle*) sockethandle)->fd, file, NULL, statbuf.st_size); -#elif defined(DARWIN) - /* TODO: header/tail could be sent in the 5th argument */ - /* TODO: Might not send the entire file for non-blocking sockets */ - ret = sendfile (file, ((MonoFDHandle*) sockethandle)->fd, 0, &statbuf.st_size, NULL, 0); -#endif - MONO_EXIT_GC_SAFE; - } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); -#else - buffer = g_malloc (SF_BUFFER_SIZE); - - do { - do { - MONO_ENTER_GC_SAFE; - ret = read (file, buffer, SF_BUFFER_SIZE); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1 || ret == 0) - break; - - do { - MONO_ENTER_GC_SAFE; - ret = send (((MonoFDHandle*) sockethandle)->fd, buffer, ret, 0); /* short sends? enclose this in a loop? */ - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - g_free (buffer); -#endif - - if (ret == -1) { - gint errnum = errno; - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return FALSE; - } - - /* Write the tail */ - if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) { - ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Tail, buffers->TailLength, 0, FALSE); - if (ret == SOCKET_ERROR) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return FALSE; - } - } - - if ((flags & TF_DISCONNECT) == TF_DISCONNECT) - mono_w32socket_close (((MonoFDHandle*) sockethandle)->fd); - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return TRUE; -} - -SOCKET -mono_w32socket_socket (int domain, int type, int protocol) -{ - SocketHandle *sockethandle; - gint fd; - -retry_socket: - MONO_ENTER_GC_SAFE; - fd = socket (domain, type, protocol); - MONO_EXIT_GC_SAFE; - if (fd == -1) { - if (domain == AF_INET && type == SOCK_RAW && protocol == 0) { - /* Retry with protocol == 4 (see bug #54565) */ - // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565 - protocol = 4; - goto retry_socket; - } - - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - return INVALID_SOCKET; - } - - sockethandle = socket_data_create(MONO_FDTYPE_SOCKET, fd); - sockethandle->domain = domain; - sockethandle->type = type; - sockethandle->protocol = protocol; - sockethandle->still_readable = 1; - - /* .net seems to set this by default for SOCK_STREAM, not for - * SOCK_DGRAM (see bug #36322) - * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322 - * - * It seems winsock has a rather different idea of what - * SO_REUSEADDR means. If it's set, then a new socket can be - * bound over an existing listening socket. There's a new - * windows-specific option called SO_EXCLUSIVEADDRUSE but - * using that means the socket MUST be closed properly, or a - * denial of service can occur. Luckily for us, winsock - * behaves as though any other system would when SO_REUSEADDR - * is true, so we don't need to do anything else here. See - * bug 53992. - * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992 - */ - { - int ret; - const int true_ = 1; - - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_)); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: Error setting SO_REUSEADDR", __func__); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - - MONO_ENTER_GC_SAFE; - close (((MonoFDHandle*) sockethandle)->fd); - MONO_EXIT_GC_SAFE; - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return INVALID_SOCKET; - } - } - - mono_fdhandle_insert ((MonoFDHandle*) sockethandle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd)); - - return ((MonoFDHandle*) sockethandle)->fd; -} - -gint -mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen) -{ - SocketHandle *sockethandle; - int ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = bind (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: bind error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - -#ifdef HAVE_GETPEERNAME - MONO_ENTER_GC_SAFE; - ret = getpeername (((MonoFDHandle*) sockethandle)->fd, name, namelen); - MONO_EXIT_GC_SAFE; -#else - ret = -1; -#endif - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getpeername error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = getsockname (((MonoFDHandle*) sockethandle)->fd, name, namelen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockname error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen) -{ - SocketHandle *sockethandle; - gint ret; - struct timeval tv; - gpointer tmp_val; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - tmp_val = optval; - if (level == SOL_SOCKET && - (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { - tmp_val = &tv; - *optlen = sizeof (tv); - } - - MONO_ENTER_GC_SAFE; - ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { - *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro - *optlen = sizeof (int); - } - - if (optname == SO_ERROR) { - if (*((int *)optval) != 0) { - *((int *) optval) = mono_w32socket_convert_error (*((int *)optval)); - sockethandle->saved_error = *((int *)optval); - } else { - *((int *)optval) = sockethandle->saved_error; - } - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen) -{ - SocketHandle *sockethandle; - gint ret; - gconstpointer tmp_val; -#if defined (__linux__) - /* This has its address taken so it cannot be moved to the if block which uses it */ - gint bufsize = 0; -#endif - struct timeval tv; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - tmp_val = optval; - if (level == SOL_SOCKET && - (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { - int ms = *((int *) optval); - tv.tv_sec = ms / 1000; - tv.tv_usec = (ms % 1000) * 1000; // micro from milli - tmp_val = &tv; - optlen = sizeof (tv); - } -#if defined (__linux__) - else if (level == SOL_SOCKET && - (optname == SO_SNDBUF || optname == SO_RCVBUF)) { - /* According to socket(7) the Linux kernel doubles the - * buffer sizes "to allow space for bookkeeping - * overhead." - */ - bufsize = *((int *) optval); - - bufsize /= 2; - tmp_val = &bufsize; - } -#endif - - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: setsockopt error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - -#if defined (SO_REUSEPORT) - /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */ - if (level == SOL_SOCKET && optname == SO_REUSEADDR) { - int type; - socklen_t type_len = sizeof (type); - - MONO_ENTER_GC_SAFE; - ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_TYPE, &type, &type_len); - MONO_EXIT_GC_SAFE; - if (!ret) { - if (type == SOCK_DGRAM || type == SOCK_STREAM) { - MONO_ENTER_GC_SAFE; - setsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_REUSEPORT, tmp_val, optlen); - MONO_EXIT_GC_SAFE; - } - } - } -#endif - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -gint -mono_w32socket_listen (SOCKET sock, gint backlog) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = listen (((MonoFDHandle*) sockethandle)->fd, backlog); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: listen error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_shutdown (SOCKET sock, gint how) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (how == SHUT_RD || how == SHUT_RDWR) - sockethandle->still_readable = 0; - - MONO_ENTER_GC_SAFE; - ret = shutdown (((MonoFDHandle*) sockethandle)->fd, how); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: shutdown error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -gint -mono_w32socket_disconnect (SOCKET sock, gboolean reuse) -{ - SocketHandle *sockethandle; - SOCKET newsock; - gint ret; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: called on socket %d!", __func__, sock); - - /* We could check the socket type here and fail unless its - * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn) - * if we really wanted to */ - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - newsock = socket (sockethandle->domain, sockethandle->type, sockethandle->protocol); - MONO_EXIT_GC_SAFE; - if (newsock == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errnum)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - /* According to Stevens "Advanced Programming in the UNIX - * Environment: UNIX File I/O" dup2() is atomic so there - * should not be a race condition between the old fd being - * closed and the new socket fd being copied over */ - do { - MONO_ENTER_GC_SAFE; - ret = dup2 (newsock, ((MonoFDHandle*) sockethandle)->fd); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EAGAIN); - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: dup2 error: %s", __func__, g_strerror (errnum)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - close (newsock); - MONO_EXIT_GC_SAFE; - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -static gboolean -extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved) -{ - gboolean ret; - MONO_ENTER_GC_UNSAFE; - ret = mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0; - MONO_EXIT_GC_UNSAFE; - return ret; -} - -static gboolean -extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send, - OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags) -{ - gboolean ret; - MONO_ENTER_GC_UNSAFE; - ret = mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE); - MONO_EXIT_GC_UNSAFE; - return ret; -} - -const -static struct { - GUID guid; - gpointer func; -} extension_functions[] = { - { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, (gpointer)extension_disconect }, - { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, (gpointer)extension_transmit_file }, - { {0} , NULL }, -}; - -gint -mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written) -{ - SocketHandle *sockethandle; - gint ret; - gpointer buffer; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) { - gint i; - GUID *guid; - - if (inputlen < sizeof(GUID)) { - /* As far as I can tell, windows doesn't - * actually set an error here... - */ - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (outputlen < sizeof(gpointer)) { - /* Or here... */ - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (output == NULL) { - /* Or here */ - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - guid = (GUID*) input; - for (i = 0; extension_functions[i].func; i++) { - if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) { - memcpy (output, &extension_functions[i].func, sizeof(gpointer)); - *written = sizeof(gpointer); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; - } - } - - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) { - guint32 onoff; - - if (inputlen < 3 * sizeof (guint32)) { - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - onoff = *((guint32*) input); - - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32)); - MONO_EXIT_GC_SAFE; - if (ret < 0) { - mono_w32socket_set_last_error (mono_w32socket_convert_error (errno)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - -#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) - if (onoff != 0) { - /* Values are in ms, but we need s */ - guint32 keepalivetime, keepaliveinterval, rem; - - keepalivetime = *(((guint32*) input) + 1); - keepaliveinterval = *(((guint32*) input) + 2); - - /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */ - rem = keepalivetime % 1000; - keepalivetime /= 1000; - if (keepalivetime == 0 || rem >= 500) - keepalivetime++; - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32)); - MONO_EXIT_GC_SAFE; - if (ret == 0) { - rem = keepaliveinterval % 1000; - keepaliveinterval /= 1000; - if (keepaliveinterval == 0 || rem >= 500) - keepaliveinterval++; - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32)); - MONO_EXIT_GC_SAFE; - } - if (ret != 0) { - mono_w32socket_set_last_error (mono_w32socket_convert_error (errno)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; - } -#endif - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; - } - - buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL; - - MONO_ENTER_GC_SAFE; - ret = ioctl (((MonoFDHandle*) sockethandle)->fd, command, buffer); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - g_free (buffer); - - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: WSAIoctl error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (!buffer) { - *written = 0; - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; - } - - /* We just copy the buffer to the output. Some ioctls - * don't even output any data, but, well... - * - * NB windows returns WSAEFAULT if outputlen is too small */ - inputlen = (inputlen > outputlen) ? outputlen : inputlen; - - if (inputlen > 0 && output != NULL) - memcpy (output, buffer, inputlen); - - g_free (buffer); - *written = inputlen; - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gboolean -mono_w32socket_close (SOCKET sock) -{ - if (!mono_fdhandle_close (sock)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - return TRUE; -} - -gint -mono_w32socket_set_blocking (SOCKET sock, gboolean blocking) -{ -#ifdef O_NONBLOCK - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - /* This works better than ioctl(...FIONBIO...) - * on Linux (it causes connect to return - * EINPROGRESS, but the ioctl doesn't seem to) */ - MONO_ENTER_GC_SAFE; - ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK))); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -#else - mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED); - return SOCKET_ERROR; -#endif /* O_NONBLOCK */ -} - -gint -mono_w32socket_get_available (SOCKET sock, guint64 *amount) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - -#if defined (HOST_DARWIN) - // ioctl (socket, FIONREAD, XXX) returns the size of - // the UDP header as well on Darwin. - // - // Use getsockopt SO_NREAD instead to get the - // right values for TCP and UDP. - // - // ai_canonname can be null in some cases on darwin, - // where the runtime assumes it will be the value of - // the ip buffer. - - socklen_t optlen = sizeof (int); - MONO_ENTER_GC_SAFE; - ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } -#else - MONO_ENTER_GC_SAFE; - ret = ioctl (((MonoFDHandle*) sockethandle)->fd, FIONREAD, (gulong*) amount); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: ioctl error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } -#endif - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -void -mono_w32socket_set_last_error (gint32 error) -{ - mono_w32error_set_last (error); -} - -gint32 -mono_w32socket_get_last_error (void) -{ - return mono_w32error_get_last (); -} - -gint32 -mono_w32socket_convert_error (gint error) -{ - switch (error) { - case 0: return ERROR_SUCCESS; - case EACCES: return WSAEACCES; -#ifdef EADDRINUSE - case EADDRINUSE: return WSAEADDRINUSE; -#endif -#ifdef EAFNOSUPPORT - case EAFNOSUPPORT: return WSAEAFNOSUPPORT; -#endif -#if EAGAIN != EWOULDBLOCK - case EAGAIN: return WSAEWOULDBLOCK; -#endif -#ifdef EALREADY - case EALREADY: return WSAEALREADY; -#endif - case EBADF: return WSAENOTSOCK; -#ifdef ECONNABORTED - case ECONNABORTED: return WSAENETDOWN; -#endif -#ifdef ECONNREFUSED - case ECONNREFUSED: return WSAECONNREFUSED; -#endif -#ifdef ECONNRESET - case ECONNRESET: return WSAECONNRESET; -#endif - case EDOM: return WSAEINVAL; /* not a precise match, best wecan do. */ - case EFAULT: return WSAEFAULT; -#ifdef EHOSTUNREACH - case EHOSTUNREACH: return WSAEHOSTUNREACH; -#endif -#ifdef EINPROGRESS - case EINPROGRESS: return WSAEINPROGRESS; -#endif - case EINTR: return WSAEINTR; - case EINVAL: return WSAEINVAL; - case EIO: return WSA_INVALID_HANDLE; /* not a precise match, best we can do. */ -#ifdef EISCONN - case EISCONN: return WSAEISCONN; -#endif - case ELOOP: return WSAELOOP; - case ENFILE: return WSAEMFILE; /* not a precise match, best we can do. */ - case EMFILE: return WSAEMFILE; -#ifdef EMSGSIZE - case EMSGSIZE: return WSAEMSGSIZE; -#endif - case ENAMETOOLONG: return WSAENAMETOOLONG; -#ifdef ENETUNREACH - case ENETUNREACH: return WSAENETUNREACH; -#endif -#ifdef ENOBUFS - case ENOBUFS: return WSAENOBUFS; /* not documented */ -#endif - case ENOMEM: return WSAENOBUFS; -#ifdef ENOPROTOOPT - case ENOPROTOOPT: return WSAENOPROTOOPT; -#endif -#ifdef ENOSR - case ENOSR: return WSAENETDOWN; -#endif -#ifdef ENOTCONN - case ENOTCONN: return WSAENOTCONN; -#endif - case ENOTDIR: return WSA_INVALID_PARAMETER; /* not a precise match, best we can do. */ -#ifdef ENOTSOCK - case ENOTSOCK: return WSAENOTSOCK; -#endif - case ENOTTY: return WSAENOTSOCK; -#ifdef EOPNOTSUPP - case EOPNOTSUPP: return WSAEOPNOTSUPP; -#endif - case EPERM: return WSAEACCES; - case EPIPE: return WSAESHUTDOWN; -#ifdef EPROTONOSUPPORT - case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT; -#endif -#if ERESTARTSYS - case ERESTARTSYS: return WSAENETDOWN; -#endif - /*FIXME: case EROFS: return WSAE????; */ -#ifdef ESOCKTNOSUPPORT - case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT; -#endif -#ifdef ETIMEDOUT - case ETIMEDOUT: return WSAETIMEDOUT; -#endif -#ifdef EWOULDBLOCK - case EWOULDBLOCK: return WSAEWOULDBLOCK; -#endif -#ifdef EADDRNOTAVAIL - case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL; -#endif - /* This might happen with unix sockets */ - case ENOENT: return WSAECONNREFUSED; -#ifdef EDESTADDRREQ - case EDESTADDRREQ: return WSAEDESTADDRREQ; -#endif -#ifdef EHOSTDOWN - case EHOSTDOWN: return WSAEHOSTDOWN; -#endif -#ifdef ENETDOWN - case ENETDOWN: return WSAENETDOWN; -#endif - case ENODEV: return WSAENETDOWN; -#ifdef EPROTOTYPE - case EPROTOTYPE: return WSAEPROTOTYPE; -#endif -#ifdef ENXIO - case ENXIO: return WSAENXIO; -#endif -#ifdef ENONET - case ENONET: return WSAENETUNREACH; -#endif -#ifdef ENOKEY - case ENOKEY: return WSAENETUNREACH; -#endif - default: - g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error)); - } -} - -gboolean -mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle) -{ - SocketHandle *sockethandle; - - if (!mono_fdhandle_lookup_and_ref (GPOINTER_TO_INT(handle), (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - *duplicate_handle = handle; - return TRUE; -} diff --git a/src/mono/mono/metadata/w32socket-win32.c b/src/mono/mono/metadata/w32socket-win32.c deleted file mode 100644 index 40eb6c89415564..00000000000000 --- a/src/mono/mono/metadata/w32socket-win32.c +++ /dev/null @@ -1,309 +0,0 @@ -/** - * \file - * Windows specific socket code. - * - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include -#include - -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -#include - -#include "w32socket.h" -#include "w32socket-internals.h" - -#include "utils/w32api.h" -#include "utils/mono-os-wait.h" -#include "icall-decl.h" - -#define LOGDEBUG(...) - -void -mono_w32socket_initialize (void) -{ -} - -void -mono_w32socket_cleanup (void) -{ -} - -// See win32_wait_interrupt_handler for details. -static void -win32_io_interrupt_handler(gpointer ignored) -{ -} - -#define INTERRUPTABLE_SOCKET_CALL(blocking, ret, op, sock, ...) \ - MonoThreadInfo *info = mono_thread_info_current (); \ - gboolean alerted = FALSE; \ - if (blocking && info) { \ - mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted); \ - if (alerted) { \ - WSASetLastError (WSAEINTR); \ - } else { \ - mono_win32_enter_blocking_io_call (info, (HANDLE)sock); \ - } \ - } \ - if (!alerted) { \ - MONO_ENTER_GC_SAFE; \ - if (blocking && info && mono_thread_info_is_interrupt_state (info)) { \ - WSASetLastError (WSAEINTR); \ - } else { \ - ret = op (sock, __VA_ARGS__); \ - } \ - MONO_EXIT_GC_SAFE; \ - } \ - if (blocking && info && !alerted) { \ - mono_win32_leave_blocking_io_call (info, (HANDLE)sock); \ - mono_thread_info_uninstall_interrupt (&alerted); \ - } - -SOCKET mono_w32socket_accept (SOCKET s, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking) -{ - SOCKET ret = INVALID_SOCKET; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, accept, s, addr, addrlen); - return ret; -} - -int mono_w32socket_connect (SOCKET s, const struct sockaddr *name, int namelen, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, connect, s, name, namelen); - return ret; -} - -int mono_w32socket_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, recv, s, buf, len, flags); - return ret; -} - -int mono_w32socket_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, recvfrom, s, buf, len, flags, from, fromlen); - return ret; -} - -int mono_w32socket_recvbuffers (SOCKET s, WSABUF *lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 *lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, WSARecv, s, lpBuffers, dwBufferCount, (LPDWORD)lpNumberOfBytesRecvd, (LPDWORD)lpFlags, (LPWSAOVERLAPPED)lpOverlapped, (LPWSAOVERLAPPED_COMPLETION_ROUTINE)lpCompletionRoutine); - return ret; -} - -int mono_w32socket_send (SOCKET s, void *buf, int len, int flags, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, send, s, (const char *)buf, len, flags); - return ret; -} - -int mono_w32socket_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, sendto, s, buf, len, flags, to, tolen); - return ret; -} - -int mono_w32socket_sendbuffers (SOCKET s, WSABUF *lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, WSASend, s, lpBuffers, dwBufferCount, (LPDWORD)lpNumberOfBytesRecvd, lpFlags, (LPWSAOVERLAPPED)lpOverlapped, (LPWSAOVERLAPPED_COMPLETION_ROUTINE)lpCompletionRoutine); - return ret; -} - -#if HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE -static gint -internal_w32socket_transmit_file (SOCKET sock, gpointer file, TRANSMIT_FILE_BUFFERS *lpTransmitBuffers, guint32 dwReserved, gboolean blocking) -{ - gint ret = ERROR_NOT_SUPPORTED; - LPFN_TRANSMITFILE transmit_file; - GUID transmit_file_guid = WSAID_TRANSMITFILE; - DWORD output_bytes; - - if (!WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &transmit_file_guid, sizeof (GUID), &transmit_file, sizeof (LPFN_TRANSMITFILE), &output_bytes, NULL, NULL)) { - MonoThreadInfo *info = mono_thread_info_current (); - gboolean alerted = FALSE; - - if (blocking && info) { - mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted); - if (alerted) { - WSASetLastError (WSAEINTR); - } else { - mono_win32_enter_blocking_io_call (info, (HANDLE)sock); - } - } - - if (!alerted) { - MONO_ENTER_GC_SAFE; - if (blocking && info && mono_thread_info_is_interrupt_state (info)) { - WSASetLastError (WSAEINTR); - } else { - if (transmit_file (sock, file, 0, 0, NULL, lpTransmitBuffers, dwReserved)) - ret = 0; - } - MONO_EXIT_GC_SAFE; - } - - if (blocking && info && !alerted) { - mono_win32_leave_blocking_io_call (info, (HANDLE)sock); - mono_thread_info_uninstall_interrupt (&alerted); - } - } - - if (ret != 0) - ret = WSAGetLastError (); - - return ret; -} -#endif /* HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE */ - -#if HAVE_API_SUPPORT_WIN32_DISCONNECT_EX -static gint -internal_w32socket_disconnect (SOCKET sock, gboolean reuse, gboolean blocking) -{ - gint ret = ERROR_NOT_SUPPORTED; - LPFN_DISCONNECTEX disconnect; - GUID disconnect_guid = WSAID_DISCONNECTEX; - DWORD output_bytes; - - if (!WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &disconnect_guid, sizeof (GUID), &disconnect, sizeof (LPFN_DISCONNECTEX), &output_bytes, NULL, NULL)) { - MonoThreadInfo *info = mono_thread_info_current (); - gboolean alerted = FALSE; - - if (blocking && info) { - mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted); - if (alerted) { - WSASetLastError (WSAEINTR); - } else { - mono_win32_enter_blocking_io_call (info, (HANDLE)sock); - } - } - - if (!alerted) { - MONO_ENTER_GC_SAFE; - if (blocking && info && mono_thread_info_is_interrupt_state (info)) { - WSASetLastError (WSAEINTR); - } else { - if (disconnect (sock, NULL, reuse ? TF_REUSE_SOCKET : 0, 0)) - ret = 0; - } - MONO_EXIT_GC_SAFE; - } - - if (blocking && info && !alerted) { - mono_win32_leave_blocking_io_call (info, (HANDLE)sock); - mono_thread_info_uninstall_interrupt (&alerted); - } - } - - if (ret != 0) - ret = WSAGetLastError (); - - return ret; -} -#endif /* HAVE_API_SUPPORT_WIN32_DISCONNECT_EX */ - -#if HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE -BOOL mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, gpointer lpTransmitBuffers, guint32 dwReserved, gboolean blocking) -{ - return internal_w32socket_transmit_file (hSocket, hFile, (LPTRANSMIT_FILE_BUFFERS)lpTransmitBuffers, dwReserved, blocking) == 0 ? TRUE : FALSE; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_TRANSMIT_FILE -BOOL mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, gpointer lpTransmitBuffers, guint32 dwReserved, gboolean blocking) -{ - g_unsupported_api ("TransmitFile"); - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif /* HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE */ - -#if HAVE_API_SUPPORT_WIN32_DISCONNECT_EX -gint -mono_w32socket_disconnect (SOCKET sock, gboolean reuse) -{ - gint ret = SOCKET_ERROR; - - ret = internal_w32socket_disconnect (sock, reuse, TRUE); -#if HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE - if (ret == 0) - ret = internal_w32socket_transmit_file (sock, NULL, NULL, TF_DISCONNECT | (reuse ? TF_REUSE_SOCKET : 0), TRUE); -#endif /* HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE */ - - return ret; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_DISCONNECT_EX -gint -mono_w32socket_disconnect (SOCKET sock, gboolean reuse) -{ - g_unsupported_api ("DisconnectEx"); - SetLastError (ERROR_NOT_SUPPORTED); - return ERROR_NOT_SUPPORTED; -} -#endif /* HAVE_API_SUPPORT_WIN32_DISCONNECT_EX */ - -gint -mono_w32socket_set_blocking (SOCKET sock, gboolean blocking) -{ - gint ret; - gulong nonblocking_long = !blocking; - MONO_ENTER_GC_SAFE; - ret = ioctlsocket (sock, FIONBIO, &nonblocking_long); - MONO_EXIT_GC_SAFE; - return ret; -} - -gint -mono_w32socket_get_available (SOCKET sock, guint64 *amount) -{ - gint ret; - u_long amount_long = 0; - MONO_ENTER_GC_SAFE; - ret = ioctlsocket (sock, FIONREAD, &amount_long); - *amount = amount_long; - MONO_EXIT_GC_SAFE; - return ret; -} - -void -mono_w32socket_set_last_error (gint32 error) -{ - WSASetLastError (error); -} - -gint32 -mono_w32socket_get_last_error (void) -{ - return WSAGetLastError (); -} - -gint32 -mono_w32socket_convert_error (gint error) -{ - return (error > 0 && error < WSABASEERR) ? error + WSABASEERR : error; -} - -gboolean -mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle) -{ - gboolean ret; - - MONO_ENTER_GC_SAFE; - ret = DuplicateHandle (GetCurrentProcess(), handle, GINT_TO_POINTER(targetProcessId), duplicate_handle, 0, 0, 0x00000002 /* DUPLICATE_SAME_ACCESS */); - MONO_EXIT_GC_SAFE; - - return ret; -} diff --git a/src/mono/mono/metadata/w32socket.h b/src/mono/mono/metadata/w32socket.h deleted file mode 100644 index 650e64d6f3411a..00000000000000 --- a/src/mono/mono/metadata/w32socket.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * \file - * System.Net.Sockets.Socket support - * - * Author: - * Dick Porter (dick@ximian.com) - * - * (C) 2001 Ximian, Inc. - */ - -#ifndef _MONO_METADATA_W32SOCKET_H_ -#define _MONO_METADATA_W32SOCKET_H_ - -#include -#include -#include -#include - -#ifndef HOST_WIN32 -#define INVALID_SOCKET ((SOCKET)(guint32)(~0)) -#define SOCKET_ERROR (-1) - -typedef gint SOCKET; - -typedef struct { - guint32 len; - gpointer buf; -} WSABUF, *LPWSABUF; -#endif - -#endif /* _MONO_METADATA_W32SOCKET_H_ */ diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index b3b4b609df9c77..410c445501146a 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -68,7 +68,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index b87b6caf990696..582bb6fbff1e09 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -634,11 +634,6 @@ mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code, MonoJumpInfo *ji, gpoi #ifdef HOST_WASM -/* -The following functions don't belong here, but are due to laziness. -*/ -gboolean mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize); - G_BEGIN_DECLS void * getgrnam (const char *name); @@ -650,25 +645,6 @@ int sem_timedwait (sem_t *sem, const struct timespec *abs_timeout); G_END_DECLS -//w32file-wasm.c -gboolean -mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize) -{ - glong len; - gboolean status = FALSE; - - gunichar2 *ret = g_utf8_to_utf16 ("memfs", -1, NULL, &len, NULL); - if (ret != NULL && len < fsbuffersize) { - memcpy (fsbuffer, ret, len * sizeof (gunichar2)); - fsbuffer [len] = 0; - status = TRUE; - } - if (ret != NULL) - g_free (ret); - - return status; -} - G_BEGIN_DECLS //llvm builtin's that we should not have used in the first place