Edit: following approach turned out to be too complex to worth pursuing (all sys-calls allow us to get device path, which is something .NET users are not used to)
Details
As of today, FileStream.Name delegates all the work to the strategy:
|
/// <summary>Gets the path that was passed to the constructor.</summary> |
|
public virtual string Name => _strategy.Name; |
Which returns "[Unknown]" if path is not available:
|
internal sealed override string Name => _fileHandle.Path ?? SR.IO_UnknownFileName; |
We should extend SafeFileHandle.Name with the ability to fetch the file path for regular files (and document it as a breaking change).
The Windows implementation from src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.cs should use the GetFinalPathNameByHandle sys-call to obtain the path.
The Unix implementation from src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs should extend pal_io.c and pal_io.h with a method that takes the file descriptor, buffer and writeable size and populates it with data:
- calls
readlink("/proc/self/fd/3", buf, size); on Linux
- calls
fcntl(fd, F_GETPATH, buf); on BSD systems (apple platforms + FreeBSD)
- sets
errno = ENOTSUP and returns -1 on other systems. In such case the calling managed method needs to return SR.IO_UnknownFileName
We don't need dedicated tests, it's fine to just extend the tests from src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/SafeFileHandle/GetFileType.cs.
We need to use the property in src/libraries/System.Diagnostics.Process/tests/ProcessHandlesTests.cs in order to implement a test that ensures that given file handle was not inherited when Process was started:
- creates an inheritable
SafeFileHandle that points to a regular file
- spawns a new remote executor process with
InheritedHandles = [] and passes the raw file descriptor as a string and file path to the RemoteExecutor.Invoke method. Then inside remote executor we need to ensure that given file handle is not available. If it's available, then we need to check the path it points to by creating a FileStream from it and using Name API and comparing it with the path passed via args.
- use this test as a starting point
Edit: following approach turned out to be too complex to worth pursuing (all sys-calls allow us to get device path, which is something .NET users are not used to)
Details
As of today,
FileStream.Namedelegates all the work to the strategy:runtime/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.cs
Lines 430 to 431 in 68b538c
Which returns "[Unknown]" if path is not available:
runtime/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/OSFileStreamStrategy.cs
Line 91 in 68b538c
We should extend
SafeFileHandle.Namewith the ability to fetch the file path for regular files (and document it as a breaking change).The Windows implementation from
src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Windows.csshould use theGetFinalPathNameByHandlesys-call to obtain the path.The Unix implementation from
src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.csshould extendpal_io.candpal_io.hwith a method that takes the file descriptor, buffer and writeable size and populates it with data:readlink("/proc/self/fd/3", buf, size);on Linuxfcntl(fd, F_GETPATH, buf);on BSD systems (apple platforms + FreeBSD)errno = ENOTSUPand returns-1on other systems. In such case the calling managed method needs to returnSR.IO_UnknownFileNameWe don't need dedicated tests, it's fine to just extend the tests from
src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/SafeFileHandle/GetFileType.cs.We need to use the property in
src/libraries/System.Diagnostics.Process/tests/ProcessHandlesTests.csin order to implement a test that ensures that given file handle was not inherited whenProcesswas started:SafeFileHandlethat points to a regular fileInheritedHandles = []and passes the raw file descriptor as a string and file path to theRemoteExecutor.Invokemethod. Then inside remote executor we need to ensure that given file handle is not available. If it's available, then we need to check the path it points to by creating aFileStreamfrom it and usingNameAPI and comparing it with the path passed via args.