dotnet / runtime

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

`System.IO.DirectoryInfo` misreports the `Extension` property for instances constructed with a trailing path (directory) separator #101730

Open mklement0 opened 5 months ago

mklement0 commented 5 months ago

Description

System.IO.DirectoryInfo misreports the Extension property for instances constructed with a trailing path (directory) separator: it unexpectedly returns the empty string.

Note:

Reproduction Steps

// OK -> ".bar"
new System.IO.DirectoryInfo("foo.bar").Extension

// !! BROKEN -> ""
// Note that .Name works fine.
new System.IO.DirectoryInfo("foo.bar/").Extension

Expected behavior

Both statements should return "bar"

Actual behavior

The statement using the path with the trailing path (directory) separator unexpectedly returns "" (the empty string).

Regression?

No. Also affects .NET Framework.

Known Workarounds

No response

Configuration

.NET 8.0.4, .NET 9.0.0-preview.1.24080.9 All platforms (irrespective of whether \ or / i used).

Other information

No response

dotnet-policy-service[bot] commented 5 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 3 months ago

This is also how Path.GetExtension works. What was your scenario that led you to find this? I wasn't expecting Extension to be in FileSystemInfo but rather in FileInfo.

jozkee commented 3 months ago

The problem is that the code stops as soon as it sees a directory separator. One possible way to solve this could be to trim the trailing separator.

https://github.com/dotnet/runtime/blob/4f96b8f541a62245eb5ca4b643363785cc0d58bf/src/libraries/System.Private.CoreLib/src/System/IO/FileSystemInfo.cs#L57

mklement0 commented 3 months ago

I discovered it in the context of the linked PowerShell issue (https://github.com/PowerShell/PowerShell/issues/21553)

.NET, for better or worse, generally makes no distinction between directories and files with respect to what it considers the extension part of the name.

That Path.GetExtension() behaves the way it does is defensible, but if you construct a System.IO.DirectoryInfo instance with a trailing directory separator that otherwise behaves the same as without it (.Name, .Exists), I think it equally makes sense to ignore this incidental separator with respect to .Extension.