Netatalk 4.6.0 is available!
Today we’re releasing Netatalk 4.6.0, the fastest and most capable AFP server we’ve ever shipped; Netatalk Client 1.0, our client’s first production release; and a rebuilt netatalk.io, the new home for both.
Apple is withdrawing AFP support in macOS Golden Gate. That ends an era, but not the protocol: millions of Macs and NAS devices, decades of archives, studios, labs, and retro-computing setups speak AFP every day. Our answer is to advance. This cycle modernized, hardened, and accelerated the whole stack, and for the first time Netatalk provides both sides of the connection. The server has long run almost anywhere, but mounting AFP was effectively Apple-only. With Netatalk Client 1.0 that constraint is gone: Linux, FreeBSD, NetBSD, OpenBSD, macOS, and illumos/Solaris can now all mount AFP volumes natively. AFP support isn’t just surviving Apple’s retreat — it is reaching more platforms than it ever has.
A file server rebuilt for speed
The network transport now negotiates transfer sizes as the AFP specification intends and aligns every frame to the network path and disk, so bulk transfers stream at full quantum with no wasted packets or buffers. The directory cache defaults to adaptive replacement (ARC) for 10–50% better hit ratios and now caches state, metadata, and resource-fork data, so browsing classic Mac content doesn’t touch the disk once cached. Hot paths were profiled syscall by syscall to strip redundant lookups and path walks, and background cache maintenance is now lock-free, ending latency spikes on busy and single-core systems.
The numbers: benchmarked with the project’s lantest tooling, each release in its stock configuration, 4.6.0 completes the full test set ~55% faster than 4.4.1 and ~45% faster than 4.5.1, and is 200–300% faster on the operations used most — 2.9× on bulk deletes, 2.7× on directory enumeration, 2.3× on file creation and server-side copies. All of it is on by default; every knob remains for specialists.
Strictly coherent caching, correct locking
The caching layers are now strictly coherent: every entry is validated, cross-process changes propagate immediately, and structural defects in the directory cache — some twenty years old — were found by a purpose-built attack test suite and fixed. Locking and delete semantics now match POSIX, macOS, and Samba: files viewed over AFP no longer wedge as “in use”, open forks behave like opens everywhere else, and byte-range locks land where other filesystems put them.
Netatalk alongside other accessors (Samba, NFS, etc)
That work unblocked the headline feature: Netatalk now shares volumes correctly with other protocols. What used to take several coordinated, easily mis-set options is now one switch — declare a volume multi-protocol and every coherency and locking default snaps to the safe value, whether the other accessor is Samba, NFS, or a local process; leave it off and a Netatalk-only server keeps the fast path. Option names match Samba’s, configuration parsing fails closed, and an end-to-end interoperability test — a kernel CIFS mount and a Netatalk Client mount on one shared volume — guards it in CI.
Spotlight search, feature complete
Finder search over AFP now just works: multi-word searches match every word, quoted phrases match exactly, folder-scoped searches stay in the folder, and result limits are honoured — served straight from the CNID database with no external indexer, on every supported platform. Pluggable backends remain for full-text indexing.
Modern database backends
SQLite is now the default catalog backend — zero-configuration and in-process — with MySQL/MariaDB for large or multi-server deployments. Both now distinguish contention, disk-full, and corruption instead of ending user sessions, and even 32-bit ID exhaustion recovers cleanly. The legacy Berkeley DB (dbd) scheme is deprecated and will be removed.
Security and resilience
This cycle closed more than twenty CVEs, hardened every authentication method (DHX, DHX2, SRP), and tightened wire-format parsing throughout. Even the classic AppleTalk transport was modernised — and gained its first unit tests. Every change is now gated by a continuous performance dashboard, a shaped-network test harness, thread-sanitised protocol suites, and JUnit-reported specification tests.
All users of previous Netatalk versions are encouraged to upgrade to 4.6.0.
Breaking changes
SRP UAM hardening
The local verifiers for the Secure Remote Password UAM are now stored in a new format: individual UID files instead of a monolithic flat file. This enables afppasswd to run without elevated privileges. Before existing users can authenticate with SRP after upgrading, you have to migrate the verifiers. Do this by stopping netatalk, then running the following command:
sudo afppasswd -m
See the Upgrading chapter in the manual for more information.
Randnum UAM hardening
Since afppasswd no longer runs with elevated privileges, only root can update passwords for Randnum users. F.e. to reset the password for existing Randnum user alice:
sudo afppasswd -r -a alice
Randnum is still an insecure authentication method, only recommended for deployments with very old Mac clients.
FCE notification script
The fce_ev_script.sh Filesystem Change Events notification sample script distributed with Netatalk for a long time has been improved and renamed to fce_ev_script. It is now installed installed by the build system into libexec with its own man page. Therefore you can now use it out of the box for sophisticated FCE logging, for instance if your install prefix is /usr/local:
[Global]
fce notify script = /usr/local/libexec/netatalk/fce_ev_script
fce version = 2
fce events = fmod,fdel,ddel,fcre,dcre,fmov,dmov,login,logout
Defaults and fallbacks
SQLite (sqlite) is the new default CNID backend, replacing the Database Daemon (dbd).
When the Extended Attributes check fail, we fall back to the AppleDouble v2 metadata backend rather than none.
ARC cache is now the default, rather than LRU.
The afp read locks has been renamed to strict locking. New option multi protocol enables this and other interoperability settings. See the afp.conf man page for more information.
nad capabilities
The nad utility can now decode and encode MacBinary, BinHex, and StuffIt archives.
It can also now operate on non-AFP paths if you append the -f argument to the command.
Installation
netatalk-4.6.0.tar.xz is the Netatalk source distribution. See INSTALL for required dependencies, then build with:
# Extract the source
tar -xf netatalk-4.6.0.tar.xz
cd netatalk-4.6.0
# Configure and build
meson setup build
meson compile -C build
# Install
sudo meson install -C build
netatalk-4.6.0.wbm.gz is the Webmin module tarball. To install the module:
# Adjust the path to match your Webmin installation
/usr/share/webmin/install-module.pl netatalk-4.6.0.wbm.gz
What’s Changed
- afpd: Update IPC state back to “active” after reconnect. by @NJRoadfan in #3053
- libatalk: Fallback to ADv2 EAs with autodetect fails by @NJRoadfan in #3060
- libatalk: Fix various AppleDouble v2 EA backend issues. by @NJRoadfan in #3056
- meson: add error flag for implicit function declaration by @rdmark in #3059
- meson: Simplify CUPS detection by @NJRoadfan in #3071
- nad: introduce support for MacBinary and BinHex conversion by @rdmark in #3052
- libatalk: overhaul copyright headers by @rdmark in #3069
- afpd: remove obsolete dbd backend guard for CatSearch by @rdmark in #3072
- meson: prefer sqlite and mysql over dbd as default CNID backend by @rdmark in #3077
- docs: improve manual overview, AFP clients, MacIP gateway by @rdmark in #3078
- papd: Update CUPS interface to support libcups 3.x by @NJRoadfan in #3073
- docs: fold the Interoperability manual chapter into Configuration by @rdmark in #3080
- spectest: lock/delete/exchange tests for the server-side lock-fix plan by @andylemin in #3075
- DragonflyBSD: fix AppleDouble CNID, symlink, and create-error bugs by @andylemin in #3081
- afpd: fix error handling in afp_exchangefiles and auth_load by @andylemin in #3087
- initscripts: fix OpenRC service script for netatalk by @DerVerruckteFuchs in #3090
- testsuite: generate test431 AppleDouble data programmatically by @rdmark in #3092
- lantest: test improvements and optimisations, emit CSV aggregates, perf plotter labels by @andylemin in #3094
- afpd: make of_unhash() idempotent by @andylemin in #3105
- adouble: give ad2openflags a fallback access mode; open exchange metadata RDWR by @andylemin in #3104
- macipgw: Send back a complete config packet by @NJRoadfan in #3095
- afpd: size the fork table to backable fds; probe RLIMIT_NOFILE; never exit cnid_metad for RLIMIT by @andylemin in #3103
- refactor potentially unsafe C library calls flagged by OpenBSD linker by @rdmark in #2981
- adouble: log silently-dropped set_lock() returns in ad_lock cleanup and adf_relockrange by @andylemin in #3111
- afpd: report ad_close() failure in of_closefork() instead of swallowing it by @andylemin in #3112
- adouble: don’t kill afpd on fchdir-restore failure in ad_metadataat/ad_openat by @andylemin in #3110
- afpd: close() leaked fork on afp_openfork() error; guard refcount underflow; add fault-injection unit tests by @andylemin in #3108
- adouble: strip destructive flags on read-only downgrade retry, log fcntl(F_UNSHARE) failures in of_closefork() by @andylemin in #3109
- meson: define unused attribute wrapper in config header by @rdmark in #3117
- fix: use bounded strlcpy/snprintf in ftw.c by @orbisai0security in #3135
- meson: detect freebsd style init scripts for dragonflybsd by @rdmark in #3139
- nad: introduce StuffIt (.sit) endocing and decoding support by @rdmark in #3123
- libatalk: add Umich copyright notice to two adouble source files by @rdmark in #3141
- flesh out contributing policy with AI assistance and testing by @rdmark in #3142
- docs: the fallback for xattr is now AD sidecars rather than none by @rdmark in #3144
- deletefile(): POSIX-lock-safe, GET-only open-conflict check, and fix no-access/no-lock open blocking delete by @andylemin in #3145
- afpd: harden build_fce_packet() remaining accounting by @rdmark in #3153
- afpd: convert FCE modify paths before notify scripts by @rdmark in #3154
- contrib: harden and install FCE notify script helper by @rdmark in #3155
- dbd: clear AFPVOL_NOV2TOEACONV flag to allow AD to xattr conversion by @rdmark in #3152
- nad: Update Stuff-It routines to support timestamps by @NJRoadfan in #3167
- contrib: add copyright and license to fce_ev_script.sh by @rdmark in #3156
- testsuite: CatSearch test code quality and layout cleanup by @rdmark in #3170
- nad: avoid empty StuffIt resource sidecars by @rdmark in #3168
- test: expand afp_logintest with UAM test suite by @rdmark in #3165
- meson: print all features in configure summary, refactor sendfile logic by @rdmark in #3171
- afpd: fix ad_lock.c release-path over-release, strands, and share-mode defects by @andylemin in #3169
- afpd: harden copyfile held-handle use; fix ad_write rlen-on-error; rfork-cache guard/log by @andylemin in #3175
- lantest: split stat/open/read/close test; add client and server copy tests by @andylemin in #3177
- afpd: O(1) free-slot FIFO fork allocator, refnum == slot by @andylemin in #3180
- introduce bstring compatibility header by @rdmark in #3179
- afpd: remove unused assignment, use const in catsearch by @rdmark in #3182
- macipgw: use compile-time lengths for fixed strings by @rdmark in #3183
- afpd: use fixed-width AFP text encoding hints by @rdmark in #3184
- testsuite: keep write frames within DSI quantum in speedtest by @rdmark in #3186
- docs: make the manpage generation script portable by @rdmark in #3189
- testsuite: clarify speedtest write quantum limit by @rdmark in #3187
- afpd: sweep die_pending at afp_disconnect() exit: label to avoid race by @andylemin in #3194
- netatalk: compile a dedicated dconf database, not update the system one by @rdmark in #3193
- testsuite: Add a new shaped-network performance harness by @andylemin in #3203
- DSI Quantum optimisations, alignments and performance regression fixes by @andylemin in #3196
- enhance vulnerability reporting guidelines by @rdmark in #3208
- afpd: normalise the FPDelete blocking model to POSIX/macOS/Samba semantics by @andylemin in #3210
- idle-worker: three-flag lock-free idle worker handshake; covered-job cancellation for deferred dircache cleanup by @andylemin in #3212
- adouble: avoid entry bounds overflow by @rdmark in #3219
- Samba interop: ea = samba defaults the coherency settings; strict boolean config parsing; afp read locks renamed strict locking; fail-closed volume config loader by @andylemin in #3223
- afpd: relative-stat dircache validation via a parent-dirfd cache by @andylemin in #3222
- lantest: align test workloads and add perf dashboard history baselines by @andylemin in #3230
- afpd: eliminate redundant metadata work in the FPCopyFile path by @andylemin in #3231
- afpd: use designated initializer for Cur_Path by @rdmark in #3233
- flesh out authors of contributed code and normalize names by @rdmark in #3235
- docs: append compilation instructions to INSTALL.md by @rdmark in #3244
- doc: substitute manpage markdown titles for website by @rdmark in #3245
- afpd: eliminate per-entry rfork probes and per-op getcwd on hot paths by @andylemin in #3241
- consistently render the AFP sleep command as FPZzzzz by @rdmark in #3248
- testsuite: add DHX and DHX2 auth support to AFP test runners by @rdmark in #3247
- testsuite: introduce Junit XML test reporting for spectest by @rdmark in #3250
- doc: document that Time Machine paths must be static by @rdmark in #3260
- doc: overhaul the ACL chapter in the manual with support matrix by @rdmark in #3258
- afpd: ignore permission options without UNIX privileges by @rdmark in #3257
- webmin: restore use of ui_checked_columns_row elements by @rdmark in #3261
- create a README for the tests by @rdmark in #3262
- afpd: a stock config gets the documented 64K dircache by @andylemin in #3264
- afpd: default dircache mode to ARC by @andylemin in #3265
- afpd: enable the resource-fork data cache by default by @andylemin in #3266
- netatalk: start cnid_metad only when a volume uses the dbd scheme by @andylemin in #3269
- uams: harden SRP, DHX2, and DHX multi step error handling by @rdmark in #2932
- cnid: sqlite-default residual cleanup; dsi: raise the listen backlog to 128 by @andylemin in #3267
- Spotlight cnid search: honor every “word” of a multi-word Finder search query, quoted phrases, folder scope, and the results limit by @andylemin in #3271
- asp: wait only in poll() so deferred signals are always reachable by @andylemin in #3275
- cnid: classify contended vs corrupt vs broken sqlite backends end to end; stop contention and disk-full ending AFP sessions by @andylemin in #3278
- add flag category descriptions to volume.h by @rdmark in #3287
- afpd: multi protocol option declares multi-accessor volumes; dircache validation freq defaults to 100 by @andylemin in #3286
- update bstring to version 1.1.1 by @rdmark in #3289
- cnid: reach exhaustion recovery, announce it, and classify mysql errors by @andylemin in #3281
- dircache: remove entries by stored node; fix duplicate-key creation, curdir loss, missing volume purge, and dead asserts by @andylemin in #3285
- ci: hardening of workflow and job level permissions by @rdmark in #3290
- spotlight: avoid lossy string length conversion by @rdmark in #3292
- testsuite: document FPEnumerate reply buffer and remove stale FIXMEs by @rdmark in #3293
- update astyle rules for side comments and continuation indent by @rdmark in #3162
- spotlight: reject empty CNID arrays by @rdmark in #3294
- spotlight: validate CNID array elements by @rdmark in #3295
- testsuite: clean up AFP client parameter definitions by @rdmark in #3297
- cnid: clean up only stale rows the sqlite backend itself wrote by @andylemin in #3298
- test: minor cleanup of afpd unit test by @rdmark in #3304
- dbd: validate directory descriptors before *at calls by @rdmark in #3305
- Follow-ups to recent hardening commits: cnid, dbd, adouble, unicode by @andylemin in #3306
- afppasswd: harden credential-store management by @rdmark in #3307
New Contributors
- @DerVerruckteFuchs made their first contribution in #3090
Full Changelog: https://github.com/Netatalk/netatalk/compare/netatalk-4-5-0…netatalk-4-6-0
Downloads
- netatalk-4.6.0.tar.xz (1.5 MB)
- netatalk-4.6.0.tar.xz.asc (0.0 MB)
- netatalk-4.6.0.tar.xz.sha256sum (0.0 MB)
- netatalk-4.6.0.tar.xz.sha512sum (0.0 MB)
- netatalk-4.6.0.wbm.gz (0.1 MB)
- netatalk-4.6.0.wbm.gz.asc (0.0 MB)
- netatalk-4.6.0.wbm.gz.sha256sum (0.0 MB)
- netatalk-4.6.0.wbm.gz.sha512sum (0.0 MB)
Footnotes
Release published on 2026-09-15
Generated from GitHub Release Notes