dotnet / runtime

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

PhysicalFileInfo should report the right Length and LastModifiedTime for symbolic links #63424

Open brunolins16 opened 2 years ago

brunolins16 commented 2 years ago

Description

The ASP.NET core framework uses the PhysicalFileProvider to get physical files information PhysicalFileInfo in a lot places. However, the Length and LastModified properties are not set to the correct value when the file is a symbolic link, as reported here https://github.com/dotnet/aspnetcore/issues/39170.

The issue happens in both Windows and Linux.

Reproduction Steps

using Microsoft.Extensions.FileProviders;

File.WriteAllText("sample.txt", "Dummy Contenxt");
File.CreateSymbolicLink("linksample.txt", "sample.txt");

var provider = new PhysicalFileProvider(Directory.GetCurrentDirectory());
var linkInfo = provider.GetFileInfo("linksample.txt");
var originalInfo = provider.GetFileInfo("sample.txt");

Console.WriteLine($"Original file size: {originalInfo.Length}");
Console.WriteLine($"Link file size: {linkInfo.Length}");

File.Delete("linksample.txt");
File.Delete("sample.txt");

Expected behavior

Original file size: 14
Link file size: 14

Actual behavior

Windows

Original file size: 14
Link file size: 0

Linux

Original file size: 14
Link file size: 10

Regression?

No response

Known Workarounds

The following code, to the sample, give us the right information:

if (!string.IsNullOrEmpty(linkInfo.PhysicalPath))
{
    var followedLinkFileInfo = new FileInfo(linkInfo.PhysicalPath).ResolveLinkTarget(true) as FileInfo;
    Console.WriteLine($"Followed Link file size: {followedLinkFileInfo.Length}");
}

Configuration

OS: Ubuntu 20.04 and Windows 11 (22525.1000)

Other information

No response

ghost commented 2 years ago

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

Issue Details
### Description The ASP.NET core framework uses the [PhysicalFileProvider](https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileProvider.cs) to get physical files information [PhysicalFileInfo](https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PhysicalFileInfo.cs) in a lot places. However, the `Length` and `LastModified` properties are not set to the correct value when the file is a symbolic link, as reported here https://github.com/dotnet/aspnetcore/issues/39170. The issue happens in both `Windows` and `Linux`. ### Reproduction Steps ``` csharp using Microsoft.Extensions.FileProviders; File.WriteAllText("sample.txt", "Dummy Contenxt"); File.CreateSymbolicLink("linksample.txt", "sample.txt"); var provider = new PhysicalFileProvider(Directory.GetCurrentDirectory()); var linkInfo = provider.GetFileInfo("linksample.txt"); var originalInfo = provider.GetFileInfo("sample.txt"); Console.WriteLine($"Original file size: {originalInfo.Length}"); Console.WriteLine($"Link file size: {linkInfo.Length}"); File.Delete("linksample.txt"); File.Delete("sample.txt"); ``` ### Expected behavior ``` Original file size: 14 Link file size: 14 ``` ### Actual behavior ### Windows ``` Original file size: 14 Link file size: 0 ``` ### Linux ``` Original file size: 14 Link file size: 10 ``` ### Regression? _No response_ ### Known Workarounds The following code, to the sample, give us the right information: ``` csharp if (!string.IsNullOrEmpty(linkInfo.PhysicalPath)) { var followedLinkFileInfo = new FileInfo(linkInfo.PhysicalPath).ResolveLinkTarget(true) as FileInfo; Console.WriteLine($"Followed Link file size: {followedLinkFileInfo.Length}"); } ``` ### Configuration OS: Ubuntu 20.04 and Windows 11 (22525.1000) ### Other information _No response_
Author: brunolins16
Assignees: -
Labels: `area-System.IO`, `untriaged`
Milestone: -
StasPerekrestov commented 2 years ago

Hello. If I'm not mistaken, the issue also affects asp.net core.

For instance, when a web app is hosted in Kubernetes(k8s) and leverages from using k8s secrets, e.g. mounts a secret to a file path, it often leads to a set of symbolic links on a file system. If the web app serves the content of these secrets as static files, it leads to an issue that kestrel cannot determine files lends and uses an incorrect value in the HTTP Content-Length header. In the example below, please see the Content-Length HTTP header value.

/app/wwwroot/.well-known # tree -ah
.
├── [  60]  ..2022_05_06_15_52_59.3929185971
│   └── [5.6K]  apple-developer-merchantid-domain-association.txt
├── [  32]  ..data -> ..2022_05_06_15_52_59.3929185971
└── [  56]  apple-developer-merchantid-domain-association.txt -> ..data/apple-developer-merchantid-domain-association.txt

2 directories, 2 files
/app/wwwroot/.well-known # ls -lah
total 4K
drwxrwsrwt    3 root     1337         100 May  6 15:52 .
drwxr-xr-x    1 root     root        4.0K May  6 15:53 ..
drwxr-sr-x    2 root     1337          60 May  6 15:52 ..2022_05_06_15_52_59.3929185971
lrwxrwxrwx    1 root     1337          32 May  6 15:52 ..data -> ..2022_05_06_15_52_59.3929185971
lrwxrwxrwx    1 root     1337          56 May  6 15:52 apple-developer-merchantid-domain-association.txt -> ..data/apple-developer-merchantid-domain-association.txt
/app/wwwroot/.well-known # curl http://localhost:8080/.well-known/apple-developer-merchantid-domain-association.txt -I
HTTP/1.1 200 OK
Content-Length: 56
Content-Type: text/plain
Date: Fri, 06 May 2022 16:30:07 GMT
Server: Kestrel
Accept-Ranges: bytes
ETag: "1d861615bf5ffb8"
Last-Modified: Fri, 06 May 2022 15:52:59 GMT

/app/wwwroot/.well-known # curl http://localhost:8080/.well-known/..2022_05_06_15_52_59.3929185971/apple-developer-merchantid-domain-association.txt -I
HTTP/1.1 200 OK
Content-Length: 5758
Content-Type: text/plain
Date: Fri, 06 May 2022 16:30:12 GMT
Server: Kestrel
Accept-Ranges: bytes
ETag: "1d861615bf5e9fe"
Last-Modified: Fri, 06 May 2022 15:52:59 GMT

/app/wwwroot/.well-known

Thank you.

jozkee commented 2 years ago

This is not only an issue on PhysicalFIleInfo, the problem comes from the underlying FileInfo. Changing any current behavior would be a breaking change, but this could be resolved with this API proposal https://github.com/dotnet/runtime/issues/52908.