]> git.ipfire.org Git - thirdparty/rsync.git/commitdiff
testsuite: read xattrs natively instead of shelling out to getfattr
authorAndrew Tridgell <andrew@tridgell.net>
Fri, 22 May 2026 04:52:46 +0000 (14:52 +1000)
committerAndrew Tridgell <andrew@tridgell.net>
Fri, 22 May 2026 05:15:22 +0000 (15:15 +1000)
xattr_set() sets attributes with the native os.setxattr(), but
xattr_dump() read them back by running "getfattr -d". That asymmetry
breaks "make check" on any system where rsync is built with xattr
support (libattr headers present) but the attr package's CLI tools are
not installed -- common on Android/Termux and minimal CI images: setting
succeeds via os.setxattr, then xattr_dump's getfattr raises
FileNotFoundError, which crashes the test (reported FAIL) instead of
running or skipping it. That's why "make check" was failing here on
xattrs / xattrs-hlink.

Read the xattrs natively with os.listxattr()/os.getxattr() on Linux,
symmetric with xattr_set(), so the suite needs no external getfattr; the
output still mimics "getfattr -d" and only has to be self-consistent
between the source and destination dumps. Cygwin keeps the CLI path
(Python there lacks os.*xattr). make check now passes with no attr
package installed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testsuite/rsyncfns.py

index 371c2c251b0cdd3fd4d26149ddeaf4aa42494b98..f151fd5e19e709b02a2ac217f820deec4494394a 100644 (file)
@@ -620,7 +620,29 @@ def xattr_dump(*paths) -> str:
     for comparing a source tree against its rsync'd copy. The format only
     needs to be self-consistent on a given OS (we never compare across OSes),
     mirroring the per-OS xls() in the old xattrs.test."""
-    if _SYSTEM == 'Linux' or _CYGWIN:
+    if _SYSTEM == 'Linux':
+        # Read xattrs natively (symmetric with the os.setxattr used in
+        # xattr_set) so the suite needs no external getfattr. The attr
+        # package's CLI tools are frequently absent -- on Android/Termux
+        # and minimal CI images -- even when the filesystem itself supports
+        # user xattrs, in which case shelling out to getfattr would crash
+        # the test instead of exercising it. The output mimics "getfattr
+        # -d": a "# file:" header then sorted name="value" lines, files
+        # with no user xattrs omitted.
+        out = []
+        for p in paths:
+            sp = str(p)
+            names = sorted(n for n in os.listxattr(sp) if n.startswith('user.'))
+            if not names:
+                continue
+            out.append(f'# file: {sp}\n')
+            for n in names:
+                v = os.getxattr(sp, n).decode('utf-8', 'surrogateescape')
+                out.append(f'{n}="{v}"\n')
+            out.append('\n')
+        return ''.join(out)
+    if _CYGWIN:
+        # Python on Cygwin lacks os.*xattr, so use the CLI there.
         return subprocess.check_output(
             ['getfattr', '-d', *(str(p) for p in paths)], text=True)
     if _SYSTEM == 'Darwin':