1To use this patch, run these commands for a successful build:
2
3    patch -p1 <patches/acls.diff
4    ./prepare-source
5    ./configure --enable-acl-support
6    make
7
8See the --acls (-A) option in the revised man page for a note on using this
9latest ACL-enabling patch to send files to an older ACL-enabled rsync.
10
11--- old/Makefile.in
12+++ new/Makefile.in
13@@ -26,15 +26,15 @@ VERSION=@VERSION@
14 .SUFFIXES:
15 .SUFFIXES: .c .o
16 
17-HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h
18+HEADERS=byteorder.h config.h errcode.h proto.h rsync.h smb_acls.h lib/pool_alloc.h
19 LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
20-	lib/permstring.o lib/pool_alloc.o @LIBOBJS@
21+	lib/permstring.o lib/pool_alloc.o lib/sysacls.o @LIBOBJS@
22 ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
23 	zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
24 OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \
25 	main.o checksum.o match.o syscall.o log.o backup.o
26 OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
27-	fileio.o batch.o clientname.o chmod.o
28+	fileio.o batch.o clientname.o chmod.o acls.o
29 OBJS3=progress.o pipe.o
30 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
31 popt_OBJS=popt/findme.o  popt/popt.o  popt/poptconfig.o \
32--- old/acls.c
33+++ new/acls.c
34@@ -0,0 +1,1098 @@
35+/*
36+ * Handle passing Access Control Lists between systems.
37+ *
38+ * Copyright (C) 1996 Andrew Tridgell
39+ * Copyright (C) 1996 Paul Mackerras
40+ * Copyright (C) 2006 Wayne Davison
41+ *
42+ * This program is free software; you can redistribute it and/or modify
43+ * it under the terms of the GNU General Public License as published by
44+ * the Free Software Foundation; either version 2 of the License, or
45+ * (at your option) any later version.
46+ *
47+ * This program is distributed in the hope that it will be useful,
48+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
49+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
50+ * GNU General Public License for more details.
51+ *
52+ * You should have received a copy of the GNU General Public License along
53+ * with this program; if not, write to the Free Software Foundation, Inc.,
54+ * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
55+ */
56+
57+#include "rsync.h"
58+#include "lib/sysacls.h"
59+
60+#ifdef SUPPORT_ACLS
61+
62+extern int dry_run;
63+extern int read_only;
64+extern int list_only;
65+extern int orig_umask;
66+extern int preserve_acls;
67+extern unsigned int file_struct_len;
68+
69+/* === ACL structures === */
70+
71+typedef struct {
72+	id_t id;
73+	uchar access;
74+} id_access;
75+
76+typedef struct {
77+	id_access *idas;
78+	int count;
79+} ida_entries;
80+
81+#define NO_ENTRY ((uchar)0x80)
82+typedef struct rsync_acl {
83+	ida_entries users;
84+	ida_entries groups;
85+	/* These will be NO_ENTRY if there's no such entry. */
86+	uchar user_obj;
87+	uchar group_obj;
88+	uchar mask;
89+	uchar other;
90+} rsync_acl;
91+
92+typedef struct {
93+	rsync_acl racl;
94+	SMB_ACL_T sacl;
95+} acl_duo;
96+
97+static const rsync_acl empty_rsync_acl = {
98+	{NULL, 0}, {NULL, 0}, NO_ENTRY, NO_ENTRY, NO_ENTRY, NO_ENTRY
99+};
100+
101+static item_list access_acl_list = EMPTY_ITEM_LIST;
102+static item_list default_acl_list = EMPTY_ITEM_LIST;
103+
104+/* === Calculations on ACL types === */
105+
106+static const char *str_acl_type(SMB_ACL_TYPE_T type)
107+{
108+	return type == SMB_ACL_TYPE_ACCESS ? "SMB_ACL_TYPE_ACCESS"
109+	     : type == SMB_ACL_TYPE_DEFAULT ? "SMB_ACL_TYPE_DEFAULT"
110+	     : "unknown SMB_ACL_TYPE_T";
111+}
112+
113+#define OTHER_TYPE(t) (SMB_ACL_TYPE_ACCESS+SMB_ACL_TYPE_DEFAULT-(t))
114+#define BUMP_TYPE(t) ((t = OTHER_TYPE(t)) == SMB_ACL_TYPE_DEFAULT)
115+
116+static int count_racl_entries(const rsync_acl *racl)
117+{
118+	return racl->users.count + racl->groups.count
119+	     + (racl->user_obj != NO_ENTRY)
120+	     + (racl->group_obj != NO_ENTRY)
121+	     + (racl->mask != NO_ENTRY)
122+	     + (racl->other != NO_ENTRY);
123+}
124+
125+static int calc_sacl_entries(const rsync_acl *racl)
126+{
127+	/* A System ACL always gets user/group/other permission entries. */
128+	return racl->users.count + racl->groups.count
129+#ifdef ACLS_NEED_MASK
130+	     + 4;
131+#else
132+	     + (racl->mask != NO_ENTRY) + 3;
133+#endif
134+}
135+
136+/* Extracts and returns the permission bits from the ACL.  This cannot be
137+ * called on an rsync_acl that has NO_ENTRY in any spot but the mask. */
138+static int rsync_acl_get_perms(const rsync_acl *racl)
139+{
140+	return (racl->user_obj << 6)
141+	     + ((racl->mask != NO_ENTRY ? racl->mask : racl->group_obj) << 3)
142+	     + racl->other;
143+}
144+
145+/* Removes the permission-bit entries from the ACL because these
146+ * can be reconstructed from the file's mode. */
147+static void rsync_acl_strip_perms(rsync_acl *racl)
148+{
149+	racl->user_obj = NO_ENTRY;
150+	if (racl->mask == NO_ENTRY)
151+		racl->group_obj = NO_ENTRY;
152+	else {
153+		if (racl->group_obj == racl->mask)
154+			racl->group_obj = NO_ENTRY;
155+		racl->mask = NO_ENTRY;
156+	}
157+	racl->other = NO_ENTRY;
158+}
159+
160+/* Given an empty rsync_acl, fake up the permission bits. */
161+static void rsync_acl_fake_perms(rsync_acl *racl, mode_t mode)
162+{
163+	racl->user_obj = (mode >> 6) & 7;
164+	racl->group_obj = (mode >> 3) & 7;
165+	racl->other = mode & 7;
166+}
167+
168+/* === Rsync ACL functions === */
169+
170+static BOOL ida_entries_equal(const ida_entries *ial1, const ida_entries *ial2)
171+{
172+	id_access *ida1, *ida2;
173+	int count = ial1->count;
174+	if (count != ial2->count)
175+		return False;
176+	ida1 = ial1->idas;
177+	ida2 = ial2->idas;
178+	for (; count--; ida1++, ida2++) {
179+		if (ida1->access != ida2->access || ida1->id != ida2->id)
180+			return False;
181+	}
182+	return True;
183+}
184+
185+static BOOL rsync_acl_equal(const rsync_acl *racl1, const rsync_acl *racl2)
186+{
187+	return racl1->user_obj == racl2->user_obj
188+	    && racl1->group_obj == racl2->group_obj
189+	    && racl1->mask == racl2->mask
190+	    && racl1->other == racl2->other
191+	    && ida_entries_equal(&racl1->users, &racl2->users)
192+	    && ida_entries_equal(&racl1->groups, &racl2->groups);
193+}
194+
195+/* Are the extended (non-permission-bit) entries equal?  If so, the rest of
196+ * the ACL will be handled by the normal mode-preservation code.  This is
197+ * only meaningful for access ACLs!  Note: the 1st arg is a fully-populated
198+ * rsync_acl, but the 2nd parameter can be a condensed rsync_acl, which means
199+ * that it might have several of its permission objects set to NO_ENTRY. */
200+static BOOL rsync_acl_equal_enough(const rsync_acl *racl1,
201+				   const rsync_acl *racl2, mode_t m)
202+{
203+	if ((racl1->mask ^ racl2->mask) & NO_ENTRY)
204+		return False; /* One has a mask and the other doesn't */
205+
206+	/* When there's a mask, the group_obj becomes an extended entry. */
207+	if (racl1->mask != NO_ENTRY) {
208+		/* A condensed rsync_acl with a mask can only have no
209+		 * group_obj when it was identical to the mask.  This
210+		 * means that it was also identical to the group attrs
211+		 * from the mode. */
212+		if (racl2->group_obj == NO_ENTRY) {
213+			if (racl1->group_obj != ((m >> 3) & 7))
214+				return False;
215+		} else if (racl1->group_obj != racl2->group_obj)
216+			return False;
217+	}
218+	return ida_entries_equal(&racl1->users, &racl2->users)
219+	    && ida_entries_equal(&racl1->groups, &racl2->groups);
220+}
221+
222+static void rsync_acl_free(rsync_acl *racl)
223+{
224+	if (racl->users.idas)
225+		free(racl->users.idas);
226+	if (racl->groups.idas)
227+		free(racl->groups.idas);
228+	*racl = empty_rsync_acl;
229+}
230+
231+void free_acl(statx *sxp)
232+{
233+	if (sxp->acc_acl) {
234+		rsync_acl_free(sxp->acc_acl);
235+		free(sxp->acc_acl);
236+		sxp->acc_acl = NULL;
237+	}
238+	if (sxp->def_acl) {
239+		rsync_acl_free(sxp->def_acl);
240+		free(sxp->def_acl);
241+		sxp->def_acl = NULL;
242+	}
243+}
244+
245+static int id_access_sorter(const void *r1, const void *r2)
246+{
247+	id_access *ida1 = (id_access *)r1;
248+	id_access *ida2 = (id_access *)r2;
249+	id_t rid1 = ida1->id, rid2 = ida2->id;
250+	return rid1 == rid2 ? 0 : rid1 < rid2 ? -1 : 1;
251+}
252+
253+static void sort_ida_entries(ida_entries *idal)
254+{
255+	if (!idal->count)
256+		return;
257+	qsort(idal->idas, idal->count, sizeof idal->idas[0], id_access_sorter);
258+}
259+
260+/* Transfer the count id_access items out of the temp_ida_list into either
261+ * the users or groups ida_entries list in racl. */
262+static void save_idas(item_list *temp_ida_list, rsync_acl *racl, SMB_ACL_TAG_T type)
263+{
264+	id_access *idas;
265+	ida_entries *ent;
266+
267+	if (temp_ida_list->count) {
268+		int cnt = temp_ida_list->count;
269+		id_access *temp_idas = temp_ida_list->items;
270+		if (!(idas = new_array(id_access, cnt)))
271+			out_of_memory("save_idas");
272+		memcpy(idas, temp_idas, cnt * sizeof *temp_idas);
273+	} else
274+		idas = NULL;
275+
276+	ent = type == SMB_ACL_USER ? &racl->users : &racl->groups;
277+
278+	if (ent->count) {
279+		rprintf(FERROR, "save_idas: disjoint list found for type %d\n", type);
280+		exit_cleanup(RERR_UNSUPPORTED);
281+	}
282+	ent->count = temp_ida_list->count;
283+	ent->idas = idas;
284+
285+	/* Truncate the temporary list now that its idas have been saved. */
286+	temp_ida_list->count = 0;
287+}
288+
289+/* === System ACLs === */
290+
291+/* Unpack system ACL -> rsync ACL verbatim.  Return whether we succeeded. */
292+static BOOL unpack_smb_acl(rsync_acl *racl, SMB_ACL_T sacl)
293+{
294+	static item_list temp_ida_list = EMPTY_ITEM_LIST;
295+	SMB_ACL_TAG_T prior_list_type = 0;
296+	SMB_ACL_ENTRY_T entry;
297+	const char *errfun;
298+	int rc;
299+
300+	errfun = "sys_acl_get_entry";
301+	for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
302+	     rc == 1;
303+	     rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
304+		SMB_ACL_TAG_T tag_type;
305+		SMB_ACL_PERMSET_T permset;
306+		uchar access;
307+		void *qualifier;
308+		id_access *ida;
309+		if ((rc = sys_acl_get_tag_type(entry, &tag_type))) {
310+			errfun = "sys_acl_get_tag_type";
311+			break;
312+		}
313+		if ((rc = sys_acl_get_permset(entry, &permset))) {
314+			errfun = "sys_acl_get_tag_type";
315+			break;
316+		}
317+		access = (sys_acl_get_perm(permset, SMB_ACL_READ) ? 4 : 0)
318+		       | (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? 2 : 0)
319+		       | (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? 1 : 0);
320+		/* continue == done with entry; break == store in temporary ida list */
321+		switch (tag_type) {
322+		case SMB_ACL_USER_OBJ:
323+			if (racl->user_obj == NO_ENTRY)
324+				racl->user_obj = access;
325+			else
326+				rprintf(FINFO, "unpack_smb_acl: warning: duplicate USER_OBJ entry ignored\n");
327+			continue;
328+		case SMB_ACL_USER:
329+			break;
330+		case SMB_ACL_GROUP_OBJ:
331+			if (racl->group_obj == NO_ENTRY)
332+				racl->group_obj = access;
333+			else
334+				rprintf(FINFO, "unpack_smb_acl: warning: duplicate GROUP_OBJ entry ignored\n");
335+			continue;
336+		case SMB_ACL_GROUP:
337+			break;
338+		case SMB_ACL_MASK:
339+			if (racl->mask == NO_ENTRY)
340+				racl->mask = access;
341+			else
342+				rprintf(FINFO, "unpack_smb_acl: warning: duplicate MASK entry ignored\n");
343+			continue;
344+		case SMB_ACL_OTHER:
345+			if (racl->other == NO_ENTRY)
346+				racl->other = access;
347+			else
348+				rprintf(FINFO, "unpack_smb_acl: warning: duplicate OTHER entry ignored\n");
349+			continue;
350+		default:
351+			rprintf(FINFO, "unpack_smb_acl: warning: entry with unrecognized tag type ignored\n");
352+			continue;
353+		}
354+		if (!(qualifier = sys_acl_get_qualifier(entry))) {
355+			errfun = "sys_acl_get_tag_type";
356+			rc = EINVAL;
357+			break;
358+		}
359+		if (tag_type != prior_list_type) {
360+			if (prior_list_type)
361+				save_idas(&temp_ida_list, racl, prior_list_type);
362+			prior_list_type = tag_type;
363+		}
364+		ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
365+		ida->id = *((id_t *)qualifier);
366+		ida->access = access;
367+		sys_acl_free_qualifier(qualifier, tag_type);
368+	}
369+	if (rc) {
370+		rsyserr(FERROR, errno, "unpack_smb_acl: %s()", errfun);
371+		rsync_acl_free(racl);
372+		return False;
373+	}
374+	if (prior_list_type)
375+		save_idas(&temp_ida_list, racl, prior_list_type);
376+
377+	sort_ida_entries(&racl->users);
378+	sort_ida_entries(&racl->groups);
379+
380+#ifdef ACLS_NEED_MASK
381+	if (!racl->users.count && !racl->groups.count && racl->mask != NO_ENTRY) {
382+		/* Throw away a superfluous mask, but mask off the
383+		 * group perms with it first. */
384+		racl->group_obj &= racl->mask;
385+		racl->mask = NO_ENTRY;
386+	}
387+#endif
388+
389+	return True;
390+}
391+
392+/* Synactic sugar for system calls */
393+
394+#define CALL_OR_ERROR(func,args,str) \
395+	do { \
396+		if (func args) { \
397+			errfun = str; \
398+			goto error_exit; \
399+		} \
400+	} while (0)
401+
402+#define COE(func,args) CALL_OR_ERROR(func,args,#func)
403+#define COE2(func,args) CALL_OR_ERROR(func,args,NULL)
404+
405+/* Store the permissions in the system ACL entry. */
406+static int store_access_in_entry(uchar access, SMB_ACL_ENTRY_T entry)
407+{
408+	const char *errfun = NULL;
409+	SMB_ACL_PERMSET_T permset;
410+
411+	COE( sys_acl_get_permset,(entry, &permset) );
412+	COE( sys_acl_clear_perms,(permset) );
413+	if (access & 4)
414+		COE( sys_acl_add_perm,(permset, SMB_ACL_READ) );
415+	if (access & 2)
416+		COE( sys_acl_add_perm,(permset, SMB_ACL_WRITE) );
417+	if (access & 1)
418+		COE( sys_acl_add_perm,(permset, SMB_ACL_EXECUTE) );
419+	COE( sys_acl_set_permset,(entry, permset) );
420+
421+	return 0;
422+
423+  error_exit:
424+	rsyserr(FERROR, errno, "store_access_in_entry %s()", errfun);
425+	return -1;
426+}
427+
428+/* Pack rsync ACL -> system ACL verbatim.  Return whether we succeeded. */
429+static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsync_acl *racl)
430+{
431+#ifdef ACLS_NEED_MASK
432+	uchar mask_bits;
433+#endif
434+	size_t count;
435+	id_access *ida;
436+	const char *errfun = NULL;
437+	SMB_ACL_ENTRY_T entry;
438+
439+	if (!(*smb_acl = sys_acl_init(calc_sacl_entries(racl)))) {
440+		rsyserr(FERROR, errno, "pack_smb_acl: sys_acl_init()");
441+		return False;
442+	}
443+
444+	COE( sys_acl_create_entry,(smb_acl, &entry) );
445+	COE( sys_acl_set_tag_type,(entry, SMB_ACL_USER_OBJ) );
446+	COE2( store_access_in_entry,(racl->user_obj & 7, entry) );
447+
448+	for (ida = racl->users.idas, count = racl->users.count; count--; ida++) {
449+		COE( sys_acl_create_entry,(smb_acl, &entry) );
450+		COE( sys_acl_set_tag_type,(entry, SMB_ACL_USER) );
451+		COE( sys_acl_set_qualifier,(entry, (void*)&ida->id) );
452+		COE2( store_access_in_entry,(ida->access, entry) );
453+	}
454+
455+	COE( sys_acl_create_entry,(smb_acl, &entry) );
456+	COE( sys_acl_set_tag_type,(entry, SMB_ACL_GROUP_OBJ) );
457+	COE2( store_access_in_entry,(racl->group_obj & 7, entry) );
458+
459+	for (ida = racl->groups.idas, count = racl->groups.count; count--; ida++) {
460+		COE( sys_acl_create_entry,(smb_acl, &entry) );
461+		COE( sys_acl_set_tag_type,(entry, SMB_ACL_GROUP) );
462+		COE( sys_acl_set_qualifier,(entry, (void*)&ida->id) );
463+		COE2( store_access_in_entry,(ida->access, entry) );
464+	}
465+
466+#ifdef ACLS_NEED_MASK
467+	mask_bits = racl->mask == NO_ENTRY ? racl->group_obj & 7 : racl->mask;
468+	COE( sys_acl_create_entry,(smb_acl, &entry) );
469+	COE( sys_acl_set_tag_type,(entry, SMB_ACL_MASK) );
470+	COE2( store_access_in_entry,(mask_bits, entry) );
471+#else
472+	if (racl->mask != NO_ENTRY) {
473+		COE( sys_acl_create_entry,(smb_acl, &entry) );
474+		COE( sys_acl_set_tag_type,(entry, SMB_ACL_MASK) );
475+		COE2( store_access_in_entry,(racl->mask, entry) );
476+	}
477+#endif
478+
479+	COE( sys_acl_create_entry,(smb_acl, &entry) );
480+	COE( sys_acl_set_tag_type,(entry, SMB_ACL_OTHER) );
481+	COE2( store_access_in_entry,(racl->other & 7, entry) );
482+
483+#ifdef DEBUG
484+	if (sys_acl_valid(*smb_acl) < 0)
485+		rprintf(FERROR, "pack_smb_acl: warning: system says the ACL I packed is invalid\n");
486+#endif
487+
488+	return True;
489+
490+  error_exit:
491+	if (errfun) {
492+		rsyserr(FERROR, errno, "pack_smb_acl %s()", errfun);
493+	}
494+	sys_acl_free_acl(*smb_acl);
495+	return False;
496+}
497+
498+static int find_matching_rsync_acl(SMB_ACL_TYPE_T type,
499+				   const item_list *racl_list,
500+				   const rsync_acl *racl)
501+{
502+	static int access_match = -1, default_match = -1;
503+	int *match = type == SMB_ACL_TYPE_ACCESS ? &access_match : &default_match;
504+	size_t count = racl_list->count;
505+
506+	/* If this is the first time through or we didn't match the last
507+	 * time, then start at the end of the list, which should be the
508+	 * best place to start hunting. */
509+	if (*match == -1)
510+		*match = racl_list->count - 1;
511+	while (count--) {
512+		rsync_acl *base = racl_list->items;
513+		if (rsync_acl_equal(base + *match, racl))
514+			return *match;
515+		if (!(*match)--)
516+			*match = racl_list->count - 1;
517+	}
518+
519+	*match = -1;
520+	return *match;
521+}
522+
523+/* Return the Access Control List for the given filename. */
524+int get_acl(const char *fname, statx *sxp)
525+{
526+	SMB_ACL_TYPE_T type;
527+
528+	if (S_ISLNK(sxp->st.st_mode))
529+		return 0;
530+
531+	type = SMB_ACL_TYPE_ACCESS;
532+	do {
533+		SMB_ACL_T sacl = sys_acl_get_file(fname, type);
534+		rsync_acl *racl = new(rsync_acl);
535+
536+		if (!racl)
537+			out_of_memory("get_acl");
538+		*racl = empty_rsync_acl;
539+		if (type == SMB_ACL_TYPE_ACCESS)
540+			sxp->acc_acl = racl;
541+		else
542+			sxp->def_acl = racl;
543+
544+		if (sacl) {
545+			BOOL ok = unpack_smb_acl(racl, sacl);
546+
547+			sys_acl_free_acl(sacl);
548+			if (!ok) {
549+				free_acl(sxp);
550+				return -1;
551+			}
552+		} else if (errno == ENOTSUP) {
553+			/* ACLs are not supported, so pretend we have a basic ACL. */
554+			if (type == SMB_ACL_TYPE_ACCESS)
555+				rsync_acl_fake_perms(racl, sxp->st.st_mode);
556+		} else {
557+			rsyserr(FERROR, errno, "get_acl: sys_acl_get_file(%s, %s)",
558+				fname, str_acl_type(type));
559+			free_acl(sxp);
560+			return -1;
561+		}
562+	} while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
563+
564+	return 0;
565+}
566+
567+/* === Send functions === */
568+
569+/* The general strategy with the tag_type <-> character mapping is that
570+ * lowercase implies that no qualifier follows, where uppercase does.
571+ * A similar idiom for the ACL type (access or default) itself, but
572+ * lowercase in this instance means there's no ACL following, so the
573+ * ACL is a repeat, so the receiver should reuse the last of the same
574+ * type ACL. */
575+
576+/* Send the ida list over the file descriptor. */
577+static void send_ida_entries(int f, const ida_entries *idal, char tag_char)
578+{
579+	id_access *ida;
580+	size_t count = idal->count;
581+	for (ida = idal->idas; count--; ida++) {
582+		write_byte(f, tag_char);
583+		write_byte(f, ida->access);
584+		write_int(f, ida->id);
585+		/* FIXME: sorta wasteful: we should maybe buffer as
586+		 * many ids as max(ACL_USER + ACL_GROUP) objects to
587+		 * keep from making so many calls. */
588+		if (tag_char == 'U')
589+			add_uid(ida->id);
590+		else
591+			add_gid(ida->id);
592+	}
593+}
594+
595+/* Send an rsync ACL over the file descriptor. */
596+static void send_rsync_acl(int f, const rsync_acl *racl)
597+{
598+	size_t count = count_racl_entries(racl);
599+	write_int(f, count);
600+	if (racl->user_obj != NO_ENTRY) {
601+		write_byte(f, 'u');
602+		write_byte(f, racl->user_obj);
603+	}
604+	send_ida_entries(f, &racl->users, 'U');
605+	if (racl->group_obj != NO_ENTRY) {
606+		write_byte(f, 'g');
607+		write_byte(f, racl->group_obj);
608+	}
609+	send_ida_entries(f, &racl->groups, 'G');
610+	if (racl->mask != NO_ENTRY) {
611+		write_byte(f, 'm');
612+		write_byte(f, racl->mask);
613+	}
614+	if (racl->other != NO_ENTRY) {
615+		write_byte(f, 'o');
616+		write_byte(f, racl->other);
617+	}
618+}
619+
620+/* Send the ACL from the statx structure down the indicated file descriptor.
621+ * This also frees the ACL data. */
622+void send_acl(statx *sxp, int f)
623+{
624+	SMB_ACL_TYPE_T type;
625+	rsync_acl *racl, *new_racl;
626+	item_list *racl_list;
627+	int ndx;
628+
629+	if (S_ISLNK(sxp->st.st_mode))
630+		return;
631+
632+	type = SMB_ACL_TYPE_ACCESS;
633+	racl = sxp->acc_acl;
634+	racl_list = &access_acl_list;
635+	do {
636+		if (!racl) {
637+			racl = new(rsync_acl);
638+			if (!racl)
639+				out_of_memory("send_acl");
640+			*racl = empty_rsync_acl;
641+			if (type == SMB_ACL_TYPE_ACCESS) {
642+				rsync_acl_fake_perms(racl, sxp->st.st_mode);
643+				sxp->acc_acl = racl;
644+			} else
645+				sxp->def_acl = racl;
646+		}
647+
648+		/* Avoid sending values that can be inferred from other data,
649+		 * but only when preserve_acls == 1 (it is 2 when we must be
650+		 * backward compatible with older acls.diff versions). */
651+		if (type == SMB_ACL_TYPE_ACCESS && preserve_acls == 1)
652+			rsync_acl_strip_perms(racl);
653+		if ((ndx = find_matching_rsync_acl(type, racl_list, racl)) != -1) {
654+			write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
655+			write_int(f, ndx);
656+		} else {
657+			new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000);
658+			write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
659+			send_rsync_acl(f, racl);
660+			*new_racl = *racl;
661+			*racl = empty_rsync_acl;
662+		}
663+		racl = sxp->def_acl;
664+		racl_list = &default_acl_list;
665+	} while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
666+
667+	free_acl(sxp);
668+}
669+
670+/* === Receive functions === */
671+
672+static void receive_rsync_acl(rsync_acl *racl, int f, SMB_ACL_TYPE_T type)
673+{
674+	static item_list temp_ida_list = EMPTY_ITEM_LIST;
675+	SMB_ACL_TAG_T tag_type = 0, prior_list_type = 0;
676+	uchar computed_mask_bits = 0;
677+	id_access *ida;
678+	size_t count;
679+
680+	if (!(count = read_int(f)))
681+		return;
682+
683+	while (count--) {
684+		char tag = read_byte(f);
685+		uchar access = read_byte(f);
686+		if (access & ~ (4 | 2 | 1)) {
687+			rprintf(FERROR, "receive_rsync_acl: bogus permset %o\n",
688+				access);
689+			exit_cleanup(RERR_STREAMIO);
690+		}
691+		switch (tag) {
692+		case 'u':
693+			if (racl->user_obj != NO_ENTRY) {
694+				rprintf(FERROR, "receive_rsync_acl: error: duplicate USER_OBJ entry\n");
695+				exit_cleanup(RERR_STREAMIO);
696+			}
697+			racl->user_obj = access;
698+			continue;
699+		case 'U':
700+			tag_type = SMB_ACL_USER;
701+			break;
702+		case 'g':
703+			if (racl->group_obj != NO_ENTRY) {
704+				rprintf(FERROR, "receive_rsync_acl: error: duplicate GROUP_OBJ entry\n");
705+				exit_cleanup(RERR_STREAMIO);
706+			}
707+			racl->group_obj = access;
708+			continue;
709+		case 'G':
710+			tag_type = SMB_ACL_GROUP;
711+			break;
712+		case 'm':
713+			if (racl->mask != NO_ENTRY) {
714+				rprintf(FERROR, "receive_rsync_acl: error: duplicate MASK entry\n");
715+				exit_cleanup(RERR_STREAMIO);
716+			}
717+			racl->mask = access;
718+			continue;
719+		case 'o':
720+			if (racl->other != NO_ENTRY) {
721+				rprintf(FERROR, "receive_rsync_acl: error: duplicate OTHER entry\n");
722+				exit_cleanup(RERR_STREAMIO);
723+			}
724+			racl->other = access;
725+			continue;
726+		default:
727+			rprintf(FERROR, "receive_rsync_acl: unknown tag %c\n",
728+				tag);
729+			exit_cleanup(RERR_STREAMIO);
730+		}
731+		if (tag_type != prior_list_type) {
732+			if (prior_list_type)
733+				save_idas(&temp_ida_list, racl, prior_list_type);
734+			prior_list_type = tag_type;
735+		}
736+		ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
737+		ida->access = access;
738+		ida->id = read_int(f);
739+		computed_mask_bits |= access;
740+	}
741+	if (prior_list_type)
742+		save_idas(&temp_ida_list, racl, prior_list_type);
743+
744+	if (type == SMB_ACL_TYPE_DEFAULT) {
745+		/* Ensure that these are never unset. */
746+		if (racl->user_obj == NO_ENTRY)
747+			racl->user_obj = 7;
748+		if (racl->group_obj == NO_ENTRY)
749+			racl->group_obj = 0;
750+		if (racl->other == NO_ENTRY)
751+			racl->other = 0;
752+	}
753+
754+	if (!racl->users.count && !racl->groups.count) {
755+		/* If we received a superfluous mask, throw it away. */
756+		if (racl->mask != NO_ENTRY) {
757+			/* Mask off the group perms with it first. */
758+			racl->group_obj &= racl->mask | NO_ENTRY;
759+			racl->mask = NO_ENTRY;
760+		}
761+	} else if (racl->mask == NO_ENTRY) /* Must be non-empty with lists. */
762+		racl->mask = computed_mask_bits | (racl->group_obj & 7);
763+}
764+
765+/* Receive the ACL info the sender has included for this file-list entry. */
766+void receive_acl(struct file_struct *file, int f)
767+{
768+	SMB_ACL_TYPE_T type;
769+	item_list *racl_list;
770+	char *ndx_ptr;
771+
772+	if (S_ISLNK(file->mode))
773+		return;
774+
775+	type = SMB_ACL_TYPE_ACCESS;
776+	racl_list = &access_acl_list;
777+	ndx_ptr = (char*)file + file_struct_len;
778+	do {
779+		char tag = read_byte(f);
780+		int ndx;
781+
782+		if (tag == 'A' || tag == 'a') {
783+			if (type != SMB_ACL_TYPE_ACCESS) {
784+				rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
785+					f_name(file, NULL));
786+				exit_cleanup(RERR_STREAMIO);
787+			}
788+		} else if (tag == 'D' || tag == 'd') {
789+			if (type == SMB_ACL_TYPE_ACCESS) {
790+				rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
791+					f_name(file, NULL));
792+				exit_cleanup(RERR_STREAMIO);
793+			}
794+		} else {
795+			rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
796+				f_name(file, NULL), tag);
797+			exit_cleanup(RERR_STREAMIO);
798+		}
799+		if (tag == 'A' || tag == 'D') {
800+			acl_duo *duo_item;
801+			ndx = racl_list->count;
802+			duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
803+			duo_item->racl = empty_rsync_acl;
804+			receive_rsync_acl(&duo_item->racl, f, type);
805+			duo_item->sacl = NULL;
806+		} else {
807+			ndx = read_int(f);
808+			if (ndx < 0 || (size_t)ndx >= racl_list->count) {
809+				rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
810+					f_name(file, NULL), str_acl_type(type), ndx);
811+				exit_cleanup(RERR_STREAMIO);
812+			}
813+		}
814+		SIVAL(ndx_ptr, 0, ndx);
815+		racl_list = &default_acl_list;
816+		ndx_ptr += 4;
817+	} while (BUMP_TYPE(type) && S_ISDIR(file->mode));
818+}
819+
820+/* Turn the ACL data in statx into cached ACL data, setting the index
821+ * values in the file struct. */
822+void cache_acl(struct file_struct *file, statx *sxp)
823+{
824+	SMB_ACL_TYPE_T type;
825+	rsync_acl *racl;
826+	item_list *racl_list;
827+	char *ndx_ptr;
828+	int ndx;
829+
830+	if (S_ISLNK(file->mode))
831+		return;
832+
833+	type = SMB_ACL_TYPE_ACCESS;
834+	racl = sxp->acc_acl;
835+	racl_list = &access_acl_list;
836+	ndx_ptr = (char*)file + file_struct_len;
837+	do {
838+		if (!racl)
839+			ndx = -1;
840+		else if ((ndx = find_matching_rsync_acl(type, racl_list, racl)) == -1) {
841+			acl_duo *new_duo;
842+			ndx = racl_list->count;
843+			new_duo = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
844+			new_duo->racl = *racl;
845+			new_duo->sacl = NULL;
846+			*racl = empty_rsync_acl;
847+		}
848+		SIVAL(ndx_ptr, 0, ndx);
849+		racl = sxp->def_acl;
850+		racl_list = &default_acl_list;
851+		ndx_ptr += 4;
852+	} while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
853+
854+	free_acl(sxp);
855+}
856+
857+static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode, mode_t mode)
858+{
859+	SMB_ACL_ENTRY_T entry;
860+	const char *errfun;
861+	int rc;
862+
863+	if (S_ISDIR(mode)) {
864+		/* If the sticky bit is going on, it's not safe to allow all
865+		 * the new ACL to go into effect before it gets set. */
866+#ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
867+		if (mode & S_ISVTX)
868+			mode &= ~0077;
869+#else
870+		if (mode & S_ISVTX && !(old_mode & S_ISVTX))
871+			mode &= ~0077;
872+	} else {
873+		/* If setuid or setgid is going off, it's not safe to allow all
874+		 * the new ACL to go into effect before they get cleared. */
875+		if ((old_mode & S_ISUID && !(mode & S_ISUID))
876+		 || (old_mode & S_ISGID && !(mode & S_ISGID)))
877+			mode &= ~0077;
878+#endif
879+	}
880+
881+	errfun = "sys_acl_get_entry";
882+	for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
883+	     rc == 1;
884+	     rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
885+		SMB_ACL_TAG_T tag_type;
886+		if ((rc = sys_acl_get_tag_type(entry, &tag_type))) {
887+			errfun = "sys_acl_get_tag_type";
888+			break;
889+		}
890+		switch (tag_type) {
891+		case SMB_ACL_USER_OBJ:
892+			COE2( store_access_in_entry,((mode >> 6) & 7, entry) );
893+			break;
894+		case SMB_ACL_GROUP_OBJ:
895+			/* group is only empty when identical to group perms. */
896+			if (racl->group_obj != NO_ENTRY)
897+				break;
898+			COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
899+			break;
900+		case SMB_ACL_MASK:
901+#ifndef ACLS_NEED_MASK
902+			/* mask is only empty when we don't need it. */
903+			if (racl->mask == NO_ENTRY)
904+				break;
905+#endif
906+			COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
907+			break;
908+		case SMB_ACL_OTHER:
909+			COE2( store_access_in_entry,(mode & 7, entry) );
910+			break;
911+		}
912+	}
913+	if (rc) {
914+	  error_exit:
915+		if (errfun) {
916+			rsyserr(FERROR, errno, "change_sacl_perms: %s()",
917+				errfun);
918+		}
919+		return (mode_t)~0;
920+	}
921+
922+#ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
923+	/* Ensure that chmod() will be called to restore any lost setid bits. */
924+	if (old_mode & (S_ISUID | S_ISGID | S_ISVTX)
925+	 && (old_mode & CHMOD_BITS) == (mode & CHMOD_BITS))
926+		old_mode &= ~(S_ISUID | S_ISGID | S_ISVTX);
927+#endif
928+
929+	/* Return the mode of the file on disk, as we will set them. */
930+	return (old_mode & ~ACCESSPERMS) | (mode & ACCESSPERMS);
931+}
932+
933+/* Set ACL on indicated filename.
934+ *
935+ * This sets extended access ACL entries and default ACL.  If convenient,
936+ * it sets permission bits along with the access ACL and signals having
937+ * done so by modifying sxp->st.st_mode.
938+ *
939+ * Returns 1 for unchanged, 0 for changed, -1 for failed.  Call this
940+ * with fname set to NULL to just check if the ACL is unchanged. */
941+int set_acl(const char *fname, const struct file_struct *file, statx *sxp)
942+{
943+	int unchanged = 1;
944+	SMB_ACL_TYPE_T type;
945+	char *ndx_ptr;
946+
947+	if (!dry_run && (read_only || list_only)) {
948+		errno = EROFS;
949+		return -1;
950+	}
951+
952+	if (S_ISLNK(file->mode))
953+		return 1;
954+
955+	type = SMB_ACL_TYPE_ACCESS;
956+	ndx_ptr = (char*)file + file_struct_len;
957+	do {
958+		acl_duo *duo_item;
959+		BOOL eq;
960+		int32 ndx = IVAL(ndx_ptr, 0);
961+
962+		ndx_ptr += 4;
963+
964+		if (type == SMB_ACL_TYPE_ACCESS) {
965+			if (ndx < 0 || (size_t)ndx >= access_acl_list.count)
966+				continue;
967+			duo_item = access_acl_list.items;
968+			duo_item += ndx;
969+			eq = sxp->acc_acl
970+			    && rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, file->mode);
971+		} else {
972+			if (ndx < 0 || (size_t)ndx >= default_acl_list.count)
973+				continue;
974+			duo_item = default_acl_list.items;
975+			duo_item += ndx;
976+			eq = sxp->def_acl
977+			    && rsync_acl_equal(sxp->def_acl, &duo_item->racl);
978+		}
979+		if (eq)
980+			continue;
981+		if (!dry_run && fname) {
982+			if (type == SMB_ACL_TYPE_DEFAULT
983+			 && duo_item->racl.user_obj == NO_ENTRY) {
984+				if (sys_acl_delete_def_file(fname) < 0) {
985+					rsyserr(FERROR, errno, "set_acl: sys_acl_delete_def_file(%s)",
986+						fname);
987+					unchanged = -1;
988+					continue;
989+				}
990+			} else {
991+				mode_t cur_mode = sxp->st.st_mode;
992+				if (!duo_item->sacl
993+				 && !pack_smb_acl(&duo_item->sacl, &duo_item->racl)) {
994+					unchanged = -1;
995+					continue;
996+				}
997+				if (type == SMB_ACL_TYPE_ACCESS) {
998+					cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl,
999+								     cur_mode, file->mode);
1000+					if (cur_mode == (mode_t)~0)
1001+						continue;
1002+				}
1003+				if (sys_acl_set_file(fname, type, duo_item->sacl) < 0) {
1004+					rsyserr(FERROR, errno, "set_acl: sys_acl_set_file(%s, %s)",
1005+						fname, str_acl_type(type));
1006+					unchanged = -1;
1007+					continue;
1008+				}
1009+				if (type == SMB_ACL_TYPE_ACCESS)
1010+					sxp->st.st_mode = cur_mode;
1011+			}
1012+		}
1013+		if (unchanged == 1)
1014+			unchanged = 0;
1015+	} while (BUMP_TYPE(type) && S_ISDIR(file->mode));
1016+
1017+	return unchanged;
1018+}
1019+
1020+/* === Enumeration functions for uid mapping === */
1021+
1022+/* Context -- one and only one.  Should be cycled through once on uid
1023+ * mapping and once on gid mapping. */
1024+static item_list *_enum_racl_lists[] = {
1025+	&access_acl_list, &default_acl_list, NULL
1026+};
1027+
1028+static item_list **enum_racl_list = &_enum_racl_lists[0];
1029+static int enum_ida_index = 0;
1030+static size_t enum_racl_index = 0;
1031+
1032+/* This returns the next tag_type id from the given ACL for the next entry,
1033+ * or it returns 0 if there are no more tag_type ids in the acl. */
1034+static id_t *next_ace_id(SMB_ACL_TAG_T tag_type, const rsync_acl *racl)
1035+{
1036+	const ida_entries *idal = tag_type == SMB_ACL_USER ? &racl->users : &racl->groups;
1037+	if (enum_ida_index < idal->count) {
1038+		id_access *ida = &idal->idas[enum_ida_index++];
1039+		return &ida->id;
1040+	}
1041+	enum_ida_index = 0;
1042+	return NULL;
1043+}
1044+
1045+static id_t *next_acl_id(SMB_ACL_TAG_T tag_type, const item_list *racl_list)
1046+{
1047+	for (; enum_racl_index < racl_list->count; enum_racl_index++) {
1048+		id_t *id;
1049+		acl_duo *duo_item = racl_list->items;
1050+		duo_item += enum_racl_index;
1051+		if ((id = next_ace_id(tag_type, &duo_item->racl)) != NULL)
1052+			return id;
1053+	}
1054+	enum_racl_index = 0;
1055+	return NULL;
1056+}
1057+
1058+static id_t *next_acl_list_id(SMB_ACL_TAG_T tag_type)
1059+{
1060+	for (; *enum_racl_list; enum_racl_list++) {
1061+		id_t *id = next_acl_id(tag_type, *enum_racl_list);
1062+		if (id)
1063+			return id;
1064+	}
1065+	enum_racl_list = &_enum_racl_lists[0];
1066+	return NULL;
1067+}
1068+
1069+id_t *next_acl_uid()
1070+{
1071+	return next_acl_list_id(SMB_ACL_USER);
1072+}
1073+
1074+id_t *next_acl_gid()
1075+{
1076+	return next_acl_list_id(SMB_ACL_GROUP);
1077+}
1078+
1079+/* This is used by dest_mode(). */
1080+int default_perms_for_dir(const char *dir)
1081+{
1082+	rsync_acl racl;
1083+	SMB_ACL_T sacl;
1084+	BOOL ok;
1085+	int perms;
1086+
1087+	if (dir == NULL)
1088+		dir = ".";
1089+	perms = ACCESSPERMS & ~orig_umask;
1090+	/* Read the directory's default ACL.  If it has none, this will successfully return an empty ACL. */
1091+	sacl = sys_acl_get_file(dir, SMB_ACL_TYPE_DEFAULT);
1092+	if (sacl == NULL) {
1093+		/* Couldn't get an ACL.  Darn. */
1094+		switch (errno) {
1095+		case ENOTSUP:
1096+			/* ACLs are disabled.  We could yell at the user to turn them on, but... */
1097+			break;
1098+		case ENOENT:
1099+			if (dry_run) {
1100+				/* We're doing a dry run, so the containing directory
1101+				 * wasn't actually created.  Don't worry about it. */
1102+				break;
1103+			}
1104+			/* Otherwise fall through. */
1105+		default:
1106+			rprintf(FERROR, "default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n",
1107+				dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno));
1108+		}
1109+		return perms;
1110+	}
1111+
1112+	/* Convert it. */
1113+	racl = empty_rsync_acl;
1114+	ok = unpack_smb_acl(&racl, sacl);
1115+	sys_acl_free_acl(sacl);
1116+	if (!ok) {
1117+		rprintf(FERROR, "default_perms_for_dir: unpack_smb_acl failed, falling back on umask\n");
1118+		return perms;
1119+	}
1120+
1121+	/* Apply the permission-bit entries of the default ACL, if any. */
1122+	if (racl.user_obj != NO_ENTRY) {
1123+		perms = rsync_acl_get_perms(&racl);
1124+		if (verbose > 2)
1125+			rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir);
1126+	}
1127+
1128+	rsync_acl_free(&racl);
1129+	return perms;
1130+}
1131+
1132+#endif /* SUPPORT_ACLS */
1133--- old/backup.c
1134+++ new/backup.c
1135@@ -29,6 +29,7 @@ extern char *backup_suffix;
1136 extern char *backup_dir;
1137 
1138 extern int am_root;
1139+extern int preserve_acls;
1140 extern int preserve_devices;
1141 extern int preserve_specials;
1142 extern int preserve_links;
1143@@ -94,7 +95,8 @@ path
1144 ****************************************************************************/
1145 static int make_bak_dir(char *fullpath)
1146 {
1147-	STRUCT_STAT st;
1148+	statx sx;
1149+	struct file_struct *file;
1150 	char *rel = fullpath + backup_dir_len;
1151 	char *end = rel + strlen(rel);
1152 	char *p = end;
1153@@ -126,13 +128,24 @@ static int make_bak_dir(char *fullpath)
1154 		if (p >= rel) {
1155 			/* Try to transfer the directory settings of the
1156 			 * actual dir that the files are coming from. */
1157-			if (do_stat(rel, &st) < 0) {
1158+			if (do_stat(rel, &sx.st) < 0) {
1159 				rsyserr(FERROR, errno,
1160 					"make_bak_dir stat %s failed",
1161 					full_fname(rel));
1162 			} else {
1163-				do_lchown(fullpath, st.st_uid, st.st_gid);
1164-				do_chmod(fullpath, st.st_mode);
1165+#ifdef SUPPORT_ACLS
1166+				sx.acc_acl = sx.def_acl = NULL;
1167+#endif
1168+				if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
1169+					continue;
1170+#ifdef SUPPORT_ACLS
1171+				if (preserve_acls) {
1172+					get_acl(rel, &sx);
1173+					cache_acl(file, &sx);
1174+				}
1175+#endif
1176+				set_file_attrs(fullpath, file, NULL, 0);
1177+				free(file);
1178 			}
1179 		}
1180 		*p = '/';
1181@@ -170,15 +183,18 @@ static int robust_move(char *src, char *
1182  * We will move the file to be deleted into a parallel directory tree. */
1183 static int keep_backup(char *fname)
1184 {
1185-	STRUCT_STAT st;
1186+	statx sx;
1187 	struct file_struct *file;
1188 	char *buf;
1189 	int kept = 0;
1190 	int ret_code;
1191 
1192 	/* return if no file to keep */
1193-	if (do_lstat(fname, &st) < 0)
1194+	if (do_lstat(fname, &sx.st) < 0)
1195 		return 1;
1196+#ifdef SUPPORT_ACLS
1197+	sx.acc_acl = sx.def_acl = NULL;
1198+#endif
1199 
1200 	if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
1201 		return 1; /* the file could have disappeared */
1202@@ -186,6 +202,13 @@ static int keep_backup(char *fname)
1203 	if (!(buf = get_backup_name(fname)))
1204 		return 0;
1205 
1206+#ifdef SUPPORT_ACLS
1207+	if (preserve_acls) {
1208+		get_acl(fname, &sx);
1209+		cache_acl(file, &sx);
1210+	}
1211+#endif
1212+
1213 	/* Check to see if this is a device file, or link */
1214 	if ((am_root && preserve_devices && IS_DEVICE(file->mode))
1215 	 || (preserve_specials && IS_SPECIAL(file->mode))) {
1216@@ -254,7 +277,7 @@ static int keep_backup(char *fname)
1217 		if (robust_move(fname, buf) != 0) {
1218 			rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
1219 				full_fname(fname), buf);
1220-		} else if (st.st_nlink > 1) {
1221+		} else if (sx.st.st_nlink > 1) {
1222 			/* If someone has hard-linked the file into the backup
1223 			 * dir, rename() might return success but do nothing! */
1224 			robust_unlink(fname); /* Just in case... */
1225--- old/configure.in
1226+++ new/configure.in
1227@@ -515,6 +515,11 @@ if test x"$ac_cv_func_strcasecmp" = x"no
1228     AC_CHECK_LIB(resolv, strcasecmp)
1229 fi
1230 
1231+AC_CHECK_FUNCS(aclsort)
1232+if test x"$ac_cv_func_aclsort" = x"no"; then
1233+    AC_CHECK_LIB(sec, aclsort)
1234+fi
1235+
1236 dnl At the moment we don't test for a broken memcmp(), because all we
1237 dnl need to do is test for equality, not comparison, and it seems that
1238 dnl every platform has a memcmp that can do at least that.
1239@@ -779,6 +784,78 @@ AC_SUBST(OBJ_RESTORE)
1240 AC_SUBST(CC_SHOBJ_FLAG)
1241 AC_SUBST(BUILD_POPT)
1242 
1243+AC_CHECK_HEADERS(sys/acl.h acl/libacl.h)
1244+AC_CHECK_FUNCS(_acl __acl _facl __facl)
1245+#################################################
1246+# check for ACL support
1247+
1248+AC_MSG_CHECKING(whether to support ACLs)
1249+AC_ARG_ENABLE(acl-support,
1250+AC_HELP_STRING([--enable-acl-support], [Include ACL support (default=no)]),
1251+[ case "$enableval" in
1252+  yes)
1253+
1254+		case "$host_os" in
1255+		*sysv5*)
1256+			AC_MSG_RESULT(Using UnixWare ACLs)
1257+			AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
1258+			;;
1259+		*solaris*|*cygwin*)
1260+			AC_MSG_RESULT(Using solaris ACLs)
1261+			AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
1262+			;;
1263+		*hpux*)
1264+			AC_MSG_RESULT(Using HPUX ACLs)
1265+			AC_DEFINE(HAVE_HPUX_ACLS, 1, [true if you have HPUX ACLs])
1266+			;;
1267+		*irix*)
1268+			AC_MSG_RESULT(Using IRIX ACLs)
1269+			AC_DEFINE(HAVE_IRIX_ACLS, 1, [true if you have IRIX ACLs])
1270+			;;
1271+		*aix*)
1272+			AC_MSG_RESULT(Using AIX ACLs)
1273+			AC_DEFINE(HAVE_AIX_ACLS, 1, [true if you have AIX ACLs])
1274+			;;
1275+		*osf*)
1276+			AC_MSG_RESULT(Using Tru64 ACLs)
1277+			AC_DEFINE(HAVE_TRU64_ACLS, 1, [true if you have Tru64 ACLs])
1278+			LIBS="$LIBS -lpacl"
1279+			;;
1280+		*)
1281+		    AC_MSG_RESULT(ACLs requested -- running tests)
1282+		    AC_CHECK_LIB(acl,acl_get_file)
1283+			AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
1284+			AC_TRY_LINK([#include <sys/types.h>
1285+#include <sys/acl.h>],
1286+[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
1287+samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
1288+			AC_MSG_CHECKING(ACL test results)
1289+			if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
1290+			    AC_MSG_RESULT(Using posix ACLs)
1291+			    AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
1292+			    AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
1293+				AC_TRY_LINK([#include <sys/types.h>
1294+#include <sys/acl.h>],
1295+[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
1296+samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
1297+			    if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
1298+				AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
1299+			    fi
1300+			else
1301+			    AC_MSG_ERROR(Failed to find ACL support)
1302+			fi
1303+			;;
1304+		esac
1305+		;;
1306+  *)
1307+    AC_MSG_RESULT(no)
1308+	AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs])
1309+    ;;
1310+  esac ],
1311+  AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs])
1312+  AC_MSG_RESULT(no)
1313+)
1314+
1315 AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
1316 AC_OUTPUT
1317 
1318--- old/flist.c
1319+++ new/flist.c
1320@@ -40,6 +40,7 @@ extern int filesfrom_fd;
1321 extern int one_file_system;
1322 extern int copy_dirlinks;
1323 extern int keep_dirlinks;
1324+extern int preserve_acls;
1325 extern int preserve_links;
1326 extern int preserve_hard_links;
1327 extern int preserve_devices;
1328@@ -133,6 +134,8 @@ static void list_file_entry(struct file_
1329 
1330 	permstring(permbuf, f->mode);
1331 
1332+	/* TODO: indicate '+' if the entry has an ACL. */
1333+
1334 #ifdef SUPPORT_LINKS
1335 	if (preserve_links && S_ISLNK(f->mode)) {
1336 		rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
1337@@ -495,6 +498,9 @@ static struct file_struct *receive_file_
1338 	char thisname[MAXPATHLEN];
1339 	unsigned int l1 = 0, l2 = 0;
1340 	int alloc_len, basename_len, dirname_len, linkname_len, sum_len;
1341+#ifdef SUPPORT_ACLS
1342+	int xtra_len;
1343+#endif
1344 	OFF_T file_length;
1345 	char *basename, *dirname, *bp;
1346 	struct file_struct *file;
1347@@ -598,13 +604,27 @@ static struct file_struct *receive_file_
1348 
1349 	sum_len = always_checksum && S_ISREG(mode) ? MD4_SUM_LENGTH : 0;
1350 
1351+#ifdef SUPPORT_ACLS
1352+	/* We need one or two index int32s when we're preserving ACLs. */
1353+	if (preserve_acls)
1354+		xtra_len = (S_ISDIR(mode) ? 2 : 1) * 4;
1355+	else
1356+		xtra_len = 0;
1357+#endif
1358+
1359 	alloc_len = file_struct_len + dirname_len + basename_len
1360+#ifdef SUPPORT_ACLS
1361+		  + xtra_len
1362+#endif
1363 		  + linkname_len + sum_len;
1364 	bp = pool_alloc(flist->file_pool, alloc_len, "receive_file_entry");
1365 
1366 	file = (struct file_struct *)bp;
1367 	memset(bp, 0, file_struct_len);
1368 	bp += file_struct_len;
1369+#ifdef SUPPORT_ACLS
1370+	bp += xtra_len;
1371+#endif
1372 
1373 	file->modtime = modtime;
1374 	file->length = file_length;
1375@@ -699,6 +719,11 @@ static struct file_struct *receive_file_
1376 		read_buf(f, sum, checksum_len);
1377 	}
1378 
1379+#ifdef SUPPORT_ACLS
1380+	if (preserve_acls)
1381+		receive_acl(file, f);
1382+#endif
1383+
1384 	return file;
1385 }
1386 
1387@@ -949,6 +974,9 @@ static struct file_struct *send_file_nam
1388 					  unsigned short flags)
1389 {
1390 	struct file_struct *file;
1391+#ifdef SUPPORT_ACLS
1392+	statx sx;
1393+#endif
1394 
1395 	file = make_file(fname, flist, stp, flags,
1396 			 f == -2 ? SERVER_FILTERS : ALL_FILTERS);
1397@@ -958,6 +986,15 @@ static struct file_struct *send_file_nam
1398 	if (chmod_modes && !S_ISLNK(file->mode))
1399 		file->mode = tweak_mode(file->mode, chmod_modes);
1400 
1401+#ifdef SUPPORT_ACLS
1402+	if (preserve_acls) {
1403+		sx.st.st_mode = file->mode;
1404+		sx.acc_acl = sx.def_acl = NULL;
1405+		if (get_acl(fname, &sx) < 0)
1406+			return NULL;
1407+	}
1408+#endif
1409+
1410 	maybe_emit_filelist_progress(flist->count + flist_count_offset);
1411 
1412 	flist_expand(flist);
1413@@ -965,6 +1002,15 @@ static struct file_struct *send_file_nam
1414 	if (file->basename[0]) {
1415 		flist->files[flist->count++] = file;
1416 		send_file_entry(file, f);
1417+#ifdef SUPPORT_ACLS
1418+		if (preserve_acls)
1419+			send_acl(&sx, f);
1420+#endif
1421+	} else {
1422+#ifdef SUPPORT_ACLS
1423+		if (preserve_acls)
1424+			free_acl(&sx);
1425+#endif
1426 	}
1427 	return file;
1428 }
1429--- old/generator.c
1430+++ new/generator.c
1431@@ -35,6 +35,7 @@ extern int do_progress;
1432 extern int relative_paths;
1433 extern int implied_dirs;
1434 extern int keep_dirlinks;
1435+extern int preserve_acls;
1436 extern int preserve_links;
1437 extern int preserve_devices;
1438 extern int preserve_specials;
1439@@ -85,6 +86,7 @@ extern long block_size; /* "long" becaus
1440 extern int max_delete;
1441 extern int force_delete;
1442 extern int one_file_system;
1443+extern mode_t orig_umask;
1444 extern struct stats stats;
1445 extern dev_t filesystem_dev;
1446 extern char *backup_dir;
1447@@ -317,22 +319,27 @@ static void do_delete_pass(struct file_l
1448 		rprintf(FINFO, "                    \r");
1449 }
1450 
1451-int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st)
1452+int unchanged_attrs(struct file_struct *file, statx *sxp)
1453 {
1454 	if (preserve_perms
1455-	 && (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
1456+	 && (sxp->st.st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
1457 		return 0;
1458 
1459-	if (am_root && preserve_uid && st->st_uid != file->uid)
1460+	if (am_root && preserve_uid && sxp->st.st_uid != file->uid)
1461 		return 0;
1462 
1463-	if (preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid)
1464+	if (preserve_gid && file->gid != GID_NONE && sxp->st.st_gid != file->gid)
1465+		return 0;
1466+
1467+#ifdef SUPPORT_ACLS
1468+	if (preserve_acls && set_acl(NULL, file, sxp) == 0)
1469 		return 0;
1470+#endif
1471 
1472 	return 1;
1473 }
1474 
1475-void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st,
1476+void itemize(struct file_struct *file, int ndx, int statret, statx *sxp,
1477 	     int32 iflags, uchar fnamecmp_type, char *xname)
1478 {
1479 	if (statret >= 0) { /* A from-dest-dir statret can == 1! */
1480@@ -340,19 +347,23 @@ void itemize(struct file_struct *file, i
1481 		    : S_ISDIR(file->mode) ? !omit_dir_times
1482 		    : !S_ISLNK(file->mode);
1483 
1484-		if (S_ISREG(file->mode) && file->length != st->st_size)
1485+		if (S_ISREG(file->mode) && file->length != sxp->st.st_size)
1486 			iflags |= ITEM_REPORT_SIZE;
1487 		if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
1488 		     && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
1489-		    || (keep_time && cmp_time(file->modtime, st->st_mtime) != 0))
1490+		    || (keep_time && cmp_time(file->modtime, sxp->st.st_mtime) != 0))
1491 			iflags |= ITEM_REPORT_TIME;
1492-		if ((file->mode & CHMOD_BITS) != (st->st_mode & CHMOD_BITS))
1493+		if ((file->mode & CHMOD_BITS) != (sxp->st.st_mode & CHMOD_BITS))
1494 			iflags |= ITEM_REPORT_PERMS;
1495-		if (preserve_uid && am_root && file->uid != st->st_uid)
1496+		if (preserve_uid && am_root && file->uid != sxp->st.st_uid)
1497 			iflags |= ITEM_REPORT_OWNER;
1498 		if (preserve_gid && file->gid != GID_NONE
1499-		    && st->st_gid != file->gid)
1500+		    && sxp->st.st_gid != file->gid)
1501 			iflags |= ITEM_REPORT_GROUP;
1502+#ifdef SUPPORT_ACLS
1503+		if (preserve_acls && set_acl(NULL, file, sxp) == 0)
1504+			iflags |= ITEM_REPORT_ACL;
1505+#endif
1506 	} else
1507 		iflags |= ITEM_IS_NEW;
1508 
1509@@ -605,7 +616,7 @@ void check_for_finished_hlinks(int itemi
1510  * handling the file, -1 if no dest-linking occurred, or a non-negative
1511  * value if we found an alternate basis file. */
1512 static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
1513-			 char *cmpbuf, STRUCT_STAT *stp, int itemizing,
1514+			 char *cmpbuf, statx *sxp, int itemizing,
1515 			 int maybe_ATTRS_REPORT, enum logcode code)
1516 {
1517 	int best_match = -1;
1518@@ -614,7 +625,7 @@ static int try_dests_reg(struct file_str
1519 
1520 	do {
1521 		pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
1522-		if (link_stat(cmpbuf, stp, 0) < 0 || !S_ISREG(stp->st_mode))
1523+		if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode))
1524 			continue;
1525 		switch (match_level) {
1526 		case 0:
1527@@ -622,16 +633,20 @@ static int try_dests_reg(struct file_str
1528 			match_level = 1;
1529 			/* FALL THROUGH */
1530 		case 1:
1531-			if (!unchanged_file(cmpbuf, file, stp))
1532+			if (!unchanged_file(cmpbuf, file, &sxp->st))
1533 				continue;
1534 			best_match = j;
1535 			match_level = 2;
1536 			/* FALL THROUGH */
1537 		case 2:
1538-			if (!unchanged_attrs(file, stp))
1539+#ifdef SUPPORT_ACLS
1540+			if (preserve_acls)
1541+				get_acl(cmpbuf, sxp);
1542+#endif
1543+			if (!unchanged_attrs(file, sxp))
1544 				continue;
1545 			if (always_checksum && preserve_times
1546-			 && cmp_time(stp->st_mtime, file->modtime))
1547+			 && cmp_time(sxp->st.st_mtime, file->modtime))
1548 				continue;
1549 			best_match = j;
1550 			match_level = 3;
1551@@ -646,14 +661,14 @@ static int try_dests_reg(struct file_str
1552 	if (j != best_match) {
1553 		j = best_match;
1554 		pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
1555-		if (link_stat(cmpbuf, stp, 0) < 0)
1556+		if (link_stat(cmpbuf, &sxp->st, 0) < 0)
1557 			return -1;
1558 	}
1559 
1560 	if (match_level == 3 && !copy_dest) {
1561 #ifdef SUPPORT_HARD_LINKS
1562 		if (link_dest) {
1563-			if (hard_link_one(file, ndx, fname, 0, stp,
1564+			if (hard_link_one(file, ndx, fname, 0, sxp,
1565 					  cmpbuf, 1,
1566 					  itemizing && verbose > 1,
1567 					  code) < 0)
1568@@ -665,8 +680,13 @@ static int try_dests_reg(struct file_str
1569 			}
1570 		} else
1571 #endif
1572-		if (itemizing)
1573-			itemize(file, ndx, 0, stp, 0, 0, NULL);
1574+		if (itemizing) {
1575+#ifdef SUPPORT_ACLS
1576+			if (preserve_acls && !ACL_READY(*sxp))
1577+				get_acl(fname, sxp);
1578+#endif
1579+			itemize(file, ndx, 0, sxp, 0, 0, NULL);
1580+		}
1581 		if (verbose > 1 && maybe_ATTRS_REPORT) {
1582 			rprintf(FCLIENT, "%s is uptodate\n", fname);
1583 		}
1584@@ -682,8 +702,13 @@ static int try_dests_reg(struct file_str
1585 			}
1586 			return -1;
1587 		}
1588-		if (itemizing)
1589-			itemize(file, ndx, 0, stp, ITEM_LOCAL_CHANGE, 0, NULL);
1590+		if (itemizing) {
1591+#ifdef SUPPORT_ACLS
1592+			if (preserve_acls && !ACL_READY(*sxp))
1593+				get_acl(fname, sxp);
1594+#endif
1595+			itemize(file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
1596+		}
1597 		set_file_attrs(fname, file, NULL, 0);
1598 		if (maybe_ATTRS_REPORT
1599 		 && ((!itemizing && verbose && match_level == 2)
1600@@ -707,13 +732,18 @@ static int try_dests_non(struct file_str
1601 			 enum logcode code)
1602 {
1603 	char fnamebuf[MAXPATHLEN];
1604-	STRUCT_STAT st;
1605+	statx sx;
1606 	int i = 0;
1607 
1608 	do {
1609 		pathjoin(fnamebuf, MAXPATHLEN, basis_dir[i], fname);
1610-		if (link_stat(fnamebuf, &st, 0) < 0 || S_ISDIR(st.st_mode)
1611-		 || !unchanged_attrs(file, &st))
1612+		if (link_stat(fnamebuf, &sx.st, 0) < 0 || S_ISDIR(sx.st.st_mode))
1613+			continue;
1614+#ifdef SUPPORT_ACLS
1615+		if (preserve_acls)
1616+			get_acl(fnamebuf, &sx);
1617+#endif
1618+		if (!unchanged_attrs(file, &sx))
1619 			continue;
1620 		if (S_ISLNK(file->mode)) {
1621 #ifdef SUPPORT_LINKS
1622@@ -726,10 +756,10 @@ static int try_dests_non(struct file_str
1623 #endif
1624 				continue;
1625 		} else if (IS_SPECIAL(file->mode)) {
1626-			if (!IS_SPECIAL(st.st_mode) || st.st_rdev != file->u.rdev)
1627+			if (!IS_SPECIAL(sx.st.st_mode) || sx.st.st_rdev != file->u.rdev)
1628 				continue;
1629 		} else if (IS_DEVICE(file->mode)) {
1630-			if (!IS_DEVICE(st.st_mode) || st.st_rdev != file->u.rdev)
1631+			if (!IS_DEVICE(sx.st.st_mode) || sx.st.st_rdev != file->u.rdev)
1632 				continue;
1633 		} else {
1634 			rprintf(FERROR,
1635@@ -760,7 +790,15 @@ static int try_dests_non(struct file_str
1636 			int changes = compare_dest ? 0 : ITEM_LOCAL_CHANGE
1637 				    + (link_dest ? ITEM_XNAME_FOLLOWS : 0);
1638 			char *lp = link_dest ? "" : NULL;
1639-			itemize(file, ndx, 0, &st, changes, 0, lp);
1640+#ifdef SUPPORT_ACLS
1641+			if (preserve_acls)
1642+				get_acl(fname, &sx);
1643+#endif
1644+			itemize(file, ndx, 0, &sx, changes, 0, lp);
1645+#ifdef SUPPORT_ACLS
1646+			if (preserve_acls)
1647+				free_acl(&sx);
1648+#endif
1649 		}
1650 		if (verbose > 1 && maybe_ATTRS_REPORT) {
1651 			rprintf(FCLIENT, "%s is uptodate\n", fname);
1652@@ -772,6 +810,7 @@ static int try_dests_non(struct file_str
1653 }
1654 
1655 static int phase = 0;
1656+static int dflt_perms;
1657 
1658 /* Acts on the_file_list->file's ndx'th item, whose name is fname.  If a dir,
1659  * make sure it exists, and has the right permissions/timestamp info.  For
1660@@ -793,7 +832,8 @@ static void recv_generator(char *fname, 
1661 	static int need_fuzzy_dirlist = 0;
1662 	struct file_struct *fuzzy_file = NULL;
1663 	int fd = -1, f_copy = -1;
1664-	STRUCT_STAT st, real_st, partial_st;
1665+	statx sx, real_sx;
1666+	STRUCT_STAT partial_st;
1667 	struct file_struct *back_file = NULL;
1668 	int statret, real_ret, stat_errno;
1669 	char *fnamecmp, *partialptr, *backupptr = NULL;
1670@@ -849,6 +889,9 @@ static void recv_generator(char *fname, 
1671 		} else if (!dry_run)
1672 			return;
1673 	}
1674+#ifdef SUPPORT_ACLS
1675+	sx.acc_acl = sx.def_acl = NULL;
1676+#endif
1677 	if (dry_run > 1) {
1678 		statret = -1;
1679 		stat_errno = ENOENT;
1680@@ -856,7 +899,7 @@ static void recv_generator(char *fname, 
1681 		char *dn = file->dirname ? file->dirname : ".";
1682 		if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
1683 			if (relative_paths && !implied_dirs
1684-			 && do_stat(dn, &st) < 0
1685+			 && do_stat(dn, &sx.st) < 0
1686 			 && create_directory_path(fname) < 0) {
1687 				rsyserr(FERROR, errno,
1688 					"recv_generator: mkdir %s failed",
1689@@ -868,6 +911,10 @@ static void recv_generator(char *fname, 
1690 			}
1691 			if (fuzzy_basis)
1692 				need_fuzzy_dirlist = 1;
1693+#ifdef SUPPORT_ACLS
1694+			if (!preserve_perms)
1695+				dflt_perms = default_perms_for_dir(dn);
1696+#endif
1697 		}
1698 		parent_dirname = dn;
1699 
1700@@ -876,7 +923,7 @@ static void recv_generator(char *fname, 
1701 			need_fuzzy_dirlist = 0;
1702 		}
1703 
1704-		statret = link_stat(fname, &st,
1705+		statret = link_stat(fname, &sx.st,
1706 				    keep_dirlinks && S_ISDIR(file->mode));
1707 		stat_errno = errno;
1708 	}
1709@@ -894,8 +941,9 @@ static void recv_generator(char *fname, 
1710 	 * mode based on the local permissions and some heuristics. */
1711 	if (!preserve_perms) {
1712 		int exists = statret == 0
1713-			  && S_ISDIR(st.st_mode) == S_ISDIR(file->mode);
1714-		file->mode = dest_mode(file->mode, st.st_mode, exists);
1715+			  && S_ISDIR(sx.st.st_mode) == S_ISDIR(file->mode);
1716+		file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms,
1717+				       exists);
1718 	}
1719 
1720 	if (S_ISDIR(file->mode)) {
1721@@ -904,8 +952,8 @@ static void recv_generator(char *fname, 
1722 		 * file of that name and it is *not* a directory, then
1723 		 * we need to delete it.  If it doesn't exist, then
1724 		 * (perhaps recursively) create it. */
1725-		if (statret == 0 && !S_ISDIR(st.st_mode)) {
1726-			if (delete_item(fname, st.st_mode, del_opts) < 0)
1727+		if (statret == 0 && !S_ISDIR(sx.st.st_mode)) {
1728+			if (delete_item(fname, sx.st.st_mode, del_opts) < 0)
1729 				return;
1730 			statret = -1;
1731 		}
1732@@ -920,7 +968,11 @@ static void recv_generator(char *fname, 
1733 					sr = -1;
1734 				new_root_dir = 0;
1735 			}
1736-			itemize(file, ndx, sr, &st,
1737+#ifdef SUPPORT_ACLS
1738+			if (preserve_acls && sr == 0)
1739+				get_acl(fname, &sx);
1740+#endif
1741+			itemize(file, ndx, sr, &sx,
1742 				sr ? ITEM_LOCAL_CHANGE : 0, 0, NULL);
1743 		}
1744 		if (statret != 0 && do_mkdir(fname,file->mode) < 0 && errno != EEXIST) {
1745@@ -940,19 +992,19 @@ static void recv_generator(char *fname, 
1746 				return;
1747 			}
1748 		}
1749-		if (set_file_attrs(fname, file, statret ? NULL : &st, 0)
1750+		if (set_file_attrs(fname, file, statret ? NULL : &sx, 0)
1751 		    && verbose && code != FNONE && f_out != -1)
1752 			rprintf(code, "%s/\n", fname);
1753 		if (delete_during && f_out != -1 && !phase && dry_run < 2
1754 		    && (file->flags & FLAG_DEL_HERE))
1755-			delete_in_dir(the_file_list, fname, file, &st);
1756-		return;
1757+			delete_in_dir(the_file_list, fname, file, &sx.st);
1758+		goto cleanup;
1759 	}
1760 
1761 	if (preserve_hard_links && file->link_u.links
1762-	    && hard_link_check(file, ndx, fname, statret, &st,
1763+	    && hard_link_check(file, ndx, fname, statret, &sx,
1764 			       itemizing, code, HL_CHECK_MASTER))
1765-		return;
1766+		goto cleanup;
1767 
1768 	if (preserve_links && S_ISLNK(file->mode)) {
1769 #ifdef SUPPORT_LINKS
1770@@ -970,7 +1022,7 @@ static void recv_generator(char *fname, 
1771 			char lnk[MAXPATHLEN];
1772 			int len;
1773 
1774-			if (!S_ISDIR(st.st_mode)
1775+			if (!S_ISDIR(sx.st.st_mode)
1776 			    && (len = readlink(fname, lnk, MAXPATHLEN-1)) > 0) {
1777 				lnk[len] = 0;
1778 				/* A link already pointing to the
1779@@ -978,10 +1030,10 @@ static void recv_generator(char *fname, 
1780 				 * required. */
1781 				if (strcmp(lnk, file->u.link) == 0) {
1782 					if (itemizing) {
1783-						itemize(file, ndx, 0, &st, 0,
1784+						itemize(file, ndx, 0, &sx, 0,
1785 							0, NULL);
1786 					}
1787-					set_file_attrs(fname, file, &st,
1788+					set_file_attrs(fname, file, &sx,
1789 						       maybe_ATTRS_REPORT);
1790 					if (preserve_hard_links
1791 					    && file->link_u.links) {
1792@@ -996,9 +1048,9 @@ static void recv_generator(char *fname, 
1793 			}
1794 			/* Not the right symlink (or not a symlink), so
1795 			 * delete it. */
1796-			if (delete_item(fname, st.st_mode, del_opts) < 0)
1797+			if (delete_item(fname, sx.st.st_mode, del_opts) < 0)
1798 				return;
1799-			if (!S_ISLNK(st.st_mode))
1800+			if (!S_ISLNK(sx.st.st_mode))
1801 				statret = -1;
1802 		} else if (basis_dir[0] != NULL) {
1803 			if (try_dests_non(file, fname, ndx, itemizing,
1804@@ -1015,7 +1067,7 @@ static void recv_generator(char *fname, 
1805 			}
1806 		}
1807 		if (preserve_hard_links && file->link_u.links
1808-		    && hard_link_check(file, ndx, fname, -1, &st,
1809+		    && hard_link_check(file, ndx, fname, -1, &sx,
1810 				       itemizing, code, HL_SKIP))
1811 			return;
1812 		if (do_symlink(file->u.link,fname) != 0) {
1813@@ -1024,7 +1076,7 @@ static void recv_generator(char *fname, 
1814 		} else {
1815 			set_file_attrs(fname, file, NULL, 0);
1816 			if (itemizing) {
1817-				itemize(file, ndx, statret, &st,
1818+				itemize(file, ndx, statret, &sx,
1819 					ITEM_LOCAL_CHANGE, 0, NULL);
1820 			}
1821 			if (code != FNONE && verbose) {
1822@@ -1059,18 +1111,22 @@ static void recv_generator(char *fname, 
1823 				code = FNONE;
1824 			}
1825 		}
1826+#ifdef SUPPORT_ACLS
1827+		if (preserve_acls && statret == 0)
1828+			get_acl(fname, &sx);
1829+#endif
1830 		if (statret != 0
1831-		 || (st.st_mode & ~CHMOD_BITS) != (file->mode & ~CHMOD_BITS)
1832-		 || st.st_rdev != file->u.rdev) {
1833+		 || (sx.st.st_mode & ~CHMOD_BITS) != (file->mode & ~CHMOD_BITS)
1834+		 || sx.st.st_rdev != file->u.rdev) {
1835 			if (statret == 0
1836-			 && delete_item(fname, st.st_mode, del_opts) < 0)
1837-				return;
1838+			 && delete_item(fname, sx.st.st_mode, del_opts) < 0)
1839+				goto cleanup;
1840 			if (preserve_hard_links && file->link_u.links
1841-			    && hard_link_check(file, ndx, fname, -1, &st,
1842+			    && hard_link_check(file, ndx, fname, -1, &sx,
1843 					       itemizing, code, HL_SKIP))
1844-				return;
1845-			if ((IS_DEVICE(file->mode) && !IS_DEVICE(st.st_mode))
1846-			 || (IS_SPECIAL(file->mode) && !IS_SPECIAL(st.st_mode)))
1847+				goto cleanup;
1848+			if ((IS_DEVICE(file->mode) && !IS_DEVICE(sx.st.st_mode))
1849+			 || (IS_SPECIAL(file->mode) && !IS_SPECIAL(sx.st.st_mode)))
1850 				statret = -1;
1851 			if (verbose > 2) {
1852 				rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
1853@@ -1083,7 +1139,7 @@ static void recv_generator(char *fname, 
1854 			} else {
1855 				set_file_attrs(fname, file, NULL, 0);
1856 				if (itemizing) {
1857-					itemize(file, ndx, statret, &st,
1858+					itemize(file, ndx, statret, &sx,
1859 						ITEM_LOCAL_CHANGE, 0, NULL);
1860 				}
1861 				if (code != FNONE && verbose)
1862@@ -1097,14 +1153,14 @@ static void recv_generator(char *fname, 
1863 			}
1864 		} else {
1865 			if (itemizing)
1866-				itemize(file, ndx, statret, &st, 0, 0, NULL);
1867-			set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
1868+				itemize(file, ndx, statret, &sx, 0, 0, NULL);
1869+			set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
1870 			if (preserve_hard_links && file->link_u.links)
1871 				hard_link_cluster(file, ndx, itemizing, code);
1872 			if (remove_source_files == 1)
1873 				goto return_with_success;
1874 		}
1875-		return;
1876+		goto cleanup;
1877 	}
1878 
1879 	if (!S_ISREG(file->mode)) {
1880@@ -1138,7 +1194,7 @@ static void recv_generator(char *fname, 
1881 	}
1882 
1883 	if (update_only && statret == 0
1884-	    && cmp_time(st.st_mtime, file->modtime) > 0) {
1885+	    && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
1886 		if (verbose > 1)
1887 			rprintf(FINFO, "%s is newer\n", fname);
1888 		return;
1889@@ -1147,20 +1203,20 @@ static void recv_generator(char *fname, 
1890 	fnamecmp = fname;
1891 	fnamecmp_type = FNAMECMP_FNAME;
1892 
1893-	if (statret == 0 && !S_ISREG(st.st_mode)) {
1894-		if (delete_item(fname, st.st_mode, del_opts) != 0)
1895+	if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
1896+		if (delete_item(fname, sx.st.st_mode, del_opts) != 0)
1897 			return;
1898 		statret = -1;
1899 		stat_errno = ENOENT;
1900 	}
1901 
1902 	if (statret != 0 && basis_dir[0] != NULL) {
1903-		int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &st,
1904+		int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx,
1905 				      itemizing, maybe_ATTRS_REPORT, code);
1906 		if (j == -2) {
1907 			if (remove_source_files == 1)
1908 				goto return_with_success;
1909-			return;
1910+			goto cleanup;
1911 		}
1912 		if (j >= 0) {
1913 			fnamecmp = fnamecmpbuf;
1914@@ -1170,7 +1226,7 @@ static void recv_generator(char *fname, 
1915 	}
1916 
1917 	real_ret = statret;
1918-	real_st = st;
1919+	real_sx = sx;
1920 
1921 	if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL
1922 	    && link_stat(partialptr, &partial_st, 0) == 0
1923@@ -1189,7 +1245,7 @@ static void recv_generator(char *fname, 
1924 				rprintf(FINFO, "fuzzy basis selected for %s: %s\n",
1925 					fname, fnamecmpbuf);
1926 			}
1927-			st.st_size = fuzzy_file->length;
1928+			sx.st.st_size = fuzzy_file->length;
1929 			statret = 0;
1930 			fnamecmp = fnamecmpbuf;
1931 			fnamecmp_type = FNAMECMP_FUZZY;
1932@@ -1198,7 +1254,7 @@ static void recv_generator(char *fname, 
1933 
1934 	if (statret != 0) {
1935 		if (preserve_hard_links && file->link_u.links
1936-		    && hard_link_check(file, ndx, fname, statret, &st,
1937+		    && hard_link_check(file, ndx, fname, statret, &sx,
1938 				       itemizing, code, HL_SKIP))
1939 			return;
1940 		if (stat_errno == ENOENT)
1941@@ -1208,39 +1264,52 @@ static void recv_generator(char *fname, 
1942 		return;
1943 	}
1944 
1945-	if (append_mode && st.st_size > file->length)
1946+	if (append_mode && sx.st.st_size > file->length)
1947 		return;
1948 
1949 	if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
1950 		;
1951 	else if (fnamecmp_type == FNAMECMP_FUZZY)
1952 		;
1953-	else if (unchanged_file(fnamecmp, file, &st)) {
1954+	else if (unchanged_file(fnamecmp, file, &sx.st)) {
1955 		if (partialptr) {
1956 			do_unlink(partialptr);
1957 			handle_partial_dir(partialptr, PDIR_DELETE);
1958 		}
1959 		if (itemizing) {
1960-			itemize(file, ndx, real_ret, &real_st,
1961+#ifdef SUPPORT_ACLS
1962+			if (preserve_acls && real_ret == 0)
1963+				get_acl(fnamecmp, &real_sx);
1964+#endif
1965+			itemize(file, ndx, real_ret, &real_sx,
1966 				0, 0, NULL);
1967+#ifdef SUPPORT_ACLS
1968+			if (preserve_acls) {
1969+				if (fnamecmp_type == FNAMECMP_FNAME) {
1970+					sx.acc_acl = real_sx.acc_acl;
1971+					sx.def_acl = real_sx.def_acl;
1972+				} else
1973+					free_acl(&real_sx);
1974+			}
1975+#endif
1976 		}
1977-		set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
1978+		set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
1979 		if (preserve_hard_links && file->link_u.links)
1980 			hard_link_cluster(file, ndx, itemizing, code);
1981 		if (remove_source_files != 1)
1982-			return;
1983+			goto cleanup;
1984 	  return_with_success:
1985 		if (!dry_run) {
1986 			char numbuf[4];
1987 			SIVAL(numbuf, 0, ndx);
1988 			send_msg(MSG_SUCCESS, numbuf, 4);
1989 		}
1990-		return;
1991+		goto cleanup;
1992 	}
1993 
1994   prepare_to_open:
1995 	if (partialptr) {
1996-		st = partial_st;
1997+		sx.st = partial_st;
1998 		fnamecmp = partialptr;
1999 		fnamecmp_type = FNAMECMP_PARTIAL_DIR;
2000 		statret = 0;
2001@@ -1264,17 +1333,21 @@ static void recv_generator(char *fname, 
2002 	  pretend_missing:
2003 		/* pretend the file didn't exist */
2004 		if (preserve_hard_links && file->link_u.links
2005-		    && hard_link_check(file, ndx, fname, statret, &st,
2006+		    && hard_link_check(file, ndx, fname, statret, &sx,
2007 				       itemizing, code, HL_SKIP))
2008-			return;
2009+			goto cleanup;
2010 		statret = real_ret = -1;
2011+#ifdef SUPPORT_ACLS
2012+		if (preserve_acls && ACL_READY(sx))
2013+			free_acl(&sx);
2014+#endif
2015 		goto notify_others;
2016 	}
2017 
2018 	if (inplace && make_backups && fnamecmp_type == FNAMECMP_FNAME) {
2019 		if (!(backupptr = get_backup_name(fname))) {
2020 			close(fd);
2021-			return;
2022+			goto cleanup;
2023 		}
2024 		if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) {
2025 			close(fd);
2026@@ -1285,7 +1358,7 @@ static void recv_generator(char *fname, 
2027 				full_fname(backupptr));
2028 			free(back_file);
2029 			close(fd);
2030-			return;
2031+			goto cleanup;
2032 		}
2033 		if ((f_copy = do_open(backupptr,
2034 		    O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
2035@@ -1293,14 +1366,14 @@ static void recv_generator(char *fname, 
2036 				full_fname(backupptr));
2037 			free(back_file);
2038 			close(fd);
2039-			return;
2040+			goto cleanup;
2041 		}
2042 		fnamecmp_type = FNAMECMP_BACKUP;
2043 	}
2044 
2045 	if (verbose > 3) {
2046 		rprintf(FINFO, "gen mapped %s of size %.0f\n",
2047-			fnamecmp, (double)st.st_size);
2048+			fnamecmp, (double)sx.st.st_size);
2049 	}
2050 
2051 	if (verbose > 2)
2052@@ -1318,24 +1391,32 @@ static void recv_generator(char *fname, 
2053 			iflags |= ITEM_BASIS_TYPE_FOLLOWS;
2054 		if (fnamecmp_type == FNAMECMP_FUZZY)
2055 			iflags |= ITEM_XNAME_FOLLOWS;
2056-		itemize(file, -1, real_ret, &real_st, iflags, fnamecmp_type,
2057+#ifdef SUPPORT_ACLS
2058+		if (preserve_acls && real_ret == 0)
2059+			get_acl(fnamecmp, &real_sx);
2060+#endif
2061+		itemize(file, -1, real_ret, &real_sx, iflags, fnamecmp_type,
2062 			fuzzy_file ? fuzzy_file->basename : NULL);
2063+#ifdef SUPPORT_ACLS
2064+		if (preserve_acls)
2065+			free_acl(&real_sx);
2066+#endif
2067 	}
2068 
2069 	if (!do_xfers) {
2070 		if (preserve_hard_links && file->link_u.links)
2071 			hard_link_cluster(file, ndx, itemizing, code);
2072-		return;
2073+		goto cleanup;
2074 	}
2075 	if (read_batch)
2076-		return;
2077+		goto cleanup;
2078 
2079 	if (statret != 0 || whole_file) {
2080 		write_sum_head(f_out, NULL);
2081-		return;
2082+		goto cleanup;
2083 	}
2084 
2085-	generate_and_send_sums(fd, st.st_size, f_out, f_copy);
2086+	generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy);
2087 
2088 	if (f_copy >= 0) {
2089 		close(f_copy);
2090@@ -1348,6 +1429,13 @@ static void recv_generator(char *fname, 
2091 	}
2092 
2093 	close(fd);
2094+
2095+  cleanup:
2096+#ifdef SUPPORT_ACLS
2097+	if (preserve_acls)
2098+		free_acl(&sx);
2099+#endif
2100+	return;
2101 }
2102 
2103 void generate_files(int f_out, struct file_list *flist, char *local_name)
2104@@ -1407,6 +1495,8 @@ void generate_files(int f_out, struct fi
2105 	 * notice that and let us know via the redo pipe (or its closing). */
2106 	ignore_timeout = 1;
2107 
2108+	dflt_perms = (ACCESSPERMS & ~orig_umask);
2109+
2110 	for (i = 0; i < flist->count; i++) {
2111 		struct file_struct *file = flist->files[i];
2112 
2113--- old/hlink.c
2114+++ new/hlink.c
2115@@ -26,6 +26,7 @@
2116 extern int verbose;
2117 extern int do_xfers;
2118 extern int link_dest;
2119+extern int preserve_acls;
2120 extern int make_backups;
2121 extern int remove_source_files;
2122 extern int stdout_format_has_i;
2123@@ -147,15 +148,19 @@ void init_hard_links(void)
2124 
2125 #ifdef SUPPORT_HARD_LINKS
2126 static int maybe_hard_link(struct file_struct *file, int ndx,
2127-			   char *fname, int statret, STRUCT_STAT *st,
2128+			   char *fname, int statret, statx *sxp,
2129 			   char *toname, STRUCT_STAT *to_st,
2130 			   int itemizing, enum logcode code)
2131 {
2132 	if (statret == 0) {
2133-		if (st->st_dev == to_st->st_dev
2134-		 && st->st_ino == to_st->st_ino) {
2135+		if (sxp->st.st_dev == to_st->st_dev
2136+		 && sxp->st.st_ino == to_st->st_ino) {
2137 			if (itemizing) {
2138-				itemize(file, ndx, statret, st,
2139+#ifdef SUPPORT_ACLS
2140+				if (preserve_acls && !ACL_READY(*sxp))
2141+					get_acl(fname, sxp);
2142+#endif
2143+				itemize(file, ndx, statret, sxp,
2144 					ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
2145 					0, "");
2146 			}
2147@@ -170,13 +175,13 @@ static int maybe_hard_link(struct file_s
2148 			return -1;
2149 		}
2150 	}
2151-	return hard_link_one(file, ndx, fname, statret, st, toname,
2152+	return hard_link_one(file, ndx, fname, statret, sxp, toname,
2153 			     0, itemizing, code);
2154 }
2155 #endif
2156 
2157 int hard_link_check(struct file_struct *file, int ndx, char *fname,
2158-		    int statret, STRUCT_STAT *st, int itemizing,
2159+		    int statret, statx *sxp, int itemizing,
2160 		    enum logcode code, int skip)
2161 {
2162 #ifdef SUPPORT_HARD_LINKS
2163@@ -217,7 +222,7 @@ int hard_link_check(struct file_struct *
2164 						 || st2.st_ino != st3.st_ino)
2165 							continue;
2166 						statret = 1;
2167-						st = &st3;
2168+						sxp->st = st3;
2169 						if (verbose < 2 || !stdout_format_has_i) {
2170 							itemizing = 0;
2171 							code = FNONE;
2172@@ -227,12 +232,16 @@ int hard_link_check(struct file_struct *
2173 					if (!unchanged_file(cmpbuf, file, &st3))
2174 						continue;
2175 					statret = 1;
2176-					st = &st3;
2177-					if (unchanged_attrs(file, &st3))
2178+					sxp->st = st3;
2179+#ifdef SUPPORT_ACLS
2180+					if (preserve_acls)
2181+						get_acl(cmpbuf, sxp);
2182+#endif
2183+					if (unchanged_attrs(file, sxp))
2184 						break;
2185 				} while (basis_dir[++j] != NULL);
2186 			}
2187-			maybe_hard_link(file, ndx, fname, statret, st,
2188+			maybe_hard_link(file, ndx, fname, statret, sxp,
2189 					toname, &st2, itemizing, code);
2190 			if (remove_source_files == 1 && do_xfers) {
2191 				char numbuf[4];
2192@@ -250,7 +259,7 @@ int hard_link_check(struct file_struct *
2193 
2194 #ifdef SUPPORT_HARD_LINKS
2195 int hard_link_one(struct file_struct *file, int ndx, char *fname,
2196-		  int statret, STRUCT_STAT *st, char *toname, int terse,
2197+		  int statret, statx *sxp, char *toname, int terse,
2198 		  int itemizing, enum logcode code)
2199 {
2200 	if (do_link(toname, fname)) {
2201@@ -266,7 +275,11 @@ int hard_link_one(struct file_struct *fi
2202 	}
2203 
2204 	if (itemizing) {
2205-		itemize(file, ndx, statret, st,
2206+#ifdef SUPPORT_ACLS
2207+		if (preserve_acls && statret == 0 && !ACL_READY(*sxp))
2208+			get_acl(fname, sxp);
2209+#endif
2210+		itemize(file, ndx, statret, sxp,
2211 			ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
2212 			terse ? "" : toname);
2213 	}
2214@@ -283,11 +296,12 @@ void hard_link_cluster(struct file_struc
2215 #ifdef SUPPORT_HARD_LINKS
2216 	char hlink1[MAXPATHLEN];
2217 	char *hlink2;
2218-	STRUCT_STAT st1, st2;
2219+	statx sx;
2220+	STRUCT_STAT st;
2221 	int statret, ndx = master;
2222 
2223 	file->F_HLINDEX = FINISHED_LINK;
2224-	if (link_stat(f_name(file, hlink1), &st1, 0) < 0)
2225+	if (link_stat(f_name(file, hlink1), &st, 0) < 0)
2226 		return;
2227 	if (!(file->flags & FLAG_HLINK_TOL)) {
2228 		while (!(file->flags & FLAG_HLINK_EOL)) {
2229@@ -301,9 +315,13 @@ void hard_link_cluster(struct file_struc
2230 		if (file->F_HLINDEX != SKIPPED_LINK)
2231 			continue;
2232 		hlink2 = f_name(file, NULL);
2233-		statret = link_stat(hlink2, &st2, 0);
2234-		maybe_hard_link(file, ndx, hlink2, statret, &st2,
2235-				hlink1, &st1, itemizing, code);
2236+		statret = link_stat(hlink2, &sx.st, 0);
2237+		maybe_hard_link(file, ndx, hlink2, statret, &sx,
2238+				hlink1, &st, itemizing, code);
2239+#ifdef SUPPORT_ACLS
2240+		if (preserve_acls)
2241+			free_acl(&sx);
2242+#endif
2243 		if (remove_source_files == 1 && do_xfers) {
2244 			char numbuf[4];
2245 			SIVAL(numbuf, 0, ndx);
2246--- old/lib/sysacls.c
2247+++ new/lib/sysacls.c
2248@@ -0,0 +1,3251 @@
2249+/* 
2250+   Unix SMB/CIFS implementation.
2251+   Samba system utilities for ACL support.
2252+   Copyright (C) Jeremy Allison 2000.
2253+   
2254+   This program is free software; you can redistribute it and/or modify
2255+   it under the terms of the GNU General Public License as published by
2256+   the Free Software Foundation; either version 2 of the License, or
2257+   (at your option) any later version.
2258+   
2259+   This program is distributed in the hope that it will be useful,
2260+   but WITHOUT ANY WARRANTY; without even the implied warranty of
2261+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2262+   GNU General Public License for more details.
2263+   
2264+   You should have received a copy of the GNU General Public License
2265+   along with this program; if not, write to the Free Software
2266+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2267+*/
2268+
2269+#include "rsync.h"
2270+#include "sysacls.h" /****** ADDED ******/
2271+
2272+#ifdef SUPPORT_ACLS
2273+
2274+/****** EXTRAS -- THESE ITEMS ARE NOT FROM THE SAMBA SOURCE ******/
2275+#ifdef DEBUG
2276+#undef DEBUG
2277+#endif
2278+#define DEBUG(x,y)
2279+
2280+void SAFE_FREE(void *mem)
2281+{
2282+	if (mem)
2283+		free(mem);
2284+}
2285+
2286+char *uidtoname(uid_t uid)
2287+{
2288+	static char idbuf[12];
2289+	struct passwd *pw;
2290+
2291+	if ((pw = getpwuid(uid)) == NULL) {
2292+		slprintf(idbuf, sizeof(idbuf)-1, "%ld", (long)uid);
2293+		return idbuf;
2294+	}
2295+	return pw->pw_name;
2296+}
2297+/****** EXTRAS -- END ******/
2298+
2299+/*
2300+ This file wraps all differing system ACL interfaces into a consistent
2301+ one based on the POSIX interface. It also returns the correct errors
2302+ for older UNIX systems that don't support ACLs.
2303+
2304+ The interfaces that each ACL implementation must support are as follows :
2305+
2306+ int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2307+ int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
2308+ int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p
2309+ void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
2310+ SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
2311+ SMB_ACL_T sys_acl_get_fd(int fd)
2312+ int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
2313+ int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
2314+ char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
2315+ SMB_ACL_T sys_acl_init( int count)
2316+ int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2317+ int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
2318+ int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
2319+ int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
2320+ int sys_acl_valid( SMB_ACL_T theacl )
2321+ int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2322+ int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2323+ int sys_acl_delete_def_file(const char *path)
2324+
2325+ This next one is not POSIX complient - but we *have* to have it !
2326+ More POSIX braindamage.
2327+
2328+ int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
2329+
2330+ The generic POSIX free is the following call. We split this into
2331+ several different free functions as we may need to add tag info
2332+ to structures when emulating the POSIX interface.
2333+
2334+ int sys_acl_free( void *obj_p)
2335+
2336+ The calls we actually use are :
2337+
2338+ int sys_acl_free_text(char *text) - free acl_to_text
2339+ int sys_acl_free_acl(SMB_ACL_T posix_acl)
2340+ int sys_acl_free_qualifier(void *qualifier, SMB_ACL_TAG_T tagtype)
2341+
2342+*/
2343+
2344+#if defined(HAVE_POSIX_ACLS)
2345+
2346+/* Identity mapping - easy. */
2347+
2348+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2349+{
2350+	return acl_get_entry( the_acl, entry_id, entry_p);
2351+}
2352+
2353+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
2354+{
2355+	return acl_get_tag_type( entry_d, tag_type_p);
2356+}
2357+
2358+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
2359+{
2360+	return acl_get_permset( entry_d, permset_p);
2361+}
2362+
2363+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
2364+{
2365+	return acl_get_qualifier( entry_d);
2366+}
2367+
2368+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
2369+{
2370+	return acl_get_file( path_p, type);
2371+}
2372+
2373+SMB_ACL_T sys_acl_get_fd(int fd)
2374+{
2375+	return acl_get_fd(fd);
2376+}
2377+
2378+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
2379+{
2380+	return acl_clear_perms(permset);
2381+}
2382+
2383+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
2384+{
2385+	return acl_add_perm(permset, perm);
2386+}
2387+
2388+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
2389+{
2390+#if defined(HAVE_ACL_GET_PERM_NP)
2391+	/*
2392+	 * Required for TrustedBSD-based ACL implementations where
2393+	 * non-POSIX.1e functions are denoted by a _np (non-portable)
2394+	 * suffix.
2395+	 */
2396+	return acl_get_perm_np(permset, perm);
2397+#else
2398+	return acl_get_perm(permset, perm);
2399+#endif
2400+}
2401+
2402+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
2403+{
2404+	return acl_to_text( the_acl, plen);
2405+}
2406+
2407+SMB_ACL_T sys_acl_init( int count)
2408+{
2409+	return acl_init(count);
2410+}
2411+
2412+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2413+{
2414+	return acl_create_entry(pacl, pentry);
2415+}
2416+
2417+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
2418+{
2419+	return acl_set_tag_type(entry, tagtype);
2420+}
2421+
2422+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
2423+{
2424+	return acl_set_qualifier(entry, qual);
2425+}
2426+
2427+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
2428+{
2429+	return acl_set_permset(entry, permset);
2430+}
2431+
2432+int sys_acl_valid( SMB_ACL_T theacl )
2433+{
2434+	return acl_valid(theacl);
2435+}
2436+
2437+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2438+{
2439+	return acl_set_file(name, acltype, theacl);
2440+}
2441+
2442+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2443+{
2444+	return acl_set_fd(fd, theacl);
2445+}
2446+
2447+int sys_acl_delete_def_file(const char *name)
2448+{
2449+	return acl_delete_def_file(name);
2450+}
2451+
2452+int sys_acl_free_text(char *text)
2453+{
2454+	return acl_free(text);
2455+}
2456+
2457+int sys_acl_free_acl(SMB_ACL_T the_acl) 
2458+{
2459+	return acl_free(the_acl);
2460+}
2461+
2462+int sys_acl_free_qualifier(void *qual, UNUSED(SMB_ACL_TAG_T tagtype))
2463+{
2464+	return acl_free(qual);
2465+}
2466+
2467+#elif defined(HAVE_TRU64_ACLS)
2468+/*
2469+ * The interface to DEC/Compaq Tru64 UNIX ACLs
2470+ * is based on Draft 13 of the POSIX spec which is
2471+ * slightly different from the Draft 16 interface.
2472+ * 
2473+ * Also, some of the permset manipulation functions
2474+ * such as acl_clear_perm() and acl_add_perm() appear
2475+ * to be broken on Tru64 so we have to manipulate
2476+ * the permission bits in the permset directly.
2477+ */
2478+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2479+{
2480+	SMB_ACL_ENTRY_T	entry;
2481+
2482+	if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
2483+		return -1;
2484+	}
2485+
2486+	errno = 0;
2487+	if ((entry = acl_get_entry(the_acl)) != NULL) {
2488+		*entry_p = entry;
2489+		return 1;
2490+	}
2491+
2492+	return errno ? -1 : 0;
2493+}
2494+
2495+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
2496+{
2497+	return acl_get_tag_type( entry_d, tag_type_p);
2498+}
2499+
2500+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
2501+{
2502+	return acl_get_permset( entry_d, permset_p);
2503+}
2504+
2505+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
2506+{
2507+	return acl_get_qualifier( entry_d);
2508+}
2509+
2510+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
2511+{
2512+	return acl_get_file((char *)path_p, type);
2513+}
2514+
2515+SMB_ACL_T sys_acl_get_fd(int fd)
2516+{
2517+	return acl_get_fd(fd, ACL_TYPE_ACCESS);
2518+}
2519+
2520+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
2521+{
2522+	*permset = 0;		/* acl_clear_perm() is broken on Tru64	*/
2523+
2524+	return 0;
2525+}
2526+
2527+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
2528+{
2529+	if (perm & ~(SMB_ACL_READ | SMB_ACL_WRITE | SMB_ACL_EXECUTE)) {
2530+		errno = EINVAL;
2531+		return -1;
2532+	}
2533+
2534+	*permset |= perm;	/* acl_add_perm() is broken on Tru64	*/
2535+
2536+	return 0;
2537+}
2538+
2539+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
2540+{
2541+	return *permset & perm;	/* Tru64 doesn't have acl_get_perm() */
2542+}
2543+
2544+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
2545+{
2546+	return acl_to_text( the_acl, plen);
2547+}
2548+
2549+SMB_ACL_T sys_acl_init( int count)
2550+{
2551+	return acl_init(count);
2552+}
2553+
2554+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2555+{
2556+	SMB_ACL_ENTRY_T entry;
2557+
2558+	if ((entry = acl_create_entry(pacl)) == NULL) {
2559+		return -1;
2560+	}
2561+
2562+	*pentry = entry;
2563+	return 0;
2564+}
2565+
2566+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
2567+{
2568+	return acl_set_tag_type(entry, tagtype);
2569+}
2570+
2571+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
2572+{
2573+	return acl_set_qualifier(entry, qual);
2574+}
2575+
2576+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
2577+{
2578+	return acl_set_permset(entry, permset);
2579+}
2580+
2581+int sys_acl_valid( SMB_ACL_T theacl )
2582+{
2583+	acl_entry_t	entry;
2584+
2585+	return acl_valid(theacl, &entry);
2586+}
2587+
2588+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2589+{
2590+	return acl_set_file((char *)name, acltype, theacl);
2591+}
2592+
2593+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2594+{
2595+	return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
2596+}
2597+
2598+int sys_acl_delete_def_file(const char *name)
2599+{
2600+	return acl_delete_def_file((char *)name);
2601+}
2602+
2603+int sys_acl_free_text(char *text)
2604+{
2605+	/*
2606+	 * (void) cast and explicit return 0 are for DEC UNIX
2607+	 *  which just #defines acl_free_text() to be free()
2608+	 */
2609+	(void) acl_free_text(text);
2610+	return 0;
2611+}
2612+
2613+int sys_acl_free_acl(SMB_ACL_T the_acl) 
2614+{
2615+	return acl_free(the_acl);
2616+}
2617+
2618+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
2619+{
2620+	return acl_free_qualifier(qual, tagtype);
2621+}
2622+
2623+#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
2624+
2625+/*
2626+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
2627+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
2628+ */
2629+
2630+/*
2631+ * Note that while this code implements sufficient functionality
2632+ * to support the sys_acl_* interfaces it does not provide all
2633+ * of the semantics of the POSIX ACL interfaces.
2634+ *
2635+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
2636+ * from a call to sys_acl_get_entry() should not be assumed to be
2637+ * valid after calling any of the following functions, which may
2638+ * reorder the entries in the ACL.
2639+ *
2640+ *	sys_acl_valid()
2641+ *	sys_acl_set_file()
2642+ *	sys_acl_set_fd()
2643+ */
2644+
2645+/*
2646+ * The only difference between Solaris and UnixWare / OpenUNIX is
2647+ * that the #defines for the ACL operations have different names
2648+ */
2649+#if defined(HAVE_UNIXWARE_ACLS)
2650+
2651+#define	SETACL		ACL_SET
2652+#define	GETACL		ACL_GET
2653+#define	GETACLCNT	ACL_CNT
2654+
2655+#endif
2656+
2657+
2658+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2659+{
2660+	if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
2661+		errno = EINVAL;
2662+		return -1;
2663+	}
2664+
2665+	if (entry_p == NULL) {
2666+		errno = EINVAL;
2667+		return -1;
2668+	}
2669+
2670+	if (entry_id == SMB_ACL_FIRST_ENTRY) {
2671+		acl_d->next = 0;
2672+	}
2673+
2674+	if (acl_d->next < 0) {
2675+		errno = EINVAL;
2676+		return -1;
2677+	}
2678+
2679+	if (acl_d->next >= acl_d->count) {
2680+		return 0;
2681+	}
2682+
2683+	*entry_p = &acl_d->acl[acl_d->next++];
2684+
2685+	return 1;
2686+}
2687+
2688+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
2689+{
2690+	*type_p = entry_d->a_type;
2691+
2692+	return 0;
2693+}
2694+
2695+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
2696+{
2697+	*permset_p = &entry_d->a_perm;
2698+
2699+	return 0;
2700+}
2701+
2702+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
2703+{
2704+	if (entry_d->a_type != SMB_ACL_USER
2705+	    && entry_d->a_type != SMB_ACL_GROUP) {
2706+		errno = EINVAL;
2707+		return NULL;
2708+	}
2709+
2710+	return &entry_d->a_id;
2711+}
2712+
2713+/*
2714+ * There is no way of knowing what size the ACL returned by
2715+ * GETACL will be unless you first call GETACLCNT which means
2716+ * making an additional system call.
2717+ *
2718+ * In the hope of avoiding the cost of the additional system
2719+ * call in most cases, we initially allocate enough space for
2720+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
2721+ * be too small then we use GETACLCNT to find out the actual
2722+ * size, reallocate the ACL buffer, and then call GETACL again.
2723+ */
2724+
2725+#define	INITIAL_ACL_SIZE	16
2726+
2727+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
2728+{
2729+	SMB_ACL_T	acl_d;
2730+	int		count;		/* # of ACL entries allocated	*/
2731+	int		naccess;	/* # of access ACL entries	*/
2732+	int		ndefault;	/* # of default ACL entries	*/
2733+
2734+	if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
2735+		errno = EINVAL;
2736+		return NULL;
2737+	}
2738+
2739+	count = INITIAL_ACL_SIZE;
2740+	if ((acl_d = sys_acl_init(count)) == NULL) {
2741+		return NULL;
2742+	}
2743+
2744+	/*
2745+	 * If there isn't enough space for the ACL entries we use
2746+	 * GETACLCNT to determine the actual number of ACL entries
2747+	 * reallocate and try again. This is in a loop because it
2748+	 * is possible that someone else could modify the ACL and
2749+	 * increase the number of entries between the call to
2750+	 * GETACLCNT and the call to GETACL.
2751+	 */
2752+	while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
2753+	    && errno == ENOSPC) {
2754+
2755+		sys_acl_free_acl(acl_d);
2756+
2757+		if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
2758+			return NULL;
2759+		}
2760+
2761+		if ((acl_d = sys_acl_init(count)) == NULL) {
2762+			return NULL;
2763+		}
2764+	}
2765+
2766+	if (count < 0) {
2767+		sys_acl_free_acl(acl_d);
2768+		return NULL;
2769+	}
2770+
2771+	/*
2772+	 * calculate the number of access and default ACL entries
2773+	 *
2774+	 * Note: we assume that the acl() system call returned a
2775+	 * well formed ACL which is sorted so that all of the
2776+	 * access ACL entries preceed any default ACL entries
2777+	 */
2778+	for (naccess = 0; naccess < count; naccess++) {
2779+		if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
2780+			break;
2781+	}
2782+	ndefault = count - naccess;
2783+	
2784+	/*
2785+	 * if the caller wants the default ACL we have to copy
2786+	 * the entries down to the start of the acl[] buffer
2787+	 * and mask out the ACL_DEFAULT flag from the type field
2788+	 */
2789+	if (type == SMB_ACL_TYPE_DEFAULT) {
2790+		int	i, j;
2791+
2792+		for (i = 0, j = naccess; i < ndefault; i++, j++) {
2793+			acl_d->acl[i] = acl_d->acl[j];
2794+			acl_d->acl[i].a_type &= ~ACL_DEFAULT;
2795+		}
2796+
2797+		acl_d->count = ndefault;
2798+	} else {
2799+		acl_d->count = naccess;
2800+	}
2801+
2802+	return acl_d;
2803+}
2804+
2805+SMB_ACL_T sys_acl_get_fd(int fd)
2806+{
2807+	SMB_ACL_T	acl_d;
2808+	int		count;		/* # of ACL entries allocated	*/
2809+	int		naccess;	/* # of access ACL entries	*/
2810+
2811+	count = INITIAL_ACL_SIZE;
2812+	if ((acl_d = sys_acl_init(count)) == NULL) {
2813+		return NULL;
2814+	}
2815+
2816+	while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
2817+	    && errno == ENOSPC) {
2818+
2819+		sys_acl_free_acl(acl_d);
2820+
2821+		if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
2822+			return NULL;
2823+		}
2824+
2825+		if ((acl_d = sys_acl_init(count)) == NULL) {
2826+			return NULL;
2827+		}
2828+	}
2829+
2830+	if (count < 0) {
2831+		sys_acl_free_acl(acl_d);
2832+		return NULL;
2833+	}
2834+
2835+	/*
2836+	 * calculate the number of access ACL entries
2837+	 */
2838+	for (naccess = 0; naccess < count; naccess++) {
2839+		if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
2840+			break;
2841+	}
2842+	
2843+	acl_d->count = naccess;
2844+
2845+	return acl_d;
2846+}
2847+
2848+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
2849+{
2850+	*permset_d = 0;
2851+
2852+	return 0;
2853+}
2854+
2855+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
2856+{
2857+	if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
2858+	    && perm != SMB_ACL_EXECUTE) {
2859+		errno = EINVAL;
2860+		return -1;
2861+	}
2862+
2863+	if (permset_d == NULL) {
2864+		errno = EINVAL;
2865+		return -1;
2866+	}
2867+
2868+	*permset_d |= perm;
2869+
2870+	return 0;
2871+}
2872+
2873+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
2874+{
2875+	return *permset_d & perm;
2876+}
2877+
2878+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
2879+{
2880+	int	i;
2881+	int	len, maxlen;
2882+	char	*text;
2883+
2884+	/*
2885+	 * use an initial estimate of 20 bytes per ACL entry
2886+	 * when allocating memory for the text representation
2887+	 * of the ACL
2888+	 */
2889+	len	= 0;
2890+	maxlen	= 20 * acl_d->count;
2891+	if ((text = SMB_MALLOC(maxlen)) == NULL) {
2892+		errno = ENOMEM;
2893+		return NULL;
2894+	}
2895+
2896+	for (i = 0; i < acl_d->count; i++) {
2897+		struct acl	*ap	= &acl_d->acl[i];
2898+		struct group	*gr;
2899+		char		tagbuf[12];
2900+		char		idbuf[12];
2901+		char		*tag;
2902+		char		*id	= "";
2903+		char		perms[4];
2904+		int		nbytes;
2905+
2906+		switch (ap->a_type) {
2907+			/*
2908+			 * for debugging purposes it's probably more
2909+			 * useful to dump unknown tag types rather
2910+			 * than just returning an error
2911+			 */
2912+			default:
2913+				slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
2914+					ap->a_type);
2915+				tag = tagbuf;
2916+				slprintf(idbuf, sizeof(idbuf)-1, "%ld",
2917+					(long)ap->a_id);
2918+				id = idbuf;
2919+				break;
2920+
2921+			case SMB_ACL_USER:
2922+				id = uidtoname(ap->a_id);
2923+			case SMB_ACL_USER_OBJ:
2924+				tag = "user";
2925+				break;
2926+
2927+			case SMB_ACL_GROUP:
2928+				if ((gr = getgrgid(ap->a_id)) == NULL) {
2929+					slprintf(idbuf, sizeof(idbuf)-1, "%ld",
2930+						(long)ap->a_id);
2931+					id = idbuf;
2932+				} else {
2933+					id = gr->gr_name;
2934+				}
2935+			case SMB_ACL_GROUP_OBJ:
2936+				tag = "group";
2937+				break;
2938+
2939+			case SMB_ACL_OTHER:
2940+				tag = "other";
2941+				break;
2942+
2943+			case SMB_ACL_MASK:
2944+				tag = "mask";
2945+				break;
2946+
2947+		}
2948+
2949+		perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
2950+		perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
2951+		perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
2952+		perms[3] = '\0';
2953+
2954+		/*          <tag>      :  <qualifier>   :  rwx \n  \0 */
2955+		nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
2956+
2957+		/*
2958+		 * If this entry would overflow the buffer
2959+		 * allocate enough additional memory for this
2960+		 * entry and an estimate of another 20 bytes
2961+		 * for each entry still to be processed
2962+		 */
2963+		if ((len + nbytes) > maxlen) {
2964+			char *oldtext = text;
2965+
2966+			maxlen += nbytes + 20 * (acl_d->count - i);
2967+
2968+			if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
2969+				SAFE_FREE(oldtext);
2970+				errno = ENOMEM;
2971+				return NULL;
2972+			}
2973+		}
2974+
2975+		slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
2976+		len += nbytes - 1;
2977+	}
2978+
2979+	if (len_p)
2980+		*len_p = len;
2981+
2982+	return text;
2983+}
2984+
2985+SMB_ACL_T sys_acl_init(int count)
2986+{
2987+	SMB_ACL_T	a;
2988+
2989+	if (count < 0) {
2990+		errno = EINVAL;
2991+		return NULL;
2992+	}
2993+
2994+	/*
2995+	 * note that since the definition of the structure pointed
2996+	 * to by the SMB_ACL_T includes the first element of the
2997+	 * acl[] array, this actually allocates an ACL with room
2998+	 * for (count+1) entries
2999+	 */
3000+	if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
3001+		errno = ENOMEM;
3002+		return NULL;
3003+	}
3004+
3005+	a->size = count + 1;
3006+	a->count = 0;
3007+	a->next = -1;
3008+
3009+	return a;
3010+}
3011+
3012+
3013+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
3014+{
3015+	SMB_ACL_T	acl_d;
3016+	SMB_ACL_ENTRY_T	entry_d;
3017+
3018+	if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
3019+		errno = EINVAL;
3020+		return -1;
3021+	}
3022+
3023+	if (acl_d->count >= acl_d->size) {
3024+		errno = ENOSPC;
3025+		return -1;
3026+	}
3027+
3028+	entry_d		= &acl_d->acl[acl_d->count++];
3029+	entry_d->a_type	= 0;
3030+	entry_d->a_id	= -1;
3031+	entry_d->a_perm	= 0;
3032+	*entry_p	= entry_d;
3033+
3034+	return 0;
3035+}
3036+
3037+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
3038+{
3039+	switch (tag_type) {
3040+		case SMB_ACL_USER:
3041+		case SMB_ACL_USER_OBJ:
3042+		case SMB_ACL_GROUP:
3043+		case SMB_ACL_GROUP_OBJ:
3044+		case SMB_ACL_OTHER:
3045+		case SMB_ACL_MASK:
3046+			entry_d->a_type = tag_type;
3047+			break;
3048+		default:
3049+			errno = EINVAL;
3050+			return -1;
3051+	}
3052+
3053+	return 0;
3054+}
3055+
3056+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
3057+{
3058+	if (entry_d->a_type != SMB_ACL_GROUP
3059+	    && entry_d->a_type != SMB_ACL_USER) {
3060+		errno = EINVAL;
3061+		return -1;
3062+	}
3063+
3064+	entry_d->a_id = *((id_t *)qual_p);
3065+
3066+	return 0;
3067+}
3068+
3069+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
3070+{
3071+	if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
3072+		return EINVAL;
3073+	}
3074+
3075+	entry_d->a_perm = *permset_d;
3076+
3077+	return 0;
3078+}
3079+
3080+/*
3081+ * sort the ACL and check it for validity
3082+ *
3083+ * if it's a minimal ACL with only 4 entries then we
3084+ * need to recalculate the mask permissions to make
3085+ * sure that they are the same as the GROUP_OBJ
3086+ * permissions as required by the UnixWare acl() system call.
3087+ *
3088+ * (note: since POSIX allows minimal ACLs which only contain
3089+ * 3 entries - ie there is no mask entry - we should, in theory,
3090+ * check for this and add a mask entry if necessary - however
3091+ * we "know" that the caller of this interface always specifies
3092+ * a mask so, in practice "this never happens" (tm) - if it *does*
3093+ * happen aclsort() will fail and return an error and someone will
3094+ * have to fix it ...)
3095+ */
3096+
3097+static int acl_sort(SMB_ACL_T acl_d)
3098+{
3099+	int     fixmask = (acl_d->count <= 4);
3100+
3101+	if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
3102+		errno = EINVAL;
3103+		return -1;
3104+	}
3105+	return 0;
3106+}
3107+ 
3108+int sys_acl_valid(SMB_ACL_T acl_d)
3109+{
3110+	return acl_sort(acl_d);
3111+}
3112+
3113+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
3114+{
3115+	struct stat	s;
3116+	struct acl	*acl_p;
3117+	int		acl_count;
3118+	struct acl	*acl_buf	= NULL;
3119+	int		ret;
3120+
3121+	if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
3122+		errno = EINVAL;
3123+		return -1;
3124+	}
3125+
3126+	if (acl_sort(acl_d) != 0) {
3127+		return -1;
3128+	}
3129+
3130+	acl_p		= &acl_d->acl[0];
3131+	acl_count	= acl_d->count;
3132+
3133+	/*
3134+	 * if it's a directory there is extra work to do
3135+	 * since the acl() system call will replace both
3136+	 * the access ACLs and the default ACLs (if any)
3137+	 */
3138+	if (stat(name, &s) != 0) {
3139+		return -1;
3140+	}
3141+	if (S_ISDIR(s.st_mode)) {
3142+		SMB_ACL_T	acc_acl;
3143+		SMB_ACL_T	def_acl;
3144+		SMB_ACL_T	tmp_acl;
3145+		int		i;
3146+
3147+		if (type == SMB_ACL_TYPE_ACCESS) {
3148+			acc_acl = acl_d;
3149+			def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
3150+
3151+		} else {
3152+			def_acl = acl_d;
3153+			acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
3154+		}
3155+
3156+		if (tmp_acl == NULL) {
3157+			return -1;
3158+		}
3159+
3160+		/*
3161+		 * allocate a temporary buffer for the complete ACL
3162+		 */
3163+		acl_count = acc_acl->count + def_acl->count;
3164+		acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
3165+
3166+		if (acl_buf == NULL) {
3167+			sys_acl_free_acl(tmp_acl);
3168+			errno = ENOMEM;
3169+			return -1;
3170+		}
3171+
3172+		/*
3173+		 * copy the access control and default entries into the buffer
3174+		 */
3175+		memcpy(&acl_buf[0], &acc_acl->acl[0],
3176+			acc_acl->count * sizeof(acl_buf[0]));
3177+
3178+		memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
3179+			def_acl->count * sizeof(acl_buf[0]));
3180+
3181+		/*
3182+		 * set the ACL_DEFAULT flag on the default entries
3183+		 */
3184+		for (i = acc_acl->count; i < acl_count; i++) {
3185+			acl_buf[i].a_type |= ACL_DEFAULT;
3186+		}
3187+
3188+		sys_acl_free_acl(tmp_acl);
3189+
3190+	} else if (type != SMB_ACL_TYPE_ACCESS) {
3191+		errno = EINVAL;
3192+		return -1;
3193+	}
3194+
3195+	ret = acl(name, SETACL, acl_count, acl_p);
3196+
3197+	SAFE_FREE(acl_buf);
3198+
3199+	return ret;
3200+}
3201+
3202+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
3203+{
3204+	if (acl_sort(acl_d) != 0) {
3205+		return -1;
3206+	}
3207+
3208+	return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
3209+}
3210+
3211+int sys_acl_delete_def_file(const char *path)
3212+{
3213+	SMB_ACL_T	acl_d;
3214+	int		ret;
3215+
3216+	/*
3217+	 * fetching the access ACL and rewriting it has
3218+	 * the effect of deleting the default ACL
3219+	 */
3220+	if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
3221+		return -1;
3222+	}
3223+
3224+	ret = acl(path, SETACL, acl_d->count, acl_d->acl);
3225+
3226+	sys_acl_free_acl(acl_d);
3227+	
3228+	return ret;
3229+}
3230+
3231+int sys_acl_free_text(char *text)
3232+{
3233+	SAFE_FREE(text);
3234+	return 0;
3235+}
3236+
3237+int sys_acl_free_acl(SMB_ACL_T acl_d) 
3238+{
3239+	SAFE_FREE(acl_d);
3240+	return 0;
3241+}
3242+
3243+int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype))
3244+{
3245+	return 0;
3246+}
3247+
3248+#elif defined(HAVE_HPUX_ACLS)
3249+#include <dl.h>
3250+
3251+/*
3252+ * Based on the Solaris/SCO code - with modifications.
3253+ */
3254+
3255+/*
3256+ * Note that while this code implements sufficient functionality
3257+ * to support the sys_acl_* interfaces it does not provide all
3258+ * of the semantics of the POSIX ACL interfaces.
3259+ *
3260+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
3261+ * from a call to sys_acl_get_entry() should not be assumed to be
3262+ * valid after calling any of the following functions, which may
3263+ * reorder the entries in the ACL.
3264+ *
3265+ *	sys_acl_valid()
3266+ *	sys_acl_set_file()
3267+ *	sys_acl_set_fd()
3268+ */
3269+
3270+/* This checks if the POSIX ACL system call is defined */
3271+/* which basically corresponds to whether JFS 3.3 or   */
3272+/* higher is installed. If acl() was called when it    */
3273+/* isn't defined, it causes the process to core dump   */
3274+/* so it is important to check this and avoid acl()    */
3275+/* calls if it isn't there.                            */
3276+
3277+static BOOL hpux_acl_call_presence(void)
3278+{
3279+
3280+	shl_t handle = NULL;
3281+	void *value;
3282+	int ret_val=0;
3283+	static BOOL already_checked=0;
3284+
3285+	if(already_checked)
3286+		return True;
3287+
3288+
3289+	ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
3290+
3291+	if(ret_val != 0) {
3292+		DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
3293+			ret_val, errno, strerror(errno)));
3294+		DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
3295+		return False;
3296+	}
3297+
3298+	DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
3299+
3300+	already_checked = True;
3301+	return True;
3302+}
3303+
3304+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
3305+{
3306+	if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
3307+		errno = EINVAL;
3308+		return -1;
3309+	}
3310+
3311+	if (entry_p == NULL) {
3312+		errno = EINVAL;
3313+		return -1;
3314+	}
3315+
3316+	if (entry_id == SMB_ACL_FIRST_ENTRY) {
3317+		acl_d->next = 0;
3318+	}
3319+
3320+	if (acl_d->next < 0) {
3321+		errno = EINVAL;
3322+		return -1;
3323+	}
3324+
3325+	if (acl_d->next >= acl_d->count) {
3326+		return 0;
3327+	}
3328+
3329+	*entry_p = &acl_d->acl[acl_d->next++];
3330+
3331+	return 1;
3332+}
3333+
3334+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
3335+{
3336+	*type_p = entry_d->a_type;
3337+
3338+	return 0;
3339+}
3340+
3341+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
3342+{
3343+	*permset_p = &entry_d->a_perm;
3344+
3345+	return 0;
3346+}
3347+
3348+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
3349+{
3350+	if (entry_d->a_type != SMB_ACL_USER
3351+	    && entry_d->a_type != SMB_ACL_GROUP) {
3352+		errno = EINVAL;
3353+		return NULL;
3354+	}
3355+
3356+	return &entry_d->a_id;
3357+}
3358+
3359+/*
3360+ * There is no way of knowing what size the ACL returned by
3361+ * ACL_GET will be unless you first call ACL_CNT which means
3362+ * making an additional system call.
3363+ *
3364+ * In the hope of avoiding the cost of the additional system
3365+ * call in most cases, we initially allocate enough space for
3366+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
3367+ * be too small then we use ACL_CNT to find out the actual
3368+ * size, reallocate the ACL buffer, and then call ACL_GET again.
3369+ */
3370+
3371+#define	INITIAL_ACL_SIZE	16
3372+
3373+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
3374+{
3375+	SMB_ACL_T	acl_d;
3376+	int		count;		/* # of ACL entries allocated	*/
3377+	int		naccess;	/* # of access ACL entries	*/
3378+	int		ndefault;	/* # of default ACL entries	*/
3379+
3380+	if(hpux_acl_call_presence() == False) {
3381+		/* Looks like we don't have the acl() system call on HPUX. 
3382+		 * May be the system doesn't have the latest version of JFS.
3383+		 */
3384+		return NULL; 
3385+	}
3386+
3387+	if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
3388+		errno = EINVAL;
3389+		return NULL;
3390+	}
3391+
3392+	count = INITIAL_ACL_SIZE;
3393+	if ((acl_d = sys_acl_init(count)) == NULL) {
3394+		return NULL;
3395+	}
3396+
3397+	/*
3398+	 * If there isn't enough space for the ACL entries we use
3399+	 * ACL_CNT to determine the actual number of ACL entries
3400+	 * reallocate and try again. This is in a loop because it
3401+	 * is possible that someone else could modify the ACL and
3402+	 * increase the number of entries between the call to
3403+	 * ACL_CNT and the call to ACL_GET.
3404+	 */
3405+	while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
3406+
3407+		sys_acl_free_acl(acl_d);
3408+
3409+		if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
3410+			return NULL;
3411+		}
3412+
3413+		if ((acl_d = sys_acl_init(count)) == NULL) {
3414+			return NULL;
3415+		}
3416+	}
3417+
3418+	if (count < 0) {
3419+		sys_acl_free_acl(acl_d);
3420+		return NULL;
3421+	}
3422+
3423+	/*
3424+	 * calculate the number of access and default ACL entries
3425+	 *
3426+	 * Note: we assume that the acl() system call returned a
3427+	 * well formed ACL which is sorted so that all of the
3428+	 * access ACL entries preceed any default ACL entries
3429+	 */
3430+	for (naccess = 0; naccess < count; naccess++) {
3431+		if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
3432+			break;
3433+	}
3434+	ndefault = count - naccess;
3435+	
3436+	/*
3437+	 * if the caller wants the default ACL we have to copy
3438+	 * the entries down to the start of the acl[] buffer
3439+	 * and mask out the ACL_DEFAULT flag from the type field
3440+	 */
3441+	if (type == SMB_ACL_TYPE_DEFAULT) {
3442+		int	i, j;
3443+
3444+		for (i = 0, j = naccess; i < ndefault; i++, j++) {
3445+			acl_d->acl[i] = acl_d->acl[j];
3446+			acl_d->acl[i].a_type &= ~ACL_DEFAULT;
3447+		}
3448+
3449+		acl_d->count = ndefault;
3450+	} else {
3451+		acl_d->count = naccess;
3452+	}
3453+
3454+	return acl_d;
3455+}
3456+
3457+SMB_ACL_T sys_acl_get_fd(int fd)
3458+{
3459+	/*
3460+	 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
3461+	 */
3462+
3463+	files_struct *fsp = file_find_fd(fd);
3464+
3465+	if (fsp == NULL) {
3466+		errno = EBADF;
3467+		return NULL;
3468+	}
3469+
3470+	/*
3471+	 * We know we're in the same conn context. So we
3472+	 * can use the relative path.
3473+	 */
3474+
3475+	return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
3476+}
3477+
3478+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
3479+{
3480+	*permset_d = 0;
3481+
3482+	return 0;
3483+}
3484+
3485+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
3486+{
3487+	if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
3488+	    && perm != SMB_ACL_EXECUTE) {
3489+		errno = EINVAL;
3490+		return -1;
3491+	}
3492+
3493+	if (permset_d == NULL) {
3494+		errno = EINVAL;
3495+		return -1;
3496+	}
3497+
3498+	*permset_d |= perm;
3499+
3500+	return 0;
3501+}
3502+
3503+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
3504+{
3505+	return *permset_d & perm;
3506+}
3507+
3508+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
3509+{
3510+	int	i;
3511+	int	len, maxlen;
3512+	char	*text;
3513+
3514+	/*
3515+	 * use an initial estimate of 20 bytes per ACL entry
3516+	 * when allocating memory for the text representation
3517+	 * of the ACL
3518+	 */
3519+	len	= 0;
3520+	maxlen	= 20 * acl_d->count;
3521+	if ((text = SMB_MALLOC(maxlen)) == NULL) {
3522+		errno = ENOMEM;
3523+		return NULL;
3524+	}
3525+
3526+	for (i = 0; i < acl_d->count; i++) {
3527+		struct acl	*ap	= &acl_d->acl[i];
3528+		struct group	*gr;
3529+		char		tagbuf[12];
3530+		char		idbuf[12];
3531+		char		*tag;
3532+		char		*id	= "";
3533+		char		perms[4];
3534+		int		nbytes;
3535+
3536+		switch (ap->a_type) {
3537+			/*
3538+			 * for debugging purposes it's probably more
3539+			 * useful to dump unknown tag types rather
3540+			 * than just returning an error
3541+			 */
3542+			default:
3543+				slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
3544+					ap->a_type);
3545+				tag = tagbuf;
3546+				slprintf(idbuf, sizeof(idbuf)-1, "%ld",
3547+					(long)ap->a_id);
3548+				id = idbuf;
3549+				break;
3550+
3551+			case SMB_ACL_USER:
3552+				id = uidtoname(ap->a_id);
3553+			case SMB_ACL_USER_OBJ:
3554+				tag = "user";
3555+				break;
3556+
3557+			case SMB_ACL_GROUP:
3558+				if ((gr = getgrgid(ap->a_id)) == NULL) {
3559+					slprintf(idbuf, sizeof(idbuf)-1, "%ld",
3560+						(long)ap->a_id);
3561+					id = idbuf;
3562+				} else {
3563+					id = gr->gr_name;
3564+				}
3565+			case SMB_ACL_GROUP_OBJ:
3566+				tag = "group";
3567+				break;
3568+
3569+			case SMB_ACL_OTHER:
3570+				tag = "other";
3571+				break;
3572+
3573+			case SMB_ACL_MASK:
3574+				tag = "mask";
3575+				break;
3576+
3577+		}
3578+
3579+		perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
3580+		perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
3581+		perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
3582+		perms[3] = '\0';
3583+
3584+		/*          <tag>      :  <qualifier>   :  rwx \n  \0 */
3585+		nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
3586+
3587+		/*
3588+		 * If this entry would overflow the buffer
3589+		 * allocate enough additional memory for this
3590+		 * entry and an estimate of another 20 bytes
3591+		 * for each entry still to be processed
3592+		 */
3593+		if ((len + nbytes) > maxlen) {
3594+			char *oldtext = text;
3595+
3596+			maxlen += nbytes + 20 * (acl_d->count - i);
3597+
3598+			if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
3599+				free(oldtext);
3600+				errno = ENOMEM;
3601+				return NULL;
3602+			}
3603+		}
3604+
3605+		slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
3606+		len += nbytes - 1;
3607+	}
3608+
3609+	if (len_p)
3610+		*len_p = len;
3611+
3612+	return text;
3613+}
3614+
3615+SMB_ACL_T sys_acl_init(int count)
3616+{
3617+	SMB_ACL_T	a;
3618+
3619+	if (count < 0) {
3620+		errno = EINVAL;
3621+		return NULL;
3622+	}
3623+
3624+	/*
3625+	 * note that since the definition of the structure pointed
3626+	 * to by the SMB_ACL_T includes the first element of the
3627+	 * acl[] array, this actually allocates an ACL with room
3628+	 * for (count+1) entries
3629+	 */
3630+	if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
3631+		errno = ENOMEM;
3632+		return NULL;
3633+	}
3634+
3635+	a->size = count + 1;
3636+	a->count = 0;
3637+	a->next = -1;
3638+
3639+	return a;
3640+}
3641+
3642+
3643+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
3644+{
3645+	SMB_ACL_T	acl_d;
3646+	SMB_ACL_ENTRY_T	entry_d;
3647+
3648+	if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
3649+		errno = EINVAL;
3650+		return -1;
3651+	}
3652+
3653+	if (acl_d->count >= acl_d->size) {
3654+		errno = ENOSPC;
3655+		return -1;
3656+	}
3657+
3658+	entry_d		= &acl_d->acl[acl_d->count++];
3659+	entry_d->a_type	= 0;
3660+	entry_d->a_id	= -1;
3661+	entry_d->a_perm	= 0;
3662+	*entry_p	= entry_d;
3663+
3664+	return 0;
3665+}
3666+
3667+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
3668+{
3669+	switch (tag_type) {
3670+		case SMB_ACL_USER:
3671+		case SMB_ACL_USER_OBJ:
3672+		case SMB_ACL_GROUP:
3673+		case SMB_ACL_GROUP_OBJ:
3674+		case SMB_ACL_OTHER:
3675+		case SMB_ACL_MASK:
3676+			entry_d->a_type = tag_type;
3677+			break;
3678+		default:
3679+			errno = EINVAL;
3680+			return -1;
3681+	}
3682+
3683+	return 0;
3684+}
3685+
3686+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
3687+{
3688+	if (entry_d->a_type != SMB_ACL_GROUP
3689+	    && entry_d->a_type != SMB_ACL_USER) {
3690+		errno = EINVAL;
3691+		return -1;
3692+	}
3693+
3694+	entry_d->a_id = *((id_t *)qual_p);
3695+
3696+	return 0;
3697+}
3698+
3699+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
3700+{
3701+	if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
3702+		return EINVAL;
3703+	}
3704+
3705+	entry_d->a_perm = *permset_d;
3706+
3707+	return 0;
3708+}
3709+
3710+/* Structure to capture the count for each type of ACE. */
3711+
3712+struct hpux_acl_types {
3713+	int n_user;
3714+	int n_def_user;
3715+	int n_user_obj;
3716+	int n_def_user_obj;
3717+
3718+	int n_group;
3719+	int n_def_group;
3720+	int n_group_obj;
3721+	int n_def_group_obj;
3722+
3723+	int n_other;
3724+	int n_other_obj;
3725+	int n_def_other_obj;
3726+
3727+	int n_class_obj;
3728+	int n_def_class_obj;
3729+
3730+	int n_illegal_obj;
3731+};
3732+
3733+/* count_obj:
3734+ * Counts the different number of objects in a given array of ACL
3735+ * structures.
3736+ * Inputs:
3737+ *
3738+ * acl_count      - Count of ACLs in the array of ACL strucutres.
3739+ * aclp           - Array of ACL structures.
3740+ * acl_type_count - Pointer to acl_types structure. Should already be
3741+ *                  allocated.
3742+ * Output: 
3743+ *
3744+ * acl_type_count - This structure is filled up with counts of various 
3745+ *                  acl types.
3746+ */
3747+
3748+static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
3749+{
3750+	int i;
3751+
3752+	memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
3753+
3754+	for(i=0;i<acl_count;i++) {
3755+		switch(aclp[i].a_type) {
3756+		case USER: 
3757+			acl_type_count->n_user++;
3758+			break;
3759+		case USER_OBJ: 
3760+			acl_type_count->n_user_obj++;
3761+			break;
3762+		case DEF_USER_OBJ: 
3763+			acl_type_count->n_def_user_obj++;
3764+			break;
3765+		case GROUP: 
3766+			acl_type_count->n_group++;
3767+			break;
3768+		case GROUP_OBJ: 
3769+			acl_type_count->n_group_obj++;
3770+			break;
3771+		case DEF_GROUP_OBJ: 
3772+			acl_type_count->n_def_group_obj++;
3773+			break;
3774+		case OTHER_OBJ: 
3775+			acl_type_count->n_other_obj++;
3776+			break;
3777+		case DEF_OTHER_OBJ: 
3778+			acl_type_count->n_def_other_obj++;
3779+			break;
3780+		case CLASS_OBJ:
3781+			acl_type_count->n_class_obj++;
3782+			break;
3783+		case DEF_CLASS_OBJ:
3784+			acl_type_count->n_def_class_obj++;
3785+			break;
3786+		case DEF_USER:
3787+			acl_type_count->n_def_user++;
3788+			break;
3789+		case DEF_GROUP:
3790+			acl_type_count->n_def_group++;
3791+			break;
3792+		default: 
3793+			acl_type_count->n_illegal_obj++;
3794+			break;
3795+		}
3796+	}
3797+}
3798+
3799+/* swap_acl_entries:  Swaps two ACL entries. 
3800+ *
3801+ * Inputs: aclp0, aclp1 - ACL entries to be swapped.
3802+ */
3803+
3804+static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
3805+{
3806+	struct acl temp_acl;
3807+
3808+	temp_acl.a_type = aclp0->a_type;
3809+	temp_acl.a_id = aclp0->a_id;
3810+	temp_acl.a_perm = aclp0->a_perm;
3811+
3812+	aclp0->a_type = aclp1->a_type;
3813+	aclp0->a_id = aclp1->a_id;
3814+	aclp0->a_perm = aclp1->a_perm;
3815+
3816+	aclp1->a_type = temp_acl.a_type;
3817+	aclp1->a_id = temp_acl.a_id;
3818+	aclp1->a_perm = temp_acl.a_perm;
3819+}
3820+
3821+/* prohibited_duplicate_type
3822+ * Identifies if given ACL type can have duplicate entries or 
3823+ * not.
3824+ *
3825+ * Inputs: acl_type - ACL Type.
3826+ *
3827+ * Outputs: 
3828+ *
3829+ * Return.. 
3830+ *
3831+ * True - If the ACL type matches any of the prohibited types.
3832+ * False - If the ACL type doesn't match any of the prohibited types.
3833+ */ 
3834+
3835+static BOOL hpux_prohibited_duplicate_type(int acl_type)
3836+{
3837+	switch(acl_type) {
3838+		case USER:
3839+		case GROUP:
3840+		case DEF_USER: 
3841+		case DEF_GROUP:
3842+			return True;
3843+		default:
3844+			return False;
3845+	}
3846+}
3847+
3848+/* get_needed_class_perm
3849+ * Returns the permissions of a ACL structure only if the ACL
3850+ * type matches one of the pre-determined types for computing 
3851+ * CLASS_OBJ permissions.
3852+ *
3853+ * Inputs: aclp - Pointer to ACL structure.
3854+ */
3855+
3856+static int hpux_get_needed_class_perm(struct acl *aclp)
3857+{
3858+	switch(aclp->a_type) {
3859+		case USER: 
3860+		case GROUP_OBJ: 
3861+		case GROUP: 
3862+		case DEF_USER_OBJ: 
3863+		case DEF_USER:
3864+		case DEF_GROUP_OBJ: 
3865+		case DEF_GROUP:
3866+		case DEF_CLASS_OBJ:
3867+		case DEF_OTHER_OBJ: 
3868+			return aclp->a_perm;
3869+		default: 
3870+			return 0;
3871+	}
3872+}
3873+
3874+/* acl_sort for HPUX.
3875+ * Sorts the array of ACL structures as per the description in
3876+ * aclsort man page. Refer to aclsort man page for more details
3877+ *
3878+ * Inputs:
3879+ *
3880+ * acl_count - Count of ACLs in the array of ACL structures.
3881+ * calclass  - If this is not zero, then we compute the CLASS_OBJ
3882+ *             permissions.
3883+ * aclp      - Array of ACL structures.
3884+ *
3885+ * Outputs:
3886+ *
3887+ * aclp     - Sorted array of ACL structures.
3888+ *
3889+ * Outputs:
3890+ *
3891+ * Returns 0 for success -1 for failure. Prints a message to the Samba
3892+ * debug log in case of failure.
3893+ */
3894+
3895+static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
3896+{
3897+#if !defined(HAVE_HPUX_ACLSORT)
3898+	/*
3899+	 * The aclsort() system call is availabe on the latest HPUX General
3900+	 * Patch Bundles. So for HPUX, we developed our version of acl_sort 
3901+	 * function. Because, we don't want to update to a new 
3902+	 * HPUX GR bundle just for aclsort() call.
3903+	 */
3904+
3905+	struct hpux_acl_types acl_obj_count;
3906+	int n_class_obj_perm = 0;
3907+	int i, j;
3908+ 
3909+	if(!acl_count) {
3910+		DEBUG(10,("Zero acl count passed. Returning Success\n"));
3911+		return 0;
3912+	}
3913+
3914+	if(aclp == NULL) {
3915+		DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
3916+		return -1;
3917+	}
3918+
3919+	/* Count different types of ACLs in the ACLs array */
3920+
3921+	hpux_count_obj(acl_count, aclp, &acl_obj_count);
3922+
3923+	/* There should be only one entry each of type USER_OBJ, GROUP_OBJ, 
3924+	 * CLASS_OBJ and OTHER_OBJ 
3925+	 */
3926+
3927+	if( (acl_obj_count.n_user_obj  != 1) || 
3928+		(acl_obj_count.n_group_obj != 1) || 
3929+		(acl_obj_count.n_class_obj != 1) ||
3930+		(acl_obj_count.n_other_obj != 1) 
3931+	) {
3932+		DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
3933+USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
3934+		return -1;
3935+	}
3936+
3937+	/* If any of the default objects are present, there should be only
3938+	 * one of them each.
3939+	 */
3940+
3941+	if( (acl_obj_count.n_def_user_obj  > 1) || (acl_obj_count.n_def_group_obj > 1) || 
3942+			(acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
3943+		DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
3944+or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
3945+		return -1;
3946+	}
3947+
3948+	/* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl 
3949+	 * structures.  
3950+	 *
3951+	 * Sorting crieteria - First sort by ACL type. If there are multiple entries of
3952+	 * same ACL type, sort by ACL id.
3953+	 *
3954+	 * I am using the trival kind of sorting method here because, performance isn't 
3955+	 * really effected by the ACLs feature. More over there aren't going to be more
3956+	 * than 17 entries on HPUX. 
3957+	 */
3958+
3959+	for(i=0; i<acl_count;i++) {
3960+		for (j=i+1; j<acl_count; j++) {
3961+			if( aclp[i].a_type > aclp[j].a_type ) {
3962+				/* ACL entries out of order, swap them */
3963+
3964+				hpux_swap_acl_entries((aclp+i), (aclp+j));
3965+
3966+			} else if ( aclp[i].a_type == aclp[j].a_type ) {
3967+
3968+				/* ACL entries of same type, sort by id */
3969+
3970+				if(aclp[i].a_id > aclp[j].a_id) {
3971+					hpux_swap_acl_entries((aclp+i), (aclp+j));
3972+				} else if (aclp[i].a_id == aclp[j].a_id) {
3973+					/* We have a duplicate entry. */
3974+					if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
3975+						DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
3976+							aclp[i].a_type, aclp[i].a_id));
3977+						return -1;
3978+					}
3979+				}
3980+
3981+			}
3982+		}
3983+	}
3984+
3985+	/* set the class obj permissions to the computed one. */
3986+	if(calclass) {
3987+		int n_class_obj_index = -1;
3988+
3989+		for(i=0;i<acl_count;i++) {
3990+			n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
3991+
3992+			if(aclp[i].a_type == CLASS_OBJ)
3993+				n_class_obj_index = i;
3994+		}
3995+		aclp[n_class_obj_index].a_perm = n_class_obj_perm;
3996+	}
3997+
3998+	return 0;
3999+#else
4000+	return aclsort(acl_count, calclass, aclp);
4001+#endif
4002+}
4003+
4004+/*
4005+ * sort the ACL and check it for validity
4006+ *
4007+ * if it's a minimal ACL with only 4 entries then we
4008+ * need to recalculate the mask permissions to make
4009+ * sure that they are the same as the GROUP_OBJ
4010+ * permissions as required by the UnixWare acl() system call.
4011+ *
4012+ * (note: since POSIX allows minimal ACLs which only contain
4013+ * 3 entries - ie there is no mask entry - we should, in theory,
4014+ * check for this and add a mask entry if necessary - however
4015+ * we "know" that the caller of this interface always specifies
4016+ * a mask so, in practice "this never happens" (tm) - if it *does*
4017+ * happen aclsort() will fail and return an error and someone will
4018+ * have to fix it ...)
4019+ */
4020+
4021+static int acl_sort(SMB_ACL_T acl_d)
4022+{
4023+	int fixmask = (acl_d->count <= 4);
4024+
4025+	if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
4026+		errno = EINVAL;
4027+		return -1;
4028+	}
4029+	return 0;
4030+}
4031+ 
4032+int sys_acl_valid(SMB_ACL_T acl_d)
4033+{
4034+	return acl_sort(acl_d);
4035+}
4036+
4037+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
4038+{
4039+	struct stat	s;
4040+	struct acl	*acl_p;
4041+	int		acl_count;
4042+	struct acl	*acl_buf	= NULL;
4043+	int		ret;
4044+
4045+	if(hpux_acl_call_presence() == False) {
4046+		/* Looks like we don't have the acl() system call on HPUX. 
4047+		 * May be the system doesn't have the latest version of JFS.
4048+		 */
4049+		errno=ENOSYS;
4050+		return -1; 
4051+	}
4052+
4053+	if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
4054+		errno = EINVAL;
4055+		return -1;
4056+	}
4057+
4058+	if (acl_sort(acl_d) != 0) {
4059+		return -1;
4060+	}
4061+
4062+	acl_p		= &acl_d->acl[0];
4063+	acl_count	= acl_d->count;
4064+
4065+	/*
4066+	 * if it's a directory there is extra work to do
4067+	 * since the acl() system call will replace both
4068+	 * the access ACLs and the default ACLs (if any)
4069+	 */
4070+	if (stat(name, &s) != 0) {
4071+		return -1;
4072+	}
4073+	if (S_ISDIR(s.st_mode)) {
4074+		SMB_ACL_T	acc_acl;
4075+		SMB_ACL_T	def_acl;
4076+		SMB_ACL_T	tmp_acl;
4077+		int		i;
4078+
4079+		if (type == SMB_ACL_TYPE_ACCESS) {
4080+			acc_acl = acl_d;
4081+			def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
4082+
4083+		} else {
4084+			def_acl = acl_d;
4085+			acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
4086+		}
4087+
4088+		if (tmp_acl == NULL) {
4089+			return -1;
4090+		}
4091+
4092+		/*
4093+		 * allocate a temporary buffer for the complete ACL
4094+		 */
4095+		acl_count = acc_acl->count + def_acl->count;
4096+		acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
4097+
4098+		if (acl_buf == NULL) {
4099+			sys_acl_free_acl(tmp_acl);
4100+			errno = ENOMEM;
4101+			return -1;
4102+		}
4103+
4104+		/*
4105+		 * copy the access control and default entries into the buffer
4106+		 */
4107+		memcpy(&acl_buf[0], &acc_acl->acl[0],
4108+			acc_acl->count * sizeof(acl_buf[0]));
4109+
4110+		memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
4111+			def_acl->count * sizeof(acl_buf[0]));
4112+
4113+		/*
4114+		 * set the ACL_DEFAULT flag on the default entries
4115+		 */
4116+		for (i = acc_acl->count; i < acl_count; i++) {
4117+			acl_buf[i].a_type |= ACL_DEFAULT;
4118+		}
4119+
4120+		sys_acl_free_acl(tmp_acl);
4121+
4122+	} else if (type != SMB_ACL_TYPE_ACCESS) {
4123+		errno = EINVAL;
4124+		return -1;
4125+	}
4126+
4127+	ret = acl(name, ACL_SET, acl_count, acl_p);
4128+
4129+	if (acl_buf) {
4130+		free(acl_buf);
4131+	}
4132+
4133+	return ret;
4134+}
4135+
4136+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
4137+{
4138+	/*
4139+	 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
4140+	 */
4141+
4142+	files_struct *fsp = file_find_fd(fd);
4143+
4144+	if (fsp == NULL) {
4145+		errno = EBADF;
4146+		return NULL;
4147+	}
4148+
4149+	if (acl_sort(acl_d) != 0) {
4150+		return -1;
4151+	}
4152+
4153+	/*
4154+	 * We know we're in the same conn context. So we
4155+	 * can use the relative path.
4156+	 */
4157+
4158+	return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
4159+}
4160+
4161+int sys_acl_delete_def_file(const char *path)
4162+{
4163+	SMB_ACL_T	acl_d;
4164+	int		ret;
4165+
4166+	/*
4167+	 * fetching the access ACL and rewriting it has
4168+	 * the effect of deleting the default ACL
4169+	 */
4170+	if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
4171+		return -1;
4172+	}
4173+
4174+	ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
4175+
4176+	sys_acl_free_acl(acl_d);
4177+	
4178+	return ret;
4179+}
4180+
4181+int sys_acl_free_text(char *text)
4182+{
4183+	free(text);
4184+	return 0;
4185+}
4186+
4187+int sys_acl_free_acl(SMB_ACL_T acl_d) 
4188+{
4189+	free(acl_d);
4190+	return 0;
4191+}
4192+
4193+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
4194+{
4195+	return 0;
4196+}
4197+
4198+#elif defined(HAVE_IRIX_ACLS)
4199+
4200+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
4201+{
4202+	if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
4203+		errno = EINVAL;
4204+		return -1;
4205+	}
4206+
4207+	if (entry_p == NULL) {
4208+		errno = EINVAL;
4209+		return -1;
4210+	}
4211+
4212+	if (entry_id == SMB_ACL_FIRST_ENTRY) {
4213+		acl_d->next = 0;
4214+	}
4215+
4216+	if (acl_d->next < 0) {
4217+		errno = EINVAL;
4218+		return -1;
4219+	}
4220+
4221+	if (acl_d->next >= acl_d->aclp->acl_cnt) {
4222+		return 0;
4223+	}
4224+
4225+	*entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
4226+
4227+	return 1;
4228+}
4229+
4230+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
4231+{
4232+	*type_p = entry_d->ae_tag;
4233+
4234+	return 0;
4235+}
4236+
4237+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
4238+{
4239+	*permset_p = entry_d;
4240+
4241+	return 0;
4242+}
4243+
4244+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
4245+{
4246+	if (entry_d->ae_tag != SMB_ACL_USER
4247+	    && entry_d->ae_tag != SMB_ACL_GROUP) {
4248+		errno = EINVAL;
4249+		return NULL;
4250+	}
4251+
4252+	return &entry_d->ae_id;
4253+}
4254+
4255+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
4256+{
4257+	SMB_ACL_T	a;
4258+
4259+	if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
4260+		errno = ENOMEM;
4261+		return NULL;
4262+	}
4263+	if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
4264+		SAFE_FREE(a);
4265+		return NULL;
4266+	}
4267+	a->next = -1;
4268+	a->freeaclp = True;
4269+	return a;
4270+}
4271+
4272+SMB_ACL_T sys_acl_get_fd(int fd)
4273+{
4274+	SMB_ACL_T	a;
4275+
4276+	if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
4277+		errno = ENOMEM;
4278+		return NULL;
4279+	}
4280+	if ((a->aclp = acl_get_fd(fd)) == NULL) {
4281+		SAFE_FREE(a);
4282+		return NULL;
4283+	}
4284+	a->next = -1;
4285+	a->freeaclp = True;
4286+	return a;
4287+}
4288+
4289+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
4290+{
4291+	permset_d->ae_perm = 0;
4292+
4293+	return 0;
4294+}
4295+
4296+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
4297+{
4298+	if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
4299+	    && perm != SMB_ACL_EXECUTE) {
4300+		errno = EINVAL;
4301+		return -1;
4302+	}
4303+
4304+	if (permset_d == NULL) {
4305+		errno = EINVAL;
4306+		return -1;
4307+	}
4308+
4309+	permset_d->ae_perm |= perm;
4310+
4311+	return 0;
4312+}
4313+
4314+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
4315+{
4316+	return permset_d->ae_perm & perm;
4317+}
4318+
4319+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
4320+{
4321+	return acl_to_text(acl_d->aclp, len_p);
4322+}
4323+
4324+SMB_ACL_T sys_acl_init(int count)
4325+{
4326+	SMB_ACL_T	a;
4327+
4328+	if (count < 0) {
4329+		errno = EINVAL;
4330+		return NULL;
4331+	}
4332+
4333+	if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) {
4334+		errno = ENOMEM;
4335+		return NULL;
4336+	}
4337+
4338+	a->next = -1;
4339+	a->freeaclp = False;
4340+	a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
4341+	a->aclp->acl_cnt = 0;
4342+
4343+	return a;
4344+}
4345+
4346+
4347+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
4348+{
4349+	SMB_ACL_T	acl_d;
4350+	SMB_ACL_ENTRY_T	entry_d;
4351+
4352+	if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
4353+		errno = EINVAL;
4354+		return -1;
4355+	}
4356+
4357+	if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
4358+		errno = ENOSPC;
4359+		return -1;
4360+	}
4361+
4362+	entry_d		= &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
4363+	entry_d->ae_tag	= 0;
4364+	entry_d->ae_id	= 0;
4365+	entry_d->ae_perm	= 0;
4366+	*entry_p	= entry_d;
4367+
4368+	return 0;
4369+}
4370+
4371+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
4372+{
4373+	switch (tag_type) {
4374+		case SMB_ACL_USER:
4375+		case SMB_ACL_USER_OBJ:
4376+		case SMB_ACL_GROUP:
4377+		case SMB_ACL_GROUP_OBJ:
4378+		case SMB_ACL_OTHER:
4379+		case SMB_ACL_MASK:
4380+			entry_d->ae_tag = tag_type;
4381+			break;
4382+		default:
4383+			errno = EINVAL;
4384+			return -1;
4385+	}
4386+
4387+	return 0;
4388+}
4389+
4390+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
4391+{
4392+	if (entry_d->ae_tag != SMB_ACL_GROUP
4393+	    && entry_d->ae_tag != SMB_ACL_USER) {
4394+		errno = EINVAL;
4395+		return -1;
4396+	}
4397+
4398+	entry_d->ae_id = *((id_t *)qual_p);
4399+
4400+	return 0;
4401+}
4402+
4403+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
4404+{
4405+	if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
4406+		return EINVAL;
4407+	}
4408+
4409+	entry_d->ae_perm = permset_d->ae_perm;
4410+
4411+	return 0;
4412+}
4413+
4414+int sys_acl_valid(SMB_ACL_T acl_d)
4415+{
4416+	return acl_valid(acl_d->aclp);
4417+}
4418+
4419+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
4420+{
4421+	return acl_set_file(name, type, acl_d->aclp);
4422+}
4423+
4424+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
4425+{
4426+	return acl_set_fd(fd, acl_d->aclp);
4427+}
4428+
4429+int sys_acl_delete_def_file(const char *name)
4430+{
4431+	return acl_delete_def_file(name);
4432+}
4433+
4434+int sys_acl_free_text(char *text)
4435+{
4436+	return acl_free(text);
4437+}
4438+
4439+int sys_acl_free_acl(SMB_ACL_T acl_d) 
4440+{
4441+	if (acl_d->freeaclp) {
4442+		acl_free(acl_d->aclp);
4443+	}
4444+	acl_free(acl_d);
4445+	return 0;
4446+}
4447+
4448+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
4449+{
4450+	return 0;
4451+}
4452+
4453+#elif defined(HAVE_AIX_ACLS)
4454+
4455+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
4456+
4457+int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
4458+{
4459+	struct acl_entry_link *link;
4460+	struct new_acl_entry *entry;
4461+	int keep_going;
4462+
4463+	DEBUG(10,("This is the count: %d\n",theacl->count));
4464+
4465+	/* Check if count was previously set to -1. *
4466+	 * If it was, that means we reached the end *
4467+	 * of the acl last time.                    */
4468+	if(theacl->count == -1)
4469+		return(0);
4470+
4471+	link = theacl;
4472+	/* To get to the next acl, traverse linked list until index *
4473+	 * of acl matches the count we are keeping.  This count is  *
4474+	 * incremented each time we return an acl entry.            */
4475+
4476+	for(keep_going = 0; keep_going < theacl->count; keep_going++)
4477+		link = link->nextp;
4478+
4479+	entry = *entry_p =  link->entryp;
4480+
4481+	DEBUG(10,("*entry_p is %d\n",entry_p));
4482+	DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
4483+
4484+	/* Increment count */
4485+	theacl->count++;
4486+	if(link->nextp == NULL)
4487+		theacl->count = -1;
4488+
4489+	return(1);
4490+}
4491+
4492+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
4493+{
4494+	/* Initialize tag type */
4495+
4496+	*tag_type_p = -1;
4497+	DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
4498+
4499+	/* Depending on what type of entry we have, *
4500+	 * return tag type.                         */
4501+	switch(entry_d->ace_id->id_type) {
4502+	case ACEID_USER:
4503+		*tag_type_p = SMB_ACL_USER;
4504+		break;
4505+	case ACEID_GROUP:
4506+		*tag_type_p = SMB_ACL_GROUP;
4507+		break;
4508+
4509+	case SMB_ACL_USER_OBJ:
4510+	case SMB_ACL_GROUP_OBJ:
4511+	case SMB_ACL_OTHER:
4512+		*tag_type_p = entry_d->ace_id->id_type;
4513+		break;
4514+ 
4515+	default:
4516+		return(-1);
4517+	}
4518+
4519+	return(0);
4520+}
4521+
4522+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
4523+{
4524+	DEBUG(10,("Starting AIX sys_acl_get_permset\n"));
4525+	*permset_p = &entry_d->ace_access;
4526+	DEBUG(10,("**permset_p is %d\n",**permset_p));
4527+	if(!(**permset_p & S_IXUSR) &&
4528+		!(**permset_p & S_IWUSR) &&
4529+		!(**permset_p & S_IRUSR) &&
4530+		(**permset_p != 0))
4531+			return(-1);
4532+
4533+	DEBUG(10,("Ending AIX sys_acl_get_permset\n"));
4534+	return(0);
4535+}
4536+
4537+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
4538+{
4539+	return(entry_d->ace_id->id_data);
4540+}
4541+
4542+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
4543+{
4544+	struct acl *file_acl = (struct acl *)NULL;
4545+	struct acl_entry *acl_entry;
4546+	struct new_acl_entry *new_acl_entry;
4547+	struct ace_id *idp;
4548+	struct acl_entry_link *acl_entry_link;
4549+	struct acl_entry_link *acl_entry_link_head;
4550+	int i;
4551+	int rc = 0;
4552+	uid_t user_id;
4553+
4554+	/* AIX has no DEFAULT */
4555+	if  ( type == SMB_ACL_TYPE_DEFAULT ) {
4556+		errno = ENOTSUP;
4557+		return NULL;
4558+	}
4559+
4560+	/* Get the acl using statacl */
4561+ 
4562+	DEBUG(10,("Entering sys_acl_get_file\n"));
4563+	DEBUG(10,("path_p is %s\n",path_p));
4564+
4565+	file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
4566+ 
4567+	if(file_acl == NULL) {
4568+		errno=ENOMEM;
4569+		DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
4570+		return(NULL);
4571+	}
4572+
4573+	memset(file_acl,0,BUFSIZ);
4574+
4575+	rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
4576+	if(rc == -1) {
4577+		DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
4578+		SAFE_FREE(file_acl);
4579+		return(NULL);
4580+	}
4581+
4582+	DEBUG(10,("Got facl and returned it\n"));
4583+
4584+	/* Point to the first acl entry in the acl */
4585+	acl_entry =  file_acl->acl_ext;
4586+
4587+	/* Begin setting up the head of the linked list *
4588+	 * that will be used for the storing the acl    *
4589+	 * in a way that is useful for the posix_acls.c *
4590+	 * code.                                          */
4591+
4592+	acl_entry_link_head = acl_entry_link = sys_acl_init(0);
4593+	if(acl_entry_link_head == NULL)
4594+		return(NULL);
4595+
4596+	acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
4597+	if(acl_entry_link->entryp == NULL) {
4598+		SAFE_FREE(file_acl);
4599+		errno = ENOMEM;
4600+		DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
4601+		return(NULL);
4602+	}
4603+
4604+	DEBUG(10,("acl_entry is %d\n",acl_entry));
4605+	DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
4606+
4607+	/* Check if the extended acl bit is on.   *
4608+	 * If it isn't, do not show the           *
4609+	 * contents of the acl since AIX intends *
4610+	 * the extended info to remain unused     */
4611+
4612+	if(file_acl->acl_mode & S_IXACL){
4613+		/* while we are not pointing to the very end */
4614+		while(acl_entry < acl_last(file_acl)) {
4615+			/* before we malloc anything, make sure this is  */
4616+			/* a valid acl entry and one that we want to map */
4617+			idp = id_nxt(acl_entry->ace_id);
4618+			if((acl_entry->ace_type == ACC_SPECIFY ||
4619+				(acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
4620+					acl_entry = acl_nxt(acl_entry);
4621+					continue;
4622+			}
4623+
4624+			idp = acl_entry->ace_id;
4625+
4626+			/* Check if this is the first entry in the linked list. *
4627+			 * The first entry needs to keep prevp pointing to NULL *
4628+			 * and already has entryp allocated.                  */
4629+
4630+			if(acl_entry_link_head->count != 0) {
4631+				acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
4632+
4633+				if(acl_entry_link->nextp == NULL) {
4634+					SAFE_FREE(file_acl);
4635+					errno = ENOMEM;
4636+					DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
4637+					return(NULL);
4638+				}
4639+
4640+				acl_entry_link->nextp->prevp = acl_entry_link;
4641+				acl_entry_link = acl_entry_link->nextp;
4642+				acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
4643+				if(acl_entry_link->entryp == NULL) {
4644+					SAFE_FREE(file_acl);
4645+					errno = ENOMEM;
4646+					DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
4647+					return(NULL);
4648+				}
4649+				acl_entry_link->nextp = NULL;
4650+			}
4651+
4652+			acl_entry_link->entryp->ace_len = acl_entry->ace_len;
4653+
4654+			/* Don't really need this since all types are going *
4655+			 * to be specified but, it's better than leaving it 0 */
4656+
4657+			acl_entry_link->entryp->ace_type = acl_entry->ace_type;
4658+ 
4659+			acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4660+ 
4661+			memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
4662+
4663+			/* The access in the acl entries must be left shifted by *
4664+			 * three bites, because they will ultimately be compared *
4665+			 * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
4666+
4667+			switch(acl_entry->ace_type){
4668+			case ACC_PERMIT:
4669+			case ACC_SPECIFY:
4670+				acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4671+				acl_entry_link->entryp->ace_access <<= 6;
4672+				acl_entry_link_head->count++;
4673+				break;
4674+			case ACC_DENY:
4675+				/* Since there is no way to return a DENY acl entry *
4676+				 * change to PERMIT and then shift.                 */
4677+				DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
4678+				acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
4679+				DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
4680+				acl_entry_link->entryp->ace_access <<= 6;
4681+				acl_entry_link_head->count++;
4682+				break;
4683+			default:
4684+				return(0);
4685+			}
4686+
4687+			DEBUG(10,("acl_entry = %d\n",acl_entry));
4688+			DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
4689+ 
4690+			acl_entry = acl_nxt(acl_entry);
4691+		}
4692+	} /* end of if enabled */
4693+
4694+	/* Since owner, group, other acl entries are not *
4695+	 * part of the acl entries in an acl, they must  *
4696+	 * be dummied up to become part of the list.     */
4697+
4698+	for( i = 1; i < 4; i++) {
4699+		DEBUG(10,("i is %d\n",i));
4700+		if(acl_entry_link_head->count != 0) {
4701+			acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
4702+			if(acl_entry_link->nextp == NULL) {
4703+				SAFE_FREE(file_acl);
4704+				errno = ENOMEM;
4705+				DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
4706+				return(NULL);
4707+			}
4708+
4709+			acl_entry_link->nextp->prevp = acl_entry_link;
4710+			acl_entry_link = acl_entry_link->nextp;
4711+			acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
4712+			if(acl_entry_link->entryp == NULL) {
4713+				SAFE_FREE(file_acl);
4714+				errno = ENOMEM;
4715+				DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
4716+				return(NULL);
4717+			}
4718+		}
4719+
4720+		acl_entry_link->nextp = NULL;
4721+
4722+		new_acl_entry = acl_entry_link->entryp;
4723+		idp = new_acl_entry->ace_id;
4724+
4725+		new_acl_entry->ace_len = sizeof(struct acl_entry);
4726+		new_acl_entry->ace_type = ACC_PERMIT;
4727+		idp->id_len = sizeof(struct ace_id);
4728+		DEBUG(10,("idp->id_len = %d\n",idp->id_len));
4729+		memset(idp->id_data,0,sizeof(uid_t));
4730+
4731+		switch(i) {
4732+		case 2:
4733+			new_acl_entry->ace_access = file_acl->g_access << 6;
4734+			idp->id_type = SMB_ACL_GROUP_OBJ;
4735+			break;
4736+
4737+		case 3:
4738+			new_acl_entry->ace_access = file_acl->o_access << 6;
4739+			idp->id_type = SMB_ACL_OTHER;
4740+			break;
4741+ 
4742+		case 1:
4743+			new_acl_entry->ace_access = file_acl->u_access << 6;
4744+			idp->id_type = SMB_ACL_USER_OBJ;
4745+			break;
4746+ 
4747+		default:
4748+			return(NULL);
4749+
4750+		}
4751+
4752+		acl_entry_link_head->count++;
4753+		DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
4754+	}
4755+
4756+	acl_entry_link_head->count = 0;
4757+	SAFE_FREE(file_acl);
4758+
4759+	return(acl_entry_link_head);
4760+}
4761+
4762+SMB_ACL_T sys_acl_get_fd(int fd)
4763+{
4764+	struct acl *file_acl = (struct acl *)NULL;
4765+	struct acl_entry *acl_entry;
4766+	struct new_acl_entry *new_acl_entry;
4767+	struct ace_id *idp;
4768+	struct acl_entry_link *acl_entry_link;
4769+	struct acl_entry_link *acl_entry_link_head;
4770+	int i;
4771+	int rc = 0;
4772+	uid_t user_id;
4773+
4774+	/* Get the acl using fstatacl */
4775+   
4776+	DEBUG(10,("Entering sys_acl_get_fd\n"));
4777+	DEBUG(10,("fd is %d\n",fd));
4778+	file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
4779+
4780+	if(file_acl == NULL) {
4781+		errno=ENOMEM;
4782+		DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
4783+		return(NULL);
4784+	}
4785+
4786+	memset(file_acl,0,BUFSIZ);
4787+
4788+	rc = fstatacl(fd,0,file_acl,BUFSIZ);
4789+	if(rc == -1) {
4790+		DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
4791+		SAFE_FREE(file_acl);
4792+		return(NULL);
4793+	}
4794+
4795+	DEBUG(10,("Got facl and returned it\n"));
4796+
4797+	/* Point to the first acl entry in the acl */
4798+
4799+	acl_entry =  file_acl->acl_ext;
4800+	/* Begin setting up the head of the linked list *
4801+	 * that will be used for the storing the acl    *
4802+	 * in a way that is useful for the posix_acls.c *
4803+	 * code.                                        */
4804+
4805+	acl_entry_link_head = acl_entry_link = sys_acl_init(0);
4806+	if(acl_entry_link_head == NULL){
4807+		SAFE_FREE(file_acl);
4808+		return(NULL);
4809+	}
4810+
4811+	acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
4812+
4813+	if(acl_entry_link->entryp == NULL) {
4814+		errno = ENOMEM;
4815+		DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
4816+		SAFE_FREE(file_acl);
4817+		return(NULL);
4818+	}
4819+
4820+	DEBUG(10,("acl_entry is %d\n",acl_entry));
4821+	DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
4822+ 
4823+	/* Check if the extended acl bit is on.   *
4824+	 * If it isn't, do not show the           *
4825+	 * contents of the acl since AIX intends  *
4826+	 * the extended info to remain unused     */
4827+ 
4828+	if(file_acl->acl_mode & S_IXACL){
4829+		/* while we are not pointing to the very end */
4830+		while(acl_entry < acl_last(file_acl)) {
4831+			/* before we malloc anything, make sure this is  */
4832+			/* a valid acl entry and one that we want to map */
4833+
4834+			idp = id_nxt(acl_entry->ace_id);
4835+			if((acl_entry->ace_type == ACC_SPECIFY ||
4836+				(acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
4837+					acl_entry = acl_nxt(acl_entry);
4838+					continue;
4839+			}
4840+
4841+			idp = acl_entry->ace_id;
4842+ 
4843+			/* Check if this is the first entry in the linked list. *
4844+			 * The first entry needs to keep prevp pointing to NULL *
4845+			 * and already has entryp allocated.                 */
4846+
4847+			if(acl_entry_link_head->count != 0) {
4848+				acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
4849+				if(acl_entry_link->nextp == NULL) {
4850+					errno = ENOMEM;
4851+					DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
4852+					SAFE_FREE(file_acl);
4853+					return(NULL);
4854+				}
4855+				acl_entry_link->nextp->prevp = acl_entry_link;
4856+				acl_entry_link = acl_entry_link->nextp;
4857+				acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
4858+				if(acl_entry_link->entryp == NULL) {
4859+					errno = ENOMEM;
4860+					DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
4861+					SAFE_FREE(file_acl);
4862+					return(NULL);
4863+				}
4864+
4865+				acl_entry_link->nextp = NULL;
4866+			}
4867+
4868+			acl_entry_link->entryp->ace_len = acl_entry->ace_len;
4869+
4870+			/* Don't really need this since all types are going *
4871+			 * to be specified but, it's better than leaving it 0 */
4872+
4873+			acl_entry_link->entryp->ace_type = acl_entry->ace_type;
4874+			acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4875+
4876+			memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
4877+
4878+			/* The access in the acl entries must be left shifted by *
4879+			 * three bites, because they will ultimately be compared *
4880+			 * to S_IRUSR, S_IWUSR, and S_IXUSR.                  */
4881+
4882+			switch(acl_entry->ace_type){
4883+			case ACC_PERMIT:
4884+			case ACC_SPECIFY:
4885+				acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4886+				acl_entry_link->entryp->ace_access <<= 6;
4887+				acl_entry_link_head->count++;
4888+				break;
4889+			case ACC_DENY:
4890+				/* Since there is no way to return a DENY acl entry *
4891+				 * change to PERMIT and then shift.                 */
4892+				DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
4893+				acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
4894+				DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
4895+				acl_entry_link->entryp->ace_access <<= 6;
4896+				acl_entry_link_head->count++;
4897+				break;
4898+			default:
4899+				return(0);
4900+			}
4901+
4902+			DEBUG(10,("acl_entry = %d\n",acl_entry));
4903+			DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
4904+ 
4905+			acl_entry = acl_nxt(acl_entry);
4906+		}
4907+	} /* end of if enabled */
4908+
4909+	/* Since owner, group, other acl entries are not *
4910+	 * part of the acl entries in an acl, they must  *
4911+	 * be dummied up to become part of the list.     */
4912+
4913+	for( i = 1; i < 4; i++) {
4914+		DEBUG(10,("i is %d\n",i));
4915+		if(acl_entry_link_head->count != 0){
4916+			acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
4917+			if(acl_entry_link->nextp == NULL) {
4918+				errno = ENOMEM;
4919+				DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
4920+				SAFE_FREE(file_acl);
4921+				return(NULL);
4922+			}
4923+
4924+			acl_entry_link->nextp->prevp = acl_entry_link;
4925+			acl_entry_link = acl_entry_link->nextp;
4926+			acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
4927+
4928+			if(acl_entry_link->entryp == NULL) {
4929+				SAFE_FREE(file_acl);
4930+				errno = ENOMEM;
4931+				DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
4932+				return(NULL);
4933+			}
4934+		}
4935+
4936+		acl_entry_link->nextp = NULL;
4937+ 
4938+		new_acl_entry = acl_entry_link->entryp;
4939+		idp = new_acl_entry->ace_id;
4940+ 
4941+		new_acl_entry->ace_len = sizeof(struct acl_entry);
4942+		new_acl_entry->ace_type = ACC_PERMIT;
4943+		idp->id_len = sizeof(struct ace_id);
4944+		DEBUG(10,("idp->id_len = %d\n",idp->id_len));
4945+		memset(idp->id_data,0,sizeof(uid_t));
4946+ 
4947+		switch(i) {
4948+		case 2:
4949+			new_acl_entry->ace_access = file_acl->g_access << 6;
4950+			idp->id_type = SMB_ACL_GROUP_OBJ;
4951+			break;
4952+ 
4953+		case 3:
4954+			new_acl_entry->ace_access = file_acl->o_access << 6;
4955+			idp->id_type = SMB_ACL_OTHER;
4956+			break;
4957+ 
4958+		case 1:
4959+			new_acl_entry->ace_access = file_acl->u_access << 6;
4960+			idp->id_type = SMB_ACL_USER_OBJ;
4961+			break;
4962+ 
4963+		default:
4964+			return(NULL);
4965+		}
4966+ 
4967+		acl_entry_link_head->count++;
4968+		DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
4969+	}
4970+
4971+	acl_entry_link_head->count = 0;
4972+	SAFE_FREE(file_acl);
4973+ 
4974+	return(acl_entry_link_head);
4975+}
4976+
4977+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
4978+{
4979+	*permset = *permset & ~0777;
4980+	return(0);
4981+}
4982+
4983+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
4984+{
4985+	if((perm != 0) &&
4986+			(perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0)
4987+		return(-1);
4988+
4989+	*permset |= perm;
4990+	DEBUG(10,("This is the permset now: %d\n",*permset));
4991+	return(0);
4992+}
4993+
4994+char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
4995+{
4996+	return(NULL);
4997+}
4998+
4999+SMB_ACL_T sys_acl_init( int count)
5000+{
5001+	struct acl_entry_link *theacl = NULL;
5002+ 
5003+	DEBUG(10,("Entering sys_acl_init\n"));
5004+
5005+	theacl = SMB_MALLOC_P(struct acl_entry_link);
5006+	if(theacl == NULL) {
5007+		errno = ENOMEM;
5008+		DEBUG(0,("Error in sys_acl_init is %d\n",errno));
5009+		return(NULL);
5010+	}
5011+
5012+	theacl->count = 0;
5013+	theacl->nextp = NULL;
5014+	theacl->prevp = NULL;
5015+	theacl->entryp = NULL;
5016+	DEBUG(10,("Exiting sys_acl_init\n"));
5017+	return(theacl);
5018+}
5019+
5020+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
5021+{
5022+	struct acl_entry_link *theacl;
5023+	struct acl_entry_link *acl_entryp;
5024+	struct acl_entry_link *temp_entry;
5025+	int counting;
5026+
5027+	DEBUG(10,("Entering the sys_acl_create_entry\n"));
5028+
5029+	theacl = acl_entryp = *pacl;
5030+
5031+	/* Get to the end of the acl before adding entry */
5032+
5033+	for(counting=0; counting < theacl->count; counting++){
5034+		DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
5035+		temp_entry = acl_entryp;
5036+		acl_entryp = acl_entryp->nextp;
5037+	}
5038+
5039+	if(theacl->count != 0){
5040+		temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
5041+		if(acl_entryp == NULL) {
5042+			errno = ENOMEM;
5043+			DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
5044+			return(-1);
5045+		}
5046+
5047+		DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
5048+		acl_entryp->prevp = temp_entry;
5049+		DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
5050+	}
5051+
5052+	*pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
5053+	if(*pentry == NULL) {
5054+		errno = ENOMEM;
5055+		DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
5056+		return(-1);
5057+	}
5058+
5059+	memset(*pentry,0,sizeof(struct new_acl_entry));
5060+	acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
5061+	acl_entryp->entryp->ace_type = ACC_PERMIT;
5062+	acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
5063+	acl_entryp->nextp = NULL;
5064+	theacl->count++;
5065+	DEBUG(10,("Exiting sys_acl_create_entry\n"));
5066+	return(0);
5067+}
5068+
5069+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
5070+{
5071+	DEBUG(10,("Starting AIX sys_acl_set_tag_type\n"));
5072+	entry->ace_id->id_type = tagtype;
5073+	DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
5074+	DEBUG(10,("Ending AIX sys_acl_set_tag_type\n"));
5075+}
5076+
5077+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
5078+{
5079+	DEBUG(10,("Starting AIX sys_acl_set_qualifier\n"));
5080+	memcpy(entry->ace_id->id_data,qual,sizeof(uid_t));
5081+	DEBUG(10,("Ending AIX sys_acl_set_qualifier\n"));
5082+	return(0);
5083+}
5084+
5085+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
5086+{
5087+	DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
5088+	if(!(*permset & S_IXUSR) &&
5089+		!(*permset & S_IWUSR) &&
5090+		!(*permset & S_IRUSR) &&
5091+		(*permset != 0))
5092+			return(-1);
5093+
5094+	entry->ace_access = *permset;
5095+	DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
5096+	DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
5097+	return(0);
5098+}
5099+
5100+int sys_acl_valid( SMB_ACL_T theacl )
5101+{
5102+	int user_obj = 0;
5103+	int group_obj = 0;
5104+	int other_obj = 0;
5105+	struct acl_entry_link *acl_entry;
5106+
5107+	for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
5108+		user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
5109+		group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
5110+		other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
5111+	}
5112+
5113+	DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
5114+ 
5115+	if(user_obj != 1 || group_obj != 1 || other_obj != 1)
5116+		return(-1); 
5117+
5118+	return(0);
5119+}
5120+
5121+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
5122+{
5123+	struct acl_entry_link *acl_entry_link = NULL;
5124+	struct acl *file_acl = NULL;
5125+	struct acl *file_acl_temp = NULL;
5126+	struct acl_entry *acl_entry = NULL;
5127+	struct ace_id *ace_id = NULL;
5128+	uint id_type;
5129+	uint ace_access;
5130+	uint user_id;
5131+	uint acl_length;
5132+	uint rc;
5133+
5134+	DEBUG(10,("Entering sys_acl_set_file\n"));
5135+	DEBUG(10,("File name is %s\n",name));
5136+ 
5137+	/* AIX has no default ACL */
5138+	if(acltype == SMB_ACL_TYPE_DEFAULT)
5139+		return(0);
5140+
5141+	acl_length = BUFSIZ;
5142+	file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
5143+
5144+	if(file_acl == NULL) {
5145+		errno = ENOMEM;
5146+		DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
5147+		return(-1);
5148+	}
5149+
5150+	memset(file_acl,0,BUFSIZ);
5151+
5152+	file_acl->acl_len = ACL_SIZ;
5153+	file_acl->acl_mode = S_IXACL;
5154+
5155+	for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
5156+		acl_entry_link->entryp->ace_access >>= 6;
5157+		id_type = acl_entry_link->entryp->ace_id->id_type;
5158+
5159+		switch(id_type) {
5160+		case SMB_ACL_USER_OBJ:
5161+			file_acl->u_access = acl_entry_link->entryp->ace_access;
5162+			continue;
5163+		case SMB_ACL_GROUP_OBJ:
5164+			file_acl->g_access = acl_entry_link->entryp->ace_access;
5165+			continue;
5166+		case SMB_ACL_OTHER:
5167+			file_acl->o_access = acl_entry_link->entryp->ace_access;
5168+			continue;
5169+		case SMB_ACL_MASK:
5170+			continue;
5171+		}
5172+
5173+		if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
5174+			acl_length += sizeof(struct acl_entry);
5175+			file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
5176+			if(file_acl_temp == NULL) {
5177+				SAFE_FREE(file_acl);
5178+				errno = ENOMEM;
5179+				DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
5180+				return(-1);
5181+			}  
5182+
5183+			memcpy(file_acl_temp,file_acl,file_acl->acl_len);
5184+			SAFE_FREE(file_acl);
5185+			file_acl = file_acl_temp;
5186+		}
5187+
5188+		acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
5189+		file_acl->acl_len += sizeof(struct acl_entry);
5190+		acl_entry->ace_len = acl_entry_link->entryp->ace_len;
5191+		acl_entry->ace_access = acl_entry_link->entryp->ace_access;
5192+ 
5193+		/* In order to use this, we'll need to wait until we can get denies */
5194+		/* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
5195+		acl_entry->ace_type = ACC_SPECIFY; */
5196+
5197+		acl_entry->ace_type = ACC_SPECIFY;
5198+ 
5199+		ace_id = acl_entry->ace_id;
5200+ 
5201+		ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
5202+		DEBUG(10,("The id type is %d\n",ace_id->id_type));
5203+		ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
5204+		memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
5205+		memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
5206+	}
5207+
5208+	rc = chacl(name,file_acl,file_acl->acl_len);
5209+	DEBUG(10,("errno is %d\n",errno));
5210+	DEBUG(10,("return code is %d\n",rc));
5211+	SAFE_FREE(file_acl);
5212+	DEBUG(10,("Exiting the sys_acl_set_file\n"));
5213+	return(rc);
5214+}
5215+
5216+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
5217+{
5218+	struct acl_entry_link *acl_entry_link = NULL;
5219+	struct acl *file_acl = NULL;
5220+	struct acl *file_acl_temp = NULL;
5221+	struct acl_entry *acl_entry = NULL;
5222+	struct ace_id *ace_id = NULL;
5223+	uint id_type;
5224+	uint user_id;
5225+	uint acl_length;
5226+	uint rc;
5227+ 
5228+	DEBUG(10,("Entering sys_acl_set_fd\n"));
5229+	acl_length = BUFSIZ;
5230+	file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
5231+
5232+	if(file_acl == NULL) {
5233+		errno = ENOMEM;
5234+		DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
5235+		return(-1);
5236+	}
5237+
5238+	memset(file_acl,0,BUFSIZ);
5239+ 
5240+	file_acl->acl_len = ACL_SIZ;
5241+	file_acl->acl_mode = S_IXACL;
5242+
5243+	for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
5244+		acl_entry_link->entryp->ace_access >>= 6;
5245+		id_type = acl_entry_link->entryp->ace_id->id_type;
5246+		DEBUG(10,("The id_type is %d\n",id_type));
5247+
5248+		switch(id_type) {
5249+		case SMB_ACL_USER_OBJ:
5250+			file_acl->u_access = acl_entry_link->entryp->ace_access;
5251+			continue;
5252+		case SMB_ACL_GROUP_OBJ:
5253+			file_acl->g_access = acl_entry_link->entryp->ace_access;
5254+			continue;
5255+		case SMB_ACL_OTHER:
5256+			file_acl->o_access = acl_entry_link->entryp->ace_access;
5257+			continue;
5258+		case SMB_ACL_MASK:
5259+			continue;
5260+		}
5261+
5262+		if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
5263+			acl_length += sizeof(struct acl_entry);
5264+			file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
5265+			if(file_acl_temp == NULL) {
5266+				SAFE_FREE(file_acl);
5267+				errno = ENOMEM;
5268+				DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
5269+				return(-1);
5270+			}
5271+
5272+			memcpy(file_acl_temp,file_acl,file_acl->acl_len);
5273+			SAFE_FREE(file_acl);
5274+			file_acl = file_acl_temp;
5275+		}
5276+
5277+		acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
5278+		file_acl->acl_len += sizeof(struct acl_entry);
5279+		acl_entry->ace_len = acl_entry_link->entryp->ace_len;
5280+		acl_entry->ace_access = acl_entry_link->entryp->ace_access;
5281+ 
5282+		/* In order to use this, we'll need to wait until we can get denies */
5283+		/* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
5284+			acl_entry->ace_type = ACC_SPECIFY; */
5285+ 
5286+		acl_entry->ace_type = ACC_SPECIFY;
5287+ 
5288+		ace_id = acl_entry->ace_id;
5289+ 
5290+		ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
5291+		DEBUG(10,("The id type is %d\n",ace_id->id_type));
5292+		ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
5293+		memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
5294+		memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
5295+	}
5296+ 
5297+	rc = fchacl(fd,file_acl,file_acl->acl_len);
5298+	DEBUG(10,("errno is %d\n",errno));
5299+	DEBUG(10,("return code is %d\n",rc));
5300+	SAFE_FREE(file_acl);
5301+	DEBUG(10,("Exiting sys_acl_set_fd\n"));
5302+	return(rc);
5303+}
5304+
5305+int sys_acl_delete_def_file(const char *name)
5306+{
5307+	/* AIX has no default ACL */
5308+	return 0;
5309+}
5310+
5311+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
5312+{
5313+	return(*permset & perm);
5314+}
5315+
5316+int sys_acl_free_text(char *text)
5317+{
5318+	return(0);
5319+}
5320+
5321+int sys_acl_free_acl(SMB_ACL_T posix_acl)
5322+{
5323+	struct acl_entry_link *acl_entry_link;
5324+
5325+	for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
5326+		SAFE_FREE(acl_entry_link->prevp->entryp);
5327+		SAFE_FREE(acl_entry_link->prevp);
5328+	}
5329+
5330+	SAFE_FREE(acl_entry_link->prevp->entryp);
5331+	SAFE_FREE(acl_entry_link->prevp);
5332+	SAFE_FREE(acl_entry_link->entryp);
5333+	SAFE_FREE(acl_entry_link);
5334+ 
5335+	return(0);
5336+}
5337+
5338+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
5339+{
5340+	return(0);
5341+}
5342+
5343+#else /* No ACLs. */
5344+
5345+int sys_acl_get_entry(UNUSED(SMB_ACL_T the_acl), UNUSED(int entry_id), UNUSED(SMB_ACL_ENTRY_T *entry_p))
5346+{
5347+	errno = ENOSYS;
5348+	return -1;
5349+}
5350+
5351+int sys_acl_get_tag_type(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_TAG_T *tag_type_p))
5352+{
5353+	errno = ENOSYS;
5354+	return -1;
5355+}
5356+
5357+int sys_acl_get_permset(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_PERMSET_T *permset_p))
5358+{
5359+	errno = ENOSYS;
5360+	return -1;
5361+}
5362+
5363+void *sys_acl_get_qualifier(UNUSED(SMB_ACL_ENTRY_T entry_d))
5364+{
5365+	errno = ENOSYS;
5366+	return NULL;
5367+}
5368+
5369+SMB_ACL_T sys_acl_get_file(UNUSED(const char *path_p), UNUSED(SMB_ACL_TYPE_T type))
5370+{
5371+	errno = ENOSYS;
5372+	return (SMB_ACL_T)NULL;
5373+}
5374+
5375+SMB_ACL_T sys_acl_get_fd(UNUSED(int fd))
5376+{
5377+	errno = ENOSYS;
5378+	return (SMB_ACL_T)NULL;
5379+}
5380+
5381+int sys_acl_clear_perms(UNUSED(SMB_ACL_PERMSET_T permset))
5382+{
5383+	errno = ENOSYS;
5384+	return -1;
5385+}
5386+
5387+int sys_acl_add_perm( UNUSED(SMB_ACL_PERMSET_T permset), UNUSED(SMB_ACL_PERM_T perm))
5388+{
5389+	errno = ENOSYS;
5390+	return -1;
5391+}
5392+
5393+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
5394+{
5395+	errno = ENOSYS;
5396+	return (permset & perm) ? 1 : 0;
5397+}
5398+
5399+char *sys_acl_to_text(UNUSED(SMB_ACL_T the_acl), UNUSED(ssize_t *plen))
5400+{
5401+	errno = ENOSYS;
5402+	return NULL;
5403+}
5404+
5405+int sys_acl_free_text(UNUSED(char *text))
5406+{
5407+	errno = ENOSYS;
5408+	return -1;
5409+}
5410+
5411+SMB_ACL_T sys_acl_init(UNUSED(int count))
5412+{
5413+	errno = ENOSYS;
5414+	return NULL;
5415+}
5416+
5417+int sys_acl_create_entry(UNUSED(SMB_ACL_T *pacl), UNUSED(SMB_ACL_ENTRY_T *pentry))
5418+{
5419+	errno = ENOSYS;
5420+	return -1;
5421+}
5422+
5423+int sys_acl_set_tag_type(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_TAG_T tagtype))
5424+{
5425+	errno = ENOSYS;
5426+	return -1;
5427+}
5428+
5429+int sys_acl_set_qualifier(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(void *qual))
5430+{
5431+	errno = ENOSYS;
5432+	return -1;
5433+}
5434+
5435+int sys_acl_set_permset(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_PERMSET_T permset))
5436+{
5437+	errno = ENOSYS;
5438+	return -1;
5439+}
5440+
5441+int sys_acl_valid(UNUSED(SMB_ACL_T theacl))
5442+{
5443+	errno = ENOSYS;
5444+	return -1;
5445+}
5446+
5447+int sys_acl_set_file(UNUSED(const char *name), UNUSED(SMB_ACL_TYPE_T acltype), UNUSED(SMB_ACL_T theacl))
5448+{
5449+	errno = ENOSYS;
5450+	return -1;
5451+}
5452+
5453+int sys_acl_set_fd(UNUSED(int fd), UNUSED(SMB_ACL_T theacl))
5454+{
5455+	errno = ENOSYS;
5456+	return -1;
5457+}
5458+
5459+int sys_acl_delete_def_file(UNUSED(const char *name))
5460+{
5461+	errno = ENOSYS;
5462+	return -1;
5463+}
5464+
5465+int sys_acl_free_acl(UNUSED(SMB_ACL_T the_acl))
5466+{
5467+	errno = ENOSYS;
5468+	return -1;
5469+}
5470+
5471+int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype))
5472+{
5473+	errno = ENOSYS;
5474+	return -1;
5475+}
5476+
5477+#endif /* No ACLs. */
5478+
5479+/************************************************************************
5480+ Deliberately outside the ACL defines. Return 1 if this is a "no acls"
5481+ errno, 0 if not.
5482+************************************************************************/
5483+
5484+int no_acl_syscall_error(int err)
5485+{
5486+#if defined(ENOSYS)
5487+	if (err == ENOSYS) {
5488+		return 1;
5489+	}
5490+#endif
5491+#if defined(ENOTSUP)
5492+	if (err == ENOTSUP) {
5493+		return 1;
5494+	}
5495+#endif
5496+	return 0;
5497+}
5498+
5499+#endif /* SUPPORT_ACLS */
5500--- old/lib/sysacls.h
5501+++ new/lib/sysacls.h
5502@@ -0,0 +1,40 @@
5503+#ifdef SUPPORT_ACLS
5504+
5505+#ifdef HAVE_SYS_ACL_H
5506+#include <sys/acl.h>
5507+#endif
5508+#ifdef HAVE_ACL_LIBACL_H
5509+#include <acl/libacl.h>
5510+#endif
5511+#include "smb_acls.h"
5512+
5513+#define SMB_MALLOC(cnt) new_array(char, cnt)
5514+#define SMB_MALLOC_P(obj) new_array(obj, 1)
5515+#define SMB_MALLOC_ARRAY(obj, cnt) new_array(obj, cnt)
5516+#define SMB_REALLOC(mem, cnt) realloc_array(mem, char, cnt)
5517+#define slprintf snprintf
5518+
5519+int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p);
5520+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p);
5521+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p);
5522+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d);
5523+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type);
5524+SMB_ACL_T sys_acl_get_fd(int fd);
5525+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
5526+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
5527+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
5528+char *sys_acl_to_text(SMB_ACL_T the_acl, ssize_t *plen);
5529+SMB_ACL_T sys_acl_init(int count);
5530+int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry);
5531+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype);
5532+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry, void *qual);
5533+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset);
5534+int sys_acl_valid(SMB_ACL_T theacl);
5535+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
5536+int sys_acl_set_fd(int fd, SMB_ACL_T theacl);
5537+int sys_acl_delete_def_file(const char *name);
5538+int sys_acl_free_text(char *text);
5539+int sys_acl_free_acl(SMB_ACL_T the_acl);
5540+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype);
5541+
5542+#endif /* SUPPORT_ACLS */
5543--- old/log.c
5544+++ new/log.c
5545@@ -606,8 +606,10 @@ static void log_formatted(enum logcode c
5546 			n[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
5547 			n[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
5548 			n[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
5549-			n[8] = '.';
5550-			n[9] = '\0';
5551+			n[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
5552+			n[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
5553+			n[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
5554+			n[11] = '\0';
5555 
5556 			if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
5557 				char ch = iflags & ITEM_IS_NEW ? '+' : '?';
5558--- old/options.c
5559+++ new/options.c
5560@@ -47,6 +47,7 @@ int copy_dirlinks = 0;
5561 int copy_links = 0;
5562 int preserve_links = 0;
5563 int preserve_hard_links = 0;
5564+int preserve_acls = 0;
5565 int preserve_perms = 0;
5566 int preserve_executability = 0;
5567 int preserve_devices = 0;
5568@@ -199,6 +200,7 @@ static void print_rsync_version(enum log
5569 	char const *got_socketpair = "no ";
5570 	char const *have_inplace = "no ";
5571 	char const *hardlinks = "no ";
5572+	char const *acls = "no ";
5573 	char const *links = "no ";
5574 	char const *ipv6 = "no ";
5575 	STRUCT_STAT *dumstat;
5576@@ -215,6 +217,10 @@ static void print_rsync_version(enum log
5577 	hardlinks = "";
5578 #endif
5579 
5580+#ifdef SUPPORT_ACLS
5581+	acls = "";
5582+#endif
5583+
5584 #ifdef SUPPORT_LINKS
5585 	links = "";
5586 #endif
5587@@ -227,17 +233,16 @@ static void print_rsync_version(enum log
5588 		RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
5589 	rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n");
5590 	rprintf(f, "<http://rsync.samba.org/>\n");
5591-	rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
5592-		"%shard links, %ssymlinks, batchfiles,\n",
5593-		(int) (sizeof (OFF_T) * 8),
5594-		got_socketpair, hardlinks, links);
5595+	rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, %shard links, %ssymlinks,\n",
5596+		(int) (sizeof (OFF_T) * 8), got_socketpair, hardlinks, links);
5597+
5598+	rprintf(f, "              batchfiles, %sinplace, %sIPv6, %sACLs,\n",
5599+		have_inplace, ipv6, acls);
5600 
5601 	/* Note that this field may not have type ino_t.  It depends
5602 	 * on the complicated interaction between largefile feature
5603 	 * macros. */
5604-	rprintf(f, "              %sinplace, %sIPv6, "
5605-		"%d-bit system inums, %d-bit internal inums\n",
5606-		have_inplace, ipv6,
5607+	rprintf(f, "              %d-bit system inums, %d-bit internal inums\n",
5608 		(int) (sizeof dumstat->st_ino * 8),
5609 		(int) (sizeof (int64) * 8));
5610 #ifdef MAINTAINER_MODE
5611@@ -284,7 +289,7 @@ void usage(enum logcode F)
5612   rprintf(F," -q, --quiet                 suppress non-error messages\n");
5613   rprintf(F,"     --no-motd               suppress daemon-mode MOTD (see manpage caveat)\n");
5614   rprintf(F," -c, --checksum              skip based on checksum, not mod-time & size\n");
5615-  rprintf(F," -a, --archive               archive mode; same as -rlptgoD (no -H)\n");
5616+  rprintf(F," -a, --archive               archive mode; same as -rlptgoD (no -H, -A)\n");
5617   rprintf(F,"     --no-OPTION             turn off an implied OPTION (e.g. --no-D)\n");
5618   rprintf(F," -r, --recursive             recurse into directories\n");
5619   rprintf(F," -R, --relative              use relative path names\n");
5620@@ -306,6 +311,9 @@ void usage(enum logcode F)
5621   rprintf(F," -p, --perms                 preserve permissions\n");
5622   rprintf(F," -E, --executability         preserve the file's executability\n");
5623   rprintf(F,"     --chmod=CHMOD           affect file and/or directory permissions\n");
5624+#ifdef SUPPORT_ACLS
5625+  rprintf(F," -A, --acls                  preserve ACLs (implies --perms)\n");
5626+#endif
5627   rprintf(F," -o, --owner                 preserve owner (super-user only)\n");
5628   rprintf(F," -g, --group                 preserve group\n");
5629   rprintf(F,"     --devices               preserve device files (super-user only)\n");
5630@@ -425,6 +433,9 @@ static struct poptOption long_options[] 
5631   {"no-perms",         0,  POPT_ARG_VAL,    &preserve_perms, 0, 0, 0 },
5632   {"no-p",             0,  POPT_ARG_VAL,    &preserve_perms, 0, 0, 0 },
5633   {"executability",   'E', POPT_ARG_NONE,   &preserve_executability, 0, 0, 0 },
5634+  {"acls",            'A', POPT_ARG_NONE,   0, 'A', 0, 0 },
5635+  {"no-acls",          0,  POPT_ARG_VAL,    &preserve_acls, 0, 0, 0 },
5636+  {"no-A",             0,  POPT_ARG_VAL,    &preserve_acls, 0, 0, 0 },
5637   {"times",           't', POPT_ARG_VAL,    &preserve_times, 1, 0, 0 },
5638   {"no-times",         0,  POPT_ARG_VAL,    &preserve_times, 0, 0, 0 },
5639   {"no-t",             0,  POPT_ARG_VAL,    &preserve_times, 0, 0, 0 },
5640@@ -1089,6 +1100,24 @@ int parse_arguments(int *argc, const cha
5641 			usage(FINFO);
5642 			exit_cleanup(0);
5643 
5644+		case 'A':
5645+#ifdef SUPPORT_ACLS
5646+			preserve_acls++;
5647+			preserve_perms = 1;
5648+			break;
5649+#else
5650+			/* FIXME: this should probably be ignored with a
5651+ 			 * warning and then countermeasures taken to
5652+ 			 * restrict group and other access in the presence
5653+ 			 * of any more restrictive ACLs, but this is safe
5654+			 * for now */
5655+			snprintf(err_buf,sizeof(err_buf),
5656+                                 "ACLs are not supported on this %s\n",
5657+				 am_server ? "server" : "client");
5658+			return 0;
5659+#endif
5660+
5661+
5662 		default:
5663 			/* A large opt value means that set_refuse_options()
5664 			 * turned this option off. */
5665@@ -1530,6 +1559,10 @@ void server_options(char **args,int *arg
5666 
5667 	if (preserve_hard_links)
5668 		argstr[x++] = 'H';
5669+#ifdef SUPPORT_ACLS
5670+	if (preserve_acls)
5671+		argstr[x++] = 'A';
5672+#endif
5673 	if (preserve_uid)
5674 		argstr[x++] = 'o';
5675 	if (preserve_gid)
5676--- old/receiver.c
5677+++ new/receiver.c
5678@@ -47,6 +47,7 @@ extern int keep_partial;
5679 extern int checksum_seed;
5680 extern int inplace;
5681 extern int delay_updates;
5682+extern mode_t orig_umask;
5683 extern struct stats stats;
5684 extern char *stdout_format;
5685 extern char *tmpdir;
5686@@ -350,6 +351,10 @@ int recv_files(int f_in, struct file_lis
5687 	int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
5688 	enum logcode log_code = log_before_transfer ? FLOG : FINFO;
5689 	int max_phase = protocol_version >= 29 ? 2 : 1;
5690+	int dflt_perms = (ACCESSPERMS & ~orig_umask);
5691+#ifdef SUPPORT_ACLS
5692+	char *parent_dirname = "";
5693+#endif
5694 	int i, recv_ok;
5695 
5696 	if (verbose > 2)
5697@@ -553,7 +558,16 @@ int recv_files(int f_in, struct file_lis
5698 		 * mode based on the local permissions and some heuristics. */
5699 		if (!preserve_perms) {
5700 			int exists = fd1 != -1;
5701-			file->mode = dest_mode(file->mode, st.st_mode, exists);
5702+#ifdef SUPPORT_ACLS
5703+			char *dn = file->dirname ? file->dirname : ".";
5704+			if (parent_dirname != dn
5705+			 && strcmp(parent_dirname, dn) != 0) {
5706+				dflt_perms = default_perms_for_dir(dn);
5707+				parent_dirname = dn;
5708+			}
5709+#endif
5710+			file->mode = dest_mode(file->mode, st.st_mode,
5711+					       dflt_perms, exists);
5712 		}
5713 
5714 		/* We now check to see if we are writing the file "inplace" */
5715--- old/rsync.c
5716+++ new/rsync.c
5717@@ -32,6 +32,7 @@
5718 
5719 extern int verbose;
5720 extern int dry_run;
5721+extern int preserve_acls;
5722 extern int preserve_perms;
5723 extern int preserve_executability;
5724 extern int preserve_times;
5725@@ -47,7 +48,6 @@ extern int preserve_gid;
5726 extern int inplace;
5727 extern int keep_dirlinks;
5728 extern int make_backups;
5729-extern mode_t orig_umask;
5730 extern struct stats stats;
5731 extern struct chmod_mode_struct *daemon_chmod_modes;
5732 
5733@@ -100,7 +100,8 @@ void free_sums(struct sum_struct *s)
5734 
5735 /* This is only called when we aren't preserving permissions.  Figure out what
5736  * the permissions should be and return them merged back into the mode. */
5737-mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists)
5738+mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
5739+		 int exists)
5740 {
5741 	int new_mode;
5742 	/* If the file already exists, we'll return the local permissions,
5743@@ -117,56 +118,65 @@ mode_t dest_mode(mode_t flist_mode, mode
5744 				new_mode |= (new_mode & 0444) >> 2;
5745 		}
5746 	} else {
5747-		/* Apply the umask and turn off special permissions. */
5748-		new_mode = flist_mode & (~CHMOD_BITS | (ACCESSPERMS & ~orig_umask));
5749+		/* Apply destination default permissions and turn
5750+		 * off special permissions. */
5751+		new_mode = flist_mode & (~CHMOD_BITS | dflt_perms);
5752 	}
5753 	return new_mode;
5754 }
5755 
5756-int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
5757+int set_file_attrs(char *fname, struct file_struct *file, statx *sxp,
5758 		   int flags)
5759 {
5760 	int updated = 0;
5761-	STRUCT_STAT st2;
5762+	statx sx2;
5763 	int change_uid, change_gid;
5764 	mode_t new_mode = file->mode;
5765 
5766-	if (!st) {
5767+	if (!sxp) {
5768 		if (dry_run)
5769 			return 1;
5770-		if (link_stat(fname, &st2, 0) < 0) {
5771+		if (link_stat(fname, &sx2.st, 0) < 0) {
5772 			rsyserr(FERROR, errno, "stat %s failed",
5773 				full_fname(fname));
5774 			return 0;
5775 		}
5776-		st = &st2;
5777+#ifdef SUPPORT_ACLS
5778+		sx2.acc_acl = sx2.def_acl = NULL;
5779+#endif
5780 		if (!preserve_perms && S_ISDIR(new_mode)
5781-		 && st->st_mode & S_ISGID) {
5782+		 && sx2.st.st_mode & S_ISGID) {
5783 			/* We just created this directory and its setgid
5784 			 * bit is on, so make sure it stays on. */
5785 			new_mode |= S_ISGID;
5786 		}
5787+		sxp = &sx2;
5788 	}
5789 
5790-	if (!preserve_times || (S_ISDIR(st->st_mode) && omit_dir_times))
5791+#ifdef SUPPORT_ACLS
5792+	if (preserve_acls && !ACL_READY(*sxp))
5793+		get_acl(fname, sxp);
5794+#endif
5795+
5796+	if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && omit_dir_times))
5797 		flags |= ATTRS_SKIP_MTIME;
5798 	if (!(flags & ATTRS_SKIP_MTIME)
5799-	    && cmp_time(st->st_mtime, file->modtime) != 0) {
5800-		int ret = set_modtime(fname, file->modtime, st->st_mode);
5801+	    && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
5802+		int ret = set_modtime(fname, file->modtime, sxp->st.st_mode);
5803 		if (ret < 0) {
5804 			rsyserr(FERROR, errno, "failed to set times on %s",
5805 				full_fname(fname));
5806-			return 0;
5807+			goto cleanup;
5808 		}
5809 		if (ret == 0) /* ret == 1 if symlink could not be set */
5810 			updated = 1;
5811 	}
5812 
5813-	change_uid = am_root && preserve_uid && st->st_uid != file->uid;
5814+	change_uid = am_root && preserve_uid && sxp->st.st_uid != file->uid;
5815 	change_gid = preserve_gid && file->gid != GID_NONE
5816-		&& st->st_gid != file->gid;
5817+		&& sxp->st.st_gid != file->gid;
5818 #if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
5819-	if (S_ISLNK(st->st_mode))
5820+	if (S_ISLNK(sxp->st.st_mode))
5821 		;
5822 	else
5823 #endif
5824@@ -176,45 +186,57 @@ int set_file_attrs(char *fname, struct f
5825 				rprintf(FINFO,
5826 					"set uid of %s from %ld to %ld\n",
5827 					fname,
5828-					(long)st->st_uid, (long)file->uid);
5829+					(long)sxp->st.st_uid, (long)file->uid);
5830 			}
5831 			if (change_gid) {
5832 				rprintf(FINFO,
5833 					"set gid of %s from %ld to %ld\n",
5834 					fname,
5835-					(long)st->st_gid, (long)file->gid);
5836+					(long)sxp->st.st_gid, (long)file->gid);
5837 			}
5838 		}
5839 		if (do_lchown(fname,
5840-		    change_uid ? file->uid : st->st_uid,
5841-		    change_gid ? file->gid : st->st_gid) != 0) {
5842+		    change_uid ? file->uid : sxp->st.st_uid,
5843+		    change_gid ? file->gid : sxp->st.st_gid) != 0) {
5844 			/* shouldn't have attempted to change uid or gid
5845 			 * unless have the privilege */
5846 			rsyserr(FERROR, errno, "%s %s failed",
5847 			    change_uid ? "chown" : "chgrp",
5848 			    full_fname(fname));
5849-			return 0;
5850+			goto cleanup;
5851 		}
5852 		/* a lchown had been done - we have to re-stat if the
5853 		 * destination had the setuid or setgid bits set due
5854 		 * to the side effect of the chown call */
5855-		if (st->st_mode & (S_ISUID | S_ISGID)) {
5856-			link_stat(fname, st,
5857-				  keep_dirlinks && S_ISDIR(st->st_mode));
5858+		if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
5859+			link_stat(fname, &sxp->st,
5860+				  keep_dirlinks && S_ISDIR(sxp->st.st_mode));
5861 		}
5862 		updated = 1;
5863 	}
5864 
5865 	if (daemon_chmod_modes && !S_ISLNK(new_mode))
5866 		new_mode = tweak_mode(new_mode, daemon_chmod_modes);
5867+
5868+#ifdef SUPPORT_ACLS
5869+	/* It's OK to call set_acl() now, even for a dir, as the generator
5870+	 * will enable owner-writability using chmod, if necessary.
5871+	 * 
5872+	 * If set_acl() changes permission bits in the process of setting
5873+	 * an access ACL, it changes sxp->st.st_mode so we know whether we
5874+	 * need to chmod(). */
5875+	if (preserve_acls && set_acl(fname, file, sxp) == 0)
5876+		updated = 1;
5877+#endif
5878+
5879 #ifdef HAVE_CHMOD
5880-	if ((st->st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) {
5881+	if ((sxp->st.st_mode & CHMOD_BITS) != (new_mode & CHMOD_BITS)) {
5882 		int ret = do_chmod(fname, new_mode);
5883 		if (ret < 0) {
5884 			rsyserr(FERROR, errno,
5885 				"failed to set permissions on %s",
5886 				full_fname(fname));
5887-			return 0;
5888+			goto cleanup;
5889 		}
5890 		if (ret == 0) /* ret == 1 if symlink could not be set */
5891 			updated = 1;
5892@@ -227,6 +249,11 @@ int set_file_attrs(char *fname, struct f
5893 		else
5894 			rprintf(FCLIENT, "%s is uptodate\n", fname);
5895 	}
5896+  cleanup:
5897+#ifdef SUPPORT_ACLS
5898+	if (preserve_acls && sxp == &sx2)
5899+		free_acl(&sx2);
5900+#endif
5901 	return updated;
5902 }
5903 
5904--- old/rsync.h
5905+++ new/rsync.h
5906@@ -492,6 +492,14 @@ struct idev {
5907 #define IN_LOOPBACKNET 127
5908 #endif
5909 
5910+#ifndef HAVE_NO_ACLS
5911+#define SUPPORT_ACLS 1
5912+#endif
5913+
5914+#if HAVE_UNIXWARE_ACLS|HAVE_SOLARIS_ACLS|HAVE_HPUX_ACLS
5915+#define ACLS_NEED_MASK 1
5916+#endif
5917+
5918 #define GID_NONE ((gid_t)-1)
5919 
5920 #define HL_CHECK_MASTER	0
5921@@ -653,6 +661,17 @@ struct stats {
5922 
5923 struct chmod_mode_struct;
5924 
5925+#define EMPTY_ITEM_LIST {NULL, 0, 0}
5926+
5927+typedef struct {
5928+	void *items;
5929+	size_t count;
5930+	size_t malloced;
5931+} item_list;
5932+
5933+#define EXPAND_ITEM_LIST(lp, type, incr) \
5934+	(type*)expand_item_list(lp, sizeof (type), #type, incr)
5935+
5936 #include "byteorder.h"
5937 #include "lib/mdfour.h"
5938 #include "lib/wildmatch.h"
5939@@ -669,6 +688,16 @@ struct chmod_mode_struct;
5940 #define UNUSED(x) x __attribute__((__unused__))
5941 #define NORETURN __attribute__((__noreturn__))
5942 
5943+typedef struct {
5944+    STRUCT_STAT st;
5945+#ifdef SUPPORT_ACLS
5946+    struct rsync_acl *acc_acl; /* access ACL */
5947+    struct rsync_acl *def_acl; /* default ACL */
5948+#endif
5949+} statx;
5950+
5951+#define ACL_READY(sx) ((sx).acc_acl != NULL)
5952+
5953 #include "proto.h"
5954 
5955 /* We have replacement versions of these if they're missing. */
5956--- old/rsync.yo
5957+++ new/rsync.yo
5958@@ -301,7 +301,7 @@ to the detailed description below for a 
5959  -q, --quiet                 suppress non-error messages
5960      --no-motd               suppress daemon-mode MOTD (see caveat)
5961  -c, --checksum              skip based on checksum, not mod-time & size
5962- -a, --archive               archive mode; same as -rlptgoD (no -H)
5963+ -a, --archive               archive mode; same as -rlptgoD (no -H, -A)
5964      --no-OPTION             turn off an implied OPTION (e.g. --no-D)
5965  -r, --recursive             recurse into directories
5966  -R, --relative              use relative path names
5967@@ -323,6 +323,7 @@ to the detailed description below for a 
5968  -p, --perms                 preserve permissions
5969  -E, --executability         preserve executability
5970      --chmod=CHMOD           affect file and/or directory permissions
5971+ -A, --acls                  preserve ACLs (implies -p) [non-standard]
5972  -o, --owner                 preserve owner (super-user only)
5973  -g, --group                 preserve group
5974      --devices               preserve device files (super-user only)
5975@@ -753,7 +754,9 @@ quote(itemization(
5976   permissions, though the bf(--executability) option might change just
5977   the execute permission for the file.
5978   it() New files get their "normal" permission bits set to the source
5979-  file's permissions masked with the receiving end's umask setting, and
5980+  file's permissions masked with the receiving directory's default
5981+  permissions (either the receiving process's umask, or the permissions
5982+  specified via the destination directory's default ACL), and
5983   their special permission bits disabled except in the case where a new
5984   directory inherits a setgid bit from its parent directory.
5985 ))
5986@@ -784,9 +787,11 @@ The preservation of the destination's se
5987 directories when bf(--perms) is off was added in rsync 2.6.7.  Older rsync
5988 versions erroneously preserved the three special permission bits for
5989 newly-created files when bf(--perms) was off, while overriding the
5990-destination's setgid bit setting on a newly-created directory.  (Keep in
5991-mind that it is the version of the receiving rsync that affects this
5992-behavior.)
5993+destination's setgid bit setting on a newly-created directory.  Default ACL
5994+observance was added to the ACL patch for rsync 2.6.7, so older (or
5995+non-ACL-enabled) rsyncs use the umask even if default ACLs are present.
5996+(Keep in mind that it is the version of the receiving rsync that affects
5997+these behaviors.)
5998 
5999 dit(bf(-E, --executability)) This option causes rsync to preserve the
6000 executability (or non-executability) of regular files when bf(--perms) is
6001@@ -804,6 +809,15 @@ quote(itemization(
6002 
6003 If bf(--perms) is enabled, this option is ignored.
6004 
6005+dit(bf(-A, --acls)) This option causes rsync to update the destination
6006+ACLs to be the same as the source ACLs.  This nonstandard option only
6007+works if the remote rsync also supports it.  bf(--acls) implies bf(--perms).
6008+
6009+Note also that an optimization of the ACL-sending protocol used by this
6010+version makes it incompatible with sending files to an older ACL-enabled
6011+rsync unless you double the bf(--acls) option (e.g. bf(-AA)).  This
6012+doubling is not needed when pulling files from an older rsync.
6013+
6014 dit(bf(--chmod)) This option tells rsync to apply one or more
6015 comma-separated "chmod" strings to the permission of the files in the
6016 transfer.  The resulting value is treated as though it was the permissions
6017@@ -1389,8 +1403,8 @@ if the receiving rsync is at least versi
6018 with older versions of rsync, but that also turns on the output of other
6019 verbose messages).
6020 
6021-The "%i" escape has a cryptic output that is 9 letters long.  The general
6022-format is like the string bf(YXcstpogz), where bf(Y) is replaced by the
6023+The "%i" escape has a cryptic output that is 11 letters long.  The general
6024+format is like the string bf(YXcstpoguax), where bf(Y) is replaced by the
6025 type of update being done, bf(X) is replaced by the file-type, and the
6026 other letters represent attributes that may be output if they are being
6027 modified.
6028@@ -1439,7 +1453,11 @@ quote(itemization(
6029   sender's value (requires bf(--owner) and super-user privileges).
6030   it() A bf(g) means the group is different and is being updated to the
6031   sender's value (requires bf(--group) and the authority to set the group).
6032-  it() The bf(z) slot is reserved for future use.
6033+  it() The bf(u) slot is reserved for reporting update (access) time changes
6034+  (a feature that is not yet released).
6035+  it() The bf(a) means that the ACL information changed.
6036+  it() The bf(x) slot is reserved for reporting extended attribute changes
6037+  (a feature that is not yet released).
6038 ))
6039 
6040 One other output is possible:  when deleting files, the "%i" will output
6041--- old/smb_acls.h
6042+++ new/smb_acls.h
6043@@ -0,0 +1,281 @@
6044+/* 
6045+   Unix SMB/Netbios implementation.
6046+   Version 2.2.x
6047+   Portable SMB ACL interface
6048+   Copyright (C) Jeremy Allison 2000
6049+   
6050+   This program is free software; you can redistribute it and/or modify
6051+   it under the terms of the GNU General Public License as published by
6052+   the Free Software Foundation; either version 2 of the License, or
6053+   (at your option) any later version.
6054+   
6055+   This program is distributed in the hope that it will be useful,
6056+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6057+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6058+   GNU General Public License for more details.
6059+   
6060+   You should have received a copy of the GNU General Public License
6061+   along with this program; if not, write to the Free Software
6062+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
6063+*/
6064+
6065+#ifndef _SMB_ACLS_H
6066+#define _SMB_ACLS_H
6067+
6068+#if defined HAVE_POSIX_ACLS
6069+
6070+/* This is an identity mapping (just remove the SMB_). */
6071+
6072+#define SMB_ACL_TAG_T		acl_tag_t
6073+#define SMB_ACL_TYPE_T		acl_type_t
6074+#define SMB_ACL_PERMSET_T	acl_permset_t
6075+#define SMB_ACL_PERM_T		acl_perm_t
6076+#define SMB_ACL_READ		ACL_READ
6077+#define SMB_ACL_WRITE		ACL_WRITE
6078+#define SMB_ACL_EXECUTE		ACL_EXECUTE
6079+
6080+/* Types of ACLs. */
6081+#define SMB_ACL_USER		ACL_USER
6082+#define SMB_ACL_USER_OBJ	ACL_USER_OBJ
6083+#define SMB_ACL_GROUP		ACL_GROUP
6084+#define SMB_ACL_GROUP_OBJ	ACL_GROUP_OBJ
6085+#define SMB_ACL_OTHER		ACL_OTHER
6086+#define SMB_ACL_MASK		ACL_MASK
6087+
6088+#define SMB_ACL_T		acl_t
6089+
6090+#define SMB_ACL_ENTRY_T		acl_entry_t
6091+
6092+#define SMB_ACL_FIRST_ENTRY	ACL_FIRST_ENTRY
6093+#define SMB_ACL_NEXT_ENTRY	ACL_NEXT_ENTRY
6094+
6095+#define SMB_ACL_TYPE_ACCESS	ACL_TYPE_ACCESS
6096+#define SMB_ACL_TYPE_DEFAULT	ACL_TYPE_DEFAULT
6097+
6098+#elif defined HAVE_TRU64_ACLS
6099+
6100+/* This is for DEC/Compaq Tru64 UNIX */
6101+
6102+#define SMB_ACL_TAG_T		acl_tag_t
6103+#define SMB_ACL_TYPE_T		acl_type_t
6104+#define SMB_ACL_PERMSET_T	acl_permset_t
6105+#define SMB_ACL_PERM_T		acl_perm_t
6106+#define SMB_ACL_READ		ACL_READ
6107+#define SMB_ACL_WRITE		ACL_WRITE
6108+#define SMB_ACL_EXECUTE		ACL_EXECUTE
6109+
6110+/* Types of ACLs. */
6111+#define SMB_ACL_USER		ACL_USER
6112+#define SMB_ACL_USER_OBJ	ACL_USER_OBJ
6113+#define SMB_ACL_GROUP		ACL_GROUP
6114+#define SMB_ACL_GROUP_OBJ	ACL_GROUP_OBJ
6115+#define SMB_ACL_OTHER		ACL_OTHER
6116+#define SMB_ACL_MASK		ACL_MASK
6117+
6118+#define SMB_ACL_T		acl_t
6119+
6120+#define SMB_ACL_ENTRY_T		acl_entry_t
6121+
6122+#define SMB_ACL_FIRST_ENTRY	0
6123+#define SMB_ACL_NEXT_ENTRY	1
6124+
6125+#define SMB_ACL_TYPE_ACCESS	ACL_TYPE_ACCESS
6126+#define SMB_ACL_TYPE_DEFAULT	ACL_TYPE_DEFAULT
6127+
6128+#elif defined HAVE_UNIXWARE_ACLS || defined HAVE_SOLARIS_ACLS
6129+/*
6130+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
6131+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
6132+ */
6133+
6134+/* SVR4.2 ES/MP ACLs */
6135+typedef int SMB_ACL_TAG_T;
6136+typedef int SMB_ACL_TYPE_T;
6137+typedef ushort *SMB_ACL_PERMSET_T;
6138+typedef ushort SMB_ACL_PERM_T;
6139+#define SMB_ACL_READ		4
6140+#define SMB_ACL_WRITE		2
6141+#define SMB_ACL_EXECUTE		1
6142+
6143+/* Types of ACLs. */
6144+#define SMB_ACL_USER		USER
6145+#define SMB_ACL_USER_OBJ	USER_OBJ
6146+#define SMB_ACL_GROUP		GROUP
6147+#define SMB_ACL_GROUP_OBJ	GROUP_OBJ
6148+#define SMB_ACL_OTHER		OTHER_OBJ
6149+#define SMB_ACL_MASK		CLASS_OBJ
6150+
6151+typedef struct SMB_ACL_T {
6152+	int size;
6153+	int count;
6154+	int next;
6155+	struct acl acl[1];
6156+} *SMB_ACL_T;
6157+
6158+typedef struct acl *SMB_ACL_ENTRY_T;
6159+
6160+#define SMB_ACL_FIRST_ENTRY	0
6161+#define SMB_ACL_NEXT_ENTRY	1
6162+
6163+#define SMB_ACL_TYPE_ACCESS	0
6164+#define SMB_ACL_TYPE_DEFAULT	1
6165+
6166+#ifdef __CYGWIN__
6167+#define SMB_ACL_LOSES_SPECIAL_MODE_BITS
6168+#endif
6169+
6170+#elif defined HAVE_HPUX_ACLS
6171+
6172+/*
6173+ * Based on the Solaris & UnixWare code.
6174+ */
6175+
6176+#undef GROUP
6177+#include <sys/aclv.h>
6178+
6179+/* SVR4.2 ES/MP ACLs */
6180+typedef int SMB_ACL_TAG_T;
6181+typedef int SMB_ACL_TYPE_T;
6182+typedef ushort *SMB_ACL_PERMSET_T;
6183+typedef ushort SMB_ACL_PERM_T;
6184+#define SMB_ACL_READ		4
6185+#define SMB_ACL_WRITE		2
6186+#define SMB_ACL_EXECUTE		1
6187+
6188+/* Types of ACLs. */
6189+#define SMB_ACL_USER		USER
6190+#define SMB_ACL_USER_OBJ	USER_OBJ
6191+#define SMB_ACL_GROUP		GROUP
6192+#define SMB_ACL_GROUP_OBJ	GROUP_OBJ
6193+#define SMB_ACL_OTHER		OTHER_OBJ
6194+#define SMB_ACL_MASK		CLASS_OBJ
6195+
6196+typedef struct SMB_ACL_T {
6197+	int size;
6198+	int count;
6199+	int next;
6200+	struct acl acl[1];
6201+} *SMB_ACL_T;
6202+
6203+typedef struct acl *SMB_ACL_ENTRY_T;
6204+
6205+#define SMB_ACL_FIRST_ENTRY	0
6206+#define SMB_ACL_NEXT_ENTRY	1
6207+
6208+#define SMB_ACL_TYPE_ACCESS	0
6209+#define SMB_ACL_TYPE_DEFAULT	1
6210+
6211+#elif defined HAVE_IRIX_ACLS
6212+
6213+#define SMB_ACL_TAG_T		acl_tag_t
6214+#define SMB_ACL_TYPE_T		acl_type_t
6215+#define SMB_ACL_PERMSET_T	acl_permset_t
6216+#define SMB_ACL_PERM_T		acl_perm_t
6217+#define SMB_ACL_READ		ACL_READ
6218+#define SMB_ACL_WRITE		ACL_WRITE
6219+#define SMB_ACL_EXECUTE		ACL_EXECUTE
6220+
6221+/* Types of ACLs. */
6222+#define SMB_ACL_USER		ACL_USER
6223+#define SMB_ACL_USER_OBJ	ACL_USER_OBJ
6224+#define SMB_ACL_GROUP		ACL_GROUP
6225+#define SMB_ACL_GROUP_OBJ	ACL_GROUP_OBJ
6226+#define SMB_ACL_OTHER		ACL_OTHER_OBJ
6227+#define SMB_ACL_MASK		ACL_MASK
6228+
6229+typedef struct SMB_ACL_T {
6230+	int next;
6231+	BOOL freeaclp;
6232+	struct acl *aclp;
6233+} *SMB_ACL_T;
6234+
6235+#define SMB_ACL_ENTRY_T		acl_entry_t
6236+
6237+#define SMB_ACL_FIRST_ENTRY	0
6238+#define SMB_ACL_NEXT_ENTRY	1
6239+
6240+#define SMB_ACL_TYPE_ACCESS	ACL_TYPE_ACCESS
6241+#define SMB_ACL_TYPE_DEFAULT	ACL_TYPE_DEFAULT
6242+
6243+#elif defined HAVE_AIX_ACLS
6244+
6245+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
6246+
6247+#include "/usr/include/acl.h"
6248+
6249+typedef uint *SMB_ACL_PERMSET_T;
6250+ 
6251+struct acl_entry_link{
6252+	struct acl_entry_link *prevp;
6253+	struct new_acl_entry *entryp;
6254+	struct acl_entry_link *nextp;
6255+	int count;
6256+};
6257+
6258+struct new_acl_entry{
6259+	unsigned short ace_len;
6260+	unsigned short ace_type;
6261+	unsigned int ace_access;
6262+	struct ace_id ace_id[1];
6263+};
6264+
6265+#define SMB_ACL_ENTRY_T		struct new_acl_entry*
6266+#define SMB_ACL_T		struct acl_entry_link*
6267+ 
6268+#define SMB_ACL_TAG_T		unsigned short
6269+#define SMB_ACL_TYPE_T		int
6270+#define SMB_ACL_PERM_T		uint
6271+#define SMB_ACL_READ		S_IRUSR
6272+#define SMB_ACL_WRITE		S_IWUSR
6273+#define SMB_ACL_EXECUTE		S_IXUSR
6274+
6275+/* Types of ACLs. */
6276+#define SMB_ACL_USER		ACEID_USER
6277+#define SMB_ACL_USER_OBJ	3
6278+#define SMB_ACL_GROUP		ACEID_GROUP
6279+#define SMB_ACL_GROUP_OBJ	4
6280+#define SMB_ACL_OTHER		5
6281+#define SMB_ACL_MASK		6
6282+
6283+
6284+#define SMB_ACL_FIRST_ENTRY	1
6285+#define SMB_ACL_NEXT_ENTRY	2
6286+
6287+#define SMB_ACL_TYPE_ACCESS	0
6288+#define SMB_ACL_TYPE_DEFAULT	1
6289+
6290+#else /* No ACLs. */
6291+
6292+/* No ACLS - fake it. */
6293+#define SMB_ACL_TAG_T		int
6294+#define SMB_ACL_TYPE_T		int
6295+#define SMB_ACL_PERMSET_T	mode_t
6296+#define SMB_ACL_PERM_T		mode_t
6297+#define SMB_ACL_READ		S_IRUSR
6298+#define SMB_ACL_WRITE		S_IWUSR
6299+#define SMB_ACL_EXECUTE		S_IXUSR
6300+
6301+/* Types of ACLs. */
6302+#define SMB_ACL_USER		0
6303+#define SMB_ACL_USER_OBJ	1
6304+#define SMB_ACL_GROUP		2
6305+#define SMB_ACL_GROUP_OBJ	3
6306+#define SMB_ACL_OTHER		4
6307+#define SMB_ACL_MASK		5
6308+
6309+typedef struct SMB_ACL_T {
6310+	int dummy;
6311+} *SMB_ACL_T;
6312+
6313+typedef struct SMB_ACL_ENTRY_T {
6314+	int dummy;
6315+} *SMB_ACL_ENTRY_T;
6316+
6317+#define SMB_ACL_FIRST_ENTRY	0
6318+#define SMB_ACL_NEXT_ENTRY	1
6319+
6320+#define SMB_ACL_TYPE_ACCESS	0
6321+#define SMB_ACL_TYPE_DEFAULT	1
6322+
6323+#endif /* No ACLs. */
6324+#endif /* _SMB_ACLS_H */
6325--- old/testsuite/acls.test
6326+++ new/testsuite/acls.test
6327@@ -0,0 +1,34 @@
6328+#! /bin/sh
6329+
6330+# This program is distributable under the terms of the GNU GPL (see
6331+# COPYING).
6332+
6333+# Test that rsync handles basic ACL preservation.
6334+
6335+. $srcdir/testsuite/rsync.fns
6336+
6337+$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
6338+case "$setfacl_nodef" in
6339+true) test_skipped "I don't know how to use your setfacl command" ;;
6340+esac
6341+
6342+makepath "$fromdir/foo"
6343+echo something >"$fromdir/file1"
6344+echo else >"$fromdir/file2"
6345+
6346+files='foo file1 file2'
6347+
6348+setfacl -m u:0:7 "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled"
6349+setfacl -m u:0:5 "$fromdir/file1"
6350+setfacl -m u:0:5 "$fromdir/file2"
6351+
6352+$RSYNC -avvA "$fromdir/" "$todir/"
6353+
6354+cd "$fromdir"
6355+getfacl $files >"$scratchdir/acls.txt"
6356+
6357+cd "$todir"
6358+getfacl $files | diff $diffopt "$scratchdir/acls.txt" -
6359+
6360+# The script would have aborted on error, so getting here means we've won.
6361+exit 0
6362--- old/testsuite/default-acls.test
6363+++ new/testsuite/default-acls.test
6364@@ -0,0 +1,65 @@
6365+#! /bin/sh
6366+
6367+# This program is distributable under the terms of the GNU GPL (see
6368+# COPYING).
6369+
6370+# Test that rsync obeys default ACLs. -- Matt McCutchen
6371+
6372+. $srcdir/testsuite/rsync.fns
6373+
6374+$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
6375+case "$setfacl_nodef" in
6376+true) test_skipped "I don't know how to use your setfacl command" ;;
6377+*-k*) opts='-dm u::7,g::5,o:5' ;;
6378+*) opts='-m d:u::7,d:g::5,d:o:5' ;;
6379+esac
6380+setfacl $opts "$scratchdir" || test_skipped "Your filesystem has ACLs disabled"
6381+
6382+# Call as: testit <dirname> <default-acl> <file-expected> <program-expected>
6383+testit() {
6384+    todir="$scratchdir/$1"
6385+    mkdir "$todir"
6386+    $setfacl_nodef "$todir"
6387+    if [ "$2" ]; then
6388+	case "$setfacl_nodef" in
6389+	*-k*) opts="-dm $2" ;;
6390+	*) opts="-m `echo $2 | sed 's/\([ugom]:\)/d:\1/g'`"
6391+	esac
6392+	setfacl $opts "$todir"
6393+    fi
6394+    # Make sure we obey ACLs when creating a directory to hold multiple transferred files,
6395+    # even though the directory itself is outside the transfer
6396+    $RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/"
6397+    check_perms "$todir/to" $4 "Target $1"
6398+    check_perms "$todir/to/dir" $4 "Target $1"
6399+    check_perms "$todir/to/file" $3 "Target $1"
6400+    check_perms "$todir/to/program" $4 "Target $1"
6401+    # Make sure get_local_name doesn't mess us up when transferring only one file
6402+    $RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile"
6403+    check_perms "$todir/to/anotherfile" $3 "Target $1"
6404+    # Make sure we obey default ACLs when not transferring a regular file
6405+    $RSYNC -rvv "$scratchdir/dir/" "$todir/to/anotherdir/"
6406+    check_perms "$todir/to/anotherdir" $4 "Target $1"
6407+}
6408+
6409+mkdir "$scratchdir/dir"
6410+echo "File!" >"$scratchdir/file"
6411+echo "#!/bin/sh" >"$scratchdir/program"
6412+chmod 777 "$scratchdir/dir"
6413+chmod 666 "$scratchdir/file"
6414+chmod 777 "$scratchdir/program"
6415+
6416+# Test some target directories
6417+umask 0077
6418+testit da777 u::7,g::7,o:7 rw-rw-rw- rwxrwxrwx
6419+testit da775 u::7,g::7,o:5 rw-rw-r-- rwxrwxr-x
6420+testit da750 u::7,g::5,o:0 rw-r----- rwxr-x---
6421+testit da770mask u::7,u:0:7,g::0,m:7,o:0 rw-rw---- rwxrwx---
6422+testit noda1 '' rw------- rwx------
6423+umask 0000
6424+testit noda2 '' rw-rw-rw- rwxrwxrwx
6425+umask 0022
6426+testit noda3 '' rw-r--r-- rwxr-xr-x
6427+
6428+# Hooray
6429+exit 0
6430--- old/testsuite/devices.test
6431+++ new/testsuite/devices.test
6432@@ -42,14 +42,14 @@ touch -r "$fromdir/block" "$fromdir/bloc
6433 $RSYNC -ai "$fromdir/block" "$todir/block2" \
6434     | tee "$outfile"
6435 cat <<EOT >"$chkfile"
6436-cD+++++++ block
6437+cD+++++++++ block
6438 EOT
6439 diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
6440 
6441 $RSYNC -ai "$fromdir/block2" "$todir/block" \
6442     | tee "$outfile"
6443 cat <<EOT >"$chkfile"
6444-cD+++++++ block2
6445+cD+++++++++ block2
6446 EOT
6447 diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
6448 
6449@@ -58,7 +58,7 @@ sleep 1
6450 $RSYNC -Di "$fromdir/block3" "$todir/block" \
6451     | tee "$outfile"
6452 cat <<EOT >"$chkfile"
6453-cD..T.... block3
6454+cD..T...... block3
6455 EOT
6456 diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
6457 
6458@@ -66,15 +66,15 @@ $RSYNC -aiHvv "$fromdir/" "$todir/" \
6459     | tee "$outfile"
6460 filter_outfile
6461 cat <<EOT >"$chkfile"
6462-.d..t.... ./
6463-cD..t.... block
6464-cD....... block2
6465-cD+++++++ block3
6466-hD+++++++ block2.5 => block3
6467-cD+++++++ char
6468-cD+++++++ char2
6469-cD+++++++ char3
6470-cS+++++++ fifo
6471+.d..t...... ./
6472+cD..t...... block
6473+cD......... block2
6474+cD+++++++++ block3
6475+hD+++++++++ block2.5 => block3
6476+cD+++++++++ char
6477+cD+++++++++ char2
6478+cD+++++++++ char3
6479+cS+++++++++ fifo
6480 EOT
6481 if test ! -b "$fromdir/block2.5"; then
6482     sed -e '/block2\.5/d' \
6483--- old/testsuite/itemize.test
6484+++ new/testsuite/itemize.test
6485@@ -29,15 +29,15 @@ ln "$fromdir/foo/config1" "$fromdir/foo/
6486 $RSYNC -iplr "$fromdir/" "$todir/" \
6487     | tee "$outfile"
6488 cat <<EOT >"$chkfile"
6489-cd+++++++ ./
6490-cd+++++++ bar/
6491-cd+++++++ bar/baz/
6492->f+++++++ bar/baz/rsync
6493-cd+++++++ foo/
6494->f+++++++ foo/config1
6495->f+++++++ foo/config2
6496->f+++++++ foo/extra
6497-cL+++++++ foo/sym -> ../bar/baz/rsync
6498+cd+++++++++ ./
6499+cd+++++++++ bar/
6500+cd+++++++++ bar/baz/
6501+>f+++++++++ bar/baz/rsync
6502+cd+++++++++ foo/
6503+>f+++++++++ foo/config1
6504+>f+++++++++ foo/config2
6505+>f+++++++++ foo/extra
6506+cL+++++++++ foo/sym -> ../bar/baz/rsync
6507 EOT
6508 diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
6509 
6510@@ -49,10 +49,10 @@ chmod 601 "$fromdir/foo/config2"
6511 $RSYNC -iplrH "$fromdir/" "$todir/" \
6512     | tee "$outfile"
6513 cat <<EOT >"$chkfile"
6514->f..T.... bar/baz/rsync
6515->f..T.... foo/config1
6516->f.sTp... foo/config2
6517-hf..T.... foo/extra => foo/config1
6518+>f..T...... bar/baz/rsync
6519+>f..T...... foo/config1
6520+>f.sTp..... foo/config2
6521+hf..T...... foo/extra => foo/config1
6522 EOT
6523 diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
6524 
6525@@ -69,11 +69,11 @@ chmod 777 "$todir/bar/baz/rsync"
6526 $RSYNC -iplrtc "$fromdir/" "$todir/" \
6527     | tee "$outfile"
6528 cat <<EOT >"$chkfile"
6529-.f..tp... bar/baz/rsync
6530-.d..t.... foo/
6531-.f..t.... foo/config1
6532->fcstp... foo/config2
6533-cL..T.... foo/sym -> ../bar/baz/rsync
6534+.f..tp..... bar/baz/rsync
6535+.d..t...... foo/
6536+.f..t...... foo/config1
6537+>fcstp..... foo/config2
6538+cL..T...... foo/sym -> ../bar/baz/rsync
6539 EOT
6540 diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
6541 
6542@@ -98,15 +98,15 @@ $RSYNC -ivvplrtH "$fromdir/" "$todir/" \
6543     | tee "$outfile"
6544 filter_outfile
6545 cat <<EOT >"$chkfile"
6546-.d        ./
6547-.d        bar/
6548-.d        bar/baz/
6549-.f...p... bar/baz/rsync
6550-.d        foo/
6551-.f        foo/config1
6552->f..t.... foo/config2
6553-hf        foo/extra
6554-.L        foo/sym -> ../bar/baz/rsync
6555+.d          ./
6556+.d          bar/
6557+.d          bar/baz/
6558+.f...p..... bar/baz/rsync
6559+.d          foo/
6560+.f          foo/config1
6561+>f..t...... foo/config2
6562+hf          foo/extra
6563+.L          foo/sym -> ../bar/baz/rsync
6564 EOT
6565 diff $diffopt "$chkfile" "$outfile" || test_fail "test 5 failed"
6566 
6567@@ -125,8 +125,8 @@ touch "$todir/foo/config2"
6568 $RSYNC -iplrtH "$fromdir/" "$todir/" \
6569     | tee "$outfile"
6570 cat <<EOT >"$chkfile"
6571-.f...p... foo/config1
6572->f..t.... foo/config2
6573+.f...p..... foo/config1
6574+>f..t...... foo/config2
6575 EOT
6576 diff $diffopt "$chkfile" "$outfile" || test_fail "test 7 failed"
6577 
6578@@ -135,15 +135,15 @@ $RSYNC -ivvplrtH --copy-dest=../ld "$fro
6579     | tee "$outfile"
6580 filter_outfile
6581 cat <<EOT >"$chkfile"
6582-cd+++++++ ./
6583-cd+++++++ bar/
6584-cd+++++++ bar/baz/
6585-cf        bar/baz/rsync
6586-cd+++++++ foo/
6587-cf        foo/config1
6588-cf        foo/config2
6589-hf        foo/extra => foo/config1
6590-cL..T.... foo/sym -> ../bar/baz/rsync
6591+cd+++++++++ ./
6592+cd+++++++++ bar/
6593+cd+++++++++ bar/baz/
6594+cf          bar/baz/rsync
6595+cd+++++++++ foo/
6596+cf          foo/config1
6597+cf          foo/config2
6598+hf          foo/extra => foo/config1
6599+cL..T...... foo/sym -> ../bar/baz/rsync
6600 EOT
6601 diff $diffopt "$chkfile" "$outfile" || test_fail "test 8 failed"
6602 
6603@@ -151,11 +151,11 @@ rm -rf "$todir"
6604 $RSYNC -iplrtH --copy-dest=../ld "$fromdir/" "$todir/" \
6605     | tee "$outfile"
6606 cat <<EOT >"$chkfile"
6607-cd+++++++ ./
6608-cd+++++++ bar/
6609-cd+++++++ bar/baz/
6610-cd+++++++ foo/
6611-hf        foo/extra => foo/config1
6612+cd+++++++++ ./
6613+cd+++++++++ bar/
6614+cd+++++++++ bar/baz/
6615+cd+++++++++ foo/
6616+hf          foo/extra => foo/config1
6617 EOT
6618 diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"
6619 
6620@@ -182,15 +182,15 @@ $RSYNC -ivvplrtH --link-dest="$lddir" "$
6621     | tee "$outfile"
6622 filter_outfile
6623 cat <<EOT >"$chkfile"
6624-cd+++++++ ./
6625-cd+++++++ bar/
6626-cd+++++++ bar/baz/
6627-hf        bar/baz/rsync
6628-cd+++++++ foo/
6629-hf        foo/config1
6630-hf        foo/config2
6631-hf        foo/extra => foo/config1
6632-hL        foo/sym -> ../bar/baz/rsync
6633+cd+++++++++ ./
6634+cd+++++++++ bar/
6635+cd+++++++++ bar/baz/
6636+hf          bar/baz/rsync
6637+cd+++++++++ foo/
6638+hf          foo/config1
6639+hf          foo/config2
6640+hf          foo/extra => foo/config1
6641+hL          foo/sym -> ../bar/baz/rsync
6642 EOT
6643 diff $diffopt "$chkfile" "$outfile" || test_fail "test 11 failed"
6644 
6645@@ -198,10 +198,10 @@ rm -rf "$todir"
6646 $RSYNC -iplrtH --dry-run --link-dest=../ld "$fromdir/" "$todir/" \
6647     | tee "$outfile"
6648 cat <<EOT >"$chkfile"
6649-cd+++++++ ./
6650-cd+++++++ bar/
6651-cd+++++++ bar/baz/
6652-cd+++++++ foo/
6653+cd+++++++++ ./
6654+cd+++++++++ bar/
6655+cd+++++++++ bar/baz/
6656+cd+++++++++ foo/
6657 EOT
6658 diff $diffopt "$chkfile" "$outfile" || test_fail "test 12 failed"
6659 
6660@@ -209,10 +209,10 @@ rm -rf "$todir"
6661 $RSYNC -iplrtH --link-dest=../ld "$fromdir/" "$todir/" \
6662     | tee "$outfile"
6663 cat <<EOT >"$chkfile"
6664-cd+++++++ ./
6665-cd+++++++ bar/
6666-cd+++++++ bar/baz/
6667-cd+++++++ foo/
6668+cd+++++++++ ./
6669+cd+++++++++ bar/
6670+cd+++++++++ bar/baz/
6671+cd+++++++++ foo/
6672 EOT
6673 diff $diffopt "$chkfile" "$outfile" || test_fail "test 13 failed"
6674 
6675@@ -240,14 +240,14 @@ filter_outfile
6676 # TODO fix really-old problem when combining -H with --compare-dest:
6677 # missing output for foo/extra hard-link (and it might not be updated)!
6678 cat <<EOT >"$chkfile"
6679-cd+++++++ ./
6680-cd+++++++ bar/
6681-cd+++++++ bar/baz/
6682-.f        bar/baz/rsync
6683-cd+++++++ foo/
6684-.f        foo/config1
6685-.f        foo/config2
6686-.L        foo/sym -> ../bar/baz/rsync
6687+cd+++++++++ ./
6688+cd+++++++++ bar/
6689+cd+++++++++ bar/baz/
6690+.f          bar/baz/rsync
6691+cd+++++++++ foo/
6692+.f          foo/config1
6693+.f          foo/config2
6694+.L          foo/sym -> ../bar/baz/rsync
6695 EOT
6696 diff $diffopt "$chkfile" "$outfile" || test_fail "test 15 failed"
6697 
6698@@ -255,10 +255,10 @@ rm -rf "$todir"
6699 $RSYNC -iplrtH --compare-dest="$lddir" "$fromdir/" "$todir/" \
6700     | tee "$outfile"
6701 cat <<EOT >"$chkfile"
6702-cd+++++++ ./
6703-cd+++++++ bar/
6704-cd+++++++ bar/baz/
6705-cd+++++++ foo/
6706+cd+++++++++ ./
6707+cd+++++++++ bar/
6708+cd+++++++++ bar/baz/
6709+cd+++++++++ foo/
6710 EOT
6711 diff $diffopt "$chkfile" "$outfile" || test_fail "test 16 failed"
6712 
6713--- old/uidlist.c
6714+++ new/uidlist.c
6715@@ -35,6 +35,7 @@
6716 extern int verbose;
6717 extern int preserve_uid;
6718 extern int preserve_gid;
6719+extern int preserve_acls;
6720 extern int numeric_ids;
6721 extern int am_root;
6722 
6723@@ -273,7 +274,7 @@ void send_uid_list(int f)
6724 	if (numeric_ids)
6725 		return;
6726 
6727-	if (preserve_uid) {
6728+	if (preserve_uid || preserve_acls) {
6729 		int len;
6730 		/* we send sequences of uid/byte-length/name */
6731 		for (list = uidlist; list; list = list->next) {
6732@@ -290,7 +291,7 @@ void send_uid_list(int f)
6733 		write_int(f, 0);
6734 	}
6735 
6736-	if (preserve_gid) {
6737+	if (preserve_gid || preserve_acls) {
6738 		int len;
6739 		for (list = gidlist; list; list = list->next) {
6740 			if (!list->name)
6741@@ -311,7 +312,7 @@ void recv_uid_list(int f, struct file_li
6742 	int id, i;
6743 	char *name;
6744 
6745-	if (preserve_uid && !numeric_ids) {
6746+	if ((preserve_uid || preserve_acls) && !numeric_ids) {
6747 		/* read the uid list */
6748 		while ((id = read_int(f)) != 0) {
6749 			int len = read_byte(f);
6750@@ -323,7 +324,7 @@ void recv_uid_list(int f, struct file_li
6751 		}
6752 	}
6753 
6754-	if (preserve_gid && !numeric_ids) {
6755+	if ((preserve_gid || preserve_acls) && !numeric_ids) {
6756 		/* read the gid list */
6757 		while ((id = read_int(f)) != 0) {
6758 			int len = read_byte(f);
6759@@ -335,6 +336,16 @@ void recv_uid_list(int f, struct file_li
6760 		}
6761 	}
6762 
6763+#ifdef SUPPORT_ACLS
6764+	if (preserve_acls && !numeric_ids) {
6765+		id_t *id;
6766+		while ((id = next_acl_uid(flist)) != NULL)
6767+			*id = match_uid(*id);
6768+		while ((id = next_acl_gid(flist)) != NULL)
6769+			*id = match_gid(*id);
6770+	}
6771+#endif
6772+
6773 	/* Now convert all the uids/gids from sender values to our values. */
6774 	if (am_root && preserve_uid && !numeric_ids) {
6775 		for (i = 0; i < flist->count; i++)
6776--- old/util.c
6777+++ new/util.c
6778@@ -1468,3 +1468,31 @@ int bitbag_next_bit(struct bitbag *bb, i
6779 
6780 	return -1;
6781 }
6782+
6783+void *expand_item_list(item_list *lp, size_t item_size,
6784+		       const char *desc, int incr)
6785+{
6786+	/* First time through, 0 <= 0, so list is expanded. */
6787+	if (lp->malloced <= lp->count) {
6788+		void *new_ptr;
6789+		size_t new_size = lp->malloced;
6790+		if (incr < 0)
6791+			new_size -= incr; /* increase slowly */
6792+		else if (new_size < (size_t)incr)
6793+			new_size += incr;
6794+		else
6795+			new_size *= 2;
6796+		new_ptr = realloc_array(lp->items, char, new_size * item_size);
6797+		if (verbose >= 4) {
6798+			rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n",
6799+				who_am_i(), desc, (double)new_size * item_size,
6800+				new_ptr == lp->items ? " not" : "");
6801+		}
6802+		if (!new_ptr)
6803+			out_of_memory("expand_item_list");
6804+
6805+		lp->items = new_ptr;
6806+		lp->malloced = new_size;
6807+	}
6808+	return (char*)lp->items + (lp->count++ * item_size);
6809+}
6810--- old/proto.h
6811+++ new/proto.h
6812@@ -1,6 +1,15 @@
6813 /* This file is automatically generated with "make proto". DO NOT EDIT */
6814 
6815 int allow_access(char *addr, char *host, char *allow_list, char *deny_list);
6816+void free_acl(statx *sxp);
6817+int get_acl(const char *fname, statx *sxp);
6818+void send_acl(statx *sxp, int f);
6819+void receive_acl(struct file_struct *file, int f);
6820+void cache_acl(struct file_struct *file, statx *sxp);
6821+int set_acl(const char *fname, const struct file_struct *file, statx *sxp);
6822+id_t *next_acl_uid();
6823+id_t *next_acl_gid();
6824+int default_perms_for_dir(const char *dir);
6825 void base64_encode(char *buf, int len, char *out, int pad);
6826 char *auth_server(int f_in, int f_out, int module, char *host, char *addr,
6827 		  char *leader);
6828@@ -83,18 +92,18 @@ int f_name_cmp(struct file_struct *f1, s
6829 char *f_name(struct file_struct *f, char *fbuf);
6830 struct file_list *get_dirlist(char *dirname, int dlen,
6831 			      int ignore_filter_rules);
6832-int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st);
6833-void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st,
6834+int unchanged_attrs(struct file_struct *file, statx *sxp);
6835+void itemize(struct file_struct *file, int ndx, int statret, statx *sxp,
6836 	     int32 iflags, uchar fnamecmp_type, char *xname);
6837 int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st);
6838 void check_for_finished_hlinks(int itemizing, enum logcode code);
6839 void generate_files(int f_out, struct file_list *flist, char *local_name);
6840 void init_hard_links(void);
6841 int hard_link_check(struct file_struct *file, int ndx, char *fname,
6842-		    int statret, STRUCT_STAT *st, int itemizing,
6843+		    int statret, statx *sxp, int itemizing,
6844 		    enum logcode code, int skip);
6845 int hard_link_one(struct file_struct *file, int ndx, char *fname,
6846-		  int statret, STRUCT_STAT *st, char *toname, int terse,
6847+		  int statret, statx *sxp, char *toname, int terse,
6848 		  int itemizing, enum logcode code);
6849 void hard_link_cluster(struct file_struct *file, int master, int itemizing,
6850 		       enum logcode code);
6851@@ -223,8 +232,9 @@ void show_progress(OFF_T ofs, OFF_T size
6852 int recv_files(int f_in, struct file_list *flist, char *local_name);
6853 void setup_iconv();
6854 void free_sums(struct sum_struct *s);
6855-mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists);
6856-int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
6857+mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
6858+		 int exists);
6859+int set_file_attrs(char *fname, struct file_struct *file, statx *sxp,
6860 		   int flags);
6861 RETSIGTYPE sig_int(UNUSED(int val));
6862 void finish_transfer(char *fname, char *fnametmp, char *partialptr,
6863@@ -320,4 +330,6 @@ void bitbag_set_bit(struct bitbag *bb, i
6864 void bitbag_clear_bit(struct bitbag *bb, int ndx);
6865 int bitbag_check_bit(struct bitbag *bb, int ndx);
6866 int bitbag_next_bit(struct bitbag *bb, int after);
6867+void *expand_item_list(item_list *lp, size_t item_size,
6868+		       const char *desc, int incr);
6869 int sys_gettimeofday(struct timeval *tv);
6870--- old/configure
6871+++ new/configure
6872@@ -1258,6 +1258,7 @@ Optional Features:
6873   --disable-largefile     omit support for large files
6874   --disable-ipv6          don't even try to use IPv6
6875   --disable-locale        turn off locale features
6876+  --enable-acl-support    Include ACL support (default=no)
6877 
6878 Optional Packages:
6879   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
6880@@ -12941,6 +12942,206 @@ fi
6881 fi
6882 
6883 
6884+for ac_func in aclsort
6885+do
6886+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
6887+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
6888+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
6889+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
6890+  echo $ECHO_N "(cached) $ECHO_C" >&6
6891+else
6892+  cat >conftest.$ac_ext <<_ACEOF
6893+/* confdefs.h.  */
6894+_ACEOF
6895+cat confdefs.h >>conftest.$ac_ext
6896+cat >>conftest.$ac_ext <<_ACEOF
6897+/* end confdefs.h.  */
6898+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
6899+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
6900+#define $ac_func innocuous_$ac_func
6901+
6902+/* System header to define __stub macros and hopefully few prototypes,
6903+    which can conflict with char $ac_func (); below.
6904+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
6905+    <limits.h> exists even on freestanding compilers.  */
6906+
6907+#ifdef __STDC__
6908+# include <limits.h>
6909+#else
6910+# include <assert.h>
6911+#endif
6912+
6913+#undef $ac_func
6914+
6915+/* Override any GCC internal prototype to avoid an error.
6916+   Use char because int might match the return type of a GCC
6917+   builtin and then its argument prototype would still apply.  */
6918+#ifdef __cplusplus
6919+extern "C"
6920+#endif
6921+char $ac_func ();
6922+/* The GNU C library defines this for functions which it implements
6923+    to always fail with ENOSYS.  Some functions are actually named
6924+    something starting with __ and the normal name is an alias.  */
6925+#if defined __stub_$ac_func || defined __stub___$ac_func
6926+choke me
6927+#endif
6928+
6929+int
6930+main ()
6931+{
6932+return $ac_func ();
6933+  ;
6934+  return 0;
6935+}
6936+_ACEOF
6937+rm -f conftest.$ac_objext conftest$ac_exeext
6938+if { (ac_try="$ac_link"
6939+case "(($ac_try" in
6940+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
6941+  *) ac_try_echo=$ac_try;;
6942+esac
6943+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
6944+  (eval "$ac_link") 2>conftest.er1
6945+  ac_status=$?
6946+  grep -v '^ *+' conftest.er1 >conftest.err
6947+  rm -f conftest.er1
6948+  cat conftest.err >&5
6949+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
6950+  (exit $ac_status); } &&
6951+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
6952+  { (case "(($ac_try" in
6953+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
6954+  *) ac_try_echo=$ac_try;;
6955+esac
6956+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
6957+  (eval "$ac_try") 2>&5
6958+  ac_status=$?
6959+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
6960+  (exit $ac_status); }; } &&
6961+	 { ac_try='test -s conftest$ac_exeext'
6962+  { (case "(($ac_try" in
6963+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
6964+  *) ac_try_echo=$ac_try;;
6965+esac
6966+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
6967+  (eval "$ac_try") 2>&5
6968+  ac_status=$?
6969+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
6970+  (exit $ac_status); }; }; then
6971+  eval "$as_ac_var=yes"
6972+else
6973+  echo "$as_me: failed program was:" >&5
6974+sed 's/^/| /' conftest.$ac_ext >&5
6975+
6976+	eval "$as_ac_var=no"
6977+fi
6978+
6979+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
6980+      conftest$ac_exeext conftest.$ac_ext
6981+fi
6982+ac_res=`eval echo '${'$as_ac_var'}'`
6983+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
6984+echo "${ECHO_T}$ac_res" >&6; }
6985+if test `eval echo '${'$as_ac_var'}'` = yes; then
6986+  cat >>confdefs.h <<_ACEOF
6987+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
6988+_ACEOF
6989+
6990+fi
6991+done
6992+
6993+if test x"$ac_cv_func_aclsort" = x"no"; then
6994+
6995+{ echo "$as_me:$LINENO: checking for aclsort in -lsec" >&5
6996+echo $ECHO_N "checking for aclsort in -lsec... $ECHO_C" >&6; }
6997+if test "${ac_cv_lib_sec_aclsort+set}" = set; then
6998+  echo $ECHO_N "(cached) $ECHO_C" >&6
6999+else
7000+  ac_check_lib_save_LIBS=$LIBS
7001+LIBS="-lsec  $LIBS"
7002+cat >conftest.$ac_ext <<_ACEOF
7003+/* confdefs.h.  */
7004+_ACEOF
7005+cat confdefs.h >>conftest.$ac_ext
7006+cat >>conftest.$ac_ext <<_ACEOF
7007+/* end confdefs.h.  */
7008+
7009+/* Override any GCC internal prototype to avoid an error.
7010+   Use char because int might match the return type of a GCC
7011+   builtin and then its argument prototype would still apply.  */
7012+#ifdef __cplusplus
7013+extern "C"
7014+#endif
7015+char aclsort ();
7016+int
7017+main ()
7018+{
7019+return aclsort ();
7020+  ;
7021+  return 0;
7022+}
7023+_ACEOF
7024+rm -f conftest.$ac_objext conftest$ac_exeext
7025+if { (ac_try="$ac_link"
7026+case "(($ac_try" in
7027+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7028+  *) ac_try_echo=$ac_try;;
7029+esac
7030+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7031+  (eval "$ac_link") 2>conftest.er1
7032+  ac_status=$?
7033+  grep -v '^ *+' conftest.er1 >conftest.err
7034+  rm -f conftest.er1
7035+  cat conftest.err >&5
7036+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7037+  (exit $ac_status); } &&
7038+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
7039+  { (case "(($ac_try" in
7040+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7041+  *) ac_try_echo=$ac_try;;
7042+esac
7043+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7044+  (eval "$ac_try") 2>&5
7045+  ac_status=$?
7046+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7047+  (exit $ac_status); }; } &&
7048+	 { ac_try='test -s conftest$ac_exeext'
7049+  { (case "(($ac_try" in
7050+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7051+  *) ac_try_echo=$ac_try;;
7052+esac
7053+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7054+  (eval "$ac_try") 2>&5
7055+  ac_status=$?
7056+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7057+  (exit $ac_status); }; }; then
7058+  ac_cv_lib_sec_aclsort=yes
7059+else
7060+  echo "$as_me: failed program was:" >&5
7061+sed 's/^/| /' conftest.$ac_ext >&5
7062+
7063+	ac_cv_lib_sec_aclsort=no
7064+fi
7065+
7066+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
7067+      conftest$ac_exeext conftest.$ac_ext
7068+LIBS=$ac_check_lib_save_LIBS
7069+fi
7070+{ echo "$as_me:$LINENO: result: $ac_cv_lib_sec_aclsort" >&5
7071+echo "${ECHO_T}$ac_cv_lib_sec_aclsort" >&6; }
7072+if test $ac_cv_lib_sec_aclsort = yes; then
7073+  cat >>confdefs.h <<_ACEOF
7074+#define HAVE_LIBSEC 1
7075+_ACEOF
7076+
7077+  LIBS="-lsec $LIBS"
7078+
7079+fi
7080+
7081+fi
7082+
7083+
7084 { echo "$as_me:$LINENO: checking whether utime accepts a null argument" >&5
7085 echo $ECHO_N "checking whether utime accepts a null argument... $ECHO_C" >&6; }
7086 if test "${ac_cv_func_utime_null+set}" = set; then
7087@@ -14808,6 +15009,625 @@ fi
7088 
7089 
7090 
7091+
7092+
7093+for ac_header in sys/acl.h acl/libacl.h
7094+do
7095+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
7096+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
7097+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
7098+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
7099+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
7100+  echo $ECHO_N "(cached) $ECHO_C" >&6
7101+fi
7102+ac_res=`eval echo '${'$as_ac_Header'}'`
7103+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
7104+echo "${ECHO_T}$ac_res" >&6; }
7105+else
7106+  # Is the header compilable?
7107+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
7108+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
7109+cat >conftest.$ac_ext <<_ACEOF
7110+/* confdefs.h.  */
7111+_ACEOF
7112+cat confdefs.h >>conftest.$ac_ext
7113+cat >>conftest.$ac_ext <<_ACEOF
7114+/* end confdefs.h.  */
7115+$ac_includes_default
7116+#include <$ac_header>
7117+_ACEOF
7118+rm -f conftest.$ac_objext
7119+if { (ac_try="$ac_compile"
7120+case "(($ac_try" in
7121+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7122+  *) ac_try_echo=$ac_try;;
7123+esac
7124+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7125+  (eval "$ac_compile") 2>conftest.er1
7126+  ac_status=$?
7127+  grep -v '^ *+' conftest.er1 >conftest.err
7128+  rm -f conftest.er1
7129+  cat conftest.err >&5
7130+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7131+  (exit $ac_status); } &&
7132+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
7133+  { (case "(($ac_try" in
7134+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7135+  *) ac_try_echo=$ac_try;;
7136+esac
7137+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7138+  (eval "$ac_try") 2>&5
7139+  ac_status=$?
7140+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7141+  (exit $ac_status); }; } &&
7142+	 { ac_try='test -s conftest.$ac_objext'
7143+  { (case "(($ac_try" in
7144+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7145+  *) ac_try_echo=$ac_try;;
7146+esac
7147+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7148+  (eval "$ac_try") 2>&5
7149+  ac_status=$?
7150+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7151+  (exit $ac_status); }; }; then
7152+  ac_header_compiler=yes
7153+else
7154+  echo "$as_me: failed program was:" >&5
7155+sed 's/^/| /' conftest.$ac_ext >&5
7156+
7157+	ac_header_compiler=no
7158+fi
7159+
7160+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
7161+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
7162+echo "${ECHO_T}$ac_header_compiler" >&6; }
7163+
7164+# Is the header present?
7165+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
7166+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
7167+cat >conftest.$ac_ext <<_ACEOF
7168+/* confdefs.h.  */
7169+_ACEOF
7170+cat confdefs.h >>conftest.$ac_ext
7171+cat >>conftest.$ac_ext <<_ACEOF
7172+/* end confdefs.h.  */
7173+#include <$ac_header>
7174+_ACEOF
7175+if { (ac_try="$ac_cpp conftest.$ac_ext"
7176+case "(($ac_try" in
7177+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7178+  *) ac_try_echo=$ac_try;;
7179+esac
7180+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7181+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
7182+  ac_status=$?
7183+  grep -v '^ *+' conftest.er1 >conftest.err
7184+  rm -f conftest.er1
7185+  cat conftest.err >&5
7186+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7187+  (exit $ac_status); } >/dev/null; then
7188+  if test -s conftest.err; then
7189+    ac_cpp_err=$ac_c_preproc_warn_flag
7190+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
7191+  else
7192+    ac_cpp_err=
7193+  fi
7194+else
7195+  ac_cpp_err=yes
7196+fi
7197+if test -z "$ac_cpp_err"; then
7198+  ac_header_preproc=yes
7199+else
7200+  echo "$as_me: failed program was:" >&5
7201+sed 's/^/| /' conftest.$ac_ext >&5
7202+
7203+  ac_header_preproc=no
7204+fi
7205+
7206+rm -f conftest.err conftest.$ac_ext
7207+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
7208+echo "${ECHO_T}$ac_header_preproc" >&6; }
7209+
7210+# So?  What about this header?
7211+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
7212+  yes:no: )
7213+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
7214+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
7215+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
7216+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
7217+    ac_header_preproc=yes
7218+    ;;
7219+  no:yes:* )
7220+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
7221+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
7222+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
7223+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
7224+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
7225+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
7226+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
7227+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
7228+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
7229+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
7230+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
7231+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
7232+
7233+    ;;
7234+esac
7235+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
7236+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
7237+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
7238+  echo $ECHO_N "(cached) $ECHO_C" >&6
7239+else
7240+  eval "$as_ac_Header=\$ac_header_preproc"
7241+fi
7242+ac_res=`eval echo '${'$as_ac_Header'}'`
7243+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
7244+echo "${ECHO_T}$ac_res" >&6; }
7245+
7246+fi
7247+if test `eval echo '${'$as_ac_Header'}'` = yes; then
7248+  cat >>confdefs.h <<_ACEOF
7249+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
7250+_ACEOF
7251+
7252+fi
7253+
7254+done
7255+
7256+
7257+
7258+
7259+
7260+for ac_func in _acl __acl _facl __facl
7261+do
7262+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
7263+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
7264+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
7265+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
7266+  echo $ECHO_N "(cached) $ECHO_C" >&6
7267+else
7268+  cat >conftest.$ac_ext <<_ACEOF
7269+/* confdefs.h.  */
7270+_ACEOF
7271+cat confdefs.h >>conftest.$ac_ext
7272+cat >>conftest.$ac_ext <<_ACEOF
7273+/* end confdefs.h.  */
7274+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
7275+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
7276+#define $ac_func innocuous_$ac_func
7277+
7278+/* System header to define __stub macros and hopefully few prototypes,
7279+    which can conflict with char $ac_func (); below.
7280+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
7281+    <limits.h> exists even on freestanding compilers.  */
7282+
7283+#ifdef __STDC__
7284+# include <limits.h>
7285+#else
7286+# include <assert.h>
7287+#endif
7288+
7289+#undef $ac_func
7290+
7291+/* Override any GCC internal prototype to avoid an error.
7292+   Use char because int might match the return type of a GCC
7293+   builtin and then its argument prototype would still apply.  */
7294+#ifdef __cplusplus
7295+extern "C"
7296+#endif
7297+char $ac_func ();
7298+/* The GNU C library defines this for functions which it implements
7299+    to always fail with ENOSYS.  Some functions are actually named
7300+    something starting with __ and the normal name is an alias.  */
7301+#if defined __stub_$ac_func || defined __stub___$ac_func
7302+choke me
7303+#endif
7304+
7305+int
7306+main ()
7307+{
7308+return $ac_func ();
7309+  ;
7310+  return 0;
7311+}
7312+_ACEOF
7313+rm -f conftest.$ac_objext conftest$ac_exeext
7314+if { (ac_try="$ac_link"
7315+case "(($ac_try" in
7316+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7317+  *) ac_try_echo=$ac_try;;
7318+esac
7319+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7320+  (eval "$ac_link") 2>conftest.er1
7321+  ac_status=$?
7322+  grep -v '^ *+' conftest.er1 >conftest.err
7323+  rm -f conftest.er1
7324+  cat conftest.err >&5
7325+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7326+  (exit $ac_status); } &&
7327+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
7328+  { (case "(($ac_try" in
7329+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7330+  *) ac_try_echo=$ac_try;;
7331+esac
7332+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7333+  (eval "$ac_try") 2>&5
7334+  ac_status=$?
7335+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7336+  (exit $ac_status); }; } &&
7337+	 { ac_try='test -s conftest$ac_exeext'
7338+  { (case "(($ac_try" in
7339+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7340+  *) ac_try_echo=$ac_try;;
7341+esac
7342+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7343+  (eval "$ac_try") 2>&5
7344+  ac_status=$?
7345+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7346+  (exit $ac_status); }; }; then
7347+  eval "$as_ac_var=yes"
7348+else
7349+  echo "$as_me: failed program was:" >&5
7350+sed 's/^/| /' conftest.$ac_ext >&5
7351+
7352+	eval "$as_ac_var=no"
7353+fi
7354+
7355+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
7356+      conftest$ac_exeext conftest.$ac_ext
7357+fi
7358+ac_res=`eval echo '${'$as_ac_var'}'`
7359+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
7360+echo "${ECHO_T}$ac_res" >&6; }
7361+if test `eval echo '${'$as_ac_var'}'` = yes; then
7362+  cat >>confdefs.h <<_ACEOF
7363+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
7364+_ACEOF
7365+
7366+fi
7367+done
7368+
7369+#################################################
7370+# check for ACL support
7371+
7372+{ echo "$as_me:$LINENO: checking whether to support ACLs" >&5
7373+echo $ECHO_N "checking whether to support ACLs... $ECHO_C" >&6; }
7374+# Check whether --enable-acl-support was given.
7375+if test "${enable_acl_support+set}" = set; then
7376+  enableval=$enable_acl_support;  case "$enableval" in
7377+  yes)
7378+
7379+		case "$host_os" in
7380+		*sysv5*)
7381+			{ echo "$as_me:$LINENO: result: Using UnixWare ACLs" >&5
7382+echo "${ECHO_T}Using UnixWare ACLs" >&6; }
7383+
7384+cat >>confdefs.h <<\_ACEOF
7385+#define HAVE_UNIXWARE_ACLS 1
7386+_ACEOF
7387+
7388+			;;
7389+		*solaris*|*cygwin*)
7390+			{ echo "$as_me:$LINENO: result: Using solaris ACLs" >&5
7391+echo "${ECHO_T}Using solaris ACLs" >&6; }
7392+
7393+cat >>confdefs.h <<\_ACEOF
7394+#define HAVE_SOLARIS_ACLS 1
7395+_ACEOF
7396+
7397+			;;
7398+		*hpux*)
7399+			{ echo "$as_me:$LINENO: result: Using HPUX ACLs" >&5
7400+echo "${ECHO_T}Using HPUX ACLs" >&6; }
7401+
7402+cat >>confdefs.h <<\_ACEOF
7403+#define HAVE_HPUX_ACLS 1
7404+_ACEOF
7405+
7406+			;;
7407+		*irix*)
7408+			{ echo "$as_me:$LINENO: result: Using IRIX ACLs" >&5
7409+echo "${ECHO_T}Using IRIX ACLs" >&6; }
7410+
7411+cat >>confdefs.h <<\_ACEOF
7412+#define HAVE_IRIX_ACLS 1
7413+_ACEOF
7414+
7415+			;;
7416+		*aix*)
7417+			{ echo "$as_me:$LINENO: result: Using AIX ACLs" >&5
7418+echo "${ECHO_T}Using AIX ACLs" >&6; }
7419+
7420+cat >>confdefs.h <<\_ACEOF
7421+#define HAVE_AIX_ACLS 1
7422+_ACEOF
7423+
7424+			;;
7425+		*osf*)
7426+			{ echo "$as_me:$LINENO: result: Using Tru64 ACLs" >&5
7427+echo "${ECHO_T}Using Tru64 ACLs" >&6; }
7428+
7429+cat >>confdefs.h <<\_ACEOF
7430+#define HAVE_TRU64_ACLS 1
7431+_ACEOF
7432+
7433+			LIBS="$LIBS -lpacl"
7434+			;;
7435+		*)
7436+		    { echo "$as_me:$LINENO: result: ACLs requested -- running tests" >&5
7437+echo "${ECHO_T}ACLs requested -- running tests" >&6; }
7438+
7439+{ echo "$as_me:$LINENO: checking for acl_get_file in -lacl" >&5
7440+echo $ECHO_N "checking for acl_get_file in -lacl... $ECHO_C" >&6; }
7441+if test "${ac_cv_lib_acl_acl_get_file+set}" = set; then
7442+  echo $ECHO_N "(cached) $ECHO_C" >&6
7443+else
7444+  ac_check_lib_save_LIBS=$LIBS
7445+LIBS="-lacl  $LIBS"
7446+cat >conftest.$ac_ext <<_ACEOF
7447+/* confdefs.h.  */
7448+_ACEOF
7449+cat confdefs.h >>conftest.$ac_ext
7450+cat >>conftest.$ac_ext <<_ACEOF
7451+/* end confdefs.h.  */
7452+
7453+/* Override any GCC internal prototype to avoid an error.
7454+   Use char because int might match the return type of a GCC
7455+   builtin and then its argument prototype would still apply.  */
7456+#ifdef __cplusplus
7457+extern "C"
7458+#endif
7459+char acl_get_file ();
7460+int
7461+main ()
7462+{
7463+return acl_get_file ();
7464+  ;
7465+  return 0;
7466+}
7467+_ACEOF
7468+rm -f conftest.$ac_objext conftest$ac_exeext
7469+if { (ac_try="$ac_link"
7470+case "(($ac_try" in
7471+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7472+  *) ac_try_echo=$ac_try;;
7473+esac
7474+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7475+  (eval "$ac_link") 2>conftest.er1
7476+  ac_status=$?
7477+  grep -v '^ *+' conftest.er1 >conftest.err
7478+  rm -f conftest.er1
7479+  cat conftest.err >&5
7480+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7481+  (exit $ac_status); } &&
7482+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
7483+  { (case "(($ac_try" in
7484+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7485+  *) ac_try_echo=$ac_try;;
7486+esac
7487+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7488+  (eval "$ac_try") 2>&5
7489+  ac_status=$?
7490+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7491+  (exit $ac_status); }; } &&
7492+	 { ac_try='test -s conftest$ac_exeext'
7493+  { (case "(($ac_try" in
7494+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7495+  *) ac_try_echo=$ac_try;;
7496+esac
7497+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7498+  (eval "$ac_try") 2>&5
7499+  ac_status=$?
7500+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7501+  (exit $ac_status); }; }; then
7502+  ac_cv_lib_acl_acl_get_file=yes
7503+else
7504+  echo "$as_me: failed program was:" >&5
7505+sed 's/^/| /' conftest.$ac_ext >&5
7506+
7507+	ac_cv_lib_acl_acl_get_file=no
7508+fi
7509+
7510+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
7511+      conftest$ac_exeext conftest.$ac_ext
7512+LIBS=$ac_check_lib_save_LIBS
7513+fi
7514+{ echo "$as_me:$LINENO: result: $ac_cv_lib_acl_acl_get_file" >&5
7515+echo "${ECHO_T}$ac_cv_lib_acl_acl_get_file" >&6; }
7516+if test $ac_cv_lib_acl_acl_get_file = yes; then
7517+  cat >>confdefs.h <<_ACEOF
7518+#define HAVE_LIBACL 1
7519+_ACEOF
7520+
7521+  LIBS="-lacl $LIBS"
7522+
7523+fi
7524+
7525+			{ echo "$as_me:$LINENO: checking for ACL support" >&5
7526+echo $ECHO_N "checking for ACL support... $ECHO_C" >&6; }
7527+if test "${samba_cv_HAVE_POSIX_ACLS+set}" = set; then
7528+  echo $ECHO_N "(cached) $ECHO_C" >&6
7529+else
7530+
7531+			cat >conftest.$ac_ext <<_ACEOF
7532+/* confdefs.h.  */
7533+_ACEOF
7534+cat confdefs.h >>conftest.$ac_ext
7535+cat >>conftest.$ac_ext <<_ACEOF
7536+/* end confdefs.h.  */
7537+#include <sys/types.h>
7538+#include <sys/acl.h>
7539+int
7540+main ()
7541+{
7542+ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);
7543+  ;
7544+  return 0;
7545+}
7546+_ACEOF
7547+rm -f conftest.$ac_objext conftest$ac_exeext
7548+if { (ac_try="$ac_link"
7549+case "(($ac_try" in
7550+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7551+  *) ac_try_echo=$ac_try;;
7552+esac
7553+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7554+  (eval "$ac_link") 2>conftest.er1
7555+  ac_status=$?
7556+  grep -v '^ *+' conftest.er1 >conftest.err
7557+  rm -f conftest.er1
7558+  cat conftest.err >&5
7559+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7560+  (exit $ac_status); } &&
7561+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
7562+  { (case "(($ac_try" in
7563+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7564+  *) ac_try_echo=$ac_try;;
7565+esac
7566+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7567+  (eval "$ac_try") 2>&5
7568+  ac_status=$?
7569+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7570+  (exit $ac_status); }; } &&
7571+	 { ac_try='test -s conftest$ac_exeext'
7572+  { (case "(($ac_try" in
7573+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7574+  *) ac_try_echo=$ac_try;;
7575+esac
7576+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7577+  (eval "$ac_try") 2>&5
7578+  ac_status=$?
7579+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7580+  (exit $ac_status); }; }; then
7581+  samba_cv_HAVE_POSIX_ACLS=yes
7582+else
7583+  echo "$as_me: failed program was:" >&5
7584+sed 's/^/| /' conftest.$ac_ext >&5
7585+
7586+	samba_cv_HAVE_POSIX_ACLS=no
7587+fi
7588+
7589+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
7590+      conftest$ac_exeext conftest.$ac_ext
7591+fi
7592+{ echo "$as_me:$LINENO: result: $samba_cv_HAVE_POSIX_ACLS" >&5
7593+echo "${ECHO_T}$samba_cv_HAVE_POSIX_ACLS" >&6; }
7594+			{ echo "$as_me:$LINENO: checking ACL test results" >&5
7595+echo $ECHO_N "checking ACL test results... $ECHO_C" >&6; }
7596+			if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
7597+			    { echo "$as_me:$LINENO: result: Using posix ACLs" >&5
7598+echo "${ECHO_T}Using posix ACLs" >&6; }
7599+
7600+cat >>confdefs.h <<\_ACEOF
7601+#define HAVE_POSIX_ACLS 1
7602+_ACEOF
7603+
7604+			    { echo "$as_me:$LINENO: checking for acl_get_perm_np" >&5
7605+echo $ECHO_N "checking for acl_get_perm_np... $ECHO_C" >&6; }
7606+if test "${samba_cv_HAVE_ACL_GET_PERM_NP+set}" = set; then
7607+  echo $ECHO_N "(cached) $ECHO_C" >&6
7608+else
7609+
7610+				cat >conftest.$ac_ext <<_ACEOF
7611+/* confdefs.h.  */
7612+_ACEOF
7613+cat confdefs.h >>conftest.$ac_ext
7614+cat >>conftest.$ac_ext <<_ACEOF
7615+/* end confdefs.h.  */
7616+#include <sys/types.h>
7617+#include <sys/acl.h>
7618+int
7619+main ()
7620+{
7621+ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);
7622+  ;
7623+  return 0;
7624+}
7625+_ACEOF
7626+rm -f conftest.$ac_objext conftest$ac_exeext
7627+if { (ac_try="$ac_link"
7628+case "(($ac_try" in
7629+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7630+  *) ac_try_echo=$ac_try;;
7631+esac
7632+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7633+  (eval "$ac_link") 2>conftest.er1
7634+  ac_status=$?
7635+  grep -v '^ *+' conftest.er1 >conftest.err
7636+  rm -f conftest.er1
7637+  cat conftest.err >&5
7638+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7639+  (exit $ac_status); } &&
7640+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
7641+  { (case "(($ac_try" in
7642+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7643+  *) ac_try_echo=$ac_try;;
7644+esac
7645+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7646+  (eval "$ac_try") 2>&5
7647+  ac_status=$?
7648+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7649+  (exit $ac_status); }; } &&
7650+	 { ac_try='test -s conftest$ac_exeext'
7651+  { (case "(($ac_try" in
7652+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
7653+  *) ac_try_echo=$ac_try;;
7654+esac
7655+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
7656+  (eval "$ac_try") 2>&5
7657+  ac_status=$?
7658+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
7659+  (exit $ac_status); }; }; then
7660+  samba_cv_HAVE_ACL_GET_PERM_NP=yes
7661+else
7662+  echo "$as_me: failed program was:" >&5
7663+sed 's/^/| /' conftest.$ac_ext >&5
7664+
7665+	samba_cv_HAVE_ACL_GET_PERM_NP=no
7666+fi
7667+
7668+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
7669+      conftest$ac_exeext conftest.$ac_ext
7670+fi
7671+{ echo "$as_me:$LINENO: result: $samba_cv_HAVE_ACL_GET_PERM_NP" >&5
7672+echo "${ECHO_T}$samba_cv_HAVE_ACL_GET_PERM_NP" >&6; }
7673+			    if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
7674+
7675+cat >>confdefs.h <<\_ACEOF
7676+#define HAVE_ACL_GET_PERM_NP 1
7677+_ACEOF
7678+
7679+			    fi
7680+			else
7681+			    { { echo "$as_me:$LINENO: error: Failed to find ACL support" >&5
7682+echo "$as_me: error: Failed to find ACL support" >&2;}
7683+   { (exit 1); exit 1; }; }
7684+			fi
7685+			;;
7686+		esac
7687+		;;
7688+  *)
7689+    { echo "$as_me:$LINENO: result: no" >&5
7690+echo "${ECHO_T}no" >&6; }
7691+
7692+cat >>confdefs.h <<\_ACEOF
7693+#define HAVE_NO_ACLS 1
7694+_ACEOF
7695+
7696+    ;;
7697+  esac
7698+else
7699+
7700+cat >>confdefs.h <<\_ACEOF
7701+#define HAVE_NO_ACLS 1
7702+_ACEOF
7703+
7704+  { echo "$as_me:$LINENO: result: no" >&5
7705+echo "${ECHO_T}no" >&6; }
7706+
7707+fi
7708+
7709+
7710 ac_config_files="$ac_config_files Makefile lib/dummy zlib/dummy popt/dummy shconfig"
7711 
7712 cat >confcache <<\_ACEOF
7713--- old/config.h.in
7714+++ new/config.h.in
7715@@ -27,6 +27,18 @@
7716 /* Define to 1 if the `getpgrp' function requires zero arguments. */
7717 #undef GETPGRP_VOID
7718 
7719+/* Define to 1 if you have the `aclsort' function. */
7720+#undef HAVE_ACLSORT
7721+
7722+/* true if you have acl_get_perm_np */
7723+#undef HAVE_ACL_GET_PERM_NP
7724+
7725+/* Define to 1 if you have the <acl/libacl.h> header file. */
7726+#undef HAVE_ACL_LIBACL_H
7727+
7728+/* true if you have AIX ACLs */
7729+#undef HAVE_AIX_ACLS
7730+
7731 /* Define to 1 if you have `alloca', as a function or macro. */
7732 #undef HAVE_ALLOCA
7733 
7734@@ -119,6 +131,9 @@
7735 /* Define to 1 if you have the <grp.h> header file. */
7736 #undef HAVE_GRP_H
7737 
7738+/* true if you have HPUX ACLs */
7739+#undef HAVE_HPUX_ACLS
7740+
7741 /* Define to 1 if you have the <iconv.h> header file. */
7742 #undef HAVE_ICONV_H
7743 
7744@@ -134,6 +149,9 @@
7745 /* Define to 1 if you have the <inttypes.h> header file. */
7746 #undef HAVE_INTTYPES_H
7747 
7748+/* true if you have IRIX ACLs */
7749+#undef HAVE_IRIX_ACLS
7750+
7751 /* Define to 1 if you have the <langinfo.h> header file. */
7752 #undef HAVE_LANGINFO_H
7753 
7754@@ -143,6 +161,9 @@
7755 /* Define to 1 if you have the `lchown' function. */
7756 #undef HAVE_LCHOWN
7757 
7758+/* Define to 1 if you have the `acl' library (-lacl). */
7759+#undef HAVE_LIBACL
7760+
7761 /* Define to 1 if you have the <libcharset.h> header file. */
7762 #undef HAVE_LIBCHARSET_H
7763 
7764@@ -161,6 +182,9 @@
7765 /* Define to 1 if you have the `resolv' library (-lresolv). */
7766 #undef HAVE_LIBRESOLV
7767 
7768+/* Define to 1 if you have the `sec' library (-lsec). */
7769+#undef HAVE_LIBSEC
7770+
7771 /* Define to 1 if you have the `socket' library (-lsocket). */
7772 #undef HAVE_LIBSOCKET
7773 
7774@@ -226,9 +250,15 @@
7775 /* Define to 1 if you have the `nl_langinfo' function. */
7776 #undef HAVE_NL_LANGINFO
7777 
7778+/* true if you don't have ACLs */
7779+#undef HAVE_NO_ACLS
7780+
7781 /* Define to 1 if you have the `open64' function. */
7782 #undef HAVE_OPEN64
7783 
7784+/* true if you have posix ACLs */
7785+#undef HAVE_POSIX_ACLS
7786+
7787 /* Define to 1 if you have the `putenv' function. */
7788 #undef HAVE_PUTENV
7789 
7790@@ -280,6 +310,9 @@
7791 /* Define to 1 if you have the "socketpair" function */
7792 #undef HAVE_SOCKETPAIR
7793 
7794+/* true if you have solaris ACLs */
7795+#undef HAVE_SOLARIS_ACLS
7796+
7797 /* Define to 1 if you have the <stdint.h> header file. */
7798 #undef HAVE_STDINT_H
7799 
7800@@ -325,6 +358,9 @@
7801 /* Define to 1 if `st_rdev' is member of `struct stat'. */
7802 #undef HAVE_STRUCT_STAT_ST_RDEV
7803 
7804+/* Define to 1 if you have the <sys/acl.h> header file. */
7805+#undef HAVE_SYS_ACL_H
7806+
7807 /* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
7808    */
7809 #undef HAVE_SYS_DIR_H
7810@@ -375,9 +411,15 @@
7811 /* Define to 1 if you have the `tcgetpgrp' function. */
7812 #undef HAVE_TCGETPGRP
7813 
7814+/* true if you have Tru64 ACLs */
7815+#undef HAVE_TRU64_ACLS
7816+
7817 /* Define to 1 if you have the <unistd.h> header file. */
7818 #undef HAVE_UNISTD_H
7819 
7820+/* true if you have UnixWare ACLs */
7821+#undef HAVE_UNIXWARE_ACLS
7822+
7823 /* Define to 1 if you have the "struct utimbuf" type */
7824 #undef HAVE_UTIMBUF
7825 
7826@@ -408,6 +450,18 @@
7827 /* Define to 1 if you have the `waitpid' function. */
7828 #undef HAVE_WAITPID
7829 
7830+/* Define to 1 if you have the `_acl' function. */
7831+#undef HAVE__ACL
7832+
7833+/* Define to 1 if you have the `_facl' function. */
7834+#undef HAVE__FACL
7835+
7836+/* Define to 1 if you have the `__acl' function. */
7837+#undef HAVE___ACL
7838+
7839+/* Define to 1 if you have the `__facl' function. */
7840+#undef HAVE___FACL
7841+
7842 /* Define to 1 if you have the `__va_copy' function. */
7843 #undef HAVE___VA_COPY
7844 
7845--- old/rsync.1
7846+++ new/rsync.1
7847@@ -367,7 +367,7 @@ to the detailed description below for a 
7848  \-q, \-\-quiet                 suppress non-error messages
7849      \-\-no\-motd               suppress daemon-mode MOTD (see caveat)
7850  \-c, \-\-checksum              skip based on checksum, not mod-time & size
7851- \-a, \-\-archive               archive mode; same as \-rlptgoD (no \-H)
7852+ \-a, \-\-archive               archive mode; same as \-rlptgoD (no \-H, \-A)
7853      \-\-no\-OPTION             turn off an implied OPTION (e\&.g\&. \-\-no\-D)
7854  \-r, \-\-recursive             recurse into directories
7855  \-R, \-\-relative              use relative path names
7856@@ -389,6 +389,7 @@ to the detailed description below for a 
7857  \-p, \-\-perms                 preserve permissions
7858  \-E, \-\-executability         preserve executability
7859      \-\-chmod=CHMOD           affect file and/or directory permissions
7860+ \-A, \-\-acls                  preserve ACLs (implies \-p) [non-standard]
7861  \-o, \-\-owner                 preserve owner (super-user only)
7862  \-g, \-\-group                 preserve group
7863      \-\-devices               preserve device files (super-user only)
7864@@ -870,7 +871,9 @@ permissions, though the \fB\-\-executabi
7865 the execute permission for the file\&.
7866 .IP o 
7867 New files get their "normal" permission bits set to the source
7868-file\&'s permissions masked with the receiving end\&'s umask setting, and
7869+file\&'s permissions masked with the receiving directory\&'s default
7870+permissions (either the receiving process\&'s umask, or the permissions
7871+specified via the destination directory\&'s default ACL), and
7872 their special permission bits disabled except in the case where a new
7873 directory inherits a setgid bit from its parent directory\&.
7874 .RE
7875@@ -908,9 +911,11 @@ The preservation of the destination\&'s 
7876 directories when \fB\-\-perms\fP is off was added in rsync 2\&.6\&.7\&.  Older rsync
7877 versions erroneously preserved the three special permission bits for
7878 newly-created files when \fB\-\-perms\fP was off, while overriding the
7879-destination\&'s setgid bit setting on a newly-created directory\&.  (Keep in
7880-mind that it is the version of the receiving rsync that affects this
7881-behavior\&.)
7882+destination\&'s setgid bit setting on a newly-created directory\&.  Default ACL
7883+observance was added to the ACL patch for rsync 2\&.6\&.7, so older (or
7884+non-ACL-enabled) rsyncs use the umask even if default ACLs are present\&.
7885+(Keep in mind that it is the version of the receiving rsync that affects
7886+these behaviors\&.)
7887 .IP 
7888 .IP "\fB\-E, \-\-executability\fP"
7889 This option causes rsync to preserve the
7890@@ -932,6 +937,16 @@ has a corresponding \&'r\&' permission e
7891 .IP 
7892 If \fB\-\-perms\fP is enabled, this option is ignored\&.
7893 .IP 
7894+.IP "\fB\-A, \-\-acls\fP"
7895+This option causes rsync to update the destination
7896+ACLs to be the same as the source ACLs\&.  This nonstandard option only
7897+works if the remote rsync also supports it\&.  \fB\-\-acls\fP implies \fB\-\-perms\fP\&.
7898+.IP 
7899+Note also that an optimization of the ACL-sending protocol used by this
7900+version makes it incompatible with sending files to an older ACL-enabled
7901+rsync unless you double the \fB\-\-acls\fP option (e\&.g\&. \fB\-AA\fP)\&.  This
7902+doubling is not needed when pulling files from an older rsync\&.
7903+.IP 
7904 .IP "\fB\-\-chmod\fP"
7905 This option tells rsync to apply one or more
7906 comma-separated "chmod" strings to the permission of the files in the
7907@@ -1605,8 +1620,8 @@ if the receiving rsync is at least versi
7908 with older versions of rsync, but that also turns on the output of other
7909 verbose messages)\&.
7910 .IP 
7911-The "%i" escape has a cryptic output that is 9 letters long\&.  The general
7912-format is like the string \fBYXcstpogz\fP, where \fBY\fP is replaced by the
7913+The "%i" escape has a cryptic output that is 11 letters long\&.  The general
7914+format is like the string \fBYXcstpoguax\fP, where \fBY\fP is replaced by the
7915 type of update being done, \fBX\fP is replaced by the file-type, and the
7916 other letters represent attributes that may be output if they are being
7917 modified\&.
7918@@ -1668,7 +1683,13 @@ sender\&'s value (requires \fB\-\-owner\
7919 A \fBg\fP means the group is different and is being updated to the
7920 sender\&'s value (requires \fB\-\-group\fP and the authority to set the group)\&.
7921 .IP o 
7922-The \fBz\fP slot is reserved for future use\&.
7923+The \fBu\fP slot is reserved for reporting update (access) time changes
7924+(a feature that is not yet released)\&.
7925+.IP o 
7926+The \fBa\fP means that the ACL information changed\&.
7927+.IP o 
7928+The \fBx\fP slot is reserved for reporting extended attribute changes
7929+(a feature that is not yet released)\&.
7930 .RE
7931 
7932 .IP 
7933