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