NfsSharp 0.1.3
dotnet add package NfsSharp --version 0.1.3
NuGet\Install-Package NfsSharp -Version 0.1.3
<PackageReference Include="NfsSharp" Version="0.1.3" />
<PackageVersion Include="NfsSharp" Version="0.1.3" />
<PackageReference Include="NfsSharp" />
paket add NfsSharp --version 0.1.3
#r "nuget: NfsSharp, 0.1.3"
#:package NfsSharp@0.1.3
#addin nuget:?package=NfsSharp&version=0.1.3
#tool nuget:?package=NfsSharp&version=0.1.3
NfsSharp
A full-featured .NET NFS client library supporting NFSv2, NFSv3, and NFSv4 with a single, version-agnostic API.
Features
- NFSv2, NFSv3, and NFSv4 support with automatic version negotiation
- Single
NfsCliententry point — no version-specific code in your application NfsStreamintegrates seamlessly with all .NET I/O APIs (StreamReader,CopyToAsync,JsonSerializer, etc.)- AUTH_NONE, AUTH_SYS, and RPCSEC_GSS stub (derive and override to add Kerberos)
- Auto version negotiation: tries NFSv4 → v3 → v2 when
NfsVersion.Autois used - Retry on transient failures (socket errors, timeouts) with exponential back-off
- Fully seekable streams — NFS is a random-access protocol
SetLength/SetLengthAsyncfor remote file truncation/extension- Set file timestamps (
AccessTime,ModifyTime) viaNfsSetAttributeson all protocol versions Flush/FlushAsyncissues an NFSCOMMITRPC to promote unstable writes to stable storage- Multi-target: net10.0, net9.0, net8.0, and netstandard2.0
Installation
dotnet add package NfsSharp
Or search for NfsSharp in the NuGet Package Manager UI in Visual Studio.
Quick Start
using System.IO;
// Connect and mount
await using var nfs = new NfsClient("nfs.example.com", "/exports/data");
await nfs.ConnectAsync();
// List a directory
var entries = await nfs.ReadDirAsync("reports");
foreach (var entry in entries)
Console.WriteLine($"{entry.Name} ({entry.Attributes?.Size ?? 0} bytes)");
// Read a file with StreamReader
await using NfsStream stream = await nfs.OpenFileAsync("reports/q4.csv", FileAccess.Read);
using var reader = new StreamReader(stream);
string content = await reader.ReadToEndAsync();
Console.WriteLine(content);
// Write-only stream to a newly created/truncated file
await using var ws = await nfs.OpenFileAsync("output/result.txt", FileAccess.Write, create: true);
await using var writer = new StreamWriter(ws);
await writer.WriteLineAsync("Hello from NfsSharp!");
await ws.FlushAsync(); // issues NFS COMMIT
Authentication
// AUTH_NONE (default — no credentials)
var nfs = new NfsClient("nfs.example.com", "/export");
// AUTH_SYS (Unix credentials)
var creds = new AuthSysCredentials(
machineName: "myclient",
uid: 1000,
gid: 1000,
gidList: new uint[] { 100, 200 });
var nfs = new NfsClient("nfs.example.com", "/export", creds);
// RPCSEC_GSS (Kerberos stub — derive and override EncodeBody for full support)
// var creds = new MyKerberosCredentials();
NfsStream
NfsStream is a standard System.IO.Stream. It works with every .NET API that accepts a stream:
await using NfsStream stream = await nfs.OpenFileAsync("data/archive.json", FileAccess.ReadWrite);
// Copy to a local file
using var local = File.Create("archive.json");
await stream.CopyToAsync(local);
// Deserialize JSON directly
var obj = await JsonSerializer.DeserializeAsync<MyData>(stream);
// Truncate / extend a file
await stream.SetLengthAsync(0); // truncate to empty
await stream.SetLengthAsync(4096); // extend to 4 KiB
// Commit unstable writes to stable storage
await stream.WriteAsync(data);
await stream.FlushAsync(); // issues NFS COMMIT
Downloading and Uploading Files
DownloadFileToLocalAsync and UploadFileFromLocalAsync bypass NfsStream and use parallel ranged NFS READ/WRITE calls for high-throughput bulk transfers.
// Download a remote file to a local path (4 workers, 4 MiB chunks by default)
await nfs.DownloadFileToLocalAsync("backups/db.tar.gz", "/tmp/db.tar.gz");
// Download with a progress callback and custom parallelism
var progress = new Progress<long>(bytes => Console.WriteLine($"Downloaded {bytes} bytes"));
await nfs.DownloadFileToLocalAsync(
remotePath: "large/video.mp4",
localPath: "/tmp/video.mp4",
degreeOfParallelism: 8,
chunkSize: 8 * 1024 * 1024, // 8 MiB chunks
progress: progress);
// Upload a local file to a remote path (4 workers, 4 MiB chunks by default)
await nfs.UploadFileFromLocalAsync("/tmp/report.pdf", "reports/report.pdf");
// Upload with a progress callback and custom parallelism
var uploadProgress = new Progress<long>(bytes => Console.WriteLine($"Uploaded {bytes} bytes"));
await nfs.UploadFileFromLocalAsync(
localPath: "/tmp/dataset.parquet",
remotePath: "datasets/dataset.parquet",
degreeOfParallelism: 8,
chunkSize: 8 * 1024 * 1024, // 8 MiB chunks
progress: uploadProgress);
Version Negotiation
// Auto: tries NFSv4 → v3 → v2 (default)
var nfs = new NfsClient("server", "/export", NfsVersion.Auto);
// Pin to a specific version
var nfsV3 = new NfsClient("server", "/export", NfsVersion.V3);
var nfsV4 = new NfsClient("server", "/export", NfsVersion.V4);
await nfs.ConnectAsync();
Console.WriteLine($"Negotiated: {nfs.NegotiatedVersion}"); // e.g. V3
API Reference (NfsClient)
Properties
| Property | Description |
|---|---|
NegotiatedVersion |
NFS protocol version negotiated after ConnectAsync() |
RootHandle |
Root file handle of the mounted export (available after connect) |
Methods
| Method | Description |
|---|---|
ConnectAsync(ct = default) |
Connects, negotiates version, and mounts the export |
GetAttrAsync(path, ct = default) |
Gets attributes for a path |
GetAttrAsync(handle, ct = default) |
Gets attributes for an existing file handle |
SetAttrAsync(path, attrs, ct = default) |
Applies attributes to a path |
SetAttrAsync(handle, attrs, ct = default) |
Applies attributes to an existing file handle |
ExistsAsync(path, ct = default) |
Returns whether a path exists |
ExistsAsync(handle, ct = default) |
Returns whether a handle still resolves on the server |
LookupAsync(path, ct = default) |
Resolves a path to (Handle, Attributes) |
ReadDirAsync(path, ct = default) |
Lists entries in a directory path |
ReadDirAsync(handle, ct = default) |
Lists entries in a directory handle |
ReadDirStreamAsync(path, ct = default) |
Streams directory entries by path (paged, lazy) |
ReadDirStreamAsync(handle, ct = default) |
Streams directory entries by handle (paged, lazy) |
ReadDirRecursiveAsync(path, ct = default) |
Recursively streams descendant entries by path |
ReadDirRecursiveAsync(handle, baseRelativePath = "", ct = default) |
Recursively streams descendant entries by handle |
ReadLinkAsync(path, ct = default) |
Reads the target of a symbolic link |
RemoveAsync(path, ct = default) |
Removes a file |
RmDirAsync(path, ct = default) |
Removes an empty directory |
MkDirAsync(path, attrs = null, ct = default) |
Creates a directory |
RenameAsync(sourcePath, destPath, ct = default) |
Renames or moves a file/directory |
LinkAsync(targetPath, linkPath, ct = default) |
Creates a hard link |
SymLinkAsync(linkPath, linkTarget, ct = default) |
Creates a symbolic link |
FsStatAsync(ct = default) |
Returns filesystem statistics for the mounted export |
ListExportsAsync(ct = default) |
Lists exports advertised by the server |
OpenFileAsync(path, access = FileAccess.ReadWrite, create = false, ct = default) |
Opens an NfsStream with read/write/read-write access; optional create/truncate |
DownloadFileToLocalAsync(remotePath, localPath, degreeOfParallelism = 4, chunkSize = 4 * 1024 * 1024, progress = null, ct = default) |
Fast-path download to local disk using parallel ranged reads |
UploadFileFromLocalAsync(localPath, remotePath, degreeOfParallelism = 4, chunkSize = 4 * 1024 * 1024, progress = null, ct = default) |
Fast-path upload from local disk using parallel ranged writes |
Dispose() |
Disposes client resources |
DisposeAsync() |
Asynchronously disposes client resources |
Constructors
| Constructor | Description |
|---|---|
NfsClient(server, version = NfsVersion.Auto, nfsPort = 0, mountPort = 0, connectTimeout = null, readTimeout = null) |
Creates a client with AUTH_NONE credentials and automatic export discovery at connect time |
NfsClient(server, credentials, version = NfsVersion.Auto, nfsPort = 0, mountPort = 0, connectTimeout = null, readTimeout = null) |
Creates a client with explicit credentials and automatic export discovery at connect time |
NfsClient(server, exportPath, version = NfsVersion.Auto, nfsPort = 0, mountPort = 0, connectTimeout = null, readTimeout = null) |
Creates a client with AUTH_NONE credentials and explicit export path |
NfsClient(server, exportPath, credentials, version = NfsVersion.Auto, nfsPort = 0, mountPort = 0, connectTimeout = null, readTimeout = null) |
Creates a client with explicit credentials and explicit export path |
Note: automatic export discovery requires the server to advertise exactly one export. If multiple exports exist, pass
exportPathexplicitly.
GitHub Actions Setup
CI
The CI workflow runs automatically on every push and pull request. No setup is required.
Publishing to NuGet
- Fork / clone this repository.
- Go to Settings → Secrets and variables → Actions.
- Click New repository secret and add:
- Name:
NUGET_API_KEY - Value: Your NuGet.org API key (scoped to push on the
NfsSharppackage)
- Name:
- For trusted publishing:
- On NuGet.org, navigate to your package → Manage → Trusted publishers → Add GitHub Actions publisher.
- Enter your GitHub org/repo and workflow file name (
publish.yml). - Keep
NuGet/login@v1in.github/workflows/publish.yml; it exchanges OIDC for a short-livedNUGET_API_KEYoutput used bydotnet nuget push.
- Tag a release to trigger the workflow:
git tag v0.1.0 git push origin v0.1.0
We accept donations
If you would like to support ongoing development:
- GitHub Sponsors: https://github.com/sponsors/itsWindows11
- GitHub profile: https://github.com/itsWindows11
Contributing
Contributions are welcome! Please open an issue or pull request on GitHub. For large changes, open an issue first to discuss your approach.
License
MIT — see LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Bcl.AsyncInterfaces (>= 8.0.0)
- System.Memory (>= 4.5.5)
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on NfsSharp:
| Package | Downloads |
|---|---|
|
OwlCore.Storage.NfsSharp
An OwlCore.Storage-based library that provides a full-featured implementation for the NFS file system, built on top of NfsSharp. |
GitHub repositories
This package is not used by any popular GitHub repositories.
[0.1.3]
Added INfsClient interface that mirrors all public properties and methods of NfsClient, enabling mocking and alternative implementations without changing call sites.
[0.1.2]
Added AccessTime and ModifyTime properties to NfsSetAttributes, enabling callers to set the last-access and last-modification timestamps on remote files and directories via SETATTR. Supported on NFSv2, NFSv3, and NFSv4.
[0.1.1]
Refactored stream IO to use `Memory` & `Span` overloads.
[0.1.0]
Initial release with NFSv2, NFSv3, and NFSv4 support.