FuseSharp
FuseSharp is the standalone FUSE 3 high-level mount library used by the Linux and macOS front
end of SimpleXisoDrive. It lives in its own repository so the mount layer can be tested, reused and
versioned independently: the library knows nothing about Xbox images, XDVDFS or
SimpleXisoDrive.Core - it mounts any read-only volume that implements its interface.
- Source repository: https://github.com/purelogiccode/LibFuseSharp
- NuGet package id:
LibFuseSharp(version 1.0.1) - Assembly and namespace:
LibFuseSharp/FuseSharp - Targets:
net8.0,net9.0,net10.0 - Native dependency:
libfuse3on Linux, macFUSE’slibfuse3on macOS - License: MIT
- Used by:
SimpleXisoDrive.Unixvia a pinnedPackageReference; the source is no longer vendored in this repository.
Install it with:
dotnet add package LibFuseSharp --version 1.0.1
The volume contract
A volume is exposed through two small interfaces with POSIX-style paths (/ is the root and
components are separated by /):
public interface IFuseVolume
{
string VolumeLabel { get; }
DateTime VolumeCreationTime { get; }
ulong VolumeSize { get; }
IFuseEntry? GetEntry(string path);
IEnumerable<IFuseEntry> GetFolderList(string path);
int ReadFile(IFuseEntry entry, Span<byte> buffer, long offset);
}
public interface IFuseEntry
{
string FileName { get; }
bool IsDirectory { get; }
long Size { get; }
}
The contract is deliberately read-only and minimal:
| Member | Behavior expected by FuseFileSystem |
|---|---|
VolumeLabel |
Exposed as fsname= on Linux and volname= on macOS (sanitized by the library). |
VolumeCreationTime |
Reported as the st_atim/st_mtim/st_ctim timestamps of every entry. |
VolumeSize |
Reported through statfs as the total number of 4096-byte blocks. |
GetEntry |
Returns null for a missing path (mapped to ENOENT); the root path is /. |
GetFolderList |
Returns the children of a directory; empty when the path is not a directory. |
ReadFile |
Returns the number of bytes read; throws IOException when the data cannot be read (mapped to EIO). |
FuseFileSystem never calls a mutating member: there is none. open rejects anything but
O_RDONLY with EACCES, macOS setattr returns EROFS, and every callback the library does not
implement fails with ENOSYS by default. A readdir on a regular file returns ENOTDIR; a
missing path returns ENOENT.
Mounting a volume
using FuseSharp;
var volume = new MyReadOnlyVolume();
var fileSystem = new FuseFileSystem(volume);
var exitCode = fileSystem.Run(mountPoint: "/mnt/myvolume", debug: false, onMounted: () =>
{
Console.WriteLine("Mounted.");
});
Run blocks until the file system is unmounted (Ctrl+C, SIGTERM, SIGHUP or
fusermount3 -u/umount), then returns 0 on a clean unmount. Unmounting from outside the
application (including ejecting the volume in Finder on macOS) closes the FUSE device and makes
libfuse report ENODEV; the library treats that as a normal end of the session too. The constructor
registers the native library resolver, so no separate initialization call is required.
FuseAvailability.Check can be used before mounting to print installation guidance when FUSE is
missing. Pass printInstructions: false for a side-effect-free capability probe:
if (!FuseAvailability.Check(out _, candidates: null, printInstructions: false))
return;
Components
| Component | Purpose |
|---|---|
FuseFileSystem |
High-level mount: builds the fuse_operations table, runs the FUSE session loop, maps callback results to POSIX errors and installs signal handlers that request a clean exit through fuse_exit. |
FuseInterop |
Platform-aware P/Invoke layer: loads libfuse3, declares the Linux and macOS fuse_operations layouts and struct stat/struct statvfs writes, chooses the exported fuse_new/fuse_new_31 entry point, and pokes the mount with statfs to wake a blocked loop. |
FuseAvailability |
Probes the FUSE library, /dev/fuse and fusermount3, and prints per-platform installation guidance when a prerequisite is missing. |
IFuseVolume / IFuseEntry |
The POSIX-path read-only volume contract described above. |
The library targets Linux x64/ARM64 and macOS x64/ARM64. The FUSE library can be overridden with
the LIBFUSESHARP_LIBRARY environment variable (the legacy SIMPLEXISODRIVE_FUSE_LIBRARY name is
still honored); otherwise the standard distribution paths are probed in version order.
How SimpleXisoDrive uses it
The application keeps the Xbox-specific code in SimpleXisoDrive.Core and adapts it to the
library contract in SimpleXisoDrive.Unix/FuseVolumeAdapter.cs:
FuseVolumeAdapterimplementsIFuseVolumeover anIVfsVolume(whose paths use backslashes) and converts/sub/fileto\sub\filein both directions.- Each
IVfsEntryis wrapped in an internalEntryAdaptersoReadFilecan unwrap it again and forward the read to the original entry. An entry that did not come from the adapter is rejected. - The Unix front end wires the two together:
new FuseFileSystem(new FuseVolumeAdapter(vfsContainer)).
Because the adapter lives in the application, LibFuseSharp has no project reference to
SimpleXisoDrive.Core and is consumed as a package. Library changes are made in the
LibFuseSharp repository, published to NuGet, and
then pinned by updating the PackageReference in SimpleXisoDrive.Unix.csproj.
See also
- Architecture - where
FuseSharpsits in the component and mount lifecycle. - Virtual File System - the volume behavior on the other side of the adapter.
- Linux and macOS - end-user usage and prerequisites.
- Building - building and testing the solution, including
FuseSharp.