Solaris has facl(2), which performs ACL operations on an already-open file
descriptor. This adds Solaris fd-based helpers for the ACL operations that
rsync needs while keeping the existing path-based fallback for callers without
a held fd.
On Solaris, setting an ACL on a directory replaces the combined access and
default ACL set. The path-based sys_acl_set_file() already handled this by
reading the other half of the directory ACL, merging access and default entries,
and then calling acl(..., SETACL, ...). The new sys_acl_set_fd_type() preserves
that behavior with fd-based operations: it uses fstat() to identify directories,
reads the other ACL half with sys_acl_get_fd_type(), combines the access and
default entries, marks default entries with ACL_DEFAULT, and finally writes the
combined ACL with facl(2). Deleting a default ACL similarly fetches the access
ACL through the fd and rewrites only that access ACL with facl(2), which removes
the default ACL without re-resolving the path.
Driving the apply off the held fd also closes a symlink-race on the Solaris ACL
apply (the path-based sys_acl_*file re-resolves the path -- the CVE-2026-53799
class, unfixed on Solaris until now). Added on integration: for a root receiver
a missing held fd on a confined receiver means the leaf was raced to a symlink
(acl_set_file follows it), so refuse the path-based set/delete rather than apply
the ACL to a redirected inode; a plain non-root receiver keeps the path-based
fallback for a legitimately un-pinnable owned leaf (e.g. a 0300 dir), matching
the operator-path op_pin rule.
When configure detects a patched libacl exporting acl_get_file_at /
acl_set_file_at / acl_delete_def_file_at (new HAVE_LIBACL_AT; ACL_1.3), route the
receiver's race-safe ACL get/set/delete through them instead of lib/acl.c's
xacl_* -- held fd via AT_EMPTY_PATH, dirfd+leaf via AT_SYMLINK_NOFOLLOW, reusing
the existing unpack_smb_acl/pack_smb_acl conversion. libacl's /proc/self/fd
compat makes this race-safe on every Linux kernel.
lib/acl.c stays as the fallback for a stock libacl (macro undefined -> zero change
there); it already closes the same pre-6.13 parent-symlink-race gap via its own
/proc/self/fd compat, so the two paths are equivalent in safety and prefer libacl
only when its newer bindings are present. -VV reports ACL-libacl-at and keeps
"ACL_at": true.
A stock -lacl lacks these symbols, so HAVE_LIBACL_AT is undefined on real distros
and the build is byte-identical to the lib/acl.c path until libacl ships ACL_1.3;
build against the patched lib via CPPFLAGS/LDFLAGS pointing at its install prefix.
non-name element.
- Set a define when the OS needs the name-list sorted.
- Got rid of the permset-related defines.
- Got rid of some function prototypes that rsync doesn't need.
- Got rid of the defines for the do-nothing ACL code.