Fixed a couple compile problems.
[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
125@@ -631,6 +728,10 @@ static void send_rsync_acl(rsync_acl *ra
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+ }
133
134 if (!sxp->acc_acl) {
135 sxp->acc_acl = create_racl();
136@@ -649,6 +750,146 @@ void send_acl(statx *sxp, int f)
137 }
138 }
139
140+/* === OLD Receive functions */
0870c22a 141+
4db3c954 142+static void old_recv_rsync_acl(rsync_acl *racl, int f)
fa26e11c 143+{
6250eb3e 144+ static item_list temp_ida_list = EMPTY_ITEM_LIST;
0870c22a 145+ SMB_ACL_TAG_T tag_type = 0, prior_list_type = 0;
090d78e1 146+ uchar computed_mask_bits = 0;
c6437996 147+ id_access *ida;
ad625644
WD
148+ size_t count;
149+
150+ if (!(count = read_int(f)))
fa26e11c 151+ return;
ad625644 152+
fa26e11c 153+ while (count--) {
dfadc68a 154+ char tag = read_byte(f);
c6437996
WD
155+ uchar access = read_byte(f);
156+ if (access & ~ (4 | 2 | 1)) {
4db3c954 157+ rprintf(FERROR, "old_recv_rsync_acl: bogus permset %o\n",
c6437996
WD
158+ access);
159+ exit_cleanup(RERR_STREAMIO);
160+ }
fa26e11c
WD
161+ switch (tag) {
162+ case 'u':
0870c22a 163+ if (racl->user_obj != NO_ENTRY) {
4db3c954 164+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate USER_OBJ entry\n");
c6437996
WD
165+ exit_cleanup(RERR_STREAMIO);
166+ }
167+ racl->user_obj = access;
168+ continue;
fa26e11c 169+ case 'U':
0870c22a 170+ tag_type = SMB_ACL_USER;
fa26e11c
WD
171+ break;
172+ case 'g':
0870c22a 173+ if (racl->group_obj != NO_ENTRY) {
4db3c954 174+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate GROUP_OBJ entry\n");
c6437996
WD
175+ exit_cleanup(RERR_STREAMIO);
176+ }
177+ racl->group_obj = access;
178+ continue;
fa26e11c 179+ case 'G':
0870c22a 180+ tag_type = SMB_ACL_GROUP;
fa26e11c
WD
181+ break;
182+ case 'm':
4db3c954
WD
183+ if (racl->mask_obj != NO_ENTRY) {
184+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate MASK entry\n");
c6437996
WD
185+ exit_cleanup(RERR_STREAMIO);
186+ }
4db3c954 187+ racl->mask_obj = access;
c6437996
WD
188+ continue;
189+ case 'o':
4db3c954
WD
190+ if (racl->other_obj != NO_ENTRY) {
191+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate OTHER entry\n");
c6437996
WD
192+ exit_cleanup(RERR_STREAMIO);
193+ }
4db3c954 194+ racl->other_obj = access;
c6437996 195+ continue;
fa26e11c 196+ default:
4db3c954 197+ rprintf(FERROR, "old_recv_rsync_acl: unknown tag %c\n",
fa26e11c
WD
198+ tag);
199+ exit_cleanup(RERR_STREAMIO);
200+ }
0870c22a
WD
201+ if (tag_type != prior_list_type) {
202+ if (prior_list_type)
4db3c954 203+ save_idas(racl, prior_list_type, &temp_ida_list);
0870c22a
WD
204+ prior_list_type = tag_type;
205+ }
645e162c 206+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
c6437996
WD
207+ ida->access = access;
208+ ida->id = read_int(f);
090d78e1 209+ computed_mask_bits |= access;
c6437996 210+ }
0870c22a 211+ if (prior_list_type)
4db3c954 212+ save_idas(racl, prior_list_type, &temp_ida_list);
8eb3e3ae 213+
c6437996 214+ if (!racl->users.count && !racl->groups.count) {
8eb3e3ae 215+ /* If we received a superfluous mask, throw it away. */
4db3c954 216+ if (racl->mask_obj != NO_ENTRY) {
8eb3e3ae 217+ /* Mask off the group perms with it first. */
4db3c954
WD
218+ racl->group_obj &= racl->mask_obj | NO_ENTRY;
219+ racl->mask_obj = NO_ENTRY;
fa26e11c 220+ }
4db3c954
WD
221+ } else if (racl->mask_obj == NO_ENTRY) /* Must be non-empty with lists. */
222+ racl->mask_obj = computed_mask_bits | (racl->group_obj & 7);
fa26e11c
WD
223+}
224+
0870c22a 225+/* Receive the ACL info the sender has included for this file-list entry. */
4db3c954 226+void old_recv_acl(struct file_struct *file, int f)
fa26e11c 227+{
8db8e7d2 228+ SMB_ACL_TYPE_T type;
0870c22a 229+ item_list *racl_list;
36aa3171 230+
162234a7 231+ if (S_ISLNK(file->mode))
fa26e11c 232+ return;
36aa3171 233+
8db8e7d2 234+ type = SMB_ACL_TYPE_ACCESS;
0870c22a 235+ racl_list = &access_acl_list;
8db8e7d2 236+ do {
0870c22a
WD
237+ char tag = read_byte(f);
238+ int ndx;
fa26e11c 239+
fa26e11c 240+ if (tag == 'A' || tag == 'a') {
8db8e7d2 241+ if (type != SMB_ACL_TYPE_ACCESS) {
fa26e11c 242+ rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
f4222aa5 243+ f_name(file, NULL));
fa26e11c
WD
244+ exit_cleanup(RERR_STREAMIO);
245+ }
246+ } else if (tag == 'D' || tag == 'd') {
8db8e7d2 247+ if (type == SMB_ACL_TYPE_ACCESS) {
fa26e11c 248+ rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
f4222aa5 249+ f_name(file, NULL));
fa26e11c
WD
250+ exit_cleanup(RERR_STREAMIO);
251+ }
252+ } else {
253+ rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
f4222aa5 254+ f_name(file, NULL), tag);
fa26e11c
WD
255+ exit_cleanup(RERR_STREAMIO);
256+ }
257+ if (tag == 'A' || tag == 'D') {
0870c22a
WD
258+ acl_duo *duo_item;
259+ ndx = racl_list->count;
645e162c 260+ duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
b6c2bb12 261+ duo_item->racl = empty_rsync_acl;
4db3c954 262+ old_recv_rsync_acl(&duo_item->racl, f);
0870c22a 263+ duo_item->sacl = NULL;
fa26e11c 264+ } else {
0870c22a 265+ ndx = read_int(f);
d4531ffb 266+ if (ndx < 0 || (size_t)ndx >= racl_list->count) {
fa26e11c 267+ rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
0870c22a 268+ f_name(file, NULL), str_acl_type(type), ndx);
fa26e11c
WD
269+ exit_cleanup(RERR_STREAMIO);
270+ }
fa26e11c 271+ }
70891d26
WD
272+ if (type == SMB_ACL_TYPE_ACCESS)
273+ F_ACL(file) = ndx;
274+ else
81ecd8e0 275+ F_DEF_ACL(file) = ndx;
0870c22a 276+ racl_list = &default_acl_list;
8db8e7d2 277+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
fa26e11c
WD
278+}
279+
4db3c954
WD
280 /* === Receive functions === */
281
282 static uchar recv_acl_access(uchar *name_follows_val, int f)
283@@ -768,6 +1009,11 @@ static int recv_rsync_acl(item_list *rac
284 /* Receive the ACL info the sender has included for this file-list entry. */
285 void receive_acl(struct file_struct *file, int f)
286 {
287+ if (protocol_version < 30) {
288+ old_recv_acl(file, f);
5d2612ca 289+ return;
fa26e11c 290+ }
fa26e11c 291+
4db3c954 292 F_ACL(file) = recv_rsync_acl(&access_acl_list, SMB_ACL_TYPE_ACCESS, f);
34a409bc 293
4db3c954
WD
294 if (S_ISDIR(file->mode))
295--- old/compat.c
296+++ new/compat.c
297@@ -111,13 +111,6 @@ void setup_protocol(int f_out,int f_in)
298 protocol_version);
299 exit_cleanup(RERR_PROTOCOL);
0870c22a 300 }
4db3c954
WD
301- if (preserve_acls) {
302- rprintf(FERROR,
303- "--acls requires protocol 30 or higher"
304- " (negotiated %d).\n",
305- protocol_version);
306- exit_cleanup(RERR_PROTOCOL);
307- }
0870c22a 308 }
6250eb3e 309
4db3c954 310 if (delete_mode && !(delete_before+delete_during+delete_after)) {
475c4a36
WD
311--- old/testsuite/acls.test
312+++ new/testsuite/acls.test
4db3c954 313@@ -9,10 +9,6 @@
0870c22a 314
4db3c954 315 $RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
0870c22a 316
4db3c954
WD
317-case "$RSYNC" in
318-*protocol=29*) test_skipped "ACLs require protocol 30" ;;
319-esac
320-
321 case "$setfacl_nodef" in
322 true) test_skipped "I don't know how to use your setfacl command" ;;
323 esac
324--- old/testsuite/default-acls.test
325+++ new/testsuite/default-acls.test
326@@ -9,10 +9,6 @@
125d7fca 327
4db3c954 328 $RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
6250eb3e 329
4db3c954
WD
330-case "$RSYNC" in
331-*protocol=29*) test_skipped "ACLs require protocol 30" ;;
332-esac
333-
334 case "$setfacl_nodef" in
335 true) test_skipped "I don't know how to use your setfacl command" ;;
336 *-k*) opts='-dm u::7,g::5,o:5' ;;