Fixed the sending of new files with long xattrs.
[rsync/rsync-patches.git] / acls.diff
CommitLineData
4db3c954
WD
1This patch adds backward-compatibility support for the --acls option.
2Since the main release has never had ACL support, the trunk doesn't
3need this code. If you want to make rsync 3.0.x communicate with an
4older (patched) release, use this.
5
03019e41 6To use this patch, run these commands for a successful build:
fa26e11c 7
03019e41 8 patch -p1 <patches/acls.diff
4db3c954 9 ./configure (optional if already run)
fa26e11c
WD
10 make
11
9a7eef96
WD
12--- old/acls.c
13+++ new/acls.c
4db3c954
WD
14@@ -90,6 +90,18 @@ static const char *str_acl_type(SMB_ACL_
15 : "unknown SMB_ACL_TYPE_T";
16 }
17
8db8e7d2
WD
18+#define OTHER_TYPE(t) (SMB_ACL_TYPE_ACCESS+SMB_ACL_TYPE_DEFAULT-(t))
19+#define BUMP_TYPE(t) ((t = OTHER_TYPE(t)) == SMB_ACL_TYPE_DEFAULT)
fa26e11c 20+
4db3c954 21+static int old_count_racl_entries(const rsync_acl *racl)
56294981
WD
22+{
23+ return racl->users.count + racl->groups.count
0870c22a
WD
24+ + (racl->user_obj != NO_ENTRY)
25+ + (racl->group_obj != NO_ENTRY)
4db3c954
WD
26+ + (racl->mask_obj != NO_ENTRY)
27+ + (racl->other_obj != NO_ENTRY);
0870c22a
WD
28+}
29+
4db3c954
WD
30 static int calc_sacl_entries(const rsync_acl *racl)
31 {
32 /* A System ACL always gets user/group/other permission entries. */
33@@ -545,6 +557,91 @@ int get_acl(const char *fname, statx *sx
34 return 0;
35 }
36
37+/* === OLD Send functions === */
0870c22a
WD
38+
39+/* Send the ida list over the file descriptor. */
4db3c954 40+static void old_send_ida_entries(int f, const ida_entries *idal, char tag_char)
0870c22a
WD
41+{
42+ id_access *ida;
43+ size_t count = idal->count;
44+ for (ida = idal->idas; count--; ida++) {
45+ write_byte(f, tag_char);
46+ write_byte(f, ida->access);
47+ write_int(f, ida->id);
0870c22a
WD
48+ if (tag_char == 'U')
49+ add_uid(ida->id);
50+ else
51+ add_gid(ida->id);
fa26e11c 52+ }
0870c22a
WD
53+}
54+
adabede5 55+/* Send an rsync ACL over the file descriptor. */
4db3c954 56+static void old_send_rsync_acl(int f, const rsync_acl *racl)
0870c22a 57+{
4db3c954 58+ size_t count = old_count_racl_entries(racl);
0870c22a
WD
59+ write_int(f, count);
60+ if (racl->user_obj != NO_ENTRY) {
61+ write_byte(f, 'u');
62+ write_byte(f, racl->user_obj);
63+ }
4db3c954 64+ old_send_ida_entries(f, &racl->users, 'U');
0870c22a
WD
65+ if (racl->group_obj != NO_ENTRY) {
66+ write_byte(f, 'g');
67+ write_byte(f, racl->group_obj);
fa26e11c 68+ }
4db3c954
WD
69+ old_send_ida_entries(f, &racl->groups, 'G');
70+ if (racl->mask_obj != NO_ENTRY) {
0870c22a 71+ write_byte(f, 'm');
4db3c954 72+ write_byte(f, racl->mask_obj);
0870c22a 73+ }
4db3c954 74+ if (racl->other_obj != NO_ENTRY) {
0870c22a 75+ write_byte(f, 'o');
4db3c954 76+ write_byte(f, racl->other_obj);
0870c22a
WD
77+ }
78+}
c6437996 79+
98ccc74a 80+/* Send the ACL from the statx structure down the indicated file descriptor.
0870c22a 81+ * This also frees the ACL data. */
4db3c954 82+void old_send_acl(statx *sxp, int f)
0870c22a
WD
83+{
84+ SMB_ACL_TYPE_T type;
85+ rsync_acl *racl, *new_racl;
86+ item_list *racl_list;
5d2612ca 87+ int ndx;
53c1073a 88+
0870c22a
WD
89+ type = SMB_ACL_TYPE_ACCESS;
90+ racl = sxp->acc_acl;
91+ racl_list = &access_acl_list;
92+ do {
5d2612ca
WD
93+ if (!racl) {
94+ racl = new(rsync_acl);
95+ if (!racl)
96+ out_of_memory("send_acl");
97+ *racl = empty_rsync_acl;
98+ if (type == SMB_ACL_TYPE_ACCESS) {
99+ rsync_acl_fake_perms(racl, sxp->st.st_mode);
100+ sxp->acc_acl = racl;
101+ } else
102+ sxp->def_acl = racl;
103+ }
0870c22a 104+
4db3c954 105+ if ((ndx = find_matching_rsync_acl(racl, type, racl_list)) != -1) {
0870c22a
WD
106+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
107+ write_int(f, ndx);
0870c22a 108+ } else {
645e162c 109+ new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000);
0870c22a 110+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
4db3c954 111+ old_send_rsync_acl(f, racl);
0870c22a
WD
112+ *new_racl = *racl;
113+ *racl = empty_rsync_acl;
114+ }
115+ racl = sxp->def_acl;
116+ racl_list = &default_acl_list;
117+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
118+
98ccc74a 119+ free_acl(sxp);
fa26e11c
WD
120+}
121+
4db3c954
WD
122 /* === Send functions === */
123
124 /* The general strategy with the tag_type <-> character mapping is that
ffc18846 125@@ -631,6 +728,11 @@ static void send_rsync_acl(rsync_acl *ra
4db3c954
WD
126 * This also frees the ACL data. */
127 void send_acl(statx *sxp, int f)
128 {
129+ if (protocol_version < 30) {
130+ old_send_acl(sxp, f);
131+ return;
132+ }
ffc18846 133+
4db3c954
WD
134 if (!sxp->acc_acl) {
135 sxp->acc_acl = create_racl();
ffc18846
WD
136 rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode);
137@@ -648,6 +750,146 @@ void send_acl(statx *sxp, int f)
4db3c954
WD
138 }
139 }
140
141+/* === OLD Receive functions */
0870c22a 142+
4db3c954 143+static void old_recv_rsync_acl(rsync_acl *racl, int f)
fa26e11c 144+{
6250eb3e 145+ static item_list temp_ida_list = EMPTY_ITEM_LIST;
0870c22a 146+ SMB_ACL_TAG_T tag_type = 0, prior_list_type = 0;
090d78e1 147+ uchar computed_mask_bits = 0;
c6437996 148+ id_access *ida;
ad625644
WD
149+ size_t count;
150+
151+ if (!(count = read_int(f)))
fa26e11c 152+ return;
ad625644 153+
fa26e11c 154+ while (count--) {
dfadc68a 155+ char tag = read_byte(f);
c6437996
WD
156+ uchar access = read_byte(f);
157+ if (access & ~ (4 | 2 | 1)) {
4db3c954 158+ rprintf(FERROR, "old_recv_rsync_acl: bogus permset %o\n",
c6437996
WD
159+ access);
160+ exit_cleanup(RERR_STREAMIO);
161+ }
fa26e11c
WD
162+ switch (tag) {
163+ case 'u':
0870c22a 164+ if (racl->user_obj != NO_ENTRY) {
4db3c954 165+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate USER_OBJ entry\n");
c6437996
WD
166+ exit_cleanup(RERR_STREAMIO);
167+ }
168+ racl->user_obj = access;
169+ continue;
fa26e11c 170+ case 'U':
0870c22a 171+ tag_type = SMB_ACL_USER;
fa26e11c
WD
172+ break;
173+ case 'g':
0870c22a 174+ if (racl->group_obj != NO_ENTRY) {
4db3c954 175+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate GROUP_OBJ entry\n");
c6437996
WD
176+ exit_cleanup(RERR_STREAMIO);
177+ }
178+ racl->group_obj = access;
179+ continue;
fa26e11c 180+ case 'G':
0870c22a 181+ tag_type = SMB_ACL_GROUP;
fa26e11c
WD
182+ break;
183+ case 'm':
4db3c954
WD
184+ if (racl->mask_obj != NO_ENTRY) {
185+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate MASK entry\n");
c6437996
WD
186+ exit_cleanup(RERR_STREAMIO);
187+ }
4db3c954 188+ racl->mask_obj = access;
c6437996
WD
189+ continue;
190+ case 'o':
4db3c954
WD
191+ if (racl->other_obj != NO_ENTRY) {
192+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate OTHER entry\n");
c6437996
WD
193+ exit_cleanup(RERR_STREAMIO);
194+ }
4db3c954 195+ racl->other_obj = access;
c6437996 196+ continue;
fa26e11c 197+ default:
4db3c954 198+ rprintf(FERROR, "old_recv_rsync_acl: unknown tag %c\n",
fa26e11c
WD
199+ tag);
200+ exit_cleanup(RERR_STREAMIO);
201+ }
0870c22a
WD
202+ if (tag_type != prior_list_type) {
203+ if (prior_list_type)
4db3c954 204+ save_idas(racl, prior_list_type, &temp_ida_list);
0870c22a
WD
205+ prior_list_type = tag_type;
206+ }
645e162c 207+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
c6437996
WD
208+ ida->access = access;
209+ ida->id = read_int(f);
090d78e1 210+ computed_mask_bits |= access;
c6437996 211+ }
0870c22a 212+ if (prior_list_type)
4db3c954 213+ save_idas(racl, prior_list_type, &temp_ida_list);
8eb3e3ae 214+
c6437996 215+ if (!racl->users.count && !racl->groups.count) {
8eb3e3ae 216+ /* If we received a superfluous mask, throw it away. */
4db3c954 217+ if (racl->mask_obj != NO_ENTRY) {
8eb3e3ae 218+ /* Mask off the group perms with it first. */
4db3c954
WD
219+ racl->group_obj &= racl->mask_obj | NO_ENTRY;
220+ racl->mask_obj = NO_ENTRY;
fa26e11c 221+ }
4db3c954
WD
222+ } else if (racl->mask_obj == NO_ENTRY) /* Must be non-empty with lists. */
223+ racl->mask_obj = computed_mask_bits | (racl->group_obj & 7);
fa26e11c
WD
224+}
225+
0870c22a 226+/* Receive the ACL info the sender has included for this file-list entry. */
4db3c954 227+void old_recv_acl(struct file_struct *file, int f)
fa26e11c 228+{
8db8e7d2 229+ SMB_ACL_TYPE_T type;
0870c22a 230+ item_list *racl_list;
36aa3171 231+
162234a7 232+ if (S_ISLNK(file->mode))
fa26e11c 233+ return;
36aa3171 234+
8db8e7d2 235+ type = SMB_ACL_TYPE_ACCESS;
0870c22a 236+ racl_list = &access_acl_list;
8db8e7d2 237+ do {
0870c22a
WD
238+ char tag = read_byte(f);
239+ int ndx;
fa26e11c 240+
fa26e11c 241+ if (tag == 'A' || tag == 'a') {
8db8e7d2 242+ if (type != SMB_ACL_TYPE_ACCESS) {
fa26e11c 243+ rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
f4222aa5 244+ f_name(file, NULL));
fa26e11c
WD
245+ exit_cleanup(RERR_STREAMIO);
246+ }
247+ } else if (tag == 'D' || tag == 'd') {
8db8e7d2 248+ if (type == SMB_ACL_TYPE_ACCESS) {
fa26e11c 249+ rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
f4222aa5 250+ f_name(file, NULL));
fa26e11c
WD
251+ exit_cleanup(RERR_STREAMIO);
252+ }
253+ } else {
254+ rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
f4222aa5 255+ f_name(file, NULL), tag);
fa26e11c
WD
256+ exit_cleanup(RERR_STREAMIO);
257+ }
258+ if (tag == 'A' || tag == 'D') {
0870c22a
WD
259+ acl_duo *duo_item;
260+ ndx = racl_list->count;
645e162c 261+ duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
b6c2bb12 262+ duo_item->racl = empty_rsync_acl;
4db3c954 263+ old_recv_rsync_acl(&duo_item->racl, f);
0870c22a 264+ duo_item->sacl = NULL;
fa26e11c 265+ } else {
0870c22a 266+ ndx = read_int(f);
d4531ffb 267+ if (ndx < 0 || (size_t)ndx >= racl_list->count) {
fa26e11c 268+ rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
0870c22a 269+ f_name(file, NULL), str_acl_type(type), ndx);
fa26e11c
WD
270+ exit_cleanup(RERR_STREAMIO);
271+ }
fa26e11c 272+ }
70891d26
WD
273+ if (type == SMB_ACL_TYPE_ACCESS)
274+ F_ACL(file) = ndx;
275+ else
81ecd8e0 276+ F_DEF_ACL(file) = ndx;
0870c22a 277+ racl_list = &default_acl_list;
8db8e7d2 278+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
fa26e11c
WD
279+}
280+
4db3c954
WD
281 /* === Receive functions === */
282
283 static uchar recv_acl_access(uchar *name_follows_val, int f)
ffc18846 284@@ -767,6 +1009,11 @@ static int recv_rsync_acl(item_list *rac
4db3c954
WD
285 /* Receive the ACL info the sender has included for this file-list entry. */
286 void receive_acl(struct file_struct *file, int f)
287 {
288+ if (protocol_version < 30) {
289+ old_recv_acl(file, f);
5d2612ca 290+ return;
fa26e11c 291+ }
fa26e11c 292+
4db3c954 293 F_ACL(file) = recv_rsync_acl(&access_acl_list, SMB_ACL_TYPE_ACCESS, f);
34a409bc 294
4db3c954
WD
295 if (S_ISDIR(file->mode))
296--- old/compat.c
297+++ new/compat.c
298@@ -111,13 +111,6 @@ void setup_protocol(int f_out,int f_in)
299 protocol_version);
300 exit_cleanup(RERR_PROTOCOL);
0870c22a 301 }
4db3c954
WD
302- if (preserve_acls) {
303- rprintf(FERROR,
304- "--acls requires protocol 30 or higher"
305- " (negotiated %d).\n",
306- protocol_version);
307- exit_cleanup(RERR_PROTOCOL);
308- }
0870c22a 309 }
6250eb3e 310
4db3c954 311 if (delete_mode && !(delete_before+delete_during+delete_after)) {
475c4a36
WD
312--- old/testsuite/acls.test
313+++ new/testsuite/acls.test
4db3c954 314@@ -9,10 +9,6 @@
0870c22a 315
4db3c954 316 $RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
0870c22a 317
4db3c954
WD
318-case "$RSYNC" in
319-*protocol=29*) test_skipped "ACLs require protocol 30" ;;
320-esac
321-
322 case "$setfacl_nodef" in
323 true) test_skipped "I don't know how to use your setfacl command" ;;
324 esac
325--- old/testsuite/default-acls.test
326+++ new/testsuite/default-acls.test
327@@ -9,10 +9,6 @@
125d7fca 328
4db3c954 329 $RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
6250eb3e 330
4db3c954
WD
331-case "$RSYNC" in
332-*protocol=29*) test_skipped "ACLs require protocol 30" ;;
333-esac
334-
335 case "$setfacl_nodef" in
336 true) test_skipped "I don't know how to use your setfacl command" ;;
337 *-k*) opts='-dm u::7,g::5,o:5' ;;