Repository: dotnet/runtime
File: src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEnumerator.Windows.cs (C#)

Code before:
        private IntPtr _directoryHandle;
        private string? _currentPath;
        private bool _lastEntryFound;
        private Queue<(IntPtr Handle, string Path, int RemainingDepth)>? _pending;
        private bool _isFirstGetData = true;

        /// <summary>
        /// Encapsulates a find operation.
        /// </summary>
        /// <param name="directory">The directory to search in.</param>
        /// <param name="isNormalized">Whether the directory path is already normalized or not.</param>
        /// <param name="options">Enumeration options to use.</param>
        /// <param name="expression">The search expression to potentially use for OS-level filtering (Windows only).</param>
        internal FileSystemEnumerator(string directory, bool isNormalized, EnumerationOptions? options, string? expression) :
            this(directory, isNormalized, options)
        {
            if (_options.RecurseSubdirectories)
            {
                // We can never filter when recursing, as we need to find all subdirectories to recurse into them.
                expression = null;
            }

            if (expression is not null)
            {
                // We need to ensure that the expression is prepped to be used as an NtQueryDirectoryFile filter.
                // If the match type is simple, we need to escape the special DOS wildcard characters. If it is
                // DOS style, the characters have already been escaped in the FileSystemEnumerableFactory.

                if (expression.Length > 255 || expression == "*")
                {
                    // Don't allow expressions longer than the maximum filename length. This comes back as
                    // STATUS_INVALID_PARAMETER from NtQueryDirectoryFile. We could catch that there, but
                    // don't want to mask other bad parameter issues.
                    //
                    // Also, an expression of "*" is pointless as a filter- it matches everything. "*.*"
                    // should have been converted to "*" already in the case of MatchType.Win32.
                    expression = null;
                }
                else if (_options.MatchType == MatchType.Simple && expression.AsSpan().ContainsAny(@"\""<>"))
                {
                    // Escape the escaping literal first
                    expression = expression.Replace("\\", "\\\\");

                    // Also need to escape the other special wild characters ('"', '<', and '>')
                    expression = expression.Replace("\"", "\\\"");
                    expression = expression.Replace(">", "\\>");
                    expression = expression.Replace("<", "\\<");
                }
            }

            _expression = expression;

Review comment (security):
> If it is DOS style, the characters have already been escaped in the FileSystemEnumerableFactory.

That escaping only happens for Unix, because of `Path.DirectorySeparatorChar != '\\'`.

https://github.com/dotnet/runtime/blob/740288afc442a58a01e52764e1e37490a3bb5c67/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs#L77-L86

Code after:
        private IntPtr _directoryHandle;
        private string? _currentPath;
        private bool _lastEntryFound;
        private Queue<(IntPtr Handle, string Path, int RemainingDepth)>? _pending;
        private bool _isFirstGetData = true;

        /// <summary>
        /// Encapsulates a find operation.
        /// </summary>
        /// <param name="directory">The directory to search in.</param>
        /// <param name="isNormalized">Whether the directory path is already normalized or not.</param>
        /// <param name="options">Enumeration options to use.</param>
        /// <param name="expression">The search expression to potentially use for OS-level filtering (Windows only).</param>
        internal FileSystemEnumerator(string directory, bool isNormalized, EnumerationOptions? options, string? expression) :
            this(directory, isNormalized, options)
        {
            if (_options.RecurseSubdirectories)
            {
                // We can never filter when recursing, as we need to find all subdirectories to recurse into them.
                expression = null;
            }
            else if (expression is not null)
            {
                // We need to ensure that the expression is prepped to be used as an NtQueryDirectoryFile filter.
                // If the match type is simple, we need to escape the special DOS wildcard characters. If it is
                // DOS style, the characters have already been escaped in the FileSystemEnumerableFactory.

                if (expression.Length > 255 || expression is "*" or "." or "..")
                {
                    // Don't allow expressions longer than the maximum filename length. This comes back as
                    // STATUS_INVALID_PARAMETER from NtQueryDirectoryFile. We could catch that there, but
                    // don't want to mask other bad parameter issues.
                    //
                    // Also, an expression of "*" is pointless as a filter- it matches everything. "*.*"
                    // should have been converted to "*" already in the case of MatchType.Win32.
                    //
                    // Finally, "." and ".." are invalid filter names on their own, but we allow you to see
                    // these entries if you specifically ask via EnumerationOptions.ReturnSpecialDirectories.
                    expression = null;
                }
                else if (_options.MatchType == MatchType.Simple)
                {
                    expression = FileSystemName.EscapeExpression(expression);
                }
            }

            _expression = expression;
        }

        private void Init()
        {