Fixed failing hunks.
[rsync/rsync-patches.git] / acls.diff
... / ...
CommitLineData
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
6To use this patch, run these commands for a successful build:
7
8 patch -p1 <patches/acls.diff
9 ./configure (optional if already run)
10 make
11
12--- old/acls.c
13+++ new/acls.c
14@@ -89,6 +89,18 @@ static const char *str_acl_type(SMB_ACL_
15 : "unknown SMB_ACL_TYPE_T";
16 }
17
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)
20+
21+static int old_count_racl_entries(const rsync_acl *racl)
22+{
23+ return racl->users.count + racl->groups.count
24+ + (racl->user_obj != NO_ENTRY)
25+ + (racl->group_obj != NO_ENTRY)
26+ + (racl->mask_obj != NO_ENTRY)
27+ + (racl->other_obj != NO_ENTRY);
28+}
29+
30 static int calc_sacl_entries(const rsync_acl *racl)
31 {
32 /* A System ACL always gets user/group/other permission entries. */
33@@ -544,6 +556,91 @@ int get_acl(const char *fname, statx *sx
34 return 0;
35 }
36
37+/* === OLD Send functions === */
38+
39+/* Send the ida list over the file descriptor. */
40+static void old_send_ida_entries(int f, const ida_entries *idal, char tag_char)
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);
48+ if (tag_char == 'U')
49+ add_uid(ida->id);
50+ else
51+ add_gid(ida->id);
52+ }
53+}
54+
55+/* Send an rsync ACL over the file descriptor. */
56+static void old_send_rsync_acl(int f, const rsync_acl *racl)
57+{
58+ size_t count = old_count_racl_entries(racl);
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+ }
64+ old_send_ida_entries(f, &racl->users, 'U');
65+ if (racl->group_obj != NO_ENTRY) {
66+ write_byte(f, 'g');
67+ write_byte(f, racl->group_obj);
68+ }
69+ old_send_ida_entries(f, &racl->groups, 'G');
70+ if (racl->mask_obj != NO_ENTRY) {
71+ write_byte(f, 'm');
72+ write_byte(f, racl->mask_obj);
73+ }
74+ if (racl->other_obj != NO_ENTRY) {
75+ write_byte(f, 'o');
76+ write_byte(f, racl->other_obj);
77+ }
78+}
79+
80+/* Send the ACL from the statx structure down the indicated file descriptor.
81+ * This also frees the ACL data. */
82+void old_send_acl(statx *sxp, int f)
83+{
84+ SMB_ACL_TYPE_T type;
85+ rsync_acl *racl, *new_racl;
86+ item_list *racl_list;
87+ int ndx;
88+
89+ type = SMB_ACL_TYPE_ACCESS;
90+ racl = sxp->acc_acl;
91+ racl_list = &access_acl_list;
92+ do {
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+ }
104+
105+ if ((ndx = find_matching_rsync_acl(racl, type, racl_list)) != -1) {
106+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
107+ write_int(f, ndx);
108+ } else {
109+ new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000);
110+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
111+ old_send_rsync_acl(f, racl);
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+
119+ free_acl(sxp);
120+}
121+
122 /* === Send functions === */
123
124 /* The general strategy with the tag_type <-> character mapping is that
125@@ -630,6 +727,11 @@ 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 rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode);
137@@ -647,6 +749,146 @@ void send_acl(statx *sxp, int f)
138 }
139 }
140
141+/* === OLD Receive functions */
142+
143+static void old_recv_rsync_acl(rsync_acl *racl, int f)
144+{
145+ static item_list temp_ida_list = EMPTY_ITEM_LIST;
146+ SMB_ACL_TAG_T tag_type = 0, prior_list_type = 0;
147+ uchar computed_mask_bits = 0;
148+ id_access *ida;
149+ size_t count;
150+
151+ if (!(count = read_int(f)))
152+ return;
153+
154+ while (count--) {
155+ char tag = read_byte(f);
156+ uchar access = read_byte(f);
157+ if (access & ~ (4 | 2 | 1)) {
158+ rprintf(FERROR, "old_recv_rsync_acl: bogus permset %o\n",
159+ access);
160+ exit_cleanup(RERR_STREAMIO);
161+ }
162+ switch (tag) {
163+ case 'u':
164+ if (racl->user_obj != NO_ENTRY) {
165+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate USER_OBJ entry\n");
166+ exit_cleanup(RERR_STREAMIO);
167+ }
168+ racl->user_obj = access;
169+ continue;
170+ case 'U':
171+ tag_type = SMB_ACL_USER;
172+ break;
173+ case 'g':
174+ if (racl->group_obj != NO_ENTRY) {
175+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate GROUP_OBJ entry\n");
176+ exit_cleanup(RERR_STREAMIO);
177+ }
178+ racl->group_obj = access;
179+ continue;
180+ case 'G':
181+ tag_type = SMB_ACL_GROUP;
182+ break;
183+ case 'm':
184+ if (racl->mask_obj != NO_ENTRY) {
185+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate MASK entry\n");
186+ exit_cleanup(RERR_STREAMIO);
187+ }
188+ racl->mask_obj = access;
189+ continue;
190+ case 'o':
191+ if (racl->other_obj != NO_ENTRY) {
192+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate OTHER entry\n");
193+ exit_cleanup(RERR_STREAMIO);
194+ }
195+ racl->other_obj = access;
196+ continue;
197+ default:
198+ rprintf(FERROR, "old_recv_rsync_acl: unknown tag %c\n",
199+ tag);
200+ exit_cleanup(RERR_STREAMIO);
201+ }
202+ if (tag_type != prior_list_type) {
203+ if (prior_list_type)
204+ save_idas(racl, prior_list_type, &temp_ida_list);
205+ prior_list_type = tag_type;
206+ }
207+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
208+ ida->access = access;
209+ ida->id = read_int(f);
210+ computed_mask_bits |= access;
211+ }
212+ if (prior_list_type)
213+ save_idas(racl, prior_list_type, &temp_ida_list);
214+
215+ if (!racl->users.count && !racl->groups.count) {
216+ /* If we received a superfluous mask, throw it away. */
217+ if (racl->mask_obj != NO_ENTRY) {
218+ /* Mask off the group perms with it first. */
219+ racl->group_obj &= racl->mask_obj | NO_ENTRY;
220+ racl->mask_obj = NO_ENTRY;
221+ }
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);
224+}
225+
226+/* Receive the ACL info the sender has included for this file-list entry. */
227+void old_recv_acl(struct file_struct *file, int f)
228+{
229+ SMB_ACL_TYPE_T type;
230+ item_list *racl_list;
231+
232+ if (S_ISLNK(file->mode))
233+ return;
234+
235+ type = SMB_ACL_TYPE_ACCESS;
236+ racl_list = &access_acl_list;
237+ do {
238+ char tag = read_byte(f);
239+ int ndx;
240+
241+ if (tag == 'A' || tag == 'a') {
242+ if (type != SMB_ACL_TYPE_ACCESS) {
243+ rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
244+ f_name(file, NULL));
245+ exit_cleanup(RERR_STREAMIO);
246+ }
247+ } else if (tag == 'D' || tag == 'd') {
248+ if (type == SMB_ACL_TYPE_ACCESS) {
249+ rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
250+ f_name(file, NULL));
251+ exit_cleanup(RERR_STREAMIO);
252+ }
253+ } else {
254+ rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
255+ f_name(file, NULL), tag);
256+ exit_cleanup(RERR_STREAMIO);
257+ }
258+ if (tag == 'A' || tag == 'D') {
259+ acl_duo *duo_item;
260+ ndx = racl_list->count;
261+ duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
262+ duo_item->racl = empty_rsync_acl;
263+ old_recv_rsync_acl(&duo_item->racl, f);
264+ duo_item->sacl = NULL;
265+ } else {
266+ ndx = read_int(f);
267+ if (ndx < 0 || (size_t)ndx >= racl_list->count) {
268+ rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
269+ f_name(file, NULL), str_acl_type(type), ndx);
270+ exit_cleanup(RERR_STREAMIO);
271+ }
272+ }
273+ if (type == SMB_ACL_TYPE_ACCESS)
274+ F_ACL(file) = ndx;
275+ else
276+ F_DEF_ACL(file) = ndx;
277+ racl_list = &default_acl_list;
278+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
279+}
280+
281 /* === Receive functions === */
282
283 static uchar recv_acl_access(uchar *name_follows_val, int f)
284@@ -766,6 +1008,11 @@ static int recv_rsync_acl(item_list *rac
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);
290+ return;
291+ }
292+
293 F_ACL(file) = recv_rsync_acl(&access_acl_list, SMB_ACL_TYPE_ACCESS, f);
294
295 if (S_ISDIR(file->mode))
296--- old/compat.c
297+++ new/compat.c
298@@ -115,13 +115,6 @@ void setup_protocol(int f_out,int f_in)
299 protocol_version);
300 exit_cleanup(RERR_PROTOCOL);
301 }
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- }
309 if (preserve_xattrs) {
310 rprintf(FERROR,
311 "--xattrs requires protocol 30 or higher"
312--- old/testsuite/acls.test
313+++ new/testsuite/acls.test
314@@ -9,10 +9,6 @@
315
316 $RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
317
318-case "$RSYNC" in
319-*protocol=29*) test_skipped "ACL support requires 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 @@
328
329 $RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
330
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' ;;