@ -150,8 +150,8 @@ namespace NTFSSecurity
// for itself. Before 5.0.0, [1] was read as a character class, so a file with brackets in its name was not
// for itself. Before 5.0.0, [1] was read as a character class, so a file with brackets in its name was not
// returned for its name. The enumeration returns every item for *.* as Windows does, so the comparison does
// returned for its name. The enumeration returns every item for *.* as Windows does, so the comparison does
// too; with the dot as an ordinary character, it would drop the items without a dot, most folders.
// too; with the dot as an ordinary character, it would drop the items without a dot, most folders.
// CultureInvariant: the enumeration ignores case without the culture of the thread, and with tr-TR the
// CultureInvariant: like the enumeration (see MoveNextInvariant), the comparison would otherwise treat I and i as
// comparison would otherwise treat I and i as different letters and drop items that the enumeration match ed.
// different letters with tr-TR and drop items that the enumeration return ed.
var pattern = filter = = "*.*" ? "*" : filter ;
var pattern = filter = = "*.*" ? "*" : filter ;
wildcard = new WildcardPattern ( pattern . Replace ( "`" , "``" ) . Replace ( "[" , "`[" ) . Replace ( "]" , "`]" ) , WildcardOptions . Compiled | WildcardOptions . IgnoreCase | WildcardOptions . CultureInvariant ) ;
wildcard = new WildcardPattern ( pattern . Replace ( "`" , "``" ) . Replace ( "[" , "`[" ) . Replace ( "]" , "`]" ) , WildcardOptions . Compiled | WildcardOptions . IgnoreCase | WildcardOptions . CultureInvariant ) ;
@ -208,18 +208,33 @@ namespace NTFSSecurity
{
{
if ( directory )
if ( directory )
{
{
var files = di . EnumerateDirectories ( filter , global :: System . IO . SearchOption . TopDirectoryOnly ) ;
IEnumerator files ;
WriteFileSystemInfoCollection ( files . GetEnumerator ( ) ) ;
using ( new InvariantCultureScope ( ) )
{
files = di . EnumerateDirectories ( filter , global :: System . IO . SearchOption . TopDirectoryOnly ) . GetEnumerator ( ) ;
}
WriteFileSystemInfoCollection ( files ) ;
}
}
else if ( file )
else if ( file )
{
{
var files = di . EnumerateFiles ( filter , global :: System . IO . SearchOption . TopDirectoryOnly ) ;
IEnumerator files ;
WriteFileSystemInfoCollection ( files . GetEnumerator ( ) ) ;
using ( new InvariantCultureScope ( ) )
{
files = di . EnumerateFiles ( filter , global :: System . IO . SearchOption . TopDirectoryOnly ) . GetEnumerator ( ) ;
}
WriteFileSystemInfoCollection ( files ) ;
}
}
else
else
{
{
var files = di . EnumerateFileSystemInfos ( filter , global :: System . IO . SearchOption . TopDirectoryOnly ) ;
IEnumerator files ;
WriteFileSystemInfoCollection ( files . GetEnumerator ( ) ) ;
using ( new InvariantCultureScope ( ) )
{
files = di . EnumerateFileSystemInfos ( filter , global :: System . IO . SearchOption . TopDirectoryOnly ) . GetEnumerator ( ) ;
}
WriteFileSystemInfoCollection ( files ) ;
}
}
}
}
@ -286,7 +301,7 @@ namespace NTFSSecurity
protected void WriteFileSystemInfoCollection ( IEnumerator fileSystemInfos )
protected void WriteFileSystemInfoCollection ( IEnumerator fileSystemInfos )
{
{
while ( fileSystemInfos . MoveNext ( ) )
while ( MoveNextInvariant ( fileSystemInfos ) )
{
{
FileSystemInfo current = ( FileSystemInfo ) fileSystemInfos . Current ;
FileSystemInfo current = ( FileSystemInfo ) fileSystemInfos . Current ;
if ( ! wildcard . IsMatch ( current . Name ) )
if ( ! wildcard . IsMatch ( current . Name ) )
@ -359,5 +374,32 @@ namespace NTFSSecurity
{
{
base . EndProcessing ( ) ;
base . EndProcessing ( ) ;
}
}
// AlphaFS 2.2 matches the filter with a regular expression that takes the culture of the thread, and with tr-TR the
// letters I and i differ: index* did not match Index.txt. The enumeration therefore runs with the invariant culture,
// which is back before an item reaches the pipeline, so that no later command sees it.
private static bool MoveNextInvariant ( IEnumerator enumerator )
{
using ( new InvariantCultureScope ( ) )
{
return enumerator . MoveNext ( ) ;
}
}
private sealed class InvariantCultureScope : IDisposable
{
private readonly System . Globalization . CultureInfo previous ;
public InvariantCultureScope ( )
{
previous = System . Threading . Thread . CurrentThread . CurrentCulture ;
System . Threading . Thread . CurrentThread . CurrentCulture = System . Globalization . CultureInfo . InvariantCulture ;
}
public void Dispose ( )
{
System . Threading . Thread . CurrentThread . CurrentCulture = previous ;
}
}
}
}
}
}