Skip to content

Add fchmodat() as an option to set symlink Unix access permissions - #1108

Open
mtsapv wants to merge 1 commit into
RsyncProject:masterfrom
mtsapv:obsd-symlink-perms
Open

mtsapv wants to merge 1 commit into
RsyncProject:masterfrom
mtsapv:obsd-symlink-perms

Conversation

@mtsapv

@mtsapv mtsapv commented Sep 29, 2026

Copy link
Copy Markdown

Many (perhaps all) BSD Unix systems allow users to set/modify the Unix access permissions on a symlink (as opposed to its target). OpenBSD does permit this but requires the use of fchmodat() to do so. Rsync does not provide the use of fchmodat() in this situation so it does not preserve symlink permissions when copying in OpenBSD.

The patch in the PR modifies syscall.c to provide the use of fchmodat(), on those systems that have it, as a last resort effort to setting a symlink permission prior to (ultimately) giving up on the attempt. This patch is not specific to any operating system; it only relies on the availability of fchmodat();

The PR also includes a testsuite test in that checks so see if symlink Unix access permissions are preserved on those systems that permit their change. The test is skipped on systems, such as (most) Linux variants, that don't allow changes to symlink Unix access permissions. The test, too, is not OS-specific. It tests at runtime to see if symlink access can be changed on the system and behaves accordingly.

I've run the testsuite with this patch applied on OpenBSD (7.9), FreeBSD (15.1), MacOS (Sequoia), ArchLinux (7.2.7-arch1-1), Debian (13), and Ubuntu (26.04.1 LTS). The results were all as expected. I've also run a complete system copy with Rsync on OpenBSD and Debian. On comparison of the results, the original and the copy were the same. The comparison made use of values obtained via the Unix lstat() system routine as well as MD5 checksums of file contents.

My apologies if I've submitted incorrectly. This is my first attempt at a PR.

Thanks for your attention.

syscall.c:

Add fchmodat(), if it exists on the system, as a last-resort attempt to change
the Unix access permissions for a symlink (on those systems that support it).
This is done just prior to finally abandoning such an attempt and after any
other available options for this, such as lchmod() or setattrlist().

This option is required to preserve symlink access permissions when making
copies using rsync on OpenBSD. The patch itself is not OS-specific.

testsuite:

Add a test, symlink-unix-perms_test.py, to testsuite to check on the success
of setting symlink access changes using rsync. The test is skipped on those
systems that do not allow symlink access permission changes. The test checks
at runtime whether or not the system permits symlink access changes. As with
the patch, this test is not OS-specific.
@steadytao

Copy link
Copy Markdown
Member

Make the test deterministic, use a normal Python shebang and catch only the expected unsupported-operation errors. A programming error or unexpected filesystem failure must fail the test rather than silently skip it. Please also add a configure-time compile check for the four-argument fchmodat form with AT_SYMLINK_NOFOLLOW; the constants alone do not prove that exact interface is available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants