View | Details | Raw Unified | Return to bug 249119
Collapse All | Expand All

(-)b/net/rsync/Makefile (-1 / +2 lines)
Lines 3-8 Link Here
3
3
4
PORTNAME=	rsync
4
PORTNAME=	rsync
5
DISTVERSION=	3.2.3
5
DISTVERSION=	3.2.3
6
PORTREVISION=	1
6
CATEGORIES=	net
7
CATEGORIES=	net
7
MASTER_SITES=	https://www.mirrorservice.org/sites/rsync.samba.org/src/ \
8
MASTER_SITES=	https://www.mirrorservice.org/sites/rsync.samba.org/src/ \
8
				http://rsync.mirror.garr.it/src/ \
9
				http://rsync.mirror.garr.it/src/ \
Lines 68-74 ATIMES_EXTRA_PATCHES= ${WRKSRC}/patches/atimes.diff Link Here
68
FLAGS_EXTRA_PATCHES=		${WRKSRC}/patches/fileflags.diff \
69
FLAGS_EXTRA_PATCHES=		${WRKSRC}/patches/fileflags.diff \
69
				${FILESDIR}/extrapatch-main.c
70
				${FILESDIR}/extrapatch-main.c
70
RENAMED_EXTRA_PATCHES=		${WRKSRC}/patches/detect-renamed.diff
71
RENAMED_EXTRA_PATCHES=		${WRKSRC}/patches/detect-renamed.diff
71
ACL_EXTRA_PATCHES=		${WRKSRC}/patches/acls.diff
72
ACL_EXTRA_PATCHES=		${PATCHDIR}/extrapatch-acl:-p1
72
73
73
ICONV_USES=	iconv:translit
74
ICONV_USES=	iconv:translit
74
ICONV_CONFIGURE_ENABLE=	iconv iconv-open
75
ICONV_CONFIGURE_ENABLE=	iconv iconv-open
(-)b/net/rsync/files/extrapatch-acl (+829 lines)
Added Link Here
1
diff --git a/acls.c b/acls.c
2
index 4303c2a7..a2f966a1 100644
3
--- a/acls.c
4
+++ b/acls.c
5
@@ -31,6 +31,7 @@ extern int list_only;
6
 extern int orig_umask;
7
 extern int numeric_ids;
8
 extern int inc_recurse;
9
+extern int protocol_version;
10
 extern int preserve_devices;
11
 extern int preserve_specials;
12
 
13
@@ -78,20 +79,35 @@ typedef struct rsync_acl {
14
 	uchar other_obj;
15
 } rsync_acl;
16
 
17
+typedef struct nfs4_acl {
18
+	char *nfs4_acl_text;
19
+	ssize_t nfs4_acl_len;
20
+} nfs4_acl;
21
+
22
 typedef struct {
23
 	rsync_acl racl;
24
 	SMB_ACL_T sacl;
25
 } acl_duo;
26
 
27
+typedef struct {
28
+	nfs4_acl nacl;
29
+	SMB_ACL_T sacl;
30
+} nfs4_duo;
31
+
32
 static const rsync_acl empty_rsync_acl = {
33
 	{NULL, 0}, NO_ENTRY, NO_ENTRY, NO_ENTRY, NO_ENTRY
34
 };
35
+static const nfs4_acl empty_nfs4_acl = {
36
+	NULL, -1
37
+};
38
 
39
 static item_list access_acl_list = EMPTY_ITEM_LIST;
40
 static item_list default_acl_list = EMPTY_ITEM_LIST;
41
+static item_list nfs4_acl_list = EMPTY_ITEM_LIST;
42
 
43
 static size_t prior_access_count = (size_t)-1;
44
 static size_t prior_default_count = (size_t)-1;
45
+static size_t prior_nfs4_count = (size_t)-1;
46
 
47
 /* === Calculations on ACL types === */
48
 
49
@@ -112,6 +128,18 @@ static const char *str_acl_type(SMB_ACL_TYPE_T type)
50
 	return "unknown ACL type!";
51
 }
52
 
53
+#define OTHER_TYPE(t) (SMB_ACL_TYPE_ACCESS+SMB_ACL_TYPE_DEFAULT-(t))
54
+#define BUMP_TYPE(t) ((t = OTHER_TYPE(t)) == SMB_ACL_TYPE_DEFAULT)
55
+
56
+static int old_count_racl_entries(const rsync_acl *racl)
57
+{
58
+	return racl->names.count
59
+	     + (racl->user_obj != NO_ENTRY)
60
+	     + (racl->group_obj != NO_ENTRY)
61
+	     + (racl->mask_obj != NO_ENTRY)
62
+	     + (racl->other_obj != NO_ENTRY);
63
+}
64
+
65
 static int calc_sacl_entries(const rsync_acl *racl)
66
 {
67
 	/* A System ACL always gets user/group/other permission entries. */
68
@@ -173,6 +201,17 @@ static rsync_acl *create_racl(void)
69
 	return racl;
70
 }
71
 
72
+static nfs4_acl *create_nfs4_acl(void)
73
+{
74
+	nfs4_acl *nacl = new(nfs4_acl);
75
+
76
+	if (!nacl)
77
+		out_of_memory("create_nfs4_acl");
78
+	*nacl = empty_nfs4_acl;
79
+
80
+	return nacl;
81
+}
82
+
83
 static BOOL ida_entries_equal(const ida_entries *ial1, const ida_entries *ial2)
84
 {
85
 	id_access *ida1, *ida2;
86
@@ -197,6 +236,11 @@ static BOOL rsync_acl_equal(const rsync_acl *racl1, const rsync_acl *racl2)
87
 	    && ida_entries_equal(&racl1->names, &racl2->names);
88
 }
89
 
90
+static BOOL nfs4_acl_equal(const nfs4_acl *nacl1, const nfs4_acl *nacl2)
91
+{
92
+	return (strcmp(nacl1->nfs4_acl_text, nacl2->nfs4_acl_text) == 0);
93
+}
94
+
95
 /* Are the extended (non-permission-bit) entries equal?  If so, the rest of
96
  * the ACL will be handled by the normal mode-preservation code.  This is
97
  * only meaningful for access ACLs!  Note: the 1st arg is a fully-populated
98
@@ -230,6 +274,13 @@ static void rsync_acl_free(rsync_acl *racl)
99
 	*racl = empty_rsync_acl;
100
 }
101
 
102
+static void nfs4_acl_free(nfs4_acl *nacl)
103
+{
104
+	if (nacl->nfs4_acl_text)
105
+		free(nacl->nfs4_acl_text);
106
+	*nacl = empty_nfs4_acl;
107
+}
108
+
109
 void free_acl(stat_x *sxp)
110
 {
111
 	if (sxp->acc_acl) {
112
@@ -242,6 +293,11 @@ void free_acl(stat_x *sxp)
113
 		free(sxp->def_acl);
114
 		sxp->def_acl = NULL;
115
 	}
116
+	if (sxp->nfs4_acl) {
117
+		nfs4_acl_free(sxp->nfs4_acl);
118
+		free(sxp->nfs4_acl);
119
+		sxp->nfs4_acl = NULL;
120
+	}
121
 }
122
 
123
 #ifdef SMB_ACL_NEED_SORT
124
@@ -469,6 +525,26 @@ static int find_matching_rsync_acl(const rsync_acl *racl, SMB_ACL_TYPE_T type,
125
 	return *match;
126
 }
127
 
128
+static int find_matching_nfs4_acl(const nfs4_acl *nacl, const item_list *nfs4_acl_list)
129
+{
130
+	static int nfs4_match = -1;
131
+	int *match = &nfs4_match;
132
+	size_t count = nfs4_acl_list->count;
133
+
134
+	if (*match == -1)
135
+		*match = nfs4_acl_list->count - 1;
136
+	while (count--) {
137
+		nfs4_acl *base = nfs4_acl_list->items;
138
+		if (nfs4_acl_equal(base + *match, nacl))
139
+			return *match;
140
+		if (!(*match)--)
141
+			*match = nfs4_acl_list->count - 1;
142
+	}
143
+
144
+	*match = -1;
145
+	return *match;
146
+}
147
+
148
 static int get_rsync_acl(const char *fname, rsync_acl *racl,
149
 			 SMB_ACL_TYPE_T type, mode_t mode)
150
 {
151
@@ -537,6 +613,21 @@ static int get_rsync_acl(const char *fname, rsync_acl *racl,
152
 /* Return the Access Control List for the given filename. */
153
 int get_acl(const char *fname, stat_x *sxp)
154
 {
155
+	if (sys_acl_get_brand_file(fname, &sxp->brand) < 0)
156
+		return -1;
157
+
158
+	if (sxp->brand == SMB_ACL_BRAND_NFS4) {
159
+		SMB_ACL_T sacl;
160
+		if ((sacl = sys_acl_get_file(fname, SMB_ACL_TYPE_NFS4)) == NULL)
161
+			return -1;
162
+
163
+		sxp->nfs4_acl = create_nfs4_acl();
164
+		sxp->nfs4_acl->nfs4_acl_text = acl_to_text(sacl, &sxp->nfs4_acl->nfs4_acl_len);
165
+
166
+		sys_acl_free_acl(sacl);
167
+		return 0;
168
+	}
169
+
170
 	sxp->acc_acl = create_racl();
171
 
172
 	if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
173
@@ -574,6 +665,96 @@ int get_acl(const char *fname, stat_x *sxp)
174
 	return 0;
175
 }
176
 
177
+/* === OLD Send functions === */
178
+
179
+/* Send the ida list over the file descriptor. */
180
+static void old_send_ida_entries(int f, const ida_entries *idal, char tag_char)
181
+{
182
+	id_access *ida;
183
+	size_t count = idal->count;
184
+	for (ida = idal->idas; count--; ida++) {
185
+		if (tag_char == 'U') {
186
+			if (!(ida->access & NAME_IS_USER))
187
+				continue;
188
+			add_uid(ida->id);
189
+		} else {
190
+			if (ida->access & NAME_IS_USER)
191
+				continue;
192
+			add_gid(ida->id);
193
+		}
194
+		write_byte(f, tag_char);
195
+		write_byte(f, ida->access);
196
+		write_int(f, ida->id);
197
+	}
198
+}
199
+
200
+/* Send an rsync ACL over the file descriptor. */
201
+static void old_send_rsync_acl(int f, const rsync_acl *racl)
202
+{
203
+	size_t count = old_count_racl_entries(racl);
204
+	write_int(f, count);
205
+	if (racl->user_obj != NO_ENTRY) {
206
+		write_byte(f, 'u');
207
+		write_byte(f, racl->user_obj);
208
+	}
209
+	old_send_ida_entries(f, &racl->names, 'U');
210
+	if (racl->group_obj != NO_ENTRY) {
211
+		write_byte(f, 'g');
212
+		write_byte(f, racl->group_obj);
213
+	}
214
+	old_send_ida_entries(f, &racl->names, 'G');
215
+	if (racl->mask_obj != NO_ENTRY) {
216
+		write_byte(f, 'm');
217
+		write_byte(f, racl->mask_obj);
218
+	}
219
+	if (racl->other_obj != NO_ENTRY) {
220
+		write_byte(f, 'o');
221
+		write_byte(f, racl->other_obj);
222
+	}
223
+}
224
+
225
+/* Send the ACL from the stat_x structure down the indicated file descriptor.
226
+ * This also frees the ACL data. */
227
+void old_send_acl(stat_x *sxp, int f)
228
+{
229
+	SMB_ACL_TYPE_T type;
230
+	rsync_acl *racl, *new_racl;
231
+	item_list *racl_list;
232
+	int ndx;
233
+
234
+	type = SMB_ACL_TYPE_ACCESS;
235
+	racl = sxp->acc_acl;
236
+	racl_list = &access_acl_list;
237
+	do {
238
+		if (!racl) {
239
+			racl = new(rsync_acl);
240
+			if (!racl)
241
+				out_of_memory("send_acl");
242
+			*racl = empty_rsync_acl;
243
+			if (type == SMB_ACL_TYPE_ACCESS) {
244
+				rsync_acl_fake_perms(racl, sxp->st.st_mode);
245
+				sxp->acc_acl = racl;
246
+			} else
247
+				sxp->def_acl = racl;
248
+		}
249
+
250
+		if ((ndx = find_matching_rsync_acl(racl, type, racl_list)) != -1) {
251
+			write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
252
+			write_int(f, ndx);
253
+		} else {
254
+			new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000);
255
+			write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
256
+			old_send_rsync_acl(f, racl);
257
+			*new_racl = *racl;
258
+			*racl = empty_rsync_acl;
259
+		}
260
+		racl = sxp->def_acl;
261
+		racl_list = &default_acl_list;
262
+	} while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
263
+
264
+	free_acl(sxp);
265
+}
266
+
267
 /* === Send functions === */
268
 
269
 /* Send the ida list over the file descriptor. */
270
@@ -645,10 +826,40 @@ static void send_rsync_acl(int f, rsync_acl *racl, SMB_ACL_TYPE_T type,
271
 	}
272
 }
273
 
274
+static void send_nfs4_acl(int f, nfs4_acl *nacl, item_list *nfs4_list)
275
+{
276
+	int ndx = find_matching_nfs4_acl(nacl, nfs4_list);
277
+
278
+	/* Send 0 (-1 + 1) to indicate that literal ACL data follows. */
279
+	write_varint(f, ndx + 1);
280
+
281
+	if (ndx < 0) {
282
+		nfs4_acl *new_nacl = EXPAND_ITEM_LIST(&nfs4_acl_list, nfs4_acl, 1000);
283
+
284
+		write_varint(f, nacl->nfs4_acl_len);
285
+		write_buf(f, nacl->nfs4_acl_text, nacl->nfs4_acl_len);
286
+
287
+		*new_nacl = *nacl;
288
+		*nacl = empty_nfs4_acl;
289
+	}
290
+}
291
+
292
+
293
 /* Send the ACL from the stat_x structure down the indicated file descriptor.
294
  * This also frees the ACL data. */
295
 void send_acl(int f, stat_x *sxp)
296
 {
297
+	if (protocol_version < 30) {
298
+		old_send_acl(sxp, f);
299
+		return;
300
+	}
301
+
302
+	if (sxp->brand == SMB_ACL_BRAND_NFS4) {
303
+		write_varint(f, SMB_ACL_TYPE_NFS4);
304
+		send_nfs4_acl(f, sxp->nfs4_acl, &nfs4_acl_list);
305
+		return;
306
+	}
307
+
308
 	if (!sxp->acc_acl) {
309
 		sxp->acc_acl = create_racl();
310
 		rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode);
311
@@ -656,16 +867,172 @@ void send_acl(int f, stat_x *sxp)
312
 	/* Avoid sending values that can be inferred from other data. */
313
 	rsync_acl_strip_perms(sxp);
314
 
315
+	write_varint(f, SMB_ACL_TYPE_ACCESS);
316
 	send_rsync_acl(f, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list);
317
 
318
 	if (S_ISDIR(sxp->st.st_mode)) {
319
 		if (!sxp->def_acl)
320
 			sxp->def_acl = create_racl();
321
 
322
+		write_varint(f, SMB_ACL_TYPE_DEFAULT);
323
 		send_rsync_acl(f, sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list);
324
 	}
325
 }
326
 
327
+/* === OLD Receive functions */
328
+
329
+static void old_recv_rsync_acl(rsync_acl *racl, int f)
330
+{
331
+	static item_list temp_ida_list = EMPTY_ITEM_LIST;
332
+	SMB_ACL_TAG_T tag_type = 0;
333
+	uchar computed_mask_bits = 0;
334
+	id_access *ida;
335
+	size_t count;
336
+
337
+	if (!(count = read_int(f)))
338
+		return;
339
+
340
+	while (count--) {
341
+		char tag = read_byte(f);
342
+		uchar access = read_byte(f);
343
+		if (access & ~ (4 | 2 | 1)) {
344
+			rprintf(FERROR, "old_recv_rsync_acl: bogus permset %o\n",
345
+				access);
346
+			exit_cleanup(RERR_STREAMIO);
347
+		}
348
+		switch (tag) {
349
+		case 'u':
350
+			if (racl->user_obj != NO_ENTRY) {
351
+				rprintf(FERROR, "old_recv_rsync_acl: error: duplicate USER_OBJ entry\n");
352
+				exit_cleanup(RERR_STREAMIO);
353
+			}
354
+			racl->user_obj = access;
355
+			continue;
356
+		case 'U':
357
+			tag_type = SMB_ACL_USER;
358
+			break;
359
+		case 'g':
360
+			if (racl->group_obj != NO_ENTRY) {
361
+				rprintf(FERROR, "old_recv_rsync_acl: error: duplicate GROUP_OBJ entry\n");
362
+				exit_cleanup(RERR_STREAMIO);
363
+			}
364
+			racl->group_obj = access;
365
+			continue;
366
+		case 'G':
367
+			tag_type = SMB_ACL_GROUP;
368
+			break;
369
+		case 'm':
370
+			if (racl->mask_obj != NO_ENTRY) {
371
+				rprintf(FERROR, "old_recv_rsync_acl: error: duplicate MASK entry\n");
372
+				exit_cleanup(RERR_STREAMIO);
373
+			}
374
+			racl->mask_obj = access;
375
+			continue;
376
+		case 'o':
377
+			if (racl->other_obj != NO_ENTRY) {
378
+				rprintf(FERROR, "old_recv_rsync_acl: error: duplicate OTHER entry\n");
379
+				exit_cleanup(RERR_STREAMIO);
380
+			}
381
+			racl->other_obj = access;
382
+			continue;
383
+		default:
384
+			rprintf(FERROR, "old_recv_rsync_acl: unknown tag %c\n",
385
+				tag);
386
+			exit_cleanup(RERR_STREAMIO);
387
+		}
388
+		ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
389
+		ida->access = access | (tag_type == SMB_ACL_USER ? NAME_IS_USER : 0);
390
+		ida->id = read_int(f);
391
+		computed_mask_bits |= access;
392
+	}
393
+
394
+	/* Transfer the count id_access items out of the temp_ida_list
395
+	 * into the names ida_entries list in racl. */
396
+	if (temp_ida_list.count) {
397
+#ifdef SMB_ACL_NEED_SORT
398
+		if (temp_ida_list.count > 1) {
399
+			qsort(temp_ida_list.items, temp_ida_list.count,
400
+			      sizeof (id_access), id_access_sorter);
401
+		}
402
+#endif
403
+		if (!(racl->names.idas = new_array(id_access, temp_ida_list.count)))
404
+			out_of_memory("unpack_smb_acl");
405
+		memcpy(racl->names.idas, temp_ida_list.items,
406
+		       temp_ida_list.count * sizeof (id_access));
407
+	} else
408
+		racl->names.idas = NULL;
409
+
410
+	racl->names.count = temp_ida_list.count;
411
+
412
+	/* Truncate the temporary list now that its idas have been saved. */
413
+	temp_ida_list.count = 0;
414
+
415
+	if (!racl->names.count) {
416
+		/* If we received a superfluous mask, throw it away. */
417
+		if (racl->mask_obj != NO_ENTRY) {
418
+			/* Mask off the group perms with it first. */
419
+			racl->group_obj &= racl->mask_obj | NO_ENTRY;
420
+			racl->mask_obj = NO_ENTRY;
421
+		}
422
+	} else if (racl->mask_obj == NO_ENTRY) /* Must be non-empty with lists. */
423
+		racl->mask_obj = (computed_mask_bits | racl->group_obj) & 7;
424
+}
425
+
426
+/* Receive the ACL info the sender has included for this file-list entry. */
427
+void old_recv_acl(struct file_struct *file, int f)
428
+{
429
+	SMB_ACL_TYPE_T type;
430
+	item_list *racl_list;
431
+
432
+	if (S_ISLNK(file->mode))
433
+		return;
434
+
435
+	type = SMB_ACL_TYPE_ACCESS;
436
+	racl_list = &access_acl_list;
437
+	do {
438
+		char tag = read_byte(f);
439
+		int ndx;
440
+
441
+		if (tag == 'A' || tag == 'a') {
442
+			if (type != SMB_ACL_TYPE_ACCESS) {
443
+				rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
444
+					f_name(file, NULL));
445
+				exit_cleanup(RERR_STREAMIO);
446
+			}
447
+		} else if (tag == 'D' || tag == 'd') {
448
+			if (type == SMB_ACL_TYPE_ACCESS) {
449
+				rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
450
+					f_name(file, NULL));
451
+				exit_cleanup(RERR_STREAMIO);
452
+			}
453
+		} else {
454
+			rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
455
+				f_name(file, NULL), tag);
456
+			exit_cleanup(RERR_STREAMIO);
457
+		}
458
+		if (tag == 'A' || tag == 'D') {
459
+			acl_duo *duo_item;
460
+			ndx = racl_list->count;
461
+			duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
462
+			duo_item->racl = empty_rsync_acl;
463
+			old_recv_rsync_acl(&duo_item->racl, f);
464
+			duo_item->sacl = NULL;
465
+		} else {
466
+			ndx = read_int(f);
467
+			if (ndx < 0 || (size_t)ndx >= racl_list->count) {
468
+				rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
469
+					f_name(file, NULL), str_acl_type(type), ndx);
470
+				exit_cleanup(RERR_STREAMIO);
471
+			}
472
+		}
473
+		if (type == SMB_ACL_TYPE_ACCESS)
474
+			F_ACL(file) = ndx;
475
+		else
476
+			F_DIR_DEFACL(file) = ndx;
477
+		racl_list = &default_acl_list;
478
+	} while (BUMP_TYPE(type) && S_ISDIR(file->mode));
479
+}
480
+
481
 /* === Receive functions === */
482
 
483
 static uint32 recv_acl_access(int f, uchar *name_follows_ptr)
484
@@ -779,10 +1146,58 @@ static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode
485
 	return ndx;
486
 }
487
 
488
+
489
+static int recv_nfs4_acl(int f, item_list *nfs4_acl_list, struct file_struct *file __unused)
490
+{
491
+	nfs4_duo *duo_item;
492
+	int ndx = read_varint(f);
493
+
494
+	if (ndx < 0 || (size_t)ndx > nfs4_acl_list->count) {
495
+		rprintf(FERROR_XFER, "recv_nfs4_index: %s ACL index %d > %d\n",
496
+			str_acl_type(SMB_ACL_TYPE_NFS4), ndx, (int)nfs4_acl_list->count);
497
+		exit_cleanup(RERR_STREAMIO);
498
+	}
499
+
500
+	if (ndx != 0)
501
+		return ndx - 1;
502
+
503
+	ndx = nfs4_acl_list->count;
504
+	duo_item = EXPAND_ITEM_LIST(nfs4_acl_list, nfs4_duo, 1000);
505
+	duo_item->nacl = empty_nfs4_acl;
506
+
507
+	duo_item->nacl.nfs4_acl_len = read_varint(f);
508
+	duo_item->nacl.nfs4_acl_text = new_array(char, duo_item->nacl.nfs4_acl_len + 1);
509
+	if (!duo_item->nacl.nfs4_acl_text)
510
+		out_of_memory("recv_nfs4_acl");
511
+
512
+	read_buf(f, duo_item->nacl.nfs4_acl_text, duo_item->nacl.nfs4_acl_len);
513
+	duo_item->nacl.nfs4_acl_text[duo_item->nacl.nfs4_acl_len] = 0;
514
+
515
+	duo_item->sacl = NULL;
516
+	return ndx;
517
+}
518
+
519
+
520
 /* Receive the ACL info the sender has included for this file-list entry. */
521
 void receive_acl(int f, struct file_struct *file)
522
 {
523
-	F_ACL(file) = recv_rsync_acl(f, &access_acl_list, SMB_ACL_TYPE_ACCESS, file->mode);
524
+	int ndx;
525
+	SMB_ACL_TYPE_T type;
526
+
527
+	if (protocol_version < 30) {
528
+		old_recv_acl(file, f);
529
+		return;
530
+	}
531
+
532
+	type = read_varint(f);
533
+	if (type == SMB_ACL_TYPE_NFS4){
534
+		ndx = recv_nfs4_acl(f, &nfs4_acl_list, file);
535
+		F_ACL(file) = ndx;
536
+		return;
537
+	}
538
+
539
+	ndx = recv_rsync_acl(f, &access_acl_list, SMB_ACL_TYPE_ACCESS, file->mode);
540
+	F_ACL(file) = ndx;
541
 
542
 	if (S_ISDIR(file->mode))
543
 		F_DIR_DEFACL(file) = recv_rsync_acl(f, &default_acl_list, SMB_ACL_TYPE_DEFAULT, 0);
544
@@ -806,10 +1221,37 @@ static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl
545
 	return ndx;
546
 }
547
 
548
+static int cache_nfs4_acl(nfs4_acl *nacl, item_list *nfs4_list)
549
+{
550
+	int ndx;
551
+
552
+	if (!nacl)
553
+		ndx = -1;
554
+	else if ((ndx = find_matching_nfs4_acl(nacl, nfs4_list)) == -1) {
555
+		nfs4_duo *new_duo;
556
+		ndx = nfs4_list->count;
557
+		new_duo = EXPAND_ITEM_LIST(nfs4_list, nfs4_duo, 1000);
558
+		new_duo->nacl = *nacl;
559
+		new_duo->sacl = NULL;
560
+		*nacl = empty_nfs4_acl;
561
+	}
562
+
563
+	return ndx;
564
+}
565
+
566
+
567
 /* Turn the ACL data in stat_x into cached ACL data, setting the index
568
  * values in the file struct. */
569
 void cache_tmp_acl(struct file_struct *file, stat_x *sxp)
570
 {
571
+	if (sxp->brand == SMB_ACL_BRAND_NFS4) {
572
+		if (prior_nfs4_count == (size_t)-1)
573
+			prior_nfs4_count = nfs4_acl_list.count;
574
+
575
+		F_ACL(file) = cache_nfs4_acl(sxp->nfs4_acl, &nfs4_acl_list);
576
+		return;
577
+	}
578
+
579
 	if (prior_access_count == (size_t)-1)
580
 		prior_access_count = access_acl_list.count;
581
 
582
@@ -837,6 +1279,21 @@ static void uncache_duo_acls(item_list *duo_list, size_t start)
583
 	}
584
 }
585
 
586
+static void uncache_nfs4_acls(item_list *nfs4_list, size_t start)
587
+{
588
+	nfs4_duo *nfs4_item = nfs4_list->items;
589
+	nfs4_duo *nfs4_start = nfs4_item + start;
590
+
591
+	nfs4_item += nfs4_list->count;
592
+	nfs4_list->count = start;
593
+
594
+	while (nfs4_item-- > nfs4_start) {
595
+		nfs4_acl_free(&nfs4_item->nacl);
596
+		if (nfs4_item->sacl)
597
+			sys_acl_free_acl(nfs4_item->sacl);
598
+	}
599
+}
600
+
601
 void uncache_tmp_acls(void)
602
 {
603
 	if (prior_access_count != (size_t)-1) {
604
@@ -848,6 +1305,10 @@ void uncache_tmp_acls(void)
605
 		uncache_duo_acls(&default_acl_list, prior_default_count);
606
 		prior_default_count = (size_t)-1;
607
 	}
608
+	if (prior_nfs4_count != (size_t)-1) {
609
+		uncache_nfs4_acls(&nfs4_acl_list, prior_nfs4_count);
610
+		prior_nfs4_count = (size_t)-1;
611
+	}
612
 }
613
 
614
 #ifndef HAVE_OSX_ACLS
615
@@ -999,6 +1460,7 @@ static int set_rsync_acl(const char *fname, acl_duo *duo_item,
616
 	return 0;
617
 }
618
 
619
+
620
 /* Given a fname, this sets extended access ACL entries, the default ACL (for a
621
  * dir), and the regular mode bits on the file.  Call this with fname set to
622
  * NULL to just check if the ACL is different.
623
@@ -1018,6 +1480,32 @@ int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode
624
 		return -1;
625
 	}
626
 
627
+	if (sxp->brand == SMB_ACL_BRAND_NFS4) {
628
+		ndx = F_ACL(file);
629
+		if (ndx >= 0 && (size_t)ndx < nfs4_acl_list.count) {
630
+			nfs4_duo *duo_item = nfs4_acl_list.items;
631
+			duo_item += ndx;
632
+			changed = 1;
633
+
634
+			if (!duo_item->sacl) {
635
+				duo_item->sacl = acl_from_text(duo_item->nacl.nfs4_acl_text);
636
+				if (!duo_item->sacl)
637
+					return -1;
638
+			}
639
+
640
+			if (!dry_run && fname) {
641
+				if (sys_acl_set_file(fname, SMB_ACL_TYPE_NFS4, duo_item->sacl) < 0) {
642
+					rsyserr(FERROR_XFER, errno, "set_acl: sys_acl_set_file(%s, %s)",
643
+						fname, str_acl_type(SMB_ACL_TYPE_NFS4));
644
+					return -1;
645
+				}
646
+
647
+				return changed;
648
+			}
649
+		}
650
+	}
651
+
652
+
653
 	ndx = F_ACL(file);
654
 	if (ndx >= 0 && (size_t)ndx < access_acl_list.count) {
655
 		acl_duo *duo_item = access_acl_list.items;
656
diff --git a/hlink.c b/hlink.c
657
index adec89b0..8d3982b2 100644
658
--- a/hlink.c
659
+++ b/hlink.c
660
@@ -422,7 +422,9 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
661
 				else {
662
 					sxp->acc_acl = alt_sx.acc_acl;
663
 					sxp->def_acl = alt_sx.def_acl;
664
+					sxp->nfs4_acl = alt_sx.nfs4_acl;
665
 					alt_sx.acc_acl = alt_sx.def_acl = NULL;
666
+					alt_sx.nfs4_acl = NULL;
667
 				}
668
 			}
669
 #endif
670
diff --git a/ifuncs.h b/ifuncs.h
671
index 4037639b..fd3afb61 100644
672
--- a/ifuncs.h
673
+++ b/ifuncs.h
674
@@ -77,6 +77,7 @@ init_stat_x(stat_x *sx_p)
675
 {
676
 #ifdef SUPPORT_ACLS
677
 	sx_p->acc_acl = sx_p->def_acl = NULL;
678
+	sx_p->nfs4_acl = NULL;
679
 #endif
680
 #ifdef SUPPORT_XATTRS
681
 	sx_p->xattr = NULL;
682
diff --git a/lib/sysacls.c b/lib/sysacls.c
683
index c23864fe..f049fbad 100644
684
--- a/lib/sysacls.c
685
+++ b/lib/sysacls.c
686
@@ -80,12 +80,36 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
687
 	return acl_get_file(path_p, type);
688
 }
689
 
690
-#if 0
691
 SMB_ACL_T sys_acl_get_fd(int fd)
692
 {
693
 	return acl_get_fd(fd);
694
 }
695
-#endif
696
+
697
+int sys_acl_get_brand( SMB_ACL_T the_acl, int *brand_p)
698
+{
699
+	return acl_get_brand_np(the_acl, brand_p);
700
+}
701
+
702
+int sys_acl_get_brand_file( const char *path_p, int *brand_p)
703
+{
704
+	int fd;
705
+	acl_t acl;
706
+
707
+	if ((fd = open(path_p, O_RDONLY|O_NONBLOCK)) < 0)
708
+		return -1;
709
+	if ((acl = acl_get_fd(fd)) == NULL) {
710
+		close(fd);
711
+		return -1;
712
+	}
713
+	close(fd);
714
+	if (acl_get_brand_np(acl, brand_p) < 0) {
715
+		acl_free(acl);
716
+		return -1;
717
+	}
718
+
719
+	acl_free(acl);
720
+	return 0;
721
+}
722
 
723
 #if defined(HAVE_ACL_GET_PERM_NP)
724
 #define acl_get_perm(p, b) acl_get_perm_np(p, b)
725
diff --git a/lib/sysacls.h b/lib/sysacls.h
726
index 8865dae4..76a6e31f 100644
727
--- a/lib/sysacls.h
728
+++ b/lib/sysacls.h
729
@@ -48,6 +48,7 @@
730
 #define SMB_ACL_GROUP_OBJ	ACL_GROUP_OBJ
731
 #define SMB_ACL_OTHER		ACL_OTHER
732
 #define SMB_ACL_MASK		ACL_MASK
733
+#define SMB_ACL_EVERYONE	ACL_EVERYONE
734
 
735
 #define SMB_ACL_T		acl_t
736
 
737
@@ -58,6 +59,11 @@
738
 
739
 #define SMB_ACL_TYPE_ACCESS	ACL_TYPE_ACCESS
740
 #define SMB_ACL_TYPE_DEFAULT	ACL_TYPE_DEFAULT
741
+#define	SMB_ACL_TYPE_NFS4	ACL_TYPE_NFS4
742
+
743
+#define	SMB_ACL_BRAND_UNKNOWN	ACL_BRAND_UNKNOWN
744
+#define	SMB_ACL_BRAND_POSIX	ACL_BRAND_POSIX
745
+#define	SMB_ACL_BRAND_NFS4	ACL_BRAND_NFS4
746
 
747
 #define SMB_ACL_VALID_NAME_BITS	(4 | 2 | 1)
748
 #define SMB_ACL_VALID_OBJ_BITS	(4 | 2 | 1)
749
@@ -294,6 +300,8 @@ int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *b
750
 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type);
751
 SMB_ACL_T sys_acl_get_fd(int fd);
752
 SMB_ACL_T sys_acl_init(int count);
753
+int sys_acl_get_brand( SMB_ACL_T the_acl, int *brand_p);
754
+int sys_acl_get_brand_file( const char *path_p, int *brand_p);
755
 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry);
756
 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype, uint32 bits, id_t u_g_id);
757
 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits);
758
diff --git a/rsync.c b/rsync.c
759
index e7f1f96a..41818ea4 100644
760
--- a/rsync.c
761
+++ b/rsync.c
762
@@ -627,19 +627,6 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
763
 	}
764
 #endif
765
 
766
-#ifdef SUPPORT_ACLS
767
-	/* It's OK to call set_acl() now, even for a dir, as the generator
768
-	 * will enable owner-writability using chmod, if necessary.
769
-	 * 
770
-	 * If set_acl() changes permission bits in the process of setting
771
-	 * an access ACL, it changes sxp->st.st_mode so we know whether we
772
-	 * need to chmod(). */
773
-	if (preserve_acls && !S_ISLNK(new_mode)) {
774
-		if (set_acl(fname, file, sxp, new_mode) > 0)
775
-			updated |= UPDATED_ACLS;
776
-	}
777
-#endif
778
-
779
 #ifdef HAVE_CHMOD
780
 	if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
781
 		int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
782
@@ -654,6 +641,19 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
783
 	}
784
 #endif
785
 
786
+#ifdef SUPPORT_ACLS
787
+	/* It's OK to call set_acl() now, even for a dir, as the generator
788
+	 * will enable owner-writability using chmod, if necessary.
789
+	 *
790
+	 * If set_acl() changes permission bits in the process of setting
791
+	 * an access ACL, it changes sxp->st.st_mode so we know whether we
792
+	 * need to chmod(). */
793
+	if (preserve_acls && !S_ISLNK(new_mode)) {
794
+		if (set_acl(fname, file, sxp, new_mode) > 0)
795
+			updated |= UPDATED_ACLS;
796
+	}
797
+#endif
798
+
799
 	if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) {
800
 		if (updated)
801
 			rprintf(FCLIENT, "%s\n", fname);
802
diff --git a/rsync.h b/rsync.h
803
index 0f5304ee..45dd050b 100644
804
--- a/rsync.h
805
+++ b/rsync.h
806
@@ -1119,13 +1119,22 @@ typedef struct {
807
 #ifdef SUPPORT_ACLS
808
     struct rsync_acl *acc_acl; /* access ACL */
809
     struct rsync_acl *def_acl; /* default ACL */
810
+    struct nfs4_acl *nfs4_acl; /* NFSv4 ACL */
811
+    int brand;
812
 #endif
813
 #ifdef SUPPORT_XATTRS
814
     item_list *xattr;
815
 #endif
816
 } stat_x;
817
 
818
-#define ACL_READY(sx) ((sx).acc_acl != NULL)
819
+#ifdef SUPPORT_ACLS
820
+#include "lib/sysacls.h"
821
+#endif
822
+
823
+#define ACL_READY_POSIX(sx) ((sx).acc_acl != NULL)
824
+#define ACL_READY_NFS4(sx) ((sx).nfs4_acl != NULL)
825
+#define ACL_READY(sx) (((sx).brand == SMB_ACL_BRAND_NFS4) ? (ACL_READY_NFS4(sx)) : (ACL_READY_POSIX(sx)))
826
+
827
 #define XATTR_READY(sx) ((sx).xattr != NULL)
828
 
829
 #define CLVL_NOT_SPECIFIED INT_MIN

Return to bug 249119