diff --git a/configure.REMOVED.git-id b/configure.REMOVED.git-id
index fb7756be96..5d0e94b95c 100644
--- a/configure.REMOVED.git-id
+++ b/configure.REMOVED.git-id
@@ -1 +1 @@
-780e08f1c84044d68b8cf86772043410d3356b47
\ No newline at end of file
+e3fddfdc54d7204c3e52ef2273ea8a313426467c
\ No newline at end of file
diff --git a/configure.ac.REMOVED.git-id b/configure.ac.REMOVED.git-id
index 0c9124d0eb..81c5f08b2e 100644
--- a/configure.ac.REMOVED.git-id
+++ b/configure.ac.REMOVED.git-id
@@ -1 +1 @@
-2092fc41e2cc7db82ed0569a412bdf7e09f30285
\ No newline at end of file
+f4f0b4d1402862ad9ca37078d37fedfb7dd03bed
\ No newline at end of file
diff --git a/external/api-snapshot/profiles/monodroid/System.cs.REMOVED.git-id b/external/api-snapshot/profiles/monodroid/System.cs.REMOVED.git-id
index 64729d4105..e6bf759e3e 100644
--- a/external/api-snapshot/profiles/monodroid/System.cs.REMOVED.git-id
+++ b/external/api-snapshot/profiles/monodroid/System.cs.REMOVED.git-id
@@ -1 +1 @@
-0a306482eac9dc254a050e40a50147c9f8a8f319
\ No newline at end of file
+a4d41f54aa4e797510b7305e90672d0f0b716d01
\ No newline at end of file
diff --git a/external/api-snapshot/profiles/monotouch/System.cs.REMOVED.git-id b/external/api-snapshot/profiles/monotouch/System.cs.REMOVED.git-id
index 90ff443c45..9027baaebc 100644
--- a/external/api-snapshot/profiles/monotouch/System.cs.REMOVED.git-id
+++ b/external/api-snapshot/profiles/monotouch/System.cs.REMOVED.git-id
@@ -1 +1 @@
-f1f7d7c12ac0ebb5ae0ba105d8a40604bbe64b2a
\ No newline at end of file
+e7cc3043af28842bbfcbfcc3e778a58f8ee6e205
\ No newline at end of file
diff --git a/external/api-snapshot/profiles/net_4_x/System.cs.REMOVED.git-id b/external/api-snapshot/profiles/net_4_x/System.cs.REMOVED.git-id
index 573132a531..c01074bc7f 100644
--- a/external/api-snapshot/profiles/net_4_x/System.cs.REMOVED.git-id
+++ b/external/api-snapshot/profiles/net_4_x/System.cs.REMOVED.git-id
@@ -1 +1 @@
-47154482003e653af7b9a47e14d653dd2a666e8d
\ No newline at end of file
+b081ba1d1e3552cb0f915ccd31f8797bf18c73b5
\ No newline at end of file
diff --git a/external/corefx/src/Common/src/Interop/OSX/Interop.EventStream.cs b/external/corefx/src/Common/src/Interop/OSX/Interop.EventStream.cs
index b5cbbdb499..7c6e93c761 100644
--- a/external/corefx/src/Common/src/Interop/OSX/Interop.EventStream.cs
+++ b/external/corefx/src/Common/src/Interop/OSX/Interop.EventStream.cs
@@ -82,12 +82,12 @@ internal static partial class Interop
/// The events for the corresponding path.
/// The machine-and-disk-drive-unique Event ID for the specific event.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- internal delegate void FSEventStreamCallback(
+ internal unsafe delegate void FSEventStreamCallback(
FSEventStreamRef streamReference,
IntPtr clientCallBackInfo,
size_t numEvents,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
- String[] eventPaths,
+ byte** eventPaths,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
FSEventStreamEventFlags[] eventFlags,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
diff --git a/external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.ReadDirectoryChangesW.cs b/external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.ReadDirectoryChangesW.cs
index 84cd715e57..4d4d38f0d2 100644
--- a/external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.ReadDirectoryChangesW.cs
+++ b/external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.ReadDirectoryChangesW.cs
@@ -15,7 +15,7 @@ internal partial class Interop
internal static extern unsafe bool ReadDirectoryChangesW(
SafeFileHandle hDirectory,
byte[] lpBuffer,
- int nBufferLength,
+ uint nBufferLength,
[MarshalAs(UnmanagedType.Bool)] bool bWatchSubtree,
int dwNotifyFilter,
out int lpBytesReturned,
diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs b/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs
index d86b5781ea..87c6181857 100644
--- a/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs
+++ b/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs
@@ -2,10 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
+using System.Text;
using CFStringRef = System.IntPtr;
using FSEventStreamRef = System.IntPtr;
@@ -146,8 +148,6 @@ namespace System.IO
// The EventStream to listen for events on
private SafeEventStreamHandle _eventStream;
- // A reference to the RunLoop that we can use to start or stop a Watcher
- private CFRunLoopRef _watcherRunLoop;
// Callback delegate for the EventStream events
private Interop.EventStream.FSEventStreamCallback _callback;
@@ -158,7 +158,8 @@ namespace System.IO
// Calling RunLoopStop multiple times SegFaults so protect the call to it
private bool _stopping;
- private object StopLock => this;
+
+ private ExecutionContext _context;
internal RunningInstance(
FileSystemWatcher watcher,
@@ -171,7 +172,6 @@ namespace System.IO
Debug.Assert(!cancelToken.IsCancellationRequested);
_weakWatcher = new WeakReference(watcher);
- _watcherRunLoop = IntPtr.Zero;
_fullDirectory = System.IO.Path.GetFullPath(directory);
_includeChildren = includeChildren;
_filterFlags = filter;
@@ -180,21 +180,111 @@ namespace System.IO
_stopping = false;
}
- private void CancellationCallback()
+ private static class StaticWatcherRunLoopManager
{
- lock (StopLock)
- {
- if (!_stopping && _watcherRunLoop != IntPtr.Zero)
- {
- _stopping = true;
+ // A reference to the RunLoop that we can use to start or stop a Watcher
+ private static CFRunLoopRef s_watcherRunLoop = IntPtr.Zero;
- // Stop the FS event message pump
- Interop.RunLoop.CFRunLoopStop(_watcherRunLoop);
+ private static int s_scheduledStreamsCount = 0;
+
+ private static readonly object s_lockObject = new object();
+
+ public static void ScheduleEventStream(SafeEventStreamHandle eventStream)
+ {
+ lock (s_lockObject)
+ {
+ if (s_watcherRunLoop != IntPtr.Zero)
+ {
+ // Schedule the EventStream to run on the thread's RunLoop
+ s_scheduledStreamsCount++;
+ Interop.EventStream.FSEventStreamScheduleWithRunLoop(eventStream, s_watcherRunLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
+ return;
+ }
+
+ Debug.Assert(s_scheduledStreamsCount == 0);
+ s_scheduledStreamsCount = 1;
+ var runLoopStarted = new ManualResetEventSlim();
+ new Thread(WatchForFileSystemEventsThreadStart) { IsBackground = true }.Start(new object[] { runLoopStarted, eventStream });
+ runLoopStarted.Wait();
+ }
+ }
+
+ public static void UnscheduleFromRunLoop(SafeEventStreamHandle eventStream)
+ {
+ Debug.Assert(s_watcherRunLoop != IntPtr.Zero);
+ lock (s_lockObject)
+ {
+ if (s_watcherRunLoop != IntPtr.Zero)
+ {
+ // Always unschedule the RunLoop before cleaning up
+ Interop.EventStream.FSEventStreamUnscheduleFromRunLoop(eventStream, s_watcherRunLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
+ s_scheduledStreamsCount--;
+
+ if (s_scheduledStreamsCount == 0)
+ {
+ // Stop the FS event message pump
+ Interop.RunLoop.CFRunLoopStop(s_watcherRunLoop);
+ s_watcherRunLoop = IntPtr.Zero;
+ }
+ }
+ }
+ }
+
+ private static void WatchForFileSystemEventsThreadStart(object args)
+ {
+ var inputArgs = (object[])args;
+ var runLoopStarted = (ManualResetEventSlim)inputArgs[0];
+ var _eventStream = (SafeEventStreamHandle)inputArgs[1];
+ // Get this thread's RunLoop
+ IntPtr runLoop = Interop.RunLoop.CFRunLoopGetCurrent();
+ s_watcherRunLoop = runLoop;
+ Debug.Assert(s_watcherRunLoop != IntPtr.Zero);
+
+ // Retain the RunLoop so that it doesn't get moved or cleaned up before we're done with it.
+ IntPtr retainResult = Interop.CoreFoundation.CFRetain(runLoop);
+ Debug.Assert(retainResult == runLoop, "CFRetain is supposed to return the input value");
+
+ // Schedule the EventStream to run on the thread's RunLoop
+ Interop.EventStream.FSEventStreamScheduleWithRunLoop(_eventStream, runLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
+
+ runLoopStarted.Set();
+ try
+ {
+ // Start the OS X RunLoop (a blocking call) that will pump file system changes into the callback function
+ Interop.RunLoop.CFRunLoopRun();
+ }
+ finally
+ {
+ lock (s_lockObject)
+ {
+#if MONO
+ s_watcherRunLoop = IntPtr.Zero;
+#endif
+ Interop.CoreFoundation.CFRelease(runLoop);
+ }
}
}
}
- internal void Start()
+ private void CancellationCallback()
+ {
+ if (!_stopping && _eventStream != null)
+ {
+ _stopping = true;
+
+ try
+ {
+ // When we get here, we've requested to stop so cleanup the EventStream and unschedule from the RunLoop
+ Interop.EventStream.FSEventStreamStop(_eventStream);
+ }
+ finally
+ {
+ StaticWatcherRunLoopManager.UnscheduleFromRunLoop(_eventStream);
+ }
+ }
+ }
+
+ internal unsafe void Start()
{
// Make sure _fullPath doesn't contain a link or alias
// since the OS will give back the actual, non link'd or alias'd paths
@@ -233,6 +323,8 @@ namespace System.IO
_callback = new Interop.EventStream.FSEventStreamCallback(FileSystemEventCallback);
}
+ _context = ExecutionContext.Capture();
+
// Make sure the OS file buffer(s) are fully flushed so we don't get events from cached I/O
Interop.Sys.Sync();
@@ -250,82 +342,32 @@ namespace System.IO
throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), _fullDirectory, true);
}
- // Create and start our watcher thread then wait for the thread to initialize and start
- // the RunLoop. We wait for that to prevent this function from returning before the RunLoop
- // has a chance to start so that any callers won't race with the background thread's initialization
- // and calling Stop, which would attempt to stop a RunLoop that hasn't started yet.
- var runLoopStarted = new ManualResetEventSlim();
- new Thread(WatchForFileSystemEventsThreadStart) { IsBackground = true }.Start(runLoopStarted);
- runLoopStarted.Wait();
- }
+ StaticWatcherRunLoopManager.ScheduleEventStream(_eventStream);
- private void WatchForFileSystemEventsThreadStart(object arg)
- {
- var runLoopStarted = (ManualResetEventSlim)arg;
-
- // Get this thread's RunLoop
- _watcherRunLoop = Interop.RunLoop.CFRunLoopGetCurrent();
- Debug.Assert(_watcherRunLoop != IntPtr.Zero);
-
- // Retain the RunLoop so that it doesn't get moved or cleaned up before we're done with it.
- IntPtr retainResult = Interop.CoreFoundation.CFRetain(_watcherRunLoop);
- Debug.Assert(retainResult == _watcherRunLoop, "CFRetain is supposed to return the input value");
-
- // Schedule the EventStream to run on the thread's RunLoop
- Interop.EventStream.FSEventStreamScheduleWithRunLoop(_eventStream, _watcherRunLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
-
- try
- {
- bool started = Interop.EventStream.FSEventStreamStart(_eventStream);
-
- // Notify the StartRaisingEvents call that we are initialized and about to start
- // so that it can return and avoid a race-condition around multiple threads calling Stop and Start
- runLoopStarted.Set();
-
- if (started)
+ bool started = Interop.EventStream.FSEventStreamStart(_eventStream);
+ if (!started)
+ {
+ // Try to get the Watcher to raise the error event; if we can't do that, just silently exit since the watcher is gone anyway
+ FileSystemWatcher watcher;
+ if (_weakWatcher.TryGetTarget(out watcher))
{
- // Start the OS X RunLoop (a blocking call) that will pump file system changes into the callback function
- Interop.RunLoop.CFRunLoopRun();
-
- // When we get here, we've requested to stop so cleanup the EventStream and unschedule from the RunLoop
- Interop.EventStream.FSEventStreamStop(_eventStream);
- }
- else
- {
- // Try to get the Watcher to raise the error event; if we can't do that, just silently exist since the watcher is gone anyway
- FileSystemWatcher watcher;
- if (_weakWatcher.TryGetTarget(out watcher))
- {
- // An error occurred while trying to start the run loop so fail out
- watcher.OnError(new ErrorEventArgs(new IOException(SR.EventStream_FailedToStart, Marshal.GetLastWin32Error())));
- }
- }
- }
- finally
- {
- // Always unschedule the RunLoop before cleaning up
- Interop.EventStream.FSEventStreamUnscheduleFromRunLoop(_eventStream, _watcherRunLoop, Interop.RunLoop.kCFRunLoopDefaultMode);
-
- // Release the WatcherLoop Core Foundation object.
- lock (StopLock)
- {
- Interop.CoreFoundation.CFRelease(_watcherRunLoop);
- _watcherRunLoop = IntPtr.Zero;
+ // An error occurred while trying to start the run loop so fail out
+ watcher.OnError(new ErrorEventArgs(new IOException(SR.EventStream_FailedToStart, Marshal.GetLastWin32Error())));
}
}
}
- private void FileSystemEventCallback(
- FSEventStreamRef streamRef,
- IntPtr clientCallBackInfo,
- size_t numEvents,
- String[] eventPaths,
+ private unsafe void FileSystemEventCallback(
+ FSEventStreamRef streamRef,
+ IntPtr clientCallBackInfo,
+ size_t numEvents,
+ byte** eventPaths,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
Interop.EventStream.FSEventStreamEventFlags[] eventFlags,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
FSEventStreamEventId[] eventIds)
{
- Debug.Assert((numEvents.ToInt32() == eventPaths.Length) && (numEvents.ToInt32() == eventFlags.Length) && (numEvents.ToInt32() == eventIds.Length));
+ Debug.Assert((eventPaths != null) && (numEvents.ToInt32() == eventFlags.Length) && (numEvents.ToInt32() == eventIds.Length));
// Try to get the actual watcher from our weak reference. We maintain a weak reference most of the time
// so as to avoid a rooted cycle that would prevent our processing loop from ever ending
@@ -338,18 +380,40 @@ namespace System.IO
return;
}
+ ExecutionContext context = _context;
+ if (context is null)
+ {
+ // Flow suppressed, just run here
+ ProcessEvents(numEvents.ToInt32(), eventPaths, eventFlags, eventIds, watcher);
+ }
+ else
+ {
+ ExecutionContext.Run(
+ context,
+ (object o) => ((RunningInstance)o).ProcessEvents(numEvents.ToInt32(), eventPaths, eventFlags, eventIds, watcher),
+ this);
+ }
+ }
+
+ private unsafe void ProcessEvents(int numEvents,
+ byte** eventPaths,
+ Interop.EventStream.FSEventStreamEventFlags[] eventFlags,
+ FSEventStreamEventId[] eventIds,
+ FileSystemWatcher watcher)
+ {
// Since renames come in pairs, when we find the first we need to search for the next one. Once we find it, we'll add it to this
// list so when the for-loop comes across it, we'll skip it since it's already been processed as part of the original of the pair.
List handledRenameEvents = null;
+ Memory[] events = new Memory[numEvents];
+ ParseEvents();
- for (long i = 0; i < numEvents.ToInt32(); i++)
+ for (long i = 0; i < numEvents; i++)
{
- Debug.Assert(eventPaths[i].Length > 0, "Empty events are not supported");
- Debug.Assert(eventPaths[i][eventPaths[i].Length - 1] != '/', "Trailing slashes on events is not supported");
+ ReadOnlySpan path = events[i].Span;
+ Debug.Assert(path[path.Length - 1] != '/', "Trailing slashes on events is not supported");
// Match Windows and don't notify us about changes to the Root folder
- string path = eventPaths[i];
- if (string.Compare(path, 0, _fullDirectory, 0, path.Length, StringComparison.OrdinalIgnoreCase) == 0)
+ if (_fullDirectory.Length >= path.Length && path.Equals(_fullDirectory.AsSpan(0, path.Length), StringComparison.OrdinalIgnoreCase))
{
continue;
}
@@ -366,15 +430,15 @@ namespace System.IO
// If this event is the second in a rename pair then skip it
continue;
}
- else if (CheckIfPathIsNested(path) && ((eventType = FilterEvents(eventFlags[i], path)) != 0))
+ else if (CheckIfPathIsNested(path) && ((eventType = FilterEvents(eventFlags[i])) != 0))
{
// The base FileSystemWatcher does a match check against the relative path before combining with
// the root dir; however, null is special cased to signify the root dir, so check if we should use that.
- string relativePath = null;
- if (path.Equals(_fullDirectory, StringComparison.OrdinalIgnoreCase) == false)
+ ReadOnlySpan relativePath = ReadOnlySpan.Empty;
+ if (!path.Equals(_fullDirectory, StringComparison.OrdinalIgnoreCase))
{
// Remove the root directory to get the relative path
- relativePath = path.Remove(0, _fullDirectory.Length);
+ relativePath = path.Slice(_fullDirectory.Length);
}
// Raise a notification for the event
@@ -393,7 +457,7 @@ namespace System.IO
if (((eventType & WatcherChangeTypes.Renamed) > 0))
{
// Find the rename that is paired to this rename, which should be the next rename in the list
- long pairedId = FindRenameChangePairedChange(i, eventPaths, eventFlags, eventIds);
+ long pairedId = FindRenameChangePairedChange(i, eventFlags);
if (pairedId == long.MinValue)
{
// Getting here means we have a rename without a pair, meaning it should be a create for the
@@ -416,7 +480,7 @@ namespace System.IO
{
// Remove the base directory prefix and add the paired event to the list of
// events to skip and notify the user of the rename
- string newPathRelativeName = eventPaths[pairedId].Remove(0, _fullDirectory.Length);
+ ReadOnlySpan newPathRelativeName = events[pairedId].Span.Slice(_fullDirectory.Length);
watcher.NotifyRenameEventArgs(WatcherChangeTypes.Renamed, newPathRelativeName, relativePath);
// Create a new list, if necessary, and add the event
@@ -428,6 +492,37 @@ namespace System.IO
}
}
}
+
+ ArraySegment underlyingArray;
+ if (MemoryMarshal.TryGetArray(events[i], out underlyingArray))
+ ArrayPool.Shared.Return(underlyingArray.Array);
+ }
+
+ this._context = ExecutionContext.Capture();
+
+ void ParseEvents()
+ {
+ for (int i = 0; i < events.Length; i++)
+ {
+ int byteCount = 0;
+ Debug.Assert(eventPaths[i] != null);
+ byte* temp = eventPaths[i];
+
+ // Finds the position of null character.
+ while (*temp != 0)
+ {
+ temp++;
+ byteCount++;
+ }
+
+ Debug.Assert(byteCount > 0, "Empty events are not supported");
+ events[i] = new Memory(ArrayPool.Shared.Rent(Encoding.UTF8.GetMaxCharCount(byteCount)));
+ int charCount;
+
+ // Converting an array of bytes to UTF-8 char array
+ charCount = Encoding.UTF8.GetChars(new ReadOnlySpan(eventPaths[i], byteCount), events[i].Span);
+ events[i] = events[i].Slice(0, charCount);
+ }
}
}
@@ -435,7 +530,7 @@ namespace System.IO
/// Compares the given event flags to the filter flags and returns which event (if any) corresponds
/// to those flags.
///
- private WatcherChangeTypes FilterEvents(Interop.EventStream.FSEventStreamEventFlags eventFlags, string fullPath)
+ private WatcherChangeTypes FilterEvents(Interop.EventStream.FSEventStreamEventFlags eventFlags)
{
const Interop.EventStream.FSEventStreamEventFlags changedFlags = Interop.EventStream.FSEventStreamEventFlags.kFSEventStreamEventFlagItemInodeMetaMod |
Interop.EventStream.FSEventStreamEventFlags.kFSEventStreamEventFlagItemFinderInfoMod |
@@ -487,30 +582,24 @@ namespace System.IO
IsFlagSet(flags, Interop.EventStream.FSEventStreamEventFlags.kFSEventStreamEventFlagUnmount));
}
- private bool CheckIfPathIsNested(string eventPath)
+ private bool CheckIfPathIsNested(ReadOnlySpan eventPath)
{
- bool doesPathPass = true;
-
// If we shouldn't include subdirectories, check if this path's parent is the watch directory
- if (_includeChildren == false)
- {
- // Check if the parent is the root. If so, then we'll continue processing based on the name.
- // If it isn't, then this will be set to false and we'll skip the name processing since it's irrelevant.
- string parent = System.IO.Path.GetDirectoryName(eventPath);
- doesPathPass = (string.Compare(parent, 0, _fullDirectory, 0, parent.Length, StringComparison.OrdinalIgnoreCase) == 0);
- }
-
- return doesPathPass;
+ // Check if the parent is the root. If so, then we'll continue processing based on the name.
+ // If it isn't, then this will be set to false and we'll skip the name processing since it's irrelevant.
+#if MONO
+ return _includeChildren || _fullDirectory.AsSpan().StartsWith(System.IO.Path.GetDirectoryName(eventPath.ToString()), StringComparison.OrdinalIgnoreCase);
+#else
+ return _includeChildren || _fullDirectory.AsSpan().StartsWith(System.IO.Path.GetDirectoryName(eventPath), StringComparison.OrdinalIgnoreCase);
+#endif
}
private long FindRenameChangePairedChange(
long currentIndex,
- String[] eventPaths,
- Interop.EventStream.FSEventStreamEventFlags[] eventFlags,
- FSEventStreamEventId[] eventIds)
+ Interop.EventStream.FSEventStreamEventFlags[] eventFlags)
{
// Start at one past the current index and try to find the next Rename item, which should be the old path.
- for (long i = currentIndex + 1; i < eventPaths.Length; i++)
+ for (long i = currentIndex + 1; i < eventFlags.Length; i++)
{
if (IsFlagSet(eventFlags[i], Interop.EventStream.FSEventStreamEventFlags.kFSEventStreamEventFlagItemRenamed))
{
@@ -527,12 +616,26 @@ namespace System.IO
return (value & flags) == value;
}
- private static bool DoesItemExist(string path, bool isFile)
+ private static bool DoesItemExist(ReadOnlySpan path, bool isFile)
{
- if (isFile)
- return File.Exists(path);
- else
- return Directory.Exists(path);
+ if (path.IsEmpty || path.Length == 0)
+ return false;
+
+#if MONO
+ if (!isFile)
+ return Directory.Exists(path.ToString());
+
+ return path[path.Length - 1] == '/'
+ ? false
+ : File.Exists(path.ToString());
+#else
+ if (!isFile)
+ return FileSystem.DirectoryExists(path);
+
+ return PathInternal.IsDirectorySeparator(path[path.Length - 1])
+ ? false
+ : FileSystem.FileExists(path);
+#endif
}
}
}
diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs b/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
index f0f9e0a994..39cb7412ac 100644
--- a/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
+++ b/external/corefx/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
@@ -25,15 +28,12 @@ namespace System.IO
///
public partial class FileSystemWatcher : Component, ISupportInitialize
{
- ///
- /// Private instance variables
- ///
+ // Filters collection
+ private readonly NormalizedFilterCollection _filters = new NormalizedFilterCollection();
+
// Directory being monitored
private string _directory;
- // Filter for name matching
- private string _filter;
-
// The watch filter for the API call.
private const NotifyFilters c_defaultNotifyFilters = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
private NotifyFilters _notifyFilters = c_defaultNotifyFilters;
@@ -48,11 +48,10 @@ namespace System.IO
private bool _initializing = false;
// Buffer size
- private int _internalBufferSize = 8192;
+ private uint _internalBufferSize = 8192;
// Used for synchronization
private bool _disposed;
- private ISynchronizeInvoke _synchronizingObject;
// Event handlers
private FileSystemEventHandler _onChangedHandler = null;
@@ -89,15 +88,16 @@ namespace System.IO
public FileSystemWatcher()
{
_directory = string.Empty;
- _filter = "*";
}
///
/// Initializes a new instance of the class,
/// given the specified directory to monitor.
///
- public FileSystemWatcher(string path) : this(path, "*")
+ public FileSystemWatcher(string path)
{
+ CheckPathValidity(path);
+ _directory = path;
}
///
@@ -106,21 +106,9 @@ namespace System.IO
///
public FileSystemWatcher(string path, string filter)
{
- if (path == null)
- throw new ArgumentNullException(nameof(path));
-
- // Early check for directory parameter so that an exception can be thrown as early as possible.
- if (path.Length == 0)
- throw new ArgumentException(SR.Format(SR.InvalidDirName, path), nameof(path));
-
- if (!Directory.Exists(path))
- throw new ArgumentException(SR.Format(SR.InvalidDirName_NotExists, path), nameof(path));
-
+ CheckPathValidity(path);
_directory = path;
- _filter = filter ?? throw new ArgumentNullException(nameof(filter));
-
- if (_filter == "*.*")
- _filter = "*";
+ Filter = filter ?? throw new ArgumentNullException(nameof(filter));
}
///
@@ -146,6 +134,8 @@ namespace System.IO
}
}
+ public Collection Filters => _filters;
+
///
/// Gets or sets a value indicating whether the component is enabled.
///
@@ -187,20 +177,12 @@ namespace System.IO
{
get
{
- return _filter;
+ return Filters.Count == 0 ? "*" : Filters[0];
}
set
{
- if (string.IsNullOrEmpty(value))
- {
- // Skip the string compare for "*" since it has no case-insensitive representation that differs from
- // the case-sensitive representation.
- _filter = "*";
- }
- else if (!string.Equals(_filter, value, PathInternal.StringComparison))
- {
- _filter = value == "*.*" ? "*" : value;
- }
+ Filters.Clear();
+ Filters.Add(value);
}
}
@@ -231,7 +213,7 @@ namespace System.IO
{
get
{
- return _internalBufferSize;
+ return (int)_internalBufferSize;
}
set
{
@@ -243,7 +225,7 @@ namespace System.IO
}
else
{
- _internalBufferSize = value;
+ _internalBufferSize = (uint)value;
}
Restart();
@@ -284,7 +266,7 @@ namespace System.IO
if (!Directory.Exists(value))
throw new ArgumentException(SR.Format(SR.InvalidDirName_NotExists, value), nameof(Path));
-
+
_directory = value;
Restart();
}
@@ -367,8 +349,6 @@ namespace System.IO
}
}
- ///
- ///
protected override void Dispose(bool disposing)
{
try
@@ -398,66 +378,100 @@ namespace System.IO
}
}
- ///
- /// Sees if the name given matches the name filter we have.
- ///
- ///
- private bool MatchPattern(string relativePath)
+ private static void CheckPathValidity(string path)
{
- ReadOnlySpan name = IO.Path.GetFileName(relativePath.AsSpan());
- return name.Length > 0
- ? FileSystemName.MatchesSimpleExpression(_filter, name, ignoreCase: !PathInternal.IsCaseSensitive)
- : false;
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
+
+ // Early check for directory parameter so that an exception can be thrown as early as possible.
+ if (path.Length == 0)
+ throw new ArgumentException(SR.Format(SR.InvalidDirName, path), nameof(path));
+
+ if (!Directory.Exists(path))
+ throw new ArgumentException(SR.Format(SR.InvalidDirName_NotExists, path), nameof(path));
}
- ///
- /// Raises the event to each handler in the list.
- ///
- ///
+ ///
+ /// Sees if the name given matches the name filter we have.
+ ///
+ private bool MatchPattern(ReadOnlySpan relativePath)
+ {
+ ReadOnlySpan name = IO.Path.GetFileName(relativePath);
+ if (name.Length == 0)
+ return false;
+
+ string[] filters = _filters.GetFilters();
+ if (filters.Length == 0)
+ return true;
+
+ foreach (string filter in filters)
+ {
+ if (FileSystemName.MatchesSimpleExpression(filter, name, ignoreCase: !PathInternal.IsCaseSensitive))
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Raises the event to each handler in the list.
+ ///
private void NotifyInternalBufferOverflowEvent()
{
_onErrorHandler?.Invoke(this, new ErrorEventArgs(
new InternalBufferOverflowException(SR.Format(SR.FSW_BufferOverflow, _directory))));
}
- ///
- /// Raises the event to each handler in the list.
- ///
- ///
- private void NotifyRenameEventArgs(WatcherChangeTypes action, string name, string oldName)
+ ///
+ /// Raises the event to each handler in the list.
+ ///
+ private void NotifyRenameEventArgs(WatcherChangeTypes action, ReadOnlySpan name, ReadOnlySpan oldName)
{
// filter if there's no handler or neither new name or old name match a specified pattern
RenamedEventHandler handler = _onRenamedHandler;
if (handler != null &&
(MatchPattern(name) || MatchPattern(oldName)))
{
- handler(this, new RenamedEventArgs(action, _directory, name, oldName));
+ handler(this, new RenamedEventArgs(action, _directory, name.IsEmpty ? null : name.ToString(), oldName.IsEmpty ? null : oldName.ToString()));
}
}
- ///
- /// Raises the event to each handler in the list.
- ///
- ///
- private void NotifyFileSystemEventArgs(WatcherChangeTypes changeType, string name)
+ private FileSystemEventHandler GetHandler(WatcherChangeTypes changeType)
{
- FileSystemEventHandler handler = null;
switch (changeType)
{
case WatcherChangeTypes.Created:
- handler = _onCreatedHandler;
- break;
+ return _onCreatedHandler;
case WatcherChangeTypes.Deleted:
- handler = _onDeletedHandler;
- break;
+ return _onDeletedHandler;
case WatcherChangeTypes.Changed:
- handler = _onChangedHandler;
- break;
- default:
- Debug.Fail("Unknown FileSystemEvent change type! Value: " + changeType);
- break;
+ return _onChangedHandler;
}
+ Debug.Fail("Unknown FileSystemEvent change type! Value: " + changeType);
+ return null;
+ }
+
+ ///
+ /// Raises the event to each handler in the list.
+ ///
+ private void NotifyFileSystemEventArgs(WatcherChangeTypes changeType, ReadOnlySpan name)
+ {
+ FileSystemEventHandler handler = GetHandler(changeType);
+
+ if (handler != null && MatchPattern(name.IsEmpty ? _directory : name))
+ {
+ handler(this, new FileSystemEventArgs(changeType, _directory, name.IsEmpty ? null : name.ToString()));
+ }
+ }
+
+ ///
+ /// Raises the event to each handler in the list.
+ ///
+ private void NotifyFileSystemEventArgs(WatcherChangeTypes changeType, string name)
+ {
+ FileSystemEventHandler handler = GetHandler(changeType);
+
if (handler != null && MatchPattern(string.IsNullOrEmpty(name) ? _directory : name))
{
handler(this, new FileSystemEventArgs(changeType, _directory, name));
@@ -560,9 +574,12 @@ namespace System.IO
tcs.TrySetResult(new WaitForChangedResult(e.ChangeType, e.Name, oldName: null, timedOut: false));
}
};
- if ((changeType & WatcherChangeTypes.Created) != 0) Created += fseh;
- if ((changeType & WatcherChangeTypes.Deleted) != 0) Deleted += fseh;
- if ((changeType & WatcherChangeTypes.Changed) != 0) Changed += fseh;
+ if ((changeType & WatcherChangeTypes.Created) != 0)
+ Created += fseh;
+ if ((changeType & WatcherChangeTypes.Deleted) != 0)
+ Deleted += fseh;
+ if ((changeType & WatcherChangeTypes.Changed) != 0)
+ Changed += fseh;
}
if ((changeType & WatcherChangeTypes.Renamed) != 0)
{
@@ -600,9 +617,12 @@ namespace System.IO
}
if (fseh != null)
{
- if ((changeType & WatcherChangeTypes.Changed) != 0) Changed -= fseh;
- if ((changeType & WatcherChangeTypes.Deleted) != 0) Deleted -= fseh;
- if ((changeType & WatcherChangeTypes.Created) != 0) Created -= fseh;
+ if ((changeType & WatcherChangeTypes.Changed) != 0)
+ Changed -= fseh;
+ if ((changeType & WatcherChangeTypes.Deleted) != 0)
+ Deleted -= fseh;
+ if ((changeType & WatcherChangeTypes.Created) != 0)
+ Created -= fseh;
}
}
@@ -656,17 +676,7 @@ namespace System.IO
}
}
- public ISynchronizeInvoke SynchronizingObject
- {
- get
- {
- return _synchronizingObject;
- }
- set
- {
- _synchronizingObject = value;
- }
- }
+ public ISynchronizeInvoke SynchronizingObject { get; set; }
public void BeginInit()
{
@@ -688,5 +698,101 @@ namespace System.IO
{
return _initializing || DesignMode;
}
+
+ private sealed class NormalizedFilterCollection : Collection
+ {
+ internal NormalizedFilterCollection() : base(new ImmutableStringList())
+ {
+ }
+
+ protected override void InsertItem(int index, string item)
+ {
+ base.InsertItem(index, string.IsNullOrEmpty(item) || item == "*.*" ? "*" : item);
+ }
+
+ protected override void SetItem(int index, string item)
+ {
+ base.SetItem(index, string.IsNullOrEmpty(item) || item == "*.*" ? "*" : item);
+ }
+
+ internal string[] GetFilters() => ((ImmutableStringList)Items).Items;
+
+ ///
+ /// List that maintains its underlying data in an immutable array, such that the list
+ /// will never modify an array returned from its Items property. This is to allow
+ /// the array to be enumerated safely while another thread might be concurrently mutating
+ /// the collection.
+ ///
+ private sealed class ImmutableStringList : IList
+ {
+ public string[] Items = Array.Empty();
+
+ public string this[int index]
+ {
+ get
+ {
+ string[] items = Items;
+ if ((uint)index >= (uint)items.Length)
+ {
+ throw new ArgumentOutOfRangeException(nameof(index));
+ }
+ return items[index];
+ }
+ set
+ {
+ string[] clone = (string[])Items.Clone();
+ clone[index] = value;
+ Items = clone;
+ }
+ }
+
+ public int Count => Items.Length;
+
+ public bool IsReadOnly => false;
+
+ public void Add(string item)
+ {
+ // Collection doesn't use this method.
+ throw new NotSupportedException();
+ }
+
+ public void Clear() => Items = Array.Empty();
+
+ public bool Contains(string item) => Array.IndexOf(Items, item) != -1;
+
+ public void CopyTo(string[] array, int arrayIndex) => Items.CopyTo(array, arrayIndex);
+
+ public IEnumerator GetEnumerator() => ((IEnumerable)Items).GetEnumerator();
+
+ public int IndexOf(string item) => Array.IndexOf(Items, item);
+
+ public void Insert(int index, string item)
+ {
+ string[] items = Items;
+ string[] newItems = new string[items.Length + 1];
+ items.AsSpan(0, index).CopyTo(newItems);
+ items.AsSpan(index).CopyTo(newItems.AsSpan(index + 1));
+ newItems[index] = item;
+ Items = newItems;
+ }
+
+ public bool Remove(string item)
+ {
+ // Collection doesn't use this method.
+ throw new NotSupportedException();
+ }
+
+ public void RemoveAt(int index)
+ {
+ string[] items = Items;
+ string[] newItems = new string[items.Length - 1];
+ items.AsSpan(0, index).CopyTo(newItems);
+ items.AsSpan(index + 1).CopyTo(newItems.AsSpan(index));
+ Items = newItems;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Create.cs b/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Create.cs
index b14449b3c8..765ef7aaa3 100644
--- a/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Create.cs
+++ b/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.Create.cs
@@ -26,6 +26,45 @@ namespace System.IO.Tests
}
}
+ [Fact]
+ [OuterLoop]
+ public void FileSystemWatcher_File_Create_EnablingDisablingNotAffectRaisingEvent()
+ {
+ ExecuteWithRetry(() =>
+ {
+ using (var testDirectory = new TempDirectory(GetTestFilePath()))
+ using (var watcher = new FileSystemWatcher(testDirectory.Path))
+ {
+ string fileName = Path.Combine(testDirectory.Path, "file");
+ watcher.Filter = Path.GetFileName(fileName);
+
+ int numberOfRaisedEvents = 0;
+ AutoResetEvent autoResetEvent = new AutoResetEvent(false);
+ FileSystemEventHandler handler = (o, e) =>
+ {
+ Interlocked.Increment(ref numberOfRaisedEvents);
+ autoResetEvent.Set();
+ };
+
+ watcher.Created += handler;
+
+ for (int i = 0; i < 100; i++)
+ {
+ watcher.EnableRaisingEvents = true;
+ watcher.EnableRaisingEvents = false;
+ }
+
+ watcher.EnableRaisingEvents = true;
+
+ // this should raise one and only one event
+ File.Create(fileName).Dispose();
+ Assert.True(autoResetEvent.WaitOne(WaitForExpectedEventTimeout_NoRetry));
+ Assert.False(autoResetEvent.WaitOne(SubsequentExpectedWait));
+ Assert.True(numberOfRaisedEvents == 1);
+ }
+ });
+ }
+
[Fact]
public void FileSystemWatcher_File_Create_ForcedRestart()
{
diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.MultipleWatchers.cs b/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.MultipleWatchers.cs
new file mode 100644
index 0000000000..a965a18119
--- /dev/null
+++ b/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.MultipleWatchers.cs
@@ -0,0 +1,351 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public class FileSystemWatcher_Multiple_Test : FileSystemWatcherTest
+ {
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "#34017")]
+ [OuterLoop]
+ [Fact]
+ public void FileSystemWatcher_File_Create_ExecutionContextFlowed()
+ {
+ ExecuteWithRetry(() =>
+ {
+ using (var watcher1 = new FileSystemWatcher(TestDirectory))
+ using (var watcher2 = new FileSystemWatcher(TestDirectory))
+ {
+ string fileName = Path.Combine(TestDirectory, "file");
+ watcher1.Filter = Path.GetFileName(fileName);
+ watcher2.Filter = Path.GetFileName(fileName);
+
+ var local = new AsyncLocal();
+
+ var tcs1 = new TaskCompletionSource();
+ var tcs2 = new TaskCompletionSource();
+ watcher1.Created += (s, e) => tcs1.SetResult(local.Value);
+ watcher2.Created += (s, e) => tcs2.SetResult(local.Value);
+
+ local.Value = 42;
+ watcher1.EnableRaisingEvents = true;
+ local.Value = 84;
+ watcher2.EnableRaisingEvents = true;
+ local.Value = 168;
+
+ File.Create(fileName).Dispose();
+ Task.WaitAll(new[] { tcs1.Task, tcs2.Task }, WaitForExpectedEventTimeout);
+
+ Assert.Equal(42, tcs1.Task.Result);
+ Assert.Equal(84, tcs2.Task.Result);
+ }
+ });
+ }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "#34017")]
+ [OuterLoop]
+ [Fact]
+ public void FileSystemWatcher_File_Create_SuppressedExecutionContextHandled()
+ {
+ ExecuteWithRetry(() =>
+ {
+ using (var watcher1 = new FileSystemWatcher(TestDirectory))
+ {
+ string fileName = Path.Combine(TestDirectory, "file");
+ watcher1.Filter = Path.GetFileName(fileName);
+
+ var local = new AsyncLocal();
+
+ var tcs1 = new TaskCompletionSource();
+ watcher1.Created += (s, e) => tcs1.SetResult(local.Value);
+
+ local.Value = 42;
+
+ ExecutionContext.SuppressFlow();
+ try
+ {
+ watcher1.EnableRaisingEvents = true;
+ }
+ finally
+ {
+ ExecutionContext.RestoreFlow();
+ }
+
+ File.Create(fileName).Dispose();
+ tcs1.Task.Wait(WaitForExpectedEventTimeout);
+
+ Assert.Equal(0, tcs1.Task.Result);
+ }
+ });
+ }
+
+ [OuterLoop]
+ [Fact]
+ public void FileSystemWatcher_File_Create_NotAffectEachOther()
+ {
+ ExecuteWithRetry(() =>
+ {
+ using (var watcher1 = new FileSystemWatcher(TestDirectory))
+ using (var watcher2 = new FileSystemWatcher(TestDirectory))
+ using (var watcher3 = new FileSystemWatcher(TestDirectory))
+ {
+ string fileName = Path.Combine(TestDirectory, "file");
+ watcher1.Filter = Path.GetFileName(fileName);
+ watcher2.Filter = Path.GetFileName(fileName);
+ watcher3.Filter = Path.GetFileName(fileName);
+
+ AutoResetEvent autoResetEvent1 = WatchCreated(watcher1, new[] { fileName }).EventOccured;
+ AutoResetEvent autoResetEvent2 = WatchCreated(watcher2, new[] { fileName }).EventOccured;
+ AutoResetEvent autoResetEvent3 = WatchCreated(watcher3, new[] { fileName }).EventOccured;
+
+ watcher1.EnableRaisingEvents = true;
+ watcher2.EnableRaisingEvents = true;
+ watcher3.EnableRaisingEvents = true;
+
+ File.Create(fileName).Dispose();
+ Assert.True(WaitHandle.WaitAll(new[] { autoResetEvent1, autoResetEvent2, autoResetEvent3 }, WaitForExpectedEventTimeout_NoRetry));
+
+ File.Delete(fileName);
+ watcher1.EnableRaisingEvents = false;
+
+ File.Create(fileName).Dispose();
+ Assert.False(autoResetEvent1.WaitOne(WaitForUnexpectedEventTimeout));
+ Assert.True(WaitHandle.WaitAll(new[] { autoResetEvent2, autoResetEvent3 }, WaitForExpectedEventTimeout_NoRetry));
+ }
+ });
+ }
+
+ [OuterLoop]
+ [Fact]
+ public void FileSystemWatcher_File_Create_WatchOwnPath()
+ {
+ ExecuteWithRetry(() =>
+ {
+ using (var dir = new TempDirectory(GetTestFilePath()))
+ using (var dir1 = new TempDirectory(Path.Combine(dir.Path, "dir1")))
+ using (var dir2 = new TempDirectory(Path.Combine(dir.Path, "dir2")))
+ using (var watcher1 = new FileSystemWatcher(dir1.Path, "*"))
+ using (var watcher2 = new FileSystemWatcher(dir2.Path, "*"))
+ {
+ string fileName1 = Path.Combine(dir1.Path, "file");
+ string fileName2 = Path.Combine(dir2.Path, "file");
+
+ AutoResetEvent autoResetEvent1 = WatchCreated(watcher1, new[] { fileName1 }).EventOccured;
+ AutoResetEvent autoResetEvent2 = WatchCreated(watcher2, new[] { fileName2 }).EventOccured;
+
+ watcher1.EnableRaisingEvents = true;
+ watcher2.EnableRaisingEvents = true;
+
+ File.Create(fileName1).Dispose();
+ Assert.True(autoResetEvent1.WaitOne(WaitForExpectedEventTimeout_NoRetry));
+ Assert.False(autoResetEvent2.WaitOne(WaitForUnexpectedEventTimeout));
+
+ File.Create(fileName2).Dispose();
+ Assert.True(autoResetEvent2.WaitOne(WaitForExpectedEventTimeout_NoRetry));
+ Assert.False(autoResetEvent1.WaitOne(WaitForUnexpectedEventTimeout));
+ }
+ });
+ }
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void FileSystemWatcher_File_Create_ForceLoopRestart(bool useExistingWatchers)
+ {
+ ExecuteWithRetry(() =>
+ {
+ FileSystemWatcher[] watchers = new FileSystemWatcher[64];
+ FileSystemWatcher[] watchers1 = new FileSystemWatcher[64];
+
+ try
+ {
+ string fileName = Path.Combine(TestDirectory, "file");
+ AutoResetEvent[] autoResetEvents = new AutoResetEvent[64];
+ for (var i = 0; i < watchers.Length; i++)
+ {
+ watchers[i] = new FileSystemWatcher(TestDirectory);
+ watchers[i].Filter = Path.GetFileName(fileName);
+ autoResetEvents[i] = WatchCreated(watchers[i], new[] { fileName }).EventOccured;
+ watchers[i].EnableRaisingEvents = true;
+ }
+
+ File.Create(fileName).Dispose();
+ Assert.True(WaitHandle.WaitAll(autoResetEvents, WaitForExpectedEventTimeout_NoRetry));
+
+ File.Delete(fileName);
+ for (var i = 0; i < watchers.Length; i++)
+ {
+ watchers[i].EnableRaisingEvents = false;
+ }
+
+ File.Create(fileName).Dispose();
+ Assert.False(WaitHandle.WaitAll(autoResetEvents, WaitForUnexpectedEventTimeout));
+
+ File.Delete(fileName);
+
+ if (useExistingWatchers)
+ {
+ for (var i = 0; i < watchers.Length; i++)
+ {
+ watchers[i].EnableRaisingEvents = true;
+ }
+
+ File.Create(fileName).Dispose();
+ Assert.True(WaitHandle.WaitAll(autoResetEvents, WaitForExpectedEventTimeout_NoRetry));
+ }
+ else
+ {
+ AutoResetEvent[] autoResetEvents1 = new AutoResetEvent[64];
+ for (var i = 0; i < watchers1.Length; i++)
+ {
+ watchers1[i] = new FileSystemWatcher(TestDirectory);
+ watchers1[i].Filter = Path.GetFileName(fileName);
+ autoResetEvents1[i] = WatchCreated(watchers1[i], new[] { fileName }).EventOccured;
+ watchers1[i].EnableRaisingEvents = true;
+ }
+
+ File.Create(fileName).Dispose();
+ Assert.True(WaitHandle.WaitAll(autoResetEvents1, WaitForExpectedEventTimeout_NoRetry));
+ }
+ }
+ finally
+ {
+ for (var i = 0; i < watchers.Length; i++)
+ {
+ watchers[i]?.Dispose();
+ watchers1[i]?.Dispose();
+ }
+ }
+ });
+ }
+
+ [OuterLoop]
+ [Fact]
+ public void FileSystemWatcher_File_Changed_NotAffectEachOther()
+ {
+ ExecuteWithRetry(() =>
+ {
+ using (var testDirectory = new TempDirectory(GetTestFilePath()))
+ using (var file = new TempFile(Path.Combine(testDirectory.Path, "file")))
+ using (var otherFile = new TempFile(Path.Combine(testDirectory.Path, "otherfile")))
+ using (var watcher1 = new FileSystemWatcher(testDirectory.Path, Path.GetFileName(file.Path)))
+ using (var watcher2 = new FileSystemWatcher(testDirectory.Path, Path.GetFileName(file.Path)))
+ using (var watcher3 = new FileSystemWatcher(testDirectory.Path, Path.GetFileName(otherFile.Path)))
+ {
+ AutoResetEvent autoResetEvent1 = WatchChanged(watcher1, new[] { Path.Combine(testDirectory.Path, "file") }).EventOccured;
+ AutoResetEvent autoResetEvent2 = WatchChanged(watcher2, new[] { Path.Combine(testDirectory.Path, "file") }).EventOccured;
+ AutoResetEvent autoResetEvent3 = WatchChanged(watcher3, new[] { Path.Combine(testDirectory.Path, "otherfile") }).EventOccured;
+
+ watcher1.EnableRaisingEvents = true;
+ watcher2.EnableRaisingEvents = true;
+ watcher3.EnableRaisingEvents = true;
+
+ Directory.SetLastWriteTime(file.Path, DateTime.Now + TimeSpan.FromSeconds(10));
+ Assert.True(WaitHandle.WaitAll(new[] { autoResetEvent1, autoResetEvent2 }, WaitForExpectedEventTimeout_NoRetry));
+ Assert.False(autoResetEvent3.WaitOne(WaitForUnexpectedEventTimeout));
+
+ Directory.SetLastWriteTime(otherFile.Path, DateTime.Now + TimeSpan.FromSeconds(10));
+ Assert.False(WaitHandle.WaitAll(new[] { autoResetEvent1, autoResetEvent2 }, WaitForUnexpectedEventTimeout));
+ Assert.True(autoResetEvent3.WaitOne(WaitForExpectedEventTimeout_NoRetry));
+
+ watcher1.EnableRaisingEvents = false;
+
+ Directory.SetLastWriteTime(file.Path, DateTime.Now + TimeSpan.FromSeconds(10));
+ Assert.False(WaitHandle.WaitAll(new[] { autoResetEvent1, autoResetEvent3 }, WaitForUnexpectedEventTimeout));
+ Assert.True(autoResetEvent2.WaitOne(WaitForExpectedEventTimeout_NoRetry));
+
+ Directory.SetLastWriteTime(otherFile.Path, DateTime.Now + TimeSpan.FromSeconds(10));
+ Assert.False(WaitHandle.WaitAll(new[] { autoResetEvent1, autoResetEvent2 }, WaitForUnexpectedEventTimeout));
+ Assert.True(autoResetEvent3.WaitOne(WaitForExpectedEventTimeout_NoRetry));
+ }
+ });
+ }
+
+ [OuterLoop]
+ [Fact]
+ public void FileSystemWatcher_File_Delet_NotAffectEachOther()
+ {
+ ExecuteWithRetry(() =>
+ {
+ using (var watcher1 = new FileSystemWatcher(TestDirectory))
+ using (var watcher2 = new FileSystemWatcher(TestDirectory))
+ using (var watcher3 = new FileSystemWatcher(TestDirectory))
+ {
+ string fileName = Path.Combine(TestDirectory, "file");
+ File.Create(fileName).Dispose();
+
+ watcher1.Filter = Path.GetFileName(fileName);
+ watcher2.Filter = Path.GetFileName(fileName);
+ watcher3.Filter = Path.GetFileName(fileName);
+
+ AutoResetEvent autoResetEvent1 = WatchDeleted(watcher1, new[] { fileName }).EventOccured;
+ AutoResetEvent autoResetEvent2 = WatchDeleted(watcher2, new[] { fileName }).EventOccured;
+ AutoResetEvent autoResetEvent3 = WatchDeleted(watcher3, new[] { fileName }).EventOccured;
+
+ watcher1.EnableRaisingEvents = true;
+ watcher2.EnableRaisingEvents = true;
+ watcher3.EnableRaisingEvents = true;
+
+ File.Delete(fileName);
+ Assert.True(WaitHandle.WaitAll(new[] { autoResetEvent1, autoResetEvent2, autoResetEvent3 }, WaitForExpectedEventTimeout_NoRetry));
+
+ File.Create(fileName).Dispose();
+ watcher1.EnableRaisingEvents = false;
+
+ File.Delete(fileName);
+ Assert.False(autoResetEvent1.WaitOne(WaitForUnexpectedEventTimeout));
+ Assert.True(WaitHandle.WaitAll(new[] { autoResetEvent2, autoResetEvent3 }, WaitForExpectedEventTimeout_NoRetry));
+ }
+ });
+ }
+
+ [OuterLoop]
+ [Fact]
+ [PlatformSpecific(TestPlatforms.OSX)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Mono)]
+ public void FileSystemWatcher_File_Rename_NotAffectEachOther()
+ {
+ ExecuteWithRetry(() =>
+ {
+ using (var testDirectory = new TempDirectory(GetTestFilePath()))
+ using (var file = new TempFile(Path.Combine(testDirectory.Path, "file")))
+ using (var watcher1 = new FileSystemWatcher(testDirectory.Path, Path.GetFileName(file.Path)))
+ using (var watcher2 = new FileSystemWatcher(testDirectory.Path, Path.GetFileName(file.Path)))
+ {
+ AutoResetEvent autoResetEvent1_created = WatchCreated(watcher1, new[] { Path.Combine(testDirectory.Path, "file") }).EventOccured;
+ AutoResetEvent autoResetEvent1_deleted = WatchDeleted(watcher1, new[] { Path.Combine(testDirectory.Path, "file") }).EventOccured;
+ AutoResetEvent autoResetEvent2_created = WatchCreated(watcher2, new[] { Path.Combine(testDirectory.Path, "file") }).EventOccured;
+ AutoResetEvent autoResetEvent2_deleted = WatchDeleted(watcher2, new[] { Path.Combine(testDirectory.Path, "file") }).EventOccured;
+
+ watcher1.EnableRaisingEvents = true;
+ watcher2.EnableRaisingEvents = true;
+
+ string filePath = file.Path;
+ string filePathRenamed = file.Path + "_renamed";
+
+ File.Move(filePath, filePathRenamed);
+ Assert.True(WaitHandle.WaitAll(
+ new[] { autoResetEvent1_created, autoResetEvent1_deleted, autoResetEvent2_created, autoResetEvent2_deleted },
+ WaitForExpectedEventTimeout_NoRetry));
+
+ File.Move(filePathRenamed, filePath);
+ watcher1.EnableRaisingEvents = false;
+
+ File.Move(filePath, filePathRenamed);
+ Assert.False(WaitHandle.WaitAll(
+ new[] { autoResetEvent1_created, autoResetEvent1_deleted },
+ WaitForUnexpectedEventTimeout));
+ Assert.True(WaitHandle.WaitAll(
+ new[] { autoResetEvent2_created, autoResetEvent2_deleted },
+ WaitForExpectedEventTimeout_NoRetry));
+ }
+ });
+ }
+ }
+}
diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs b/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs
index cce848e614..5035709528 100644
--- a/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs
+++ b/external/corefx/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs
@@ -474,7 +474,7 @@ namespace System.IO.Tests
using (var file = new TempFile(Path.Combine(dir.Path, "file")))
using (var fsw = new FileSystemWatcher(dir.Path))
{
- AutoResetEvent eventOccurred = WatchRenamed(fsw);
+ AutoResetEvent eventOccurred = WatchRenamed(fsw).EventOccured;
string newPath = Path.Combine(dir.Path, "newPath");
@@ -626,7 +626,7 @@ namespace System.IO.Tests
using (var dir = new TempDirectory(Path.Combine(testDirectory.Path, "dir")))
using (var fsw = new FileSystemWatcher(dir.Path))
{
- AutoResetEvent are = WatchCreated(fsw);
+ AutoResetEvent are = WatchCreated(fsw).EventOccured;
fsw.Filter = "*";
fsw.EnableRaisingEvents = true;
diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/tests/System.IO.FileSystem.Watcher.Tests.csproj b/external/corefx/src/System.IO.FileSystem.Watcher/tests/System.IO.FileSystem.Watcher.Tests.csproj
index 2b4989a1c1..0bb15ae4ae 100644
--- a/external/corefx/src/System.IO.FileSystem.Watcher/tests/System.IO.FileSystem.Watcher.Tests.csproj
+++ b/external/corefx/src/System.IO.FileSystem.Watcher/tests/System.IO.FileSystem.Watcher.Tests.csproj
@@ -30,6 +30,7 @@
+
diff --git a/external/corefx/src/System.IO.FileSystem.Watcher/tests/Utility/FileSystemWatcherTest.cs b/external/corefx/src/System.IO.FileSystem.Watcher/tests/Utility/FileSystemWatcherTest.cs
index 6614b83f67..0ce6ebb12b 100644
--- a/external/corefx/src/System.IO.FileSystem.Watcher/tests/Utility/FileSystemWatcherTest.cs
+++ b/external/corefx/src/System.IO.FileSystem.Watcher/tests/Utility/FileSystemWatcherTest.cs
@@ -4,14 +4,14 @@
using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Xunit;
+using Xunit.Sdk;
namespace System.IO.Tests
{
- public abstract class FileSystemWatcherTest : FileCleanupTestBase
+ public abstract partial class FileSystemWatcherTest : FileCleanupTestBase
{
// Events are reported asynchronously by the OS, so allow an amount of time for
// them to arrive before testing an assertion. If we expect an event to occur,
@@ -23,18 +23,20 @@ namespace System.IO.Tests
public const int LongWaitTimeout = 50000; // ms to wait for an event that takes a longer time than the average operation
public const int SubsequentExpectedWait = 10; // ms to wait for checks that occur after the first.
public const int WaitForExpectedEventTimeout_NoRetry = 3000;// ms to wait for an event that isn't surrounded by a retry.
+ public const int WaitForUnexpectedEventTimeout = 150; // ms to wait for a non-expected event.
public const int DefaultAttemptsForExpectedEvent = 3; // Number of times an expected event should be retried if failing.
public const int DefaultAttemptsForUnExpectedEvent = 2; // Number of times an unexpected event should be retried if failing.
+ public const int RetryDelayMilliseconds = 500; // ms to wait when retrying after failure
///
/// Watches the Changed WatcherChangeType and unblocks the returned AutoResetEvent when a
/// Changed event is thrown by the watcher.
///
- public static AutoResetEvent WatchChanged(FileSystemWatcher watcher, string[] expectedPaths = null)
+ public static (AutoResetEvent EventOccured, FileSystemEventHandler Handler) WatchChanged(FileSystemWatcher watcher, string[] expectedPaths = null)
{
AutoResetEvent eventOccurred = new AutoResetEvent(false);
- watcher.Changed += (o, e) =>
+ FileSystemEventHandler changeHandler = (o, e) =>
{
Assert.Equal(WatcherChangeTypes.Changed, e.ChangeType);
if (expectedPaths != null)
@@ -44,18 +46,19 @@ namespace System.IO.Tests
eventOccurred.Set();
};
- return eventOccurred;
+ watcher.Changed += changeHandler;
+ return (eventOccurred, changeHandler);
}
///
/// Watches the Created WatcherChangeType and unblocks the returned AutoResetEvent when a
/// Created event is thrown by the watcher.
///
- public static AutoResetEvent WatchCreated(FileSystemWatcher watcher, string[] expectedPaths = null)
+ public static (AutoResetEvent EventOccured, FileSystemEventHandler Handler) WatchCreated(FileSystemWatcher watcher, string[] expectedPaths = null)
{
AutoResetEvent eventOccurred = new AutoResetEvent(false);
- watcher.Created += (o, e) =>
+ FileSystemEventHandler handler = (o, e) =>
{
Assert.Equal(WatcherChangeTypes.Created, e.ChangeType);
if (expectedPaths != null)
@@ -65,18 +68,18 @@ namespace System.IO.Tests
eventOccurred.Set();
};
- return eventOccurred;
+ watcher.Created += handler;
+ return (eventOccurred, handler);
}
///
/// Watches the Renamed WatcherChangeType and unblocks the returned AutoResetEvent when a
/// Renamed event is thrown by the watcher.
///
- public static AutoResetEvent WatchDeleted(FileSystemWatcher watcher, string[] expectedPaths = null)
+ public static (AutoResetEvent EventOccured, FileSystemEventHandler Handler) WatchDeleted(FileSystemWatcher watcher, string[] expectedPaths = null)
{
AutoResetEvent eventOccurred = new AutoResetEvent(false);
-
- watcher.Deleted += (o, e) =>
+ FileSystemEventHandler handler = (o, e) =>
{
Assert.Equal(WatcherChangeTypes.Deleted, e.ChangeType);
if (expectedPaths != null)
@@ -86,18 +89,19 @@ namespace System.IO.Tests
eventOccurred.Set();
};
- return eventOccurred;
+ watcher.Deleted += handler;
+ return (eventOccurred, handler);
}
///
/// Watches the Renamed WatcherChangeType and unblocks the returned AutoResetEvent when a
/// Renamed event is thrown by the watcher.
///
- public static AutoResetEvent WatchRenamed(FileSystemWatcher watcher, string[] expectedPaths = null)
+ public static (AutoResetEvent EventOccured, RenamedEventHandler Handler) WatchRenamed(FileSystemWatcher watcher, string[] expectedPaths = null)
{
AutoResetEvent eventOccurred = new AutoResetEvent(false);
- watcher.Renamed += (o, e) =>
+ RenamedEventHandler handler = (o, e) =>
{
Assert.Equal(WatcherChangeTypes.Renamed, e.ChangeType);
if (expectedPaths != null)
@@ -107,7 +111,8 @@ namespace System.IO.Tests
eventOccurred.Set();
};
- return eventOccurred;
+ watcher.Renamed += handler;
+ return (eventOccurred, handler);
}
///
@@ -115,7 +120,7 @@ namespace System.IO.Tests
///
public static void ExpectEvent(WaitHandle eventOccurred, string eventName_NoRetry)
{
- string message = String.Format("Didn't observe a {0} event within {1}ms", eventName_NoRetry, WaitForExpectedEventTimeout_NoRetry);
+ string message = string.Format("Didn't observe a {0} event within {1}ms", eventName_NoRetry, WaitForExpectedEventTimeout_NoRetry);
Assert.True(eventOccurred.WaitOne(WaitForExpectedEventTimeout_NoRetry), message);
}
@@ -161,32 +166,63 @@ namespace System.IO.Tests
{
int attemptsCompleted = 0;
bool result = false;
+ FileSystemWatcher newWatcher = watcher;
while (!result && attemptsCompleted++ < attempts)
{
if (attemptsCompleted > 1)
{
// Re-create the watcher to get a clean iteration.
- watcher = new FileSystemWatcher()
- {
- IncludeSubdirectories = watcher.IncludeSubdirectories,
- NotifyFilter = watcher.NotifyFilter,
- Filter = watcher.Filter,
- Path = watcher.Path,
- InternalBufferSize = watcher.InternalBufferSize
- };
+ newWatcher = RecreateWatcher(newWatcher);
// Most intermittent failures in FSW are caused by either a shortage of resources (e.g. inotify instances)
// or by insufficient time to execute (e.g. CI gets bogged down). Immediately re-running a failed test
// won't resolve the first issue, so we wait a little while hoping that things clear up for the next run.
- Thread.Sleep(500);
+ Thread.Sleep(RetryDelayMilliseconds);
}
- result = ExecuteAndVerifyEvents(watcher, expectedEvents, action, attemptsCompleted == attempts, expectedPaths, timeout);
+ result = ExecuteAndVerifyEvents(newWatcher, expectedEvents, action, attemptsCompleted == attempts, expectedPaths, timeout);
if (cleanup != null)
cleanup();
}
}
+ /// Invokes the specified test action with retry on failure (other than assertion failure).
+ /// The test action.
+ /// The maximum number of times to attempt to run the test.
+ public static void ExecuteWithRetry(Action action, int maxAttempts = DefaultAttemptsForExpectedEvent)
+ {
+ for (int retry = 0; retry < maxAttempts; retry++)
+ {
+ try
+ {
+ action();
+ return;
+ }
+ catch (Exception e) when (!(e is XunitException) && retry < maxAttempts - 1)
+ {
+ Thread.Sleep(RetryDelayMilliseconds);
+ }
+ }
+ }
+
+ ///
+ /// Does verification that the given watcher will not throw exactly/only the events in "expectedEvents" when
+ /// "action" is executed.
+ ///
+ /// The FileSystemWatcher to test
+ /// All of the events that are expected to be raised by this action
+ /// The Action that will trigger events.
+ /// Optional. Undoes the action and cleans up the watcher so the test may be run again if necessary.
+ /// Optional. Adds path verification to all expected events.
+ public static void ExpectNoEvent(FileSystemWatcher watcher, WatcherChangeTypes unExpectedEvents, Action action, Action cleanup = null, string expectedPath = null, int timeout = WaitForExpectedEventTimeout)
+ {
+ bool result = ExecuteAndVerifyEvents(watcher, unExpectedEvents, action, false, new string[] { expectedPath }, timeout);
+ Assert.False(result, "Expected Event occured");
+
+ if (cleanup != null)
+ cleanup();
+ }
+
///
/// Helper for the ExpectEvent function.
///
@@ -199,8 +235,8 @@ namespace System.IO.Tests
public static bool ExecuteAndVerifyEvents(FileSystemWatcher watcher, WatcherChangeTypes expectedEvents, Action action, bool assertExpected, string[] expectedPaths, int timeout)
{
bool result = true, verifyChanged = true, verifyCreated = true, verifyDeleted = true, verifyRenamed = true;
- AutoResetEvent changed = null, created = null, deleted = null, renamed = null;
- string[] expectedFullPaths = expectedPaths == null ? null : expectedPaths.Select(e => Path.GetFullPath(e)).ToArray();
+ (AutoResetEvent EventOccured, FileSystemEventHandler Handler) changed = default, created = default, deleted = default;
+ (AutoResetEvent EventOccured, RenamedEventHandler Handler) renamed = default;
if (verifyChanged = ((expectedEvents & WatcherChangeTypes.Changed) > 0))
changed = WatchChanged(watcher, expectedPaths);
@@ -218,7 +254,8 @@ namespace System.IO.Tests
if (verifyChanged)
{
bool Changed_expected = ((expectedEvents & WatcherChangeTypes.Changed) > 0);
- bool Changed_actual = changed.WaitOne(timeout);
+ bool Changed_actual = changed.EventOccured.WaitOne(timeout);
+ watcher.Changed -= changed.Handler;
result = Changed_expected == Changed_actual;
if (assertExpected)
Assert.True(Changed_expected == Changed_actual, "Changed event did not occur as expected");
@@ -228,7 +265,8 @@ namespace System.IO.Tests
if (verifyCreated)
{
bool Created_expected = ((expectedEvents & WatcherChangeTypes.Created) > 0);
- bool Created_actual = created.WaitOne(verifyChanged ? SubsequentExpectedWait : timeout);
+ bool Created_actual = created.EventOccured.WaitOne(verifyChanged ? SubsequentExpectedWait : timeout);
+ watcher.Created -= created.Handler;
result = result && Created_expected == Created_actual;
if (assertExpected)
Assert.True(Created_expected == Created_actual, "Created event did not occur as expected");
@@ -238,7 +276,8 @@ namespace System.IO.Tests
if (verifyDeleted)
{
bool Deleted_expected = ((expectedEvents & WatcherChangeTypes.Deleted) > 0);
- bool Deleted_actual = deleted.WaitOne(verifyChanged || verifyCreated ? SubsequentExpectedWait : timeout);
+ bool Deleted_actual = deleted.EventOccured.WaitOne(verifyChanged || verifyCreated ? SubsequentExpectedWait : timeout);
+ watcher.Deleted -= deleted.Handler;
result = result && Deleted_expected == Deleted_actual;
if (assertExpected)
Assert.True(Deleted_expected == Deleted_actual, "Deleted event did not occur as expected");
@@ -248,7 +287,8 @@ namespace System.IO.Tests
if (verifyRenamed)
{
bool Renamed_expected = ((expectedEvents & WatcherChangeTypes.Renamed) > 0);
- bool Renamed_actual = renamed.WaitOne(verifyChanged || verifyCreated || verifyDeleted? SubsequentExpectedWait : timeout);
+ bool Renamed_actual = renamed.EventOccured.WaitOne(verifyChanged || verifyCreated || verifyDeleted ? SubsequentExpectedWait : timeout);
+ watcher.Renamed -= renamed.Handler;
result = result && Renamed_expected == Renamed_actual;
if (assertExpected)
Assert.True(Renamed_expected == Renamed_actual, "Renamed event did not occur as expected");
@@ -409,7 +449,7 @@ namespace System.IO.Tests
foreach (NotifyFilters filter in Enum.GetValues(typeof(NotifyFilters)))
yield return new object[] { filter };
}
-
+
// Linux and OSX systems have less precise filtering systems than Windows, so most
// metadata filters are effectively equivalent to each other on those systems. For example
// there isn't a way to filter only LastWrite events on either system; setting
@@ -430,5 +470,19 @@ namespace System.IO.Tests
NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.Size;
+
+#if MONO
+ private static FileSystemWatcher RecreateWatcher(FileSystemWatcher watcher)
+ {
+ FileSystemWatcher newWatcher = new FileSystemWatcher()
+ {
+ IncludeSubdirectories = watcher.IncludeSubdirectories,
+ NotifyFilter = watcher.NotifyFilter,
+ Path = watcher.Path,
+ InternalBufferSize = watcher.InternalBufferSize
+ };
+ return newWatcher;
+ }
+#endif
}
-}
+}
\ No newline at end of file
diff --git a/external/corefx/src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs b/external/corefx/src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs
index d272734f96..8dff0e23ae 100644
--- a/external/corefx/src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs
+++ b/external/corefx/src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs
@@ -397,27 +397,31 @@ namespace System.IO
}
}
- public static bool DirectoryExists(string fullPath)
+ public static bool DirectoryExists(ReadOnlySpan fullPath)
{
Interop.ErrorInfo ignored;
return DirectoryExists(fullPath, out ignored);
}
- private static bool DirectoryExists(string fullPath, out Interop.ErrorInfo errorInfo)
+ private static bool DirectoryExists(ReadOnlySpan fullPath, out Interop.ErrorInfo errorInfo)
{
return FileExists(fullPath, Interop.Sys.FileTypes.S_IFDIR, out errorInfo);
}
- public static bool FileExists(string fullPath)
+ public static bool FileExists(ReadOnlySpan fullPath)
{
- Interop.ErrorInfo ignored;
-
- // Input allows trailing separators in order to match Windows behavior
- // Unix does not accept trailing separators, so must be trimmed
+ Interop.ErrorInfo ignored;
+ // File.Exists() explicitly checks for a trailing separator and returns false if found. FileInfo.Exists and all other
+ // internal usages do not check for the trailing separator. Historically we've always removed the trailing separator
+ // when getting attributes as trailing separators are generally not accepted by Windows APIs. Unix will take
+ // trailing separators, but it infers that the path must be a directory (it effectively appends "."). To align with
+ // our historical behavior (outside of File.Exists()), we need to trim.
+ //
+ // See http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11 for details.
return FileExists(PathInternal.TrimEndingDirectorySeparator(fullPath), Interop.Sys.FileTypes.S_IFREG, out ignored);
}
- private static bool FileExists(string fullPath, int fileType, out Interop.ErrorInfo errorInfo)
+ private static bool FileExists(ReadOnlySpan fullPath, int fileType, out Interop.ErrorInfo errorInfo)
{
Debug.Assert(fileType == Interop.Sys.FileTypes.S_IFREG || fileType == Interop.Sys.FileTypes.S_IFDIR);
diff --git a/mcs/build/common/Consts.cs b/mcs/build/common/Consts.cs
index 388cd4807c..31eb46f02c 100644
--- a/mcs/build/common/Consts.cs
+++ b/mcs/build/common/Consts.cs
@@ -34,7 +34,7 @@ static class Consts
// Use these assembly version constants to make code more maintainable.
//
- public const string MonoVersion = "5.18.0.237";
+ public const string MonoVersion = "5.18.0.239";
public const string MonoCompany = "Mono development team";
public const string MonoProduct = "Mono Common Language Infrastructure";
public const string MonoCopyright = "(c) Various Mono authors";
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
index aa5858eead..d28bde5512 100644
--- a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
@@ -1 +1 @@
-908cd04819fde0fa5b49a8179b597c3a66e22c4e
\ No newline at end of file
+6906969e1560c229aa270d601a88da36d3b87383
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
index 742b2c4e84..9cccaca5d8 100644
--- a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
@@ -1 +1 @@
-7cfb76b39793a684c9a17a0405973089bcd5f954
\ No newline at end of file
+8260010ca66cf7bf43ddbb1ae0b222492747167a
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
index 0dc90e9181..3d1691dcac 100644
--- a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
@@ -1 +1 @@
-c95ba4d04ef7f337af46d383ede8538bd5035b34
\ No newline at end of file
+2d5243eb818f2ae2bd193faffdc1cd4ea4700dd7
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll
index cbff9ac556..14e12d232d 100644
Binary files a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll and b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll differ
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
index dbd1f77219..166c91de84 100644
--- a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
@@ -1 +1 @@
-e98e0d83cabf1f38615315bb2b7df51f73adea61
\ No newline at end of file
+3883499a603ad6ea46014f6bb783606055560eda
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
index 9da559bf2a..55d20a6df9 100644
--- a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
@@ -1 +1 @@
-0a80a6acb8e70f48b3835bbd0108b9121f32dc6d
\ No newline at end of file
+812d2587a089ec5a9f3a2433ebb0b07215307bd5
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
index 0f3e5e64fa..72988daf46 100644
--- a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
@@ -1 +1 @@
-4b0c2992c734491de65ff79d23ecc6b961c42609
\ No newline at end of file
+07c6863ea81f0ef67612f4209bc0dda817402417
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
index 152059689e..a7d62918fa 100644
--- a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
+++ b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
@@ -1 +1 @@
-74d8a027616997fa1fe916cb9eb486f73393f9c7
\ No newline at end of file
+8f029d8d6f60059315f0005365154e32d83d659e
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
index b2c24a1a1c..2f1c2c5b1f 100644
--- a/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-linux/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
@@ -1 +1 @@
-3d2eee5927931b3874594e1a689fd92b3792653e
\ No newline at end of file
+a0c4a95a9d6ac6211cff450c608792d78d313b7e
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
index aa5858eead..d28bde5512 100644
--- a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
@@ -1 +1 @@
-908cd04819fde0fa5b49a8179b597c3a66e22c4e
\ No newline at end of file
+6906969e1560c229aa270d601a88da36d3b87383
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
index 742b2c4e84..9cccaca5d8 100644
--- a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
@@ -1 +1 @@
-7cfb76b39793a684c9a17a0405973089bcd5f954
\ No newline at end of file
+8260010ca66cf7bf43ddbb1ae0b222492747167a
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
index 0dc90e9181..3d1691dcac 100644
--- a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
@@ -1 +1 @@
-c95ba4d04ef7f337af46d383ede8538bd5035b34
\ No newline at end of file
+2d5243eb818f2ae2bd193faffdc1cd4ea4700dd7
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll
index cbff9ac556..14e12d232d 100644
Binary files a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll and b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll differ
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
index dbd1f77219..166c91de84 100644
--- a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
@@ -1 +1 @@
-e98e0d83cabf1f38615315bb2b7df51f73adea61
\ No newline at end of file
+3883499a603ad6ea46014f6bb783606055560eda
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
index 9da559bf2a..55d20a6df9 100644
--- a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
@@ -1 +1 @@
-0a80a6acb8e70f48b3835bbd0108b9121f32dc6d
\ No newline at end of file
+812d2587a089ec5a9f3a2433ebb0b07215307bd5
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
index 0f3e5e64fa..72988daf46 100644
--- a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
@@ -1 +1 @@
-4b0c2992c734491de65ff79d23ecc6b961c42609
\ No newline at end of file
+07c6863ea81f0ef67612f4209bc0dda817402417
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
index 152059689e..a7d62918fa 100644
--- a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
+++ b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
@@ -1 +1 @@
-74d8a027616997fa1fe916cb9eb486f73393f9c7
\ No newline at end of file
+8f029d8d6f60059315f0005365154e32d83d659e
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
index b2c24a1a1c..2f1c2c5b1f 100644
--- a/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-macos/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
@@ -1 +1 @@
-3d2eee5927931b3874594e1a689fd92b3792653e
\ No newline at end of file
+a0c4a95a9d6ac6211cff450c608792d78d313b7e
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
index aa5858eead..d28bde5512 100644
--- a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
@@ -1 +1 @@
-908cd04819fde0fa5b49a8179b597c3a66e22c4e
\ No newline at end of file
+6906969e1560c229aa270d601a88da36d3b87383
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
index 742b2c4e84..9cccaca5d8 100644
--- a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
@@ -1 +1 @@
-7cfb76b39793a684c9a17a0405973089bcd5f954
\ No newline at end of file
+8260010ca66cf7bf43ddbb1ae0b222492747167a
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
index 0dc90e9181..3d1691dcac 100644
--- a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
@@ -1 +1 @@
-c95ba4d04ef7f337af46d383ede8538bd5035b34
\ No newline at end of file
+2d5243eb818f2ae2bd193faffdc1cd4ea4700dd7
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll
index cbff9ac556..14e12d232d 100644
Binary files a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll and b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll differ
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
index dbd1f77219..166c91de84 100644
--- a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
@@ -1 +1 @@
-e98e0d83cabf1f38615315bb2b7df51f73adea61
\ No newline at end of file
+3883499a603ad6ea46014f6bb783606055560eda
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
index 9da559bf2a..55d20a6df9 100644
--- a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
@@ -1 +1 @@
-0a80a6acb8e70f48b3835bbd0108b9121f32dc6d
\ No newline at end of file
+812d2587a089ec5a9f3a2433ebb0b07215307bd5
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
index 0f3e5e64fa..72988daf46 100644
--- a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
@@ -1 +1 @@
-4b0c2992c734491de65ff79d23ecc6b961c42609
\ No newline at end of file
+07c6863ea81f0ef67612f4209bc0dda817402417
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
index 152059689e..a7d62918fa 100644
--- a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
+++ b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
@@ -1 +1 @@
-74d8a027616997fa1fe916cb9eb486f73393f9c7
\ No newline at end of file
+8f029d8d6f60059315f0005365154e32d83d659e
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
index b2c24a1a1c..2f1c2c5b1f 100644
--- a/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-unix/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
@@ -1 +1 @@
-3d2eee5927931b3874594e1a689fd92b3792653e
\ No newline at end of file
+a0c4a95a9d6ac6211cff450c608792d78d313b7e
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
index aa5858eead..d28bde5512 100644
--- a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/Mono.Security.dll.REMOVED.git-id
@@ -1 +1 @@
-908cd04819fde0fa5b49a8179b597c3a66e22c4e
\ No newline at end of file
+6906969e1560c229aa270d601a88da36d3b87383
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
index 742b2c4e84..9cccaca5d8 100644
--- a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Configuration.dll.REMOVED.git-id
@@ -1 +1 @@
-7cfb76b39793a684c9a17a0405973089bcd5f954
\ No newline at end of file
+8260010ca66cf7bf43ddbb1ae0b222492747167a
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
index 0dc90e9181..3d1691dcac 100644
--- a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Core.dll.REMOVED.git-id
@@ -1 +1 @@
-c95ba4d04ef7f337af46d383ede8538bd5035b34
\ No newline at end of file
+2d5243eb818f2ae2bd193faffdc1cd4ea4700dd7
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll
index cbff9ac556..14e12d232d 100644
Binary files a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll and b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.IO.Compression.dll differ
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
index dbd1f77219..166c91de84 100644
--- a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Numerics.dll.REMOVED.git-id
@@ -1 +1 @@
-e98e0d83cabf1f38615315bb2b7df51f73adea61
\ No newline at end of file
+3883499a603ad6ea46014f6bb783606055560eda
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
index 9da559bf2a..55d20a6df9 100644
--- a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.Xml.dll.REMOVED.git-id
@@ -1 +1 @@
-0a80a6acb8e70f48b3835bbd0108b9121f32dc6d
\ No newline at end of file
+812d2587a089ec5a9f3a2433ebb0b07215307bd5
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
index 0f3e5e64fa..72988daf46 100644
--- a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/System.dll.REMOVED.git-id
@@ -1 +1 @@
-4b0c2992c734491de65ff79d23ecc6b961c42609
\ No newline at end of file
+07c6863ea81f0ef67612f4209bc0dda817402417
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
index 152059689e..a7d62918fa 100644
--- a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
+++ b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mcs.exe.REMOVED.git-id
@@ -1 +1 @@
-74d8a027616997fa1fe916cb9eb486f73393f9c7
\ No newline at end of file
+8f029d8d6f60059315f0005365154e32d83d659e
\ No newline at end of file
diff --git a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
index b2c24a1a1c..2f1c2c5b1f 100644
--- a/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite-win32/CA4932AE-2294-4ECD-B863-BF98FDD84F33/mscorlib.dll.REMOVED.git-id
@@ -1 +1 @@
-3d2eee5927931b3874594e1a689fd92b3792653e
\ No newline at end of file
+a0c4a95a9d6ac6211cff450c608792d78d313b7e
\ No newline at end of file
diff --git a/mono/mini/version.h b/mono/mini/version.h
index 0d15998b56..12b85d9c1a 100644
--- a/mono/mini/version.h
+++ b/mono/mini/version.h
@@ -1 +1 @@
-#define FULL_VERSION "explicit/51c4f45"
+#define FULL_VERSION "explicit/0d988bc"
diff --git a/po/mcs/de.gmo b/po/mcs/de.gmo
index 33b63ac85d..b84f6d6455 100644
Binary files a/po/mcs/de.gmo and b/po/mcs/de.gmo differ
diff --git a/po/mcs/de.po.REMOVED.git-id b/po/mcs/de.po.REMOVED.git-id
index 9f8fba7e1c..df46596f92 100644
--- a/po/mcs/de.po.REMOVED.git-id
+++ b/po/mcs/de.po.REMOVED.git-id
@@ -1 +1 @@
-a65e7b782001b86d8225d04fa68512a5bc44c967
\ No newline at end of file
+18b1807a4d1acdb4c1525b1b58f8ee1c7180f20a
\ No newline at end of file
diff --git a/po/mcs/es.gmo b/po/mcs/es.gmo
index ea35cfed20..bae3297faa 100644
Binary files a/po/mcs/es.gmo and b/po/mcs/es.gmo differ
diff --git a/po/mcs/es.po.REMOVED.git-id b/po/mcs/es.po.REMOVED.git-id
index d18e259aba..149999bd70 100644
--- a/po/mcs/es.po.REMOVED.git-id
+++ b/po/mcs/es.po.REMOVED.git-id
@@ -1 +1 @@
-fd39dee88556b3baad4dbd99270795579407ef77
\ No newline at end of file
+6e89df71c925ed8a137134b58c22502325be917c
\ No newline at end of file
diff --git a/po/mcs/ja.gmo b/po/mcs/ja.gmo
index 11cc721dc4..bd89d22d9b 100644
Binary files a/po/mcs/ja.gmo and b/po/mcs/ja.gmo differ
diff --git a/po/mcs/ja.po.REMOVED.git-id b/po/mcs/ja.po.REMOVED.git-id
index 98de4e7053..08b6d75313 100644
--- a/po/mcs/ja.po.REMOVED.git-id
+++ b/po/mcs/ja.po.REMOVED.git-id
@@ -1 +1 @@
-b4fb7a778bf8cea7d5aed1673c98ff39b4fd8468
\ No newline at end of file
+3a581243027655a91f7ea8149e2cd44124293f47
\ No newline at end of file
diff --git a/po/mcs/mcs.pot b/po/mcs/mcs.pot
index 17597b71a0..cdd4293298 100644
--- a/po/mcs/mcs.pot
+++ b/po/mcs/mcs.pot
@@ -6,9 +6,9 @@
#, fuzzy
msgid ""
msgstr ""
-"Project-Id-Version: mono 5.18.0.237\n"
+"Project-Id-Version: mono 5.18.0.239\n"
"Report-Msgid-Bugs-To: http://www.mono-project.com/Bugs\n"
-"POT-Creation-Date: 2019-01-12 08:06+0000\n"
+"POT-Creation-Date: 2019-01-15 08:09+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
diff --git a/po/mcs/pt_BR.gmo b/po/mcs/pt_BR.gmo
index 5215a163ec..d7112158cf 100644
Binary files a/po/mcs/pt_BR.gmo and b/po/mcs/pt_BR.gmo differ
diff --git a/po/mcs/pt_BR.po.REMOVED.git-id b/po/mcs/pt_BR.po.REMOVED.git-id
index 9da0840167..1fd265b345 100644
--- a/po/mcs/pt_BR.po.REMOVED.git-id
+++ b/po/mcs/pt_BR.po.REMOVED.git-id
@@ -1 +1 @@
-f62a6a2e821d7772818d78785a49b72df9f2a7a5
\ No newline at end of file
+a626d442d10692d9e6487fe822577c949347180b
\ No newline at end of file