dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.96k stars 4.65k forks source link

.NET 8 DirectoryInfo.EnumerateFiles with MatchCasing.CaseInsensitive fails on Linux #104096

Open Viech3 opened 2 months ago

Viech3 commented 2 months ago

Description

.NET 8.0.302 Ubuntu 22.04.3 LTS

Hi,

I have an Issue with DirectoryInfo.EnumerateFiles. It works fine on windows, but on Linux I have trouble with case insensitive searches.

When I search for "LOG/*.txt" I expect it to find "log/test.txt", but on Linux I get an "DirectoryNotFoundException": Could not find a part of the path '/home/user/publish/LOG'.

Reproduction Steps

Build and Execute following code on Linux:

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            if(!Directory.Exists("log"))
                Directory.CreateDirectory("log");

            if (!File.Exists("log/test.txt"))
                File.Create("log/test.txt").Dispose();

            var files = new DirectoryInfo(Environment.CurrentDirectory).EnumerateFiles("LOG/*.txt", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive });

            foreach (var file in files)
            {
                Console.WriteLine(file.FullName);
            }

            Console.WriteLine("Finished");
        }
    }
}

Expected behavior

Console displays "..../log/test.txt"

Actual behavior

Error is thrown:

Unhandled exception. System.IO.DirectoryNotFoundException: Could not find a part of the path '/home/user/publish/LOG'.

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

dotnet-policy-service[bot] commented 2 months ago

Tagging subscribers to this area: @dotnet/area-system-io See info in area-owners.md if you want to be subscribed.

jozkee commented 2 months ago

Linux filesystems are usually case-sensitive, you are probably using ext4 since that's Ubuntu's default. You can try mounting a FAT filesystem and that I think should give you case insensitive results.

jozkee commented 2 months ago

I don't notice you were using MatchCasing.CaseInsensitive. This is a bug.

We have logic that modifies the path and the searchPattern (expression). https://github.com/dotnet/runtime/blob/2f09bfa3b569a4fce7ac75fe38abb5dd8667e563/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs#L38-L43

Basically, your path /home/user/publish and your pattern LOG/*.txt are turned into /home/user/publish/LOG and *.txt. Because of that, opendir fails with the exception you are seeing.

I'm not sure what would happen if we stopped doing that. this requires experimentation.

jozkee commented 2 months ago

cc @JeremyKuhne

JeremyKuhne commented 2 months ago

@Jozkee Just a weird corner case due to existing behavior. Changing this would be pretty breaking. We should make sure the docs are clear on this behavior. The answer here is don't put subdirectories in the second argument I believe.

jozkee commented 2 months ago

Ah so the existing MatchTypes Simple and Win32 don't support subdirectories. The code re-arranging path and pattern are there for backwards compat?

If we added another MatchType, say globbing that could filter subdirectories, could this issue be addressed? Or do we always want to rearrange path and pattern?