Dev Docs Libatalk API
libatalk API Reference
Audited against Netatalk
d63155e13on 2026-10-10. This describes the current source checkout; older releases may differ.
Build and ownership
libatalk/meson.build aggregates internal static libraries into libatalk, currently with library version 23.0.0 and soversion 23. Linux builds expose the corresponding libatalk.so.23; other platforms use their own naming conventions. Consumers include daemons, UAM-related code, and utilities.
Public declarations live in include/atalk. AFP-only handlers and cache APIs in etc/afpd are not exported libatalk subsystems merely because they use shared structures.
| Module | Source | API header |
|---|---|---|
| AppleDouble | libatalk/adouble | include/atalk/adouble.h |
| CNID | libatalk/cnid | include/atalk/cnid.h |
| DSI | libatalk/dsi | include/atalk/dsi.h |
| Unicode / charset conversion | libatalk/unicode | include/atalk/unicode.h |
| VFS and EAs | libatalk/vfs | include/atalk/vfs.h, include/atalk/ea.h |
| ACL / UUID / LDAP | libatalk/acl | include/atalk/acl.h, include/atalk/uuid.h |
| Configuration and utilities | libatalk/util | include/atalk/netatalk_conf.h, include/atalk/util.h |
| Compatibility | libatalk/compat | include/atalk/compat.h |
| ASP / ATP / NBP / DDP | libatalk/asp, libatalk/atp, libatalk/nbp, libatalk/netddp | asp.h, atp.h, nbp.h, netddp.h (AppleTalk builds) |
| Spotlight allocation | libatalk/dalloc | include/atalk/dalloc.h (Spotlight builds) |
AppleDouble
struct adouble owns parsed metadata, fork descriptors, locks, and reference counts. Storage modes are AD_VERSION2 (legacy .AppleDouble files) and AD_VERSION_EA (metadata EAs with platform-dependent resource-fork storage). Apple ._ sidecars are not the same layout as Netatalk’s legacy .AppleDouble files.
| API | Implementation | Contract |
|---|---|---|
ad_init() |
libatalk/adouble/ad_open.c | Initialize from volume storage settings |
ad_open() / ad_close() |
libatalk/adouble/ad_open.c | Open/close selected data, metadata, and resource-fork components |
ad_metadata() |
libatalk/adouble/ad_open.c | Read metadata; caller must respect descriptor lifecycle |
ad_entry() |
libatalk/adouble/ad_open.c | Validated pointer into parsed metadata, or NULL |
ad_flush() |
libatalk/adouble/ad_flush.c | Persist modified metadata |
ad_read() / ad_write() |
libatalk/adouble/ad_read.c, libatalk/adouble/ad_write.c | I/O on the selected fork at an offset |
ad_lock() / ad_tmplock() / ad_unlock() |
libatalk/adouble/ad_lock.c | Tracked and temporary byte-range/share-mode locks |
sys_sendfile() / ad_recvfile() |
libatalk/adouble/ad_sendfile.c, libatalk/adouble/ad_recvfile.c | Optional platform transfer paths |
ad_ref()/ad_unref() track shared AppleDouble object ownership. They are distinct from fork-open reference counts and must not substitute for ad_close().
Metadata entry IDs such as ADEID_FINDERI, ADEID_FILEDATESI, and ADEID_AFPFILEI describe entry types. Header bounds and actual parsed data length constrain access; an entry ID alone does not prove its bytes are present.
CNID
cnid_init() registers mandatory SQLite and optional MySQL modules. The dispatch layer is libatalk/cnid/cnid.c. There is no BDB backend or signal-blocking CNID_FLAG_BLOCK dispatch behavior.
Core APIs are cnid_open(), cnid_close(), cnid_add(), cnid_get(), cnid_lookup(), cnid_resolve(), cnid_update(), cnid_delete(), cnid_getstamp(), and cnid_wipe(). CNIDs are network-order values in the AFP-facing interface.
The current search signatures are:
int cnid_find(struct _cnid_db *cdb, const char *name, size_t namelen,
void *buffer, size_t buflen, bool *more_available);
int cnid_find_scoped(struct _cnid_db *cdb, const char *name,
size_t namelen, cnid_t scope_did,
void *buffer, size_t buflen, bool *more_available);
The backend callback includes scope_did. Results require a minimum 100-slot buffer and report whether more matches exist. CNID_ERRNO() exposes unsigned backend error codes; CNID_ERRNO_IS_BACKEND_FAILURE() separates transient/unusable database answers from not-found results. See CNID Database.
DSI
DSI contains the header, buffers, sockets, timer, transport state, and optional recvfile pipe. The on-wire header is 16 bytes; code packs and decodes fields explicitly rather than sending a host-layout struct.
| API | Source |
|---|---|
dsi_init() / dsi_free() |
libatalk/dsi/dsi_init.c |
dsi_getsession() |
libatalk/dsi/dsi_getsess.c |
dsi_opensession() |
libatalk/dsi/dsi_opensess.c |
dsi_stream_read() / dsi_stream_write() / dsi_stream_send() / dsi_stream_receive() |
libatalk/dsi/dsi_stream.c |
dsi_readinit() / dsi_read() / dsi_readdone() |
libatalk/dsi/dsi_read.c |
dsi_writeinit() / dsi_write() / dsi_writeflush() |
libatalk/dsi/dsi_write.c |
dsi_cmdreply() |
libatalk/dsi/dsi_cmdreply.c |
dsi_attention() |
libatalk/dsi/dsi_attn.c |
dsi_tickle() |
libatalk/dsi/dsi_tickle.c |
dsi_close() |
libatalk/dsi/dsi_close.c |
DSI receive readahead is incoming network buffering. The server quantum limits write data, and streaming reads are a separate path. See Network Protocols.
Configuration
include/atalk/netatalk_conf.h declares afp_config_parse(), afp_config_free(), load_afp_conf_vols(), volume lookup/free helpers, charset setup, and extension-map lookup.
load_volumes() is an obsolete name. netatalk_readbuf_clamp() bounds the configured DSI buffer product. Volume option lookup and substitutions are implemented inside libatalk/util/netatalk_conf.c; most typed lookup helpers are internal, not general public APIs. See Configuration.
IPC and children
include/atalk/server_ipc.h defines the control commands, 14-byte header, and 8-byte cache-hint payload. The current sender signature takes an AFPObj, not a raw fd:
int ipc_child_write(AFPObj *obj, uint16_t command, size_t len, void *token);
ipc_server_read() dispatches parent-side messages; ipc_child_state() reports session state; ipc_send_cache_hint() sends invalidation hints. hint_buf_count() and hint_flush_pending() are parent-only batching APIs in libatalk/util/server_ipc.c.
include/atalk/server_child.h declares child-table allocation, add/remove/resolve/free, signal forwarding, authenticated-login reporting, and session transfer. afp_child_t includes the IPC/hint fds, client identity, UID/state/volumes, and opaque reconnect token. The table has 32 PID hash buckets. See libatalk/util/server_child.c.
Session signal wakeups use atalk_sigpipe_init(), atalk_sigpipe_notify(), atalk_sigpipe_readfd(), and atalk_sigpipe_drain() from libatalk/util/sigpipe.c; declarations are in include/atalk/util.h. This self-pipe is separate from the parent’s cache-hint pipe.
Unicode, VFS, and identity mapping
convert_charset(), convert_string(), and convert_string_allocate() are declared in include/atalk/unicode.h. Higher-level conversion is in libatalk/unicode/charcnv.c; iconv handles and charset registration are in libatalk/unicode/iconv.c. Conversion flags affect normalization, case handling, and invalid sequences.
initvol_vfs() selects built-in operations for a volume. include/atalk/vfs.h defines the operations table and a maximum of 3 modules. EA implementations are libatalk/vfs/ea_sys.c and libatalk/vfs/ea_ad.c; platform xattr wrappers are in libatalk/vfs/extattr.c. This is static dispatch, not a dynamic plugin-loader ABI.
UUID/name mapping is in libatalk/acl/uuid.c, local identity support in libatalk/acl/unix.c, and optional LDAP identity lookup in libatalk/acl/ldap.c. LDAP UUID lookup is not a password-authentication UAM.
SRP parameters and verifier-format helpers are shared through include/atalk/srp.h. Constant-time comparison is declared in include/atalk/constant_time.h and implemented in libatalk/util/constant_time.c.
Logging, fault handling, and errors
LOG() and log levels/types are defined in include/atalk/logger.h. libatalk/util/logger.c handles configuration, log entries, and reopen behavior. Debug calls depend on build settings as well as configured levels.
libatalk/util/fault.c installs fault-reporting support, including thread-specific setup. include/atalk/errchk.h provides cleanup macros (EC_INIT, EC_NULL, EC_NEG1, EC_ZERO, EC_CLEANUP, and EC_EXIT). Return values and errno contracts still belong to the individual API; the macros do not make every failure equivalent.
FCE declarations are in include/atalk/fce_api.h, but the event-emission implementation is AFP-specific in etc/afpd/fce_api.c and etc/afpd/fce_util.c. External FCE notifications are separate from internal cache hints.
AFP cache APIs
The following APIs are in the AFP daemon, not libatalk:
| API group | Header | Role |
|---|---|---|
dircache_init(), lookup/add/remove/purge, deferred cleanup |
etc/afpd/dircache.h | Directory/file identity and stat cache |
ad_metadata_cached(), ad_store_to_cache(), ad_rebuild_from_cache() |
etc/afpd/ad_cache.h | Cached read-only metadata |
rfork_cache_store_from_fd(), rfork_cache_free(), rfork_cache_evict_to_budget() |
etc/afpd/ad_cache.h | Resource-fork content cache |
pfd_ostat(), pfd_purge(), pfd_purge_vol(), pfd_shutdown() |
etc/afpd/pfd_cache.h | Parent-directory descriptor cache |
iw_init(), iw_grant(), iw_revoke(), iw_note_work(), iw_shutdown() |
etc/afpd/idle_worker.h | Deferred cleanup with exclusive temporal access |
iw_revoke() must precede cache access after poll(), including EINTR paths. iw_revoke_signal_safe() only revokes without waiting and is for exit paths. See Caching Architecture and AFP Daemon.
Footnotes
Generated from the Netatalk GitHub Wiki
Last updated 2026-10-21