Skip to content

Commit 5581370

Browse files
committed
net/rsync: Fix the handling of many xattrs on FreeBSD
Fix sys_llistxattr() for FreeBSD code to request a larger buffer to store the extended attributes list if the current one is too small. I also improve the attribute parsing by reducing to one the memmove calls when converting FreeBSD attribute list to the format used by Linux and extend the rsync unit tests for long xattrs lists. Changes where submitted to upstream as: RsyncProject/rsync#781 RsyncProject/rsync#766 PR: 286773 Reported by: Peter Eriksson <pen@lysator.liu.se> Obtained from: Peter Eriksson <pen@lysator.liu.se> Reviewed by: rodrigo Tested by: rodrigo Event: Berlin Hackaton 202507 Relnotes: yes
1 parent 2dc9c51 commit 5581370

File tree

3 files changed

+110
-1
lines changed

3 files changed

+110
-1
lines changed

‎net/rsync/Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PORTNAME= rsync
22
DISTVERSION= 3.4.1
3-
PORTREVISION= 2
3+
PORTREVISION= 3
44
CATEGORIES= net
55
MASTER_SITES= https://www.mirrorservice.org/sites/rsync.samba.org/src/ \
66
http://rsync.mirror.garr.it/src/ \
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--- a/lib/sysxattrs.c.orig 2022-01-16 01:21:01.000000000 +0000
2+
+++ b/lib/sysxattrs.c 2025-07-28 12:05:43.501532000 +0000
3+
@@ -126,22 +126,29 @@
4+
unsigned char keylen;
5+
ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size);
6+
7+
- if (len <= 0 || (size_t)len > size)
8+
+ if (len <= 0 || size == 0)
9+
return len;
10+
11+
+ if ((size_t)len == size) {
12+
+ /* extattr_list_link fills a buffer with a list of file attributes.
13+
+ * If the buffer size is too small the content is truncated and
14+
+ * extattr_list_link returns the number of written bytes and no
15+
+ * error is raised. If size == len assumes the buffer was too small
16+
+ * and behave like Linux requesting a larger buffer. */
17+
+ errno = ERANGE;
18+
+ return -1;
19+
+ }
20+
+
21+
/* FreeBSD puts a single-byte length before each string, with no '\0'
22+
* terminator. We need to change this into a series of null-terminted
23+
* strings. Since the size is the same, we can simply transform the
24+
* output in place. */
25+
- for (off = 0; off < len; off += keylen + 1) {
26+
- keylen = ((unsigned char*)list)[off];
27+
- if (off + keylen >= len) {
28+
- /* Should be impossible, but kernel bugs happen! */
29+
- errno = EINVAL;
30+
- return -1;
31+
- }
32+
- memmove(list+off, list+off+1, keylen);
33+
- list[off+keylen] = '\0';
34+
+ keylen = (unsigned char)list[0];
35+
+ memmove(list, list+1, len-1);
36+
+ list[len-1] = '\0';
37+
+ for (off = keylen; off < (len - 1); off += (keylen + 1)) {
38+
+ keylen = (unsigned char)list[off];
39+
+ list[off] = '\0';
40+
}
41+
42+
return len;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
--- a/testsuite/xattrs.test.orig 2022-10-20 16:09:26.000000000 +0000
2+
+++ b/testsuite/xattrs.test 2025-06-29 07:49:45.880992000 +0000
3+
@@ -10,7 +10,14 @@
4+
5+
$RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync is configured without xattr support"
6+
7+
+CYGWIN=0
8+
+
9+
case "$HOST_OS" in
10+
+cygwin*)
11+
+ CYGWIN=1
12+
+esac
13+
+
14+
+case "$HOST_OS" in
15+
darwin*)
16+
xset() {
17+
xnam="$1"
18+
@@ -80,6 +87,9 @@
19+
echo deep >"$fromdir/foo/file3"
20+
echo normal >"$fromdir/file4"
21+
echo deeper >"$fromdir/foo/bar/file5"
22+
+if [ $CYGWIN -eq 0 ]; then
23+
+ echo longxattrname >"$fromdir/file7"
24+
+fi
25+
26+
makepath "$chkdir/foo"
27+
echo wow >"$chkdir/file1"
28+
@@ -87,6 +97,10 @@
29+
30+
dirs='foo foo/bar'
31+
files='file0 file1 file2 foo/file3 file4 foo/bar/file5'
32+
+if [ $CYGWIN -eq 0 ]
33+
+then
34+
+ files="$files file7"
35+
+fi
36+
37+
uid_gid=`"$TOOLDIR/tls" "$fromdir/foo" | sed 's/^.* \([0-9][0-9]*\)\.\([0-9][0-9]*\) .*/\1:\2/'`
38+
39+
@@ -125,6 +139,16 @@
40+
xset user.foo 'old foo' "$chkdir/foo/file3"
41+
xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3"
42+
43+
+if [ $CYGWIN -eq 0 ] ; then
44+
+# Generate xattr names
45+
+SEQ=`seq 1 200`
46+
+xset user."`printf -- 'A%0.s' $SEQ`" 'first xattr' file7
47+
+xset user."`printf -- 'B%0.s' $SEQ`" 'second xattr' file7
48+
+xset user."`printf -- 'C%0.s' $SEQ`" 'third xattr' file7
49+
+xset user."`printf -- 'D%0.s' $SEQ`" 'another xattr' file7
50+
+xset user."`printf -- 'E%0.s' $SEQ`" 'final xattr' file7
51+
+fi
52+
+
53+
case $0 in
54+
*hlink*)
55+
ln foo/bar/file5 foo/bar/file6 || test_skipped "Can't create hardlink"
56+
@@ -234,6 +258,11 @@
57+
58+
cd "$todir"
59+
xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" -
60+
+
61+
+cd "$fromdir"
62+
+rm -rf "$todir"
63+
+mkfifo fifo1
64+
+checktee "$RSYNC -avX --specials $XFILT $dashH --super . '$chkdir/'" "$fromdir" "$chkdir"
65+
66+
# The script would have aborted on error, so getting here means we've won.
67+
exit 0

0 commit comments

Comments
 (0)