summaryrefslogtreecommitdiff
blob: e11960a97ee46ef4cb844e13be6ad0668d9dbfb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
commit cbbd8e2e8bf72aa46c84c7de43e19da40f040fa7
Author: Wayne Davison <wayned@samba.org>
Date:   Fri Mar 7 15:23:39 2008 -0800

    The --fake-super option conflicts with -XX (which copies internal
    rsync xattrs literally).

diff --git a/clientserver.c b/clientserver.c
index 7c15e3b..6bcbc81 100644
--- a/clientserver.c
+++ b/clientserver.c
@@ -32,6 +32,7 @@ extern int am_daemon;
 extern int am_root;
 extern int rsync_port;
 extern int ignore_errors;
+extern int preserve_xattrs;
 extern int kluge_around_eof;
 extern int daemon_over_rsh;
 extern int sanitize_paths;
@@ -745,9 +746,11 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
 	if (write_batch < 0)
 		dry_run = 1;
 
-	if (lp_fake_super(i))
+	if (lp_fake_super(i)) {
+		if (preserve_xattrs > 1)
+			preserve_xattrs = 1;
 		am_root = -1;
-	else if (am_root < 0) /* Treat --fake-super from client as --super. */
+	} else if (am_root < 0) /* Treat --fake-super from client as --super. */
 		am_root = 2;
 
 	if (filesfrom_fd == 0)
diff --git a/options.c b/options.c
index 7972121..4ac8846 100644
--- a/options.c
+++ b/options.c
@@ -1314,7 +1314,13 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
 	}
 #endif
 
-#ifndef SUPPORT_XATTRS
+#ifdef SUPPORT_XATTRS
+	if (am_root < 0 && preserve_xattrs > 1) {
+		snprintf(err_buf, sizeof err_buf,
+			 "--fake-super conflicts with -XX\n");
+		return 0;
+	}
+#else
 	if (am_root < 0) {
 		snprintf(err_buf, sizeof err_buf,
 			 "--fake-super requires an rsync with extended attributes enabled\n");
commit d724dd186ed6a2d66fa13a9357ce91e459d39e8c
Author: Wayne Davison <wayned@samba.org>
Date:   Fri Mar 7 16:16:29 2008 -0800

    Fixed the interaction of --fake-super with --link-dest & --xattrs.
    Fixed the munging of non-user namespace xattrs w/--fake-super.
    Fixed the sorting of received xattrs when name-munging occurs.
    Added xattr tests to verify that these things stay fixed.

diff --git a/testsuite/xattrs.test b/testsuite/xattrs.test
index 97c5f8d..66c3e75 100644
--- a/testsuite/xattrs.test
+++ b/testsuite/xattrs.test
@@ -20,6 +20,7 @@ case "`xattr 2>&1`" in
     xls() {
 	xattr -l "${@}"
     }
+    RUSR='rsync'
     ;;
 *)
     xset() {
@@ -31,6 +32,7 @@ case "`xattr 2>&1`" in
     xls() {
 	getfattr -d "${@}"
     }
+    RUSR='user.rsync'
     ;;
 esac
 
@@ -65,13 +67,15 @@ xset user.long 'a long attribute for our new file that tests to ensure that this
 xset user.foo 'new foo' foo/file3 foo/bar/file5
 xset user.bar 'new bar' foo/file3 foo/bar/file5
 xset user.long 'this is also a long attribute that will be truncated in the initial data send' foo/file3 foo/bar/file5
-xset user.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5
+xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5
+xset $RUSR.equal 'this short' foo/file3 foo/bar/file5
 
 xset user.short 'old short' "$chkdir/file1"
 xset user.extra 'remove me' "$chkdir/file1"
 
 xset user.foo 'old foo' "$chkdir/foo/file3"
-xset user.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3"
+xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3"
+xset $RUSR.equal 'this short' "$chkdir/foo/file3"
 
 xls $files >"$scratchdir/xattrs.txt"
 
@@ -95,10 +99,17 @@ xls $files >"$scratchdir/xattrs.txt"
 
 rm -rf "$todir"
 
-checkit "$RSYNC -aiX --link-dest=../chk . ../to" "$chkdir" "$todir"
+checkit "$RSYNC -aiX --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir"
 
 cd "$todir"
 xls $files | diff $diffopt "$scratchdir/xattrs.txt" -
 
+sed -n -e '/\.\/file1$/d' -e '/^[^ ]* *[^ ]* *[^ ]* *1 /p' "$scratchdir/ls-to" >"$scratchdir/ls-diff"
+if [ -s "$scratchdir/ls-diff" ]; then
+    echo "Missing hard links on:"
+    cat "$scratchdir/ls-diff"
+    exit 1
+fi
+
 # The script would have aborted on error, so getting here means we've won.
 exit 0
diff --git a/xattrs.c b/xattrs.c
index a436572..53363bd 100644
--- a/xattrs.c
+++ b/xattrs.c
@@ -62,9 +62,12 @@ extern int checksum_seed;
 #endif
 #define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
 
-#define XSTAT_ATTR RSYNC_PREFIX "%stat"
-#define XACC_ACL_ATTR RSYNC_PREFIX "%aacl"
-#define XDEF_ACL_ATTR RSYNC_PREFIX "%dacl"
+#define XSTAT_SUFFIX "stat"
+#define XSTAT_ATTR RSYNC_PREFIX "%" XSTAT_SUFFIX
+#define XACC_ACL_SUFFIX "aacl"
+#define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX
+#define XDEF_ACL_SUFFIX "dacl"
+#define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX
 
 typedef struct {
 	char *datum, *name;
@@ -231,7 +234,10 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
 		if (name_len > RPRE_LEN && name[RPRE_LEN] == '%'
 		 && HAS_PREFIX(name, RSYNC_PREFIX)) {
 			if ((am_sender && preserve_xattrs < 2)
-			 || (am_root < 0 && strcmp(name, XSTAT_ATTR) == 0))
+			 || (am_root < 0
+			  && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
+			   || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
+			   || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0)))
 				continue;
 		}
 
@@ -253,14 +259,6 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
 		} else
 			name_offset = datum_len;
 
-#ifdef HAVE_LINUX_XATTRS
-		if (am_root < 0 && name_len > RPRE_LEN && name[RPRE_LEN] != '%'
-		 && HAS_PREFIX(name, RSYNC_PREFIX)) {
-			name += RPRE_LEN;
-			name_len -= RPRE_LEN;
-		}
-#endif
-
 		rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
 		rxa->name = ptr + name_offset;
 		memcpy(rxa->name, name, name_len);
@@ -352,25 +350,33 @@ int send_xattr(stat_x *sxp, int f)
 		int count = sxp->xattr->count;
 		write_varint(f, count);
 		for (rxa = sxp->xattr->items; count--; rxa++) {
+			int name_len = rxa->name_len;
+			const char *name = rxa->name;
+			/* Strip the rsync prefix from disguised namespaces. */
+			if (
 #ifdef HAVE_LINUX_XATTRS
-			write_varint(f, rxa->name_len);
+			    am_root < 0
+#endif
+			 && name_len > RPRE_LEN && name[RPRE_LEN] != '%'
+			 && HAS_PREFIX(name, RSYNC_PREFIX)) {
+				name += RPRE_LEN;
+				name_len -= RPRE_LEN;
+			}
+#ifndef HAVE_LINUX_XATTRS
+			else {
+				/* Put everything else in the user namespace. */
+				name_len += UPRE_LEN;
+			}
+#endif
+			write_varint(f, name_len);
 			write_varint(f, rxa->datum_len);
-			write_buf(f, rxa->name, rxa->name_len);
-#else
-			/* We strip the rsync prefix from disguised namespaces
-			 * and put everything else in the user namespace. */
-			if (HAS_PREFIX(rxa->name, RSYNC_PREFIX)
-			 && rxa->name[RPRE_LEN] != '%') {
-				write_varint(f, rxa->name_len - RPRE_LEN);
-				write_varint(f, rxa->datum_len);
-				write_buf(f, rxa->name + RPRE_LEN, rxa->name_len - RPRE_LEN);
-			} else {
-				write_varint(f, rxa->name_len + UPRE_LEN);
-				write_varint(f, rxa->datum_len);
+#ifndef HAVE_LINUX_XATTRS
+			if (name_len > rxa->name_len) {
 				write_buf(f, USER_PREFIX, UPRE_LEN);
-				write_buf(f, rxa->name, rxa->name_len);
+				name_len -= UPRE_LEN;
 			}
 #endif
+			write_buf(f, name, name_len);
 			if (rxa->datum_len > MAX_FULL_DATUM)
 				write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
 			else
@@ -574,6 +580,11 @@ void receive_xattr(struct file_struct *file, int f)
 {
 	static item_list temp_xattr = EMPTY_ITEM_LIST;
 	int count, num;
+#ifdef HAVE_LINUX_XATTRS
+	int need_sort = 0;
+#else
+	int need_sort = 1;
+#endif
 	int ndx = read_varint(f);
 
 	if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
@@ -624,6 +635,7 @@ void receive_xattr(struct file_struct *file, int f)
 			name -= RPRE_LEN;
 			name_len += RPRE_LEN;
 			memcpy(name, RSYNC_PREFIX, RPRE_LEN);
+			need_sort = 1;
 		}
 #else
 		/* This OS only has a user namespace, so we either
@@ -655,6 +667,9 @@ void receive_xattr(struct file_struct *file, int f)
 		rxa->num = num;
 	}
 
+	if (need_sort && count > 1)
+		qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names);
+
 	ndx = rsync_xal_l.count; /* pre-incremented count */
 	rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */