Broke-up the checksump-updating patch into a non-updating version
[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
c82285d5
WD
14@@ -31,6 +31,7 @@ extern int list_only;
15 extern int orig_umask;
16 extern int numeric_ids;
17 extern int inc_recurse;
18+extern int protocol_version;
19
20 /* Flags used to indicate what items are being transmitted for an entry. */
21 #define XMIT_USER_OBJ (1<<0)
22@@ -97,6 +98,18 @@ static const char *str_acl_type(SMB_ACL_
4db3c954
WD
23 : "unknown SMB_ACL_TYPE_T";
24 }
25
8db8e7d2
WD
26+#define OTHER_TYPE(t) (SMB_ACL_TYPE_ACCESS+SMB_ACL_TYPE_DEFAULT-(t))
27+#define BUMP_TYPE(t) ((t = OTHER_TYPE(t)) == SMB_ACL_TYPE_DEFAULT)
fa26e11c 28+
4db3c954 29+static int old_count_racl_entries(const rsync_acl *racl)
56294981 30+{
e70a47f8 31+ return racl->names.count
0870c22a
WD
32+ + (racl->user_obj != NO_ENTRY)
33+ + (racl->group_obj != NO_ENTRY)
4db3c954
WD
34+ + (racl->mask_obj != NO_ENTRY)
35+ + (racl->other_obj != NO_ENTRY);
0870c22a
WD
36+}
37+
4db3c954
WD
38 static int calc_sacl_entries(const rsync_acl *racl)
39 {
40 /* A System ACL always gets user/group/other permission entries. */
c82285d5 41@@ -545,6 +558,96 @@ int get_acl(const char *fname, stat_x *s
4db3c954
WD
42 return 0;
43 }
44
45+/* === OLD Send functions === */
0870c22a
WD
46+
47+/* Send the ida list over the file descriptor. */
4db3c954 48+static void old_send_ida_entries(int f, const ida_entries *idal, char tag_char)
0870c22a
WD
49+{
50+ id_access *ida;
51+ size_t count = idal->count;
52+ for (ida = idal->idas; count--; ida++) {
e70a47f8
WD
53+ if (tag_char == 'U') {
54+ if (!(ida->access & NAME_IS_USER))
55+ continue;
56+ add_uid(ida->id);
57+ } else {
58+ if (ida->access & NAME_IS_USER)
59+ continue;
60+ add_gid(ida->id);
61+ }
0870c22a
WD
62+ write_byte(f, tag_char);
63+ write_byte(f, ida->access);
64+ write_int(f, ida->id);
fa26e11c 65+ }
0870c22a
WD
66+}
67+
adabede5 68+/* Send an rsync ACL over the file descriptor. */
4db3c954 69+static void old_send_rsync_acl(int f, const rsync_acl *racl)
0870c22a 70+{
4db3c954 71+ size_t count = old_count_racl_entries(racl);
0870c22a
WD
72+ write_int(f, count);
73+ if (racl->user_obj != NO_ENTRY) {
74+ write_byte(f, 'u');
75+ write_byte(f, racl->user_obj);
76+ }
e70a47f8 77+ old_send_ida_entries(f, &racl->names, 'U');
0870c22a
WD
78+ if (racl->group_obj != NO_ENTRY) {
79+ write_byte(f, 'g');
80+ write_byte(f, racl->group_obj);
fa26e11c 81+ }
e70a47f8 82+ old_send_ida_entries(f, &racl->names, 'G');
4db3c954 83+ if (racl->mask_obj != NO_ENTRY) {
0870c22a 84+ write_byte(f, 'm');
4db3c954 85+ write_byte(f, racl->mask_obj);
0870c22a 86+ }
4db3c954 87+ if (racl->other_obj != NO_ENTRY) {
0870c22a 88+ write_byte(f, 'o');
4db3c954 89+ write_byte(f, racl->other_obj);
0870c22a
WD
90+ }
91+}
c6437996 92+
c82285d5 93+/* Send the ACL from the stat_x structure down the indicated file descriptor.
0870c22a 94+ * This also frees the ACL data. */
c82285d5 95+void old_send_acl(stat_x *sxp, int f)
0870c22a
WD
96+{
97+ SMB_ACL_TYPE_T type;
98+ rsync_acl *racl, *new_racl;
99+ item_list *racl_list;
5d2612ca 100+ int ndx;
53c1073a 101+
0870c22a
WD
102+ type = SMB_ACL_TYPE_ACCESS;
103+ racl = sxp->acc_acl;
104+ racl_list = &access_acl_list;
105+ do {
5d2612ca
WD
106+ if (!racl) {
107+ racl = new(rsync_acl);
108+ if (!racl)
109+ out_of_memory("send_acl");
110+ *racl = empty_rsync_acl;
111+ if (type == SMB_ACL_TYPE_ACCESS) {
112+ rsync_acl_fake_perms(racl, sxp->st.st_mode);
113+ sxp->acc_acl = racl;
114+ } else
115+ sxp->def_acl = racl;
116+ }
0870c22a 117+
4db3c954 118+ if ((ndx = find_matching_rsync_acl(racl, type, racl_list)) != -1) {
0870c22a
WD
119+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
120+ write_int(f, ndx);
0870c22a 121+ } else {
645e162c 122+ new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000);
0870c22a 123+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
4db3c954 124+ old_send_rsync_acl(f, racl);
0870c22a
WD
125+ *new_racl = *racl;
126+ *racl = empty_rsync_acl;
127+ }
128+ racl = sxp->def_acl;
129+ racl_list = &default_acl_list;
130+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
131+
98ccc74a 132+ free_acl(sxp);
fa26e11c
WD
133+}
134+
4db3c954
WD
135 /* === Send functions === */
136
c8a8b4a7 137 /* Send the ida list over the file descriptor. */
c82285d5 138@@ -620,6 +723,11 @@ static void send_rsync_acl(rsync_acl *ra
4db3c954 139 * This also frees the ACL data. */
c8a8b4a7 140 void send_acl(stat_x *sxp, int f)
4db3c954
WD
141 {
142+ if (protocol_version < 30) {
143+ old_send_acl(sxp, f);
144+ return;
145+ }
ffc18846 146+
4db3c954
WD
147 if (!sxp->acc_acl) {
148 sxp->acc_acl = create_racl();
ffc18846 149 rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode);
c82285d5 150@@ -637,6 +745,160 @@ void send_acl(stat_x *sxp, int f)
4db3c954
WD
151 }
152 }
153
154+/* === OLD Receive functions */
0870c22a 155+
4db3c954 156+static void old_recv_rsync_acl(rsync_acl *racl, int f)
fa26e11c 157+{
6250eb3e 158+ static item_list temp_ida_list = EMPTY_ITEM_LIST;
e70a47f8 159+ SMB_ACL_TAG_T tag_type = 0;
090d78e1 160+ uchar computed_mask_bits = 0;
c6437996 161+ id_access *ida;
ad625644
WD
162+ size_t count;
163+
164+ if (!(count = read_int(f)))
fa26e11c 165+ return;
ad625644 166+
fa26e11c 167+ while (count--) {
dfadc68a 168+ char tag = read_byte(f);
c6437996
WD
169+ uchar access = read_byte(f);
170+ if (access & ~ (4 | 2 | 1)) {
4db3c954 171+ rprintf(FERROR, "old_recv_rsync_acl: bogus permset %o\n",
c6437996
WD
172+ access);
173+ exit_cleanup(RERR_STREAMIO);
174+ }
fa26e11c
WD
175+ switch (tag) {
176+ case 'u':
0870c22a 177+ if (racl->user_obj != NO_ENTRY) {
4db3c954 178+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate USER_OBJ entry\n");
c6437996
WD
179+ exit_cleanup(RERR_STREAMIO);
180+ }
181+ racl->user_obj = access;
182+ continue;
fa26e11c 183+ case 'U':
0870c22a 184+ tag_type = SMB_ACL_USER;
fa26e11c
WD
185+ break;
186+ case 'g':
0870c22a 187+ if (racl->group_obj != NO_ENTRY) {
4db3c954 188+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate GROUP_OBJ entry\n");
c6437996
WD
189+ exit_cleanup(RERR_STREAMIO);
190+ }
191+ racl->group_obj = access;
192+ continue;
fa26e11c 193+ case 'G':
0870c22a 194+ tag_type = SMB_ACL_GROUP;
fa26e11c
WD
195+ break;
196+ case 'm':
4db3c954
WD
197+ if (racl->mask_obj != NO_ENTRY) {
198+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate MASK entry\n");
c6437996
WD
199+ exit_cleanup(RERR_STREAMIO);
200+ }
4db3c954 201+ racl->mask_obj = access;
c6437996
WD
202+ continue;
203+ case 'o':
4db3c954
WD
204+ if (racl->other_obj != NO_ENTRY) {
205+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate OTHER entry\n");
c6437996
WD
206+ exit_cleanup(RERR_STREAMIO);
207+ }
4db3c954 208+ racl->other_obj = access;
c6437996 209+ continue;
fa26e11c 210+ default:
4db3c954 211+ rprintf(FERROR, "old_recv_rsync_acl: unknown tag %c\n",
fa26e11c
WD
212+ tag);
213+ exit_cleanup(RERR_STREAMIO);
214+ }
645e162c 215+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
e70a47f8 216+ ida->access = access | (tag_type == SMB_ACL_USER ? NAME_IS_USER : 0);
c6437996 217+ ida->id = read_int(f);
090d78e1 218+ computed_mask_bits |= access;
c6437996 219+ }
8eb3e3ae 220+
e70a47f8
WD
221+ /* Transfer the count id_access items out of the temp_ida_list
222+ * into the names ida_entries list in racl. */
223+ if (temp_ida_list.count) {
224+#ifdef SMB_ACL_NEED_SORT
225+ if (temp_ida_list.count > 1) {
226+ qsort(temp_ida_list.items, temp_ida_list.count,
227+ sizeof (id_access), id_access_sorter);
228+ }
229+#endif
230+ if (!(racl->names.idas = new_array(id_access, temp_ida_list.count)))
231+ out_of_memory("unpack_smb_acl");
232+ memcpy(racl->names.idas, temp_ida_list.items,
233+ temp_ida_list.count * sizeof (id_access));
234+ } else
235+ racl->names.idas = NULL;
236+
237+ racl->names.count = temp_ida_list.count;
238+
239+ /* Truncate the temporary list now that its idas have been saved. */
240+ temp_ida_list.count = 0;
241+
242+ if (!racl->names.count) {
8eb3e3ae 243+ /* If we received a superfluous mask, throw it away. */
4db3c954 244+ if (racl->mask_obj != NO_ENTRY) {
8eb3e3ae 245+ /* Mask off the group perms with it first. */
4db3c954
WD
246+ racl->group_obj &= racl->mask_obj | NO_ENTRY;
247+ racl->mask_obj = NO_ENTRY;
fa26e11c 248+ }
4db3c954 249+ } else if (racl->mask_obj == NO_ENTRY) /* Must be non-empty with lists. */
e70a47f8 250+ racl->mask_obj = (computed_mask_bits | racl->group_obj) & 7;
fa26e11c
WD
251+}
252+
0870c22a 253+/* Receive the ACL info the sender has included for this file-list entry. */
4db3c954 254+void old_recv_acl(struct file_struct *file, int f)
fa26e11c 255+{
8db8e7d2 256+ SMB_ACL_TYPE_T type;
0870c22a 257+ item_list *racl_list;
36aa3171 258+
162234a7 259+ if (S_ISLNK(file->mode))
fa26e11c 260+ return;
36aa3171 261+
8db8e7d2 262+ type = SMB_ACL_TYPE_ACCESS;
0870c22a 263+ racl_list = &access_acl_list;
8db8e7d2 264+ do {
0870c22a
WD
265+ char tag = read_byte(f);
266+ int ndx;
fa26e11c 267+
fa26e11c 268+ if (tag == 'A' || tag == 'a') {
8db8e7d2 269+ if (type != SMB_ACL_TYPE_ACCESS) {
fa26e11c 270+ rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
f4222aa5 271+ f_name(file, NULL));
fa26e11c
WD
272+ exit_cleanup(RERR_STREAMIO);
273+ }
274+ } else if (tag == 'D' || tag == 'd') {
8db8e7d2 275+ if (type == SMB_ACL_TYPE_ACCESS) {
fa26e11c 276+ rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
f4222aa5 277+ f_name(file, NULL));
fa26e11c
WD
278+ exit_cleanup(RERR_STREAMIO);
279+ }
280+ } else {
281+ rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
f4222aa5 282+ f_name(file, NULL), tag);
fa26e11c
WD
283+ exit_cleanup(RERR_STREAMIO);
284+ }
285+ if (tag == 'A' || tag == 'D') {
0870c22a
WD
286+ acl_duo *duo_item;
287+ ndx = racl_list->count;
645e162c 288+ duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
b6c2bb12 289+ duo_item->racl = empty_rsync_acl;
4db3c954 290+ old_recv_rsync_acl(&duo_item->racl, f);
0870c22a 291+ duo_item->sacl = NULL;
fa26e11c 292+ } else {
0870c22a 293+ ndx = read_int(f);
d4531ffb 294+ if (ndx < 0 || (size_t)ndx >= racl_list->count) {
fa26e11c 295+ rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
0870c22a 296+ f_name(file, NULL), str_acl_type(type), ndx);
fa26e11c
WD
297+ exit_cleanup(RERR_STREAMIO);
298+ }
fa26e11c 299+ }
70891d26
WD
300+ if (type == SMB_ACL_TYPE_ACCESS)
301+ F_ACL(file) = ndx;
302+ else
7bfcb297 303+ F_DIR_DEFACL(file) = ndx;
0870c22a 304+ racl_list = &default_acl_list;
8db8e7d2 305+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
fa26e11c
WD
306+}
307+
4db3c954
WD
308 /* === Receive functions === */
309
e70a47f8 310 static uint32 recv_acl_access(uchar *name_follows_ptr, int f)
c82285d5 311@@ -759,6 +1021,11 @@ static int recv_rsync_acl(item_list *rac
4db3c954
WD
312 /* Receive the ACL info the sender has included for this file-list entry. */
313 void receive_acl(struct file_struct *file, int f)
314 {
315+ if (protocol_version < 30) {
316+ old_recv_acl(file, f);
5d2612ca 317+ return;
fa26e11c 318+ }
fa26e11c 319+
4db3c954 320 F_ACL(file) = recv_rsync_acl(&access_acl_list, SMB_ACL_TYPE_ACCESS, f);
34a409bc 321
4db3c954
WD
322 if (S_ISDIR(file->mode))
323--- old/compat.c
324+++ new/compat.c
c8a8b4a7 325@@ -160,13 +160,6 @@ void setup_protocol(int f_out,int f_in)
99650e0d 326 if (protocol_version < 30) {
5ba66156
WD
327 if (append_mode == 1)
328 append_mode = 2;
8a38e00a 329- if (preserve_acls && !local_server) {
4db3c954
WD
330- rprintf(FERROR,
331- "--acls requires protocol 30 or higher"
332- " (negotiated %d).\n",
333- protocol_version);
334- exit_cleanup(RERR_PROTOCOL);
335- }
8a38e00a 336 if (preserve_xattrs && !local_server) {
5795bf59
WD
337 rprintf(FERROR,
338 "--xattrs requires protocol 30 or higher"