Linux: Handle protected_regular in inplace writes (#241)
authorAchim Leitner <git@fjl.de>
Sun, 17 Oct 2021 20:00:24 +0000 (22:00 +0200)
committerGitHub <noreply@github.com>
Sun, 17 Oct 2021 20:00:24 +0000 (13:00 -0700)
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).

.cirrus.yml
.github/workflows/build.yml
receiver.c
testsuite/protected-regular.test [new file with mode: 0644]

index 72e70379c79e17947d2580327ed64303527f3c55..5112ef885c9e41d330e2bbb13045362eaf322575 100644 (file)
@@ -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
index bbfb6566f3c35a1c1a53a5954d9fd9e4b3a270a8..9e34b4c971e667bebcd608190c3ed6652464fa91 100644 (file)
@@ -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
index 091fcd6fb185b19a6047b735938428dbdf1c1a3e..2cd8435176c4381371cc39474a039c426619ee6b 100644 (file)
@@ -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 (file)
index 0000000..40416b0
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# Copyright (C) 2021 by Achim Leitner <aleitner@lis-engineering.de>
+# 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