dotnet / dotnet/runtime

[API Proposal]: Add SafeFileHandle constructor with isLocked and deleteOnClose

Open
#128,562 3 comments 0 reactions 0 assignees View on GitHub
api-suggestion area-System.IO
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Background and motivation

I'm creating custom methods to open files/directories - the reason is to support opening a file by a root directory handle and a relative path (`openat` on Unix, `NtCreateFile` on Windows), and I'd like these methods to return a `SafeFileHandle`, not a custom handle type. On Windows, since all the options and flags are directly supported by the operating system, there is no problem with using `new SafeFileHandle(handle, ownsHandle: true)`, but on Unix, if I create a handle this way, `_isLocked` and `_deleteOnClose` will always be false, meaning that if I lock the file for `FileShare` the same way .NET does, the disposal won't unlock the file, and `DeleteOnClose` won't be supported either. In previous .NET versions such as .NET 5, `SafeFileHandle` disposal on Unix unlocked the file unconditionally, but now, `_isLocked` defaults to false, which is a regression. In any case, the only solution currently is to use reflection/unsafe access to set these fields.

To fully support this scenario, I need a new constructor on `SafeFileHandle` that accepts whether the file is locked and whether it should be deleted on close. This constructor would only be supported on Unix.

### API Proposal

```csharp
namespace Microsoft.Win32.SafeHandles;

public sealed partial class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
{
[UnsupportedOSPlatform("windows")]
public SafeFileHandle(IntPtr preexistingHandle, bool ownsHandle, bool isLocked, bool deleteOnClose);
}
```

### API Usage

```csharp
// Create a file handle using custom PInvoke and set the appropriate locking, and check if `DeleteOnClose` is true;
var handle = new SafeFileHandle(handle, ownsHandle: true, isLocked, (options & FileOptions.DeleteOnClose) != 0);
````

### Alternative Designs

The only alternative is to unseal the class, so that I can do everything appropriately on my own.

```diff
namespace Microsoft.Win32.SafeHandles;

-public sealed partial class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
+public partial class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
{
}
```

### Risks

I don't know.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.