A complete FUSE implementation for macOS — no kernel extension, no SIP changes, no third-party dependencies.
DarwinFUSE is a drop-in replacement for macFUSE that runs entirely in userspace.
It translates FUSE callbacks into NFSv4 operations over a localhost loopback server,
using macOS's built-in mount_nfs to mount the filesystem. The result: full FUSE
compatibility without touching the kernel.
No kext. No System Extension. No SIP disable. No macFUSE installation.
Works on every Mac from macOS 12 Monterey onwards, including Apple Silicon, with zero system modifications.
Download the latest .pkg from the Releases page and open it.
The installer checks for an existing macFUSE installation and will guide you through removal if needed. After installing DarwinFUSE, existing FUSE programs (sshfs, encfs, ntfs-3g, ...) work without recompilation.
An uninstaller app is included at /Applications/DarwinFUSE/Uninstall DarwinFUSE.app.
make # builds libdarwinfuse.a + libdarwinfuse.2.dylib
sudo make install # installs to /usr/local with macFUSE-compatible symlinks
make pkg # builds a .pkg installer into build/sudo ./installer/install.shEither open /Applications/DarwinFUSE/Uninstall DarwinFUSE.app or run:
sudo ./installer/uninstall.shYour FUSE program (sshfs, encfs, ntfs-3g, ...)
| fuse_operations callbacks
DarwinFUSE (libfuse.2.dylib / libdarwinfuse.a)
| NFSv4 COMPOUND translation
NFS server on 127.0.0.1:<ephemeral port>
| mount_nfs (built into macOS)
/your/mount/point
When you call fuse_main(), DarwinFUSE:
- Starts a lightweight NFSv4 TCP server on
127.0.0.1with an ephemeral port - Calls
mount_nfsto mount the server at your chosen mount point - Translates incoming NFS operations into your
fuse_operationscallbacks - Optionally daemonizes and runs a multi-threaded worker pool
Your FUSE program doesn't need to know or care that NFS is involved — the API
is the same fuse_main() / fuse_get_context() / fuse_operations you'd use
with macFUSE or libfuse on Linux.
DarwinFUSE implements the full libfuse 2.9 API plus macFUSE's Apple-specific
extensions. It installs as libfuse.2.dylib with the same install_name and
version numbers as macFUSE, so existing compiled binaries work unchanged.
| Path | Description |
|---|---|
/usr/local/lib/libfuse.2.dylib |
Dynamic library (macFUSE-compatible install_name) |
/usr/local/lib/libfuse.dylib |
Symlink |
/usr/local/lib/libdarwinfuse.a |
Static library |
/usr/local/include/fuse/ |
macFUSE-compatible headers |
/usr/local/include/darwinfuse/ |
DarwinFUSE headers |
/usr/local/lib/pkgconfig/fuse.pc |
macFUSE-compatible pkg-config |
/Applications/DarwinFUSE/ |
Uninstaller app |
| Category | Callbacks | Status |
|---|---|---|
| File metadata | getattr, fgetattr, access, readlink, utimens, chmod, chown, truncate, ftruncate |
All implemented |
| File I/O | open, create, read, write, flush, release, fsync |
All implemented |
| Directories | mkdir, rmdir, opendir, readdir, releasedir, fsyncdir |
All implemented |
| Namespace | unlink, rename, link, symlink, mknod |
All implemented |
| Extended attrs | setxattr, getxattr, listxattr, removexattr |
All implemented (Apple position param supported) |
| Filesystem | statfs, init, destroy |
All implemented |
| Locking | lock, flock |
Declared (passthrough stubs) |
| Advanced | ioctl, poll, fallocate, bmap |
Declared |
| macFUSE extensions | getxtimes, setcrtime, setbkuptime, setchgtime, chflags, setattr_x, fsetattr_x, exchange, setvolname, statfs_x, renamex |
All declared; getxtimes/setcrtime/setbkuptime wired through NFSv4 |
| Function | Status |
|---|---|
fuse_main / fuse_main_real |
Implemented |
fuse_mount / fuse_unmount |
Implemented |
fuse_new / fuse_destroy |
Implemented |
fuse_loop / fuse_loop_mt |
Implemented (thread pool) |
fuse_exit |
Implemented |
fuse_get_context |
Implemented (uid, gid, pid, private_data, umask) |
fuse_get_session |
Implemented |
fuse_set_signal_handlers / fuse_remove_signal_handlers |
Implemented |
fuse_parse_cmdline |
Implemented |
fuse_daemonize |
Implemented |
fuse_opt_parse / fuse_opt_add_arg / fuse_opt_free_args / ... |
All implemented |
fuse_version |
Implemented (returns 26) |
fuse_getgroups / fuse_interrupted |
Implemented |
All standard and macFUSE capability flags are declared:
FUSE_CAP_ASYNC_READ, POSIX_LOCKS, ATOMIC_O_TRUNC, EXPORT_SUPPORT,
BIG_WRITES, DONT_MASK, SPLICE_WRITE/MOVE/READ, FLOCK_LOCKS, IOCTL_DIR
macFUSE extensions (advertised in conn->capable on macOS):
FUSE_CAP_XTIMES, CASE_INSENSITIVE, VOL_RENAME, ALLOCATE, EXCHANGE_DATA
Including the FUSE_ENABLE_XTIMES() / FUSE_ENABLE_SETVOLNAME() / FUSE_ENABLE_CASE_INSENSITIVE() convenience macros.
These features have no NFSv4 equivalent and exist only as struct declarations for compilation compatibility:
ioctl— no mechanism to tunnel arbitrary ioctls over NFSpoll— NFS has no file-descriptor pollingwrite_buf/read_buf— zero-copy optimization, not applicable over TCPexchange— atomic file data exchange (macFUSE-only, no known users)renamex—RENAME_SWAP/RENAME_EXCL(macFUSE-only)- File locking —
lock/flockaccept and acknowledge requests but don't enforce byte-range locks
None of these are used by sshfs, encfs, or Basalt. ntfs-3g uses ioctl for
volume-level operations that don't apply to the DarwinFUSE use case.
| FUSE Client | Callbacks Used | Status |
|---|---|---|
| Basalt (encryption volumes) | ~12 core ops | Fully working |
| sshfs | ~26 ops + fuse_opt | API-complete |
| encfs | ~31 ops + xattrs | API-complete |
| ntfs-3g | ~33 ops + xtimes | API-complete (minus ioctl) |
make examples
mkdir -p /tmp/hello
sudo ./examples/hello /tmp/hello
cat /tmp/hello/volume.dmg # "Hello from DarwinFUSE!"
umount /tmp/helloLink against libdarwinfuse.a (static) or libfuse.dylib (dynamic) and include <fuse.h>:
#define FUSE_USE_VERSION 26
#include <fuse.h>
static int my_getattr(const char *path, struct stat *stbuf) { /* ... */ }
static int my_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi) { /* ... */ }
static int my_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi) { /* ... */ }
static struct fuse_operations ops = {
.getattr = my_getattr,
.readdir = my_readdir,
.read = my_read,
};
int main(int argc, char *argv[]) {
return fuse_main(argc, argv, &ops, NULL);
}Compile:
cc -o myfs myfs.c $(pkg-config --cflags --libs fuse)
# or directly:
cc -o myfs myfs.c -I/usr/local/include/fuse -L/usr/local/lib -lfuseFor programs that need separate mount/loop control:
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_chan *ch = fuse_mount("/mnt/point", &args);
struct fuse *f = fuse_new(ch, &args, &ops, sizeof(ops), NULL);
fuse_loop(f); /* or fuse_loop_mt(f) */
fuse_destroy(f);
fuse_unmount("/mnt/point", ch);include/
fuse.h Public API (libfuse 2.9 + macFUSE compatible)
fuse_opt.h Option parsing API
fuse_common.h Compatibility shim
src/
darwinfuse.c fuse_main, component API, signal handling, daemonization
nfs4_ops.c NFSv4 COMPOUND dispatcher (40+ operation handlers)
nfs4_ops.h NFSv4 constants, state structures
nfs4_server.c TCP server, poll loop, thread pool
nfs4_server.h Server lifecycle API
nfs4_xdr.c XDR encoding/decoding
nfs4_xdr.h XDR buffer types
rpc.c ONC RPC message framing
inode_table.c Dynamic inode table (path <-> inode, FNV-1a hash)
inode_table.h Inode table API (incl. xattr virtual inodes)
fuse_opt.c fuse_opt_parse implementation
fuse_context.h Thread-local context management
installer/
install.sh Command-line installer
uninstall.sh Command-line uninstaller
build_pkg.sh Builds .pkg GUI installer
Distribution.xml macOS installer distribution (multilingual)
uninstall.applescript Uninstaller app source (multilingual)
resources/ Localized installer screens (en, de, fr, es, ja, zh-Hans)
DarwinFUSE is designed as a complete macFUSE replacement. To switch:
- Uninstall macFUSE using its built-in uninstaller (System Settings > macFUSE > Remove)
- Optionally re-enable SIP (Recovery Mode > Startup Security Utility > Full Security)
- Install DarwinFUSE via the
.pkginstaller orsudo make install
Existing Homebrew-installed FUSE programs will work without reinstallation because
DarwinFUSE installs libfuse.2.dylib with the same install_name and library version
numbers as macFUSE.
DarwinFUSE was created for Basalt, a TrueCrypt-compatible encryption tool, to mount encrypted volumes on macOS without requiring macFUSE or kernel extensions. It has since grown into a general-purpose FUSE implementation suitable for any libfuse 2.x client.
MIT License. Copyright (c) 2026 Marcel Cotta.