++AC_CHECK_HEADERS(sys/acl.h)
++AC_CHECK_FUNCS(_acl __acl _facl __facl)
++#################################################
++# check for ACL support
++
++AC_MSG_CHECKING(whether to support ACLs)
++AC_ARG_ENABLE(acl-support,
++AC_HELP_STRING([--enable-acl-support], [Include ACL support (default=no)]),
++[ case "$enableval" in
++ yes)
++
++ case "$host_os" in
++ *sysv5*)
++ AC_MSG_RESULT(Using UnixWare ACLs)
++ AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
++ ;;
++ *solaris*|*cygwin*)
++ AC_MSG_RESULT(Using solaris ACLs)
++ AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
++ ;;
++ *hpux*)
++ AC_MSG_RESULT(Using HPUX ACLs)
++ AC_DEFINE(HAVE_HPUX_ACLS, 1, [true if you have HPUX ACLs])
++ ;;
++ *irix*)
++ AC_MSG_RESULT(Using IRIX ACLs)
++ AC_DEFINE(HAVE_IRIX_ACLS, 1, [true if you have IRIX ACLs])
++ ;;
++ *aix*)
++ AC_MSG_RESULT(Using AIX ACLs)
++ AC_DEFINE(HAVE_AIX_ACLS, 1, [true if you have AIX ACLs])
++ ;;
++ *osf*)
++ AC_MSG_RESULT(Using Tru64 ACLs)
++ AC_DEFINE(HAVE_TRU64_ACLS, 1, [true if you have Tru64 ACLs])
++ LIBS="$LIBS -lpacl"
++ ;;
++ *)
++ AC_MSG_RESULT(ACLs requested -- running tests)
++ AC_CHECK_LIB(acl,acl_get_file)
++ AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
++ AC_TRY_LINK([#include <sys/types.h>
++#include <sys/acl.h>],
++[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
++samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
++ AC_MSG_CHECKING(ACL test results)
++ if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
++ AC_MSG_RESULT(Using posix ACLs)
++ AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
++ AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
++ AC_TRY_LINK([#include <sys/types.h>
++#include <sys/acl.h>],
++[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
++samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
++ if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
++ AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
++ fi
++ else
++ AC_MSG_ERROR(Failed to find ACL support)
++ fi
++ ;;
++ esac
++ ;;
++ *)
++ AC_MSG_RESULT(no)
++ AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs])
++ ;;
++ esac ],
++ AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs])
++ AC_MSG_RESULT(no)
++)
++
+ AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
+ AC_OUTPUT
+
+--- old/flist.c
++++ new/flist.c
+@@ -40,6 +40,7 @@ extern int filesfrom_fd;
+ extern int one_file_system;
+ extern int copy_dirlinks;
+ extern int keep_dirlinks;
++extern int preserve_acls;
+ extern int preserve_links;
+ extern int preserve_hard_links;
+ extern int preserve_devices;
+@@ -133,6 +134,8 @@ static void list_file_entry(struct file_
+
+ permstring(permbuf, f->mode);
+
++ /* TODO: indicate '+' if the entry has an ACL. */
++
+ #ifdef SUPPORT_LINKS
+ if (preserve_links && S_ISLNK(f->mode)) {
+ rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
+@@ -491,6 +494,9 @@ static struct file_struct *receive_file_
+ char thisname[MAXPATHLEN];
+ unsigned int l1 = 0, l2 = 0;
+ int alloc_len, basename_len, dirname_len, linkname_len, sum_len;
++#ifdef SUPPORT_ACLS
++ int xtra_len;
++#endif
+ OFF_T file_length;
+ char *basename, *dirname, *bp;
+ struct file_struct *file;
+@@ -594,13 +600,27 @@ static struct file_struct *receive_file_
+
+ sum_len = always_checksum && S_ISREG(mode) ? MD4_SUM_LENGTH : 0;
+
++#ifdef SUPPORT_ACLS
++ /* We need one or two index int32s when we're preserving ACLs. */
++ if (preserve_acls)
++ xtra_len = (S_ISDIR(mode) ? 2 : 1) * 4;
++ else
++ xtra_len = 0;
++#endif
++
+ alloc_len = file_struct_len + dirname_len + basename_len
++#ifdef SUPPORT_ACLS
++ + xtra_len
++#endif
+ + linkname_len + sum_len;
+ bp = pool_alloc(flist->file_pool, alloc_len, "receive_file_entry");
+
+ file = (struct file_struct *)bp;
+ memset(bp, 0, file_struct_len);
+ bp += file_struct_len;
++#ifdef SUPPORT_ACLS
++ bp += xtra_len;
++#endif
+
+ file->modtime = modtime;
+ file->length = file_length;
+@@ -693,6 +713,11 @@ static struct file_struct *receive_file_
+ read_buf(f, sum, checksum_len);
+ }
+
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ receive_acl(file, f);
++#endif
++
+ return file;
+ }
+
+@@ -942,6 +967,9 @@ static struct file_struct *send_file_nam
+ unsigned short flags)
+ {
+ struct file_struct *file;
++#ifdef SUPPORT_ACLS
++ statx sx;
++#endif
+
+ file = make_file(fname, flist, stp, flags,
+ f == -2 ? SERVER_FILTERS : ALL_FILTERS);
+@@ -951,6 +979,15 @@ static struct file_struct *send_file_nam
+ if (chmod_modes && !S_ISLNK(file->mode))
+ file->mode = tweak_mode(file->mode, chmod_modes);
+
++#ifdef SUPPORT_ACLS
++ if (preserve_acls) {
++ sx.st.st_mode = file->mode;
++ sx.acc_acl = sx.def_acl = NULL;
++ if (get_acl(fname, &sx) < 0)
++ return NULL;
++ }
++#endif
++
+ maybe_emit_filelist_progress(flist->count + flist_count_offset);
+
+ flist_expand(flist);
+@@ -958,6 +995,15 @@ static struct file_struct *send_file_nam
+ if (file->basename[0]) {
+ flist->files[flist->count++] = file;
+ send_file_entry(file, f);
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ send_acl(&sx, f);
++#endif
++ } else {
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ free_acl(&sx);
++#endif
+ }
+ return file;
+ }
+--- old/generator.c
++++ new/generator.c
+@@ -36,6 +36,7 @@ extern int recurse;
+ extern int relative_paths;
+ extern int implied_dirs;
+ extern int keep_dirlinks;
++extern int preserve_acls;
+ extern int preserve_links;
+ extern int preserve_devices;
+ extern int preserve_specials;
+@@ -85,6 +86,7 @@ extern long block_size; /* "long" becaus
+ extern int max_delete;
+ extern int force_delete;
+ extern int one_file_system;
++extern mode_t orig_umask;
+ extern struct stats stats;
+ extern dev_t filesystem_dev;
+ extern char *backup_dir;
+@@ -317,22 +319,27 @@ static void do_delete_pass(struct file_l
+ rprintf(FINFO, " \r");
+ }
+
+-int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st)
++int unchanged_attrs(struct file_struct *file, statx *sxp)
+ {
+ if (preserve_perms
+- && (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
++ && (sxp->st.st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
+ return 0;
+
+- if (am_root && preserve_uid && st->st_uid != file->uid)
++ if (am_root && preserve_uid && sxp->st.st_uid != file->uid)
+ return 0;
+
+- if (preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid)
++ if (preserve_gid && file->gid != GID_NONE && sxp->st.st_gid != file->gid)
+ return 0;
+
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && set_acl(NULL, file, sxp) == 0)
++ return 0;
++#endif
++
+ return 1;
+ }
+
+-void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st,
++void itemize(struct file_struct *file, int ndx, int statret, statx *sxp,
+ int32 iflags, uchar fnamecmp_type, char *xname)
+ {
+ if (statret >= 0) { /* A from-dest-dir statret can == 1! */
+@@ -340,19 +347,23 @@ void itemize(struct file_struct *file, i
+ : S_ISDIR(file->mode) ? !omit_dir_times
+ : !S_ISLNK(file->mode);
+
+- if (S_ISREG(file->mode) && file->length != st->st_size)
++ if (S_ISREG(file->mode) && file->length != sxp->st.st_size)
+ iflags |= ITEM_REPORT_SIZE;
+ if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
+ && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
+- || (keep_time && cmp_time(file->modtime, st->st_mtime) != 0))
++ || (keep_time && cmp_time(file->modtime, sxp->st.st_mtime) != 0))
+ iflags |= ITEM_REPORT_TIME;
+- if ((file->mode & CHMOD_BITS) != (st->st_mode & CHMOD_BITS))
++ if ((file->mode & CHMOD_BITS) != (sxp->st.st_mode & CHMOD_BITS))
+ iflags |= ITEM_REPORT_PERMS;
+- if (preserve_uid && am_root && file->uid != st->st_uid)
++ if (preserve_uid && am_root && file->uid != sxp->st.st_uid)
+ iflags |= ITEM_REPORT_OWNER;
+ if (preserve_gid && file->gid != GID_NONE
+- && st->st_gid != file->gid)
++ && sxp->st.st_gid != file->gid)
+ iflags |= ITEM_REPORT_GROUP;
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && set_acl(NULL, file, sxp) == 0)
++ iflags |= ITEM_REPORT_ACL;
++#endif
+ } else
+ iflags |= ITEM_IS_NEW;
+
+@@ -603,7 +614,7 @@ void check_for_finished_hlinks(int itemi
+ * handling the file, -1 if no dest-linking occurred, or a non-negative
+ * value if we found an alternate basis file. */
+ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
+- char *cmpbuf, STRUCT_STAT *stp, int itemizing,
++ char *cmpbuf, statx *sxp, int itemizing,
+ int maybe_ATTRS_REPORT, enum logcode code)
+ {
+ int save_ignore_times = ignore_times;
+@@ -617,7 +628,7 @@ static int try_dests_reg(struct file_str
+
+ do {
+ pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
+- if (link_stat(cmpbuf, stp, 0) < 0 || !S_ISREG(stp->st_mode))
++ if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode))
+ continue;
+ switch (match_level) {
+ case 0:
+@@ -625,16 +636,20 @@ static int try_dests_reg(struct file_str
+ match_level = 1;
+ /* FALL THROUGH */
+ case 1:
+- if (!unchanged_file(cmpbuf, file, stp))
++ if (!unchanged_file(cmpbuf, file, &sxp->st))
+ continue;
+ best_match = j;
+ match_level = 2;
+ /* FALL THROUGH */
+ case 2:
+- if (!unchanged_attrs(file, stp))
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ get_acl(cmpbuf, sxp);
++#endif
++ if (!unchanged_attrs(file, sxp))
+ continue;
+ if (always_checksum && preserve_times
+- && cmp_time(stp->st_mtime, file->modtime))
++ && cmp_time(sxp->st.st_mtime, file->modtime))
+ continue;
+ best_match = j;
+ match_level = 3;
+@@ -651,14 +666,14 @@ static int try_dests_reg(struct file_str
+ if (j != best_match) {
+ j = best_match;
+ pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
+- if (link_stat(cmpbuf, stp, 0) < 0)
++ if (link_stat(cmpbuf, &sxp->st, 0) < 0)
+ match_level = 0;
+ }
+
+ if (match_level == 3 && !copy_dest) {
+ #ifdef SUPPORT_HARD_LINKS
+ if (link_dest) {
+- if (hard_link_one(file, ndx, fname, 0, stp,
++ if (hard_link_one(file, ndx, fname, 0, sxp,
+ cmpbuf, 1,
+ itemizing && verbose > 1,
+ code) < 0)
+@@ -667,8 +682,13 @@ static int try_dests_reg(struct file_str
+ hard_link_cluster(file, ndx, itemizing, code);
+ } else
+ #endif
+- if (itemizing)
+- itemize(file, ndx, 0, stp, 0, 0, NULL);
++ if (itemizing) {
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && !ACL_READY(*sxp))
++ get_acl(fname, sxp);
++#endif
++ itemize(file, ndx, 0, sxp, 0, 0, NULL);
++ }
+ if (verbose > 1 && maybe_ATTRS_REPORT) {
+ code = logfile_format_has_i || dry_run
+ ? FCLIENT : FINFO;
+@@ -686,8 +706,13 @@ static int try_dests_reg(struct file_str
+ }
+ return -1;
+ }
+- if (itemizing)
+- itemize(file, ndx, 0, stp, ITEM_LOCAL_CHANGE, 0, NULL);
++ if (itemizing) {
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && !ACL_READY(*sxp))
++ get_acl(fname, sxp);
++#endif
++ itemize(file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
++ }
+ set_file_attrs(fname, file, NULL, 0);
+ if (maybe_ATTRS_REPORT
+ && ((!itemizing && verbose && match_level == 2)
+@@ -712,13 +737,18 @@ static int try_dests_non(struct file_str
+ enum logcode code)
+ {
+ char fnamebuf[MAXPATHLEN];
+- STRUCT_STAT st;
++ statx sx;
+ int i = 0;
+
+ do {
+ pathjoin(fnamebuf, MAXPATHLEN, basis_dir[i], fname);
+- if (link_stat(fnamebuf, &st, 0) < 0 || S_ISDIR(st.st_mode)
+- || !unchanged_attrs(file, &st))
++ if (link_stat(fnamebuf, &sx.st, 0) < 0 || S_ISDIR(sx.st.st_mode))
++ continue;
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ get_acl(fnamebuf, &sx);
++#endif
++ if (!unchanged_attrs(file, &sx))
+ continue;
+ if (S_ISLNK(file->mode)) {
+ #ifdef SUPPORT_LINKS
+@@ -731,10 +761,10 @@ static int try_dests_non(struct file_str
+ #endif
+ continue;
+ } else if (IS_SPECIAL(file->mode)) {
+- if (!IS_SPECIAL(st.st_mode) || st.st_rdev != file->u.rdev)
++ if (!IS_SPECIAL(sx.st.st_mode) || sx.st.st_rdev != file->u.rdev)
+ continue;
+ } else if (IS_DEVICE(file->mode)) {
+- if (!IS_DEVICE(st.st_mode) || st.st_rdev != file->u.rdev)
++ if (!IS_DEVICE(sx.st.st_mode) || sx.st.st_rdev != file->u.rdev)
+ continue;
+ } else {
+ rprintf(FERROR,
+@@ -765,7 +795,15 @@ static int try_dests_non(struct file_str
+ int changes = compare_dest ? 0 : ITEM_LOCAL_CHANGE
+ + (link_dest ? ITEM_XNAME_FOLLOWS : 0);
+ char *lp = link_dest ? "" : NULL;
+- itemize(file, ndx, 0, &st, changes, 0, lp);
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ get_acl(fname, &sx);
++#endif
++ itemize(file, ndx, 0, &sx, changes, 0, lp);
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ free_acl(&sx);
++#endif
+ }
+ if (verbose > 1 && maybe_ATTRS_REPORT) {
+ code = logfile_format_has_i || dry_run
+@@ -779,6 +817,7 @@ static int try_dests_non(struct file_str
+ }
+
+ static int phase = 0;
++static int dflt_perms;
+
+ /* Acts on the_file_list->file's ndx'th item, whose name is fname. If a dir,
+ * make sure it exists, and has the right permissions/timestamp info. For
+@@ -800,7 +839,8 @@ static void recv_generator(char *fname,
+ static int need_fuzzy_dirlist = 0;
+ struct file_struct *fuzzy_file = NULL;
+ int fd = -1, f_copy = -1;
+- STRUCT_STAT st, real_st, partial_st;
++ statx sx, real_sx;
++ STRUCT_STAT partial_st;
+ struct file_struct *back_file = NULL;
+ int statret, real_ret, stat_errno;
+ char *fnamecmp, *partialptr, *backupptr = NULL;
+@@ -851,6 +891,9 @@ static void recv_generator(char *fname,
+ dry_run--;
+ missing_below = -1;
+ }
++#ifdef SUPPORT_ACLS
++ sx.acc_acl = sx.def_acl = NULL;
++#endif
+ if (dry_run > 1) {
+ statret = -1;
+ stat_errno = ENOENT;
+@@ -858,7 +901,7 @@ static void recv_generator(char *fname,
+ char *dn = file->dirname ? file->dirname : ".";
+ if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
+ if (relative_paths && !implied_dirs
+- && safe_stat(dn, &st) < 0
++ && safe_stat(dn, &sx.st) < 0
+ && create_directory_path(fname) < 0) {
+ rsyserr(FERROR, errno,
+ "recv_generator: mkdir %s failed",
+@@ -870,6 +913,10 @@ static void recv_generator(char *fname,
+ }
+ if (fuzzy_basis)
+ need_fuzzy_dirlist = 1;
++#ifdef SUPPORT_ACLS
++ if (!preserve_perms)
++ dflt_perms = default_perms_for_dir(dn);
++#endif
+ }
+ parent_dirname = dn;
+
+@@ -878,7 +925,7 @@ static void recv_generator(char *fname,
+ need_fuzzy_dirlist = 0;
+ }
+
+- statret = link_stat(fname, &st,
++ statret = link_stat(fname, &sx.st,
+ keep_dirlinks && S_ISDIR(file->mode));
+ stat_errno = errno;
+ }
+@@ -896,8 +943,9 @@ static void recv_generator(char *fname,
+ * mode based on the local permissions and some heuristics. */
+ if (!preserve_perms) {
+ int exists = statret == 0
+- && S_ISDIR(st.st_mode) == S_ISDIR(file->mode);
+- file->mode = dest_mode(file->mode, st.st_mode, exists);
++ && S_ISDIR(sx.st.st_mode) == S_ISDIR(file->mode);
++ file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms,
++ exists);
+ }
+
+ if (S_ISDIR(file->mode)) {
+@@ -906,8 +954,8 @@ static void recv_generator(char *fname,
+ * file of that name and it is *not* a directory, then
+ * we need to delete it. If it doesn't exist, then
+ * (perhaps recursively) create it. */
+- if (statret == 0 && !S_ISDIR(st.st_mode)) {
+- if (delete_item(fname, st.st_mode, del_opts) < 0)
++ if (statret == 0 && !S_ISDIR(sx.st.st_mode)) {
++ if (delete_item(fname, sx.st.st_mode, del_opts) < 0)
+ return;
+ statret = -1;
+ }
+@@ -916,7 +964,11 @@ static void recv_generator(char *fname,
+ dry_run++;
+ }
+ if (itemizing && f_out != -1) {
+- itemize(file, ndx, statret, &st,
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && statret == 0)
++ get_acl(fname, &sx);
++#endif
++ itemize(file, ndx, statret, &sx,
+ statret ? ITEM_LOCAL_CHANGE : 0, 0, NULL);
+ }
+ if (statret != 0 && do_mkdir(fname,file->mode) < 0 && errno != EEXIST) {
+@@ -928,19 +980,19 @@ static void recv_generator(char *fname,
+ full_fname(fname));
+ }
+ }
+- if (set_file_attrs(fname, file, statret ? NULL : &st, 0)
++ if (set_file_attrs(fname, file, statret ? NULL : &sx, 0)
+ && verbose && code && f_out != -1)
+ rprintf(code, "%s/\n", fname);
+ if (delete_during && f_out != -1 && !phase && dry_run < 2
+ && (file->flags & FLAG_DEL_HERE))
+- delete_in_dir(the_file_list, fname, file, &st);
+- return;
++ delete_in_dir(the_file_list, fname, file, &sx.st);
++ goto cleanup;
+ }
+
+ if (preserve_hard_links && file->link_u.links
+- && hard_link_check(file, ndx, fname, statret, &st,
++ && hard_link_check(file, ndx, fname, statret, &sx,
+ itemizing, code, HL_CHECK_MASTER))
+- return;
++ goto cleanup;
+
+ if (preserve_links && S_ISLNK(file->mode)) {
+ #ifdef SUPPORT_LINKS
+@@ -958,7 +1010,7 @@ static void recv_generator(char *fname,
+ char lnk[MAXPATHLEN];
+ int len;
+
+- if (!S_ISDIR(st.st_mode)
++ if (!S_ISDIR(sx.st.st_mode)
+ && (len = readlink(fname, lnk, MAXPATHLEN-1)) > 0) {
+ lnk[len] = 0;
+ /* A link already pointing to the
+@@ -966,10 +1018,10 @@ static void recv_generator(char *fname,
+ * required. */
+ if (strcmp(lnk, file->u.link) == 0) {
+ if (itemizing) {
+- itemize(file, ndx, 0, &st, 0,
++ itemize(file, ndx, 0, &sx, 0,
+ 0, NULL);
+ }
+- set_file_attrs(fname, file, &st,
++ set_file_attrs(fname, file, &sx,
+ maybe_ATTRS_REPORT);
+ if (preserve_hard_links
+ && file->link_u.links) {
+@@ -982,9 +1034,9 @@ static void recv_generator(char *fname,
+ }
+ /* Not the right symlink (or not a symlink), so
+ * delete it. */
+- if (delete_item(fname, st.st_mode, del_opts) < 0)
++ if (delete_item(fname, sx.st.st_mode, del_opts) < 0)
+ return;
+- if (!S_ISLNK(st.st_mode))
++ if (!S_ISLNK(sx.st.st_mode))
+ statret = -1;
+ } else if (basis_dir[0] != NULL) {
+ if (try_dests_non(file, fname, ndx, itemizing,
+@@ -1000,7 +1052,7 @@ static void recv_generator(char *fname,
+ }
+ }
+ if (preserve_hard_links && file->link_u.links
+- && hard_link_check(file, ndx, fname, -1, &st,
++ && hard_link_check(file, ndx, fname, -1, &sx,
+ itemizing, code, HL_SKIP))
+ return;
+ if (do_symlink(file->u.link,fname) != 0) {
+@@ -1009,7 +1061,7 @@ static void recv_generator(char *fname,
+ } else {
+ set_file_attrs(fname, file, NULL, 0);
+ if (itemizing) {
+- itemize(file, ndx, statret, &st,
++ itemize(file, ndx, statret, &sx,
+ ITEM_LOCAL_CHANGE, 0, NULL);
+ }
+ if (code && verbose) {
+@@ -1043,18 +1095,22 @@ static void recv_generator(char *fname,
+ itemizing = code = 0;
+ }
+ }
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && statret == 0)
++ get_acl(fname, &sx);
++#endif
+ if (statret != 0
+- || (st.st_mode & ~CHMOD_BITS) != (file->mode & ~CHMOD_BITS)
+- || st.st_rdev != file->u.rdev) {
++ || (sx.st.st_mode & ~CHMOD_BITS) != (file->mode & ~CHMOD_BITS)
++ || sx.st.st_rdev != file->u.rdev) {
+ if (statret == 0
+- && delete_item(fname, st.st_mode, del_opts) < 0)
+- return;
++ && delete_item(fname, sx.st.st_mode, del_opts) < 0)
++ goto cleanup;
+ if (preserve_hard_links && file->link_u.links
+- && hard_link_check(file, ndx, fname, -1, &st,
++ && hard_link_check(file, ndx, fname, -1, &sx,
+ itemizing, code, HL_SKIP))
+- return;
+- if ((IS_DEVICE(file->mode) && !IS_DEVICE(st.st_mode))
+- || (IS_SPECIAL(file->mode) && !IS_SPECIAL(st.st_mode)))
++ goto cleanup;
++ if ((IS_DEVICE(file->mode) && !IS_DEVICE(sx.st.st_mode))
++ || (IS_SPECIAL(file->mode) && !IS_SPECIAL(sx.st.st_mode)))
+ statret = -1;
+ if (verbose > 2) {
+ rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
+@@ -1067,7 +1123,7 @@ static void recv_generator(char *fname,
+ } else {
+ set_file_attrs(fname, file, NULL, 0);
+ if (itemizing) {
+- itemize(file, ndx, statret, &st,
++ itemize(file, ndx, statret, &sx,
+ ITEM_LOCAL_CHANGE, 0, NULL);
+ }
+ if (code && verbose)
+@@ -1079,12 +1135,12 @@ static void recv_generator(char *fname,
+ }
+ } else {
+ if (itemizing)
+- itemize(file, ndx, statret, &st, 0, 0, NULL);
+- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
++ itemize(file, ndx, statret, &sx, 0, 0, NULL);
++ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
+ if (preserve_hard_links && file->link_u.links)
+ hard_link_cluster(file, ndx, itemizing, code);
+ }
+- return;
++ goto cleanup;
+ }
+
+ if (!S_ISREG(file->mode)) {
+@@ -1118,7 +1174,7 @@ static void recv_generator(char *fname,
+ }
+
+ if (update_only && statret == 0
+- && cmp_time(st.st_mtime, file->modtime) > 0) {
++ && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
+ if (verbose > 1)
+ rprintf(FINFO, "%s is newer\n", fname);
+ return;
+@@ -1127,18 +1183,18 @@ static void recv_generator(char *fname,
+ fnamecmp = fname;
+ fnamecmp_type = FNAMECMP_FNAME;
+
+- if (statret == 0 && !S_ISREG(st.st_mode)) {
+- if (delete_item(fname, st.st_mode, del_opts) != 0)
++ if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
++ if (delete_item(fname, sx.st.st_mode, del_opts) != 0)
+ return;
+ statret = -1;
+ stat_errno = ENOENT;
+ }
+
+ if (statret != 0 && basis_dir[0] != NULL) {
+- int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &st,
++ int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx,
+ itemizing, maybe_ATTRS_REPORT, code);
+ if (j == -2)
+- return;
++ goto cleanup;
+ if (j != -1) {
+ fnamecmp = fnamecmpbuf;
+ fnamecmp_type = j;
+@@ -1147,7 +1203,7 @@ static void recv_generator(char *fname,
+ }
+
+ real_ret = statret;
+- real_st = st;
++ real_sx = sx;
+
+ if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL
+ && link_stat(partialptr, &partial_st, 0) == 0
+@@ -1166,7 +1222,7 @@ static void recv_generator(char *fname,
+ rprintf(FINFO, "fuzzy basis selected for %s: %s\n",
+ fname, fnamecmpbuf);
+ }
+- st.st_size = fuzzy_file->length;
++ sx.st.st_size = fuzzy_file->length;
+ statret = 0;
+ fnamecmp = fnamecmpbuf;
+ fnamecmp_type = FNAMECMP_FUZZY;
+@@ -1175,7 +1231,7 @@ static void recv_generator(char *fname,
+
+ if (statret != 0) {
+ if (preserve_hard_links && file->link_u.links
+- && hard_link_check(file, ndx, fname, statret, &st,
++ && hard_link_check(file, ndx, fname, statret, &sx,
+ itemizing, code, HL_SKIP))
+ return;
+ if (stat_errno == ENOENT)
+@@ -1185,31 +1241,44 @@ static void recv_generator(char *fname,
+ return;
+ }
+
+- if (append_mode && st.st_size > file->length)
++ if (append_mode && sx.st.st_size > file->length)
+ return;
+
+ if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
+ ;
+ else if (fnamecmp_type == FNAMECMP_FUZZY)
+ ;
+- else if (unchanged_file(fnamecmp, file, &st)) {
++ else if (unchanged_file(fnamecmp, file, &sx.st)) {
+ if (partialptr) {
+ do_unlink(partialptr);
+ handle_partial_dir(partialptr, PDIR_DELETE);
+ }
+ if (itemizing) {
+- itemize(file, ndx, real_ret, &real_st,
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && real_ret == 0)
++ get_acl(fname, &real_sx);
++#endif
++ itemize(file, ndx, real_ret, &real_sx,
+ 0, 0, NULL);
++#ifdef SUPPORT_ACLS
++ if (preserve_acls) {
++ if (fnamecmp_type == FNAMECMP_FNAME) {
++ sx.acc_acl = real_sx.acc_acl;
++ sx.def_acl = real_sx.def_acl;
++ } else
++ free_acl(&real_sx);
++ }
++#endif
+ }
+- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
++ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
+ if (preserve_hard_links && file->link_u.links)
+ hard_link_cluster(file, ndx, itemizing, code);
+- return;
++ goto cleanup;
+ }
+
+ prepare_to_open:
+ if (partialptr) {
+- st = partial_st;
++ sx.st = partial_st;
+ fnamecmp = partialptr;
+ fnamecmp_type = FNAMECMP_PARTIAL_DIR;
+ statret = 0;
+@@ -1233,17 +1302,21 @@ static void recv_generator(char *fname,
+ pretend_missing:
+ /* pretend the file didn't exist */
+ if (preserve_hard_links && file->link_u.links
+- && hard_link_check(file, ndx, fname, statret, &st,
++ && hard_link_check(file, ndx, fname, statret, &sx,
+ itemizing, code, HL_SKIP))
+- return;
++ goto cleanup;
+ statret = real_ret = -1;
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && ACL_READY(sx))
++ free_acl(&sx);
++#endif
+ goto notify_others;
+ }
+
+ if (inplace && make_backups && fnamecmp_type == FNAMECMP_FNAME) {
+ if (!(backupptr = get_backup_name(fname))) {
+ close(fd);
+- return;
++ goto cleanup;
+ }
+ if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) {
+ close(fd);
+@@ -1254,7 +1327,7 @@ static void recv_generator(char *fname,
+ full_fname(backupptr));
+ free(back_file);
+ close(fd);
+- return;
++ goto cleanup;
+ }
+ if ((f_copy = do_open(backupptr,
+ O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
+@@ -1262,14 +1335,14 @@ static void recv_generator(char *fname,
+ full_fname(backupptr));
+ free(back_file);
+ close(fd);
+- return;
++ goto cleanup;
+ }
+ fnamecmp_type = FNAMECMP_BACKUP;
+ }
+
+ if (verbose > 3) {
+ rprintf(FINFO, "gen mapped %s of size %.0f\n",
+- fnamecmp, (double)st.st_size);
++ fnamecmp, (double)sx.st.st_size);
+ }
+
+ if (verbose > 2)
+@@ -1287,24 +1360,32 @@ static void recv_generator(char *fname,
+ iflags |= ITEM_BASIS_TYPE_FOLLOWS;
+ if (fnamecmp_type == FNAMECMP_FUZZY)
+ iflags |= ITEM_XNAME_FOLLOWS;
+- itemize(file, -1, real_ret, &real_st, iflags, fnamecmp_type,
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && real_ret == 0)
++ get_acl(fname, &real_sx);
++#endif
++ itemize(file, -1, real_ret, &real_sx, iflags, fnamecmp_type,
+ fuzzy_file ? fuzzy_file->basename : NULL);
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ free_acl(&real_sx);
++#endif
+ }
+
+ if (!do_xfers) {
+ if (preserve_hard_links && file->link_u.links)
+ hard_link_cluster(file, ndx, itemizing, code);
+- return;
++ goto cleanup;
+ }
+ if (read_batch)
+- return;
++ goto cleanup;
+
+ if (statret != 0 || whole_file) {
+ write_sum_head(f_out, NULL);
+- return;
++ goto cleanup;
+ }
+
+- generate_and_send_sums(fd, st.st_size, f_out, f_copy);
++ generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy);
+
+ if (f_copy >= 0) {
+ close(f_copy);
+@@ -1317,6 +1398,13 @@ static void recv_generator(char *fname,
+ }
+
+ close(fd);