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