From: Achim Leitner Date: Sun, 17 Oct 2021 20:00:24 +0000 (+0200) Subject: Linux: Handle protected_regular in inplace writes (#241) X-Git-Tag: v3.2.4pre1~33 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=84498104bfe2a4662221992951e71d2a2f5ceffc;p=thirdparty%2Frsync.git Linux: Handle protected_regular in inplace writes (#241) The Linux fs.protected_regular sysctl setting could cause rsync to fail to write a file in-place with the O_CREAT flag set, so the code now tries an open without O_CREAT when it might help to avoid an EACCES error. A testsuite script is included (and slightly improved by Wayne to ensure that it outputs a SKIP when fs.protected_regular is turned off). --- diff --git a/.cirrus.yml b/.cirrus.yml index 72e70379..5112ef88 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -18,6 +18,6 @@ freebsd_task: info_script: - rsync --version test_script: - - RSYNC_EXPECT_SKIPPED=acls-default,acls,crtimes make check + - RSYNC_EXPECT_SKIPPED=acls-default,acls,crtimes,protected-regular make check ssl_file_list_script: - rsync-ssl --no-motd download.samba.org::rsyncftp/ || true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bbfb6566..9e34b4c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -105,7 +105,7 @@ jobs: - name: info run: bash -c '/usr/local/bin/rsync --version' - name: check - run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls,chown,devices,dir-sgid make check' + run: bash -c 'RSYNC_EXPECT_SKIPPED=acls-default,acls,chown,devices,dir-sgid,protected-regular make check' - name: ssl file list run: bash -c 'PATH="/usr/local/bin:$PATH" rsync-ssl --no-motd download.samba.org::rsyncftp/ || true' - name: save artifact diff --git a/receiver.c b/receiver.c index 091fcd6f..2cd84351 100644 --- a/receiver.c +++ b/receiver.c @@ -835,6 +835,12 @@ int recv_files(int f_in, int f_out, char *local_name) if (inplace || one_inplace) { fnametmp = one_inplace ? partialptr : fname; fd2 = do_open(fnametmp, O_WRONLY|O_CREAT, 0600); +#ifdef linux + if (fd2 == -1 && errno == EACCES) { + /* Maybe the error was due to protected_regular setting? */ + fd2 = do_open(fname, O_WRONLY, 0600); + } +#endif if (fd2 == -1) { rsyserr(FERROR_XFER, errno, "open %s failed", full_fname(fnametmp)); diff --git a/testsuite/protected-regular.test b/testsuite/protected-regular.test new file mode 100644 index 00000000..40416b0d --- /dev/null +++ b/testsuite/protected-regular.test @@ -0,0 +1,31 @@ +#!/bin/sh + +# Copyright (C) 2021 by Achim Leitner +# This program is distributable under the terms of the GNU GPL (see COPYING) +# +# Modern linux systems have the protected_regular feature set to 1 or 2 +# See https://www.kernel.org/doc/Documentation/sysctl/fs.txt +# Make sure we can still write these files in --inplace mode + +. "$suitedir/rsync.fns" + +test -f /proc/sys/fs/protected_regular || test_skipped "Can't find protected_regular setting (only available on Linux)" +pr_lvl=`cat /proc/sys/fs/protected_regular 2>/dev/null` || test_skipped "Can't check if fs.protected_regular is enabled (probably need root)" +test "$pr_lvl" != 0 || test_skipped "fs.protected_regular is not enabled" + +workdir="$tmpdir/files" +mkdir "$workdir" +chmod 1777 "$workdir" + +echo "Source" > "$workdir/src" +echo "" > "$workdir/dst" +chown 5001 "$workdir/dst" || test_skipped "Can't chown (probably need root)" + +# Output is only shown in case of an error +echo "Contents of $workdir:" +ls -al "$workdir" + +$RSYNC --inplace "$workdir/src" "$workdir/dst" || test_fail + +# The script would have aborted on error, so getting here means we've won. +exit 0