+@@ -1131,12 +1148,26 @@ 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 && f >= 0) {
++ 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);
+ flist->files[flist->count++] = file;
+- if (f >= 0)
++ if (f >= 0) {
+ send_file_entry(f, file, flist->count - 1);
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ send_acl(&sx, f);
++#endif
++ }
+ return file;
+ }
+
+--- old/generator.c
++++ new/generator.c
+@@ -36,6 +36,7 @@ extern int do_progress;
+ 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;
+@@ -90,6 +91,7 @@ extern int force_delete;
+ extern int one_file_system;
+ extern struct stats stats;
+ extern dev_t filesystem_dev;
++extern mode_t orig_umask;
+ extern char *backup_dir;
+ extern char *backup_suffix;
+ extern int backup_suffix_len;
+@@ -509,22 +511,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 && !BITS_EQUAL(st->st_mode, file->mode, CHMOD_BITS))
++ if (preserve_perms && !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
+ return 0;
+
+- if (am_root && preserve_uid && st->st_uid != F_UID(file))
++ if (am_root && preserve_uid && sxp->st.st_uid != F_UID(file))
+ return 0;
+
+- if (preserve_gid && F_GID(file) != GID_NONE && st->st_gid != F_GID(file))
++ if (preserve_gid && F_GID(file) != GID_NONE && sxp->st.st_gid != F_GID(file))
+ 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, int32 iflags, uchar fnamecmp_type,
++ statx *sxp, int32 iflags, uchar fnamecmp_type,
+ const char *xname)
+ {
+ if (statret >= 0) { /* A from-dest-dir statret can == 1! */
+@@ -532,20 +539,24 @@ void itemize(struct file_struct *file, i
+ : S_ISDIR(file->mode) ? !omit_dir_times
+ : !S_ISLNK(file->mode);
+
+- if (S_ISREG(file->mode) && F_LENGTH(file) != st->st_size)
++ if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
+ iflags |= ITEM_REPORT_SIZE;
+ if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
+ && !(iflags & ITEM_MATCHED)
+ && (!(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 (!BITS_EQUAL(st->st_mode, file->mode, CHMOD_BITS))
++ if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
+ iflags |= ITEM_REPORT_PERMS;
+- if (preserve_uid && am_root && F_UID(file) != st->st_uid)
++ if (preserve_uid && am_root && F_UID(file) != sxp->st.st_uid)
+ iflags |= ITEM_REPORT_OWNER;
+ if (preserve_gid && F_GID(file) != GID_NONE
+- && st->st_gid != F_GID(file))
++ && sxp->st.st_gid != F_GID(file))
+ 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;
+
+@@ -799,7 +810,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,
+ enum logcode code)
+ {
+ int best_match = -1;
+@@ -808,7 +819,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:
+@@ -816,16 +827,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 > 0 && preserve_times
+- && cmp_time(stp->st_mtime, file->modtime))
++ && cmp_time(sxp->st.st_mtime, file->modtime))
+ continue;
+ best_match = j;
+ match_level = 3;
+@@ -840,7 +855,7 @@ 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)
+ return -1;
+ }
+
+@@ -850,16 +865,25 @@ static int try_dests_reg(struct file_str
+ if (!hard_link_one(file, fname, cmpbuf, 1))
+ goto try_a_copy;
+ if (preserve_hard_links && F_IS_HLINKED(file))
+- finish_hard_link(file, fname, stp, itemizing, code, j);
++ finish_hard_link(file, fname, &sxp->st, itemizing, code, j);
+ if (itemizing && (verbose > 1 || stdout_format_has_i > 1)) {
+- itemize(file, ndx, 1, stp,
++#ifdef SUPPORT_ACLS
++ if (preserve_acls && !ACL_READY(*sxp))
++ get_acl(fname, sxp);
++#endif
++ itemize(file, ndx, 1, sxp,
+ ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
+ 0, "");
+ }
+ } 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)
+ rprintf(FCLIENT, "%s is uptodate\n", fname);
+ return -2;
+@@ -876,8 +900,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)
+@@ -888,7 +917,7 @@ static int try_dests_reg(struct file_str
+ }
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_IS_HLINKED(file))
+- finish_hard_link(file, fname, stp, itemizing, code, -1);
++ finish_hard_link(file, fname, &sxp->st, itemizing, code, -1);
+ #endif
+ return -2;
+ }
+@@ -900,7 +929,7 @@ static int try_dests_reg(struct file_str
+ * handling the file, or -1 if no dest-linking occurred, or a non-negative
+ * value if we found an alternate basis file. */
+ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
+- char *cmpbuf, STRUCT_STAT *stp, int itemizing,
++ char *cmpbuf, statx *sxp, int itemizing,
+ enum logcode code)
+ {
+ char lnk[MAXPATHLEN];
+@@ -933,24 +962,24 @@ static int try_dests_non(struct file_str
+
+ do {
+ pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
+- if (link_stat(cmpbuf, stp, 0) < 0)
++ if (link_stat(cmpbuf, &sxp->st, 0) < 0)
+ continue;
+ switch (type) {
+ case TYPE_DIR:
+- if (!S_ISDIR(stp->st_mode))
++ if (!S_ISDIR(sxp->st.st_mode))
+ continue;
+ break;
+ case TYPE_SPECIAL:
+- if (!IS_SPECIAL(stp->st_mode))
++ if (!IS_SPECIAL(sxp->st.st_mode))
+ continue;
+ break;
+ case TYPE_DEVICE:
+- if (!IS_DEVICE(stp->st_mode))
++ if (!IS_DEVICE(sxp->st.st_mode))
+ continue;
+ break;
+ #ifdef SUPPORT_LINKS
+ case TYPE_SYMLINK:
+- if (!S_ISLNK(stp->st_mode))
++ if (!S_ISLNK(sxp->st.st_mode))
+ continue;
+ break;
+ #endif
+@@ -965,7 +994,7 @@ static int try_dests_non(struct file_str
+ case TYPE_SPECIAL:
+ case TYPE_DEVICE:
+ devp = F_RDEV_P(file);
+- if (stp->st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
++ if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
+ continue;
+ break;
+ #ifdef SUPPORT_LINKS
+@@ -982,7 +1011,11 @@ static int try_dests_non(struct file_str
+ match_level = 2;
+ best_match = j;
+ }
+- if (unchanged_attrs(file, stp)) {
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ get_acl(cmpbuf, sxp);
++#endif
++ if (unchanged_attrs(file, sxp)) {
+ match_level = 3;
+ best_match = j;
+ break;
+@@ -995,7 +1028,7 @@ static int try_dests_non(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)
+ return -1;
+ }
+
+@@ -1026,7 +1059,15 @@ static int try_dests_non(struct file_str
+ : ITEM_LOCAL_CHANGE
+ + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
+ char *lp = match_level == 3 ? "" : NULL;
+- itemize(file, ndx, 0, stp, chg + ITEM_MATCHED, 0, lp);
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ get_acl(fname, sxp);
++#endif
++ itemize(file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ free_acl(sxp);
++#endif
+ }
+ if (verbose > 1 && maybe_ATTRS_REPORT) {
+ rprintf(FCLIENT, "%s%s is uptodate\n",
+@@ -1039,6 +1080,7 @@ static int try_dests_non(struct file_str
+ }
+
+ static int phase = 0;
++static int dflt_perms;
+
+ /* Acts on cur_flist->file's ndx'th item, whose name is fname. If a dir,
+ * make sure it exists, and has the right permissions/timestamp info. For
+@@ -1059,7 +1101,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;
+@@ -1104,6 +1147,9 @@ static void recv_generator(char *fname,
+ return;
+ }
+ }
++#ifdef SUPPORT_ACLS
++ sx.acc_acl = sx.def_acl = NULL;
++#endif
+ if (dry_run > 1) {
+ if (fuzzy_dirlist) {
+ flist_free(fuzzy_dirlist);
+@@ -1116,7 +1162,7 @@ static void recv_generator(char *fname,
+ const char *dn = file->dirname ? file->dirname : ".";
+ if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
+ if (relative_paths && !implied_dirs
+- && do_stat(dn, &st) < 0
++ && do_stat(dn, &sx.st) < 0
+ && create_directory_path(fname) < 0) {
+ rsyserr(FERROR, errno,
+ "recv_generator: mkdir %s failed",
+@@ -1128,6 +1174,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;
+
+@@ -1137,7 +1187,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;
+ }
+@@ -1163,8 +1213,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)) {
+@@ -1173,8 +1224,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, "directory", del_opts) != 0)
++ if (statret == 0 && !S_ISDIR(sx.st.st_mode)) {
++ if (delete_item(fname, sx.st.st_mode, "directory", del_opts) != 0)
+ return;
+ statret = -1;
+ }
+@@ -1183,14 +1234,14 @@ static void recv_generator(char *fname,
+ dry_run++;
+ }
+ real_ret = statret;
+- real_st = st;
++ real_sx = sx;
+ if (new_root_dir) {
+ if (*fname == '.' && fname[1] == '\0')
+ statret = -1;
+ new_root_dir = 0;
+ }
+ if (statret != 0 && basis_dir[0] != NULL) {
+- int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
++ int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
+ itemizing, code);
+ if (j == -2) {
+ itemizing = 0;
+@@ -1199,7 +1250,11 @@ static void recv_generator(char *fname,
+ statret = 1;
+ }
+ 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 (real_ret != 0 && do_mkdir(fname,file->mode) < 0 && errno != EEXIST) {
+@@ -1213,31 +1268,31 @@ static void recv_generator(char *fname,
+ "*** Skipping any contents from this failed directory ***\n");
+ missing_below = F_DEPTH(file);
+ file->flags |= FLAG_MISSING_DIR;
+- return;
++ goto cleanup;
+ }
+ }
+- if (set_file_attrs(fname, file, real_ret ? NULL : &real_st, 0)
++ if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, 0)
+ && verbose && code != FNONE && f_out != -1)
+ rprintf(code, "%s/\n", fname);
+ if (real_ret != 0 && one_file_system)
+- real_st.st_dev = filesystem_dev;
++ real_sx.st.st_dev = filesystem_dev;
+ if (inc_recurse) {
+ if (one_file_system) {
+ uint32 *devp = F_DIRDEV_P(file);
+- DEV_MAJOR(devp) = major(real_st.st_dev);
+- DEV_MINOR(devp) = minor(real_st.st_dev);
++ DEV_MAJOR(devp) = major(real_sx.st.st_dev);
++ DEV_MINOR(devp) = minor(real_sx.st.st_dev);
+ }
+ }
+ else if (delete_during && f_out != -1 && !phase && dry_run < 2
+ && (file->flags & FLAG_XFER_DIR))
+- delete_in_dir(cur_flist, fname, file, &real_st.st_dev);
+- return;
++ delete_in_dir(cur_flist, fname, file, &real_sx.st.st_dev);
++ goto cleanup;
+ }
+
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_HLINK_NOT_FIRST(file)
+- && hard_link_check(file, ndx, fname, statret, &st, itemizing, code))
+- return;
++ && hard_link_check(file, ndx, fname, statret, &sx, itemizing, code))
++ goto cleanup;
+ #endif
+
+ if (preserve_links && S_ISLNK(file->mode)) {
+@@ -1257,28 +1312,28 @@ static void recv_generator(char *fname,
+ char lnk[MAXPATHLEN];
+ int len;
+
+- if (!S_ISLNK(st.st_mode))
++ if (!S_ISLNK(sx.st.st_mode))
+ statret = -1;
+ else if ((len = readlink(fname, lnk, MAXPATHLEN-1)) > 0
+ && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') {
+ /* The link is pointing to the right place. */
+ if (itemizing)
+- itemize(file, ndx, 0, &st, 0, 0, NULL);
+- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
++ itemize(file, ndx, 0, &sx, 0, 0, NULL);
++ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_IS_HLINKED(file))
+- finish_hard_link(file, fname, &st, itemizing, code, -1);
++ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
+ #endif
+ if (remove_source_files == 1)
+ goto return_with_success;
+- return;
++ goto cleanup;
+ }
+ /* Not the right symlink (or not a symlink), so
+ * delete it. */
+- if (delete_item(fname, st.st_mode, "symlink", del_opts) != 0)
+- return;
++ if (delete_item(fname, sx.st.st_mode, "symlink", del_opts) != 0)
++ goto cleanup;
+ } else if (basis_dir[0] != NULL) {
+- int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
++ int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
+ itemizing, code);
+ if (j == -2) {
+ #ifndef CAN_HARDLINK_SYMLINK
+@@ -1287,7 +1342,7 @@ static void recv_generator(char *fname,
+ } else
+ #endif
+ if (!copy_dest)
+- return;
++ goto cleanup;
+ itemizing = 0;
+ code = FNONE;
+ } else if (j >= 0)
+@@ -1295,7 +1350,7 @@ static void recv_generator(char *fname,
+ }
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_HLINK_NOT_LAST(file))
+- return;
++ goto cleanup;
+ #endif
+ if (do_symlink(sl, fname) != 0) {
+ rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
+@@ -1303,7 +1358,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 != FNONE && verbose)
+@@ -1319,7 +1374,7 @@ static void recv_generator(char *fname,
+ goto return_with_success;
+ }
+ #endif
+- return;
++ goto cleanup;
+ }
+
+ if ((am_root && preserve_devices && IS_DEVICE(file->mode))
+@@ -1329,33 +1384,38 @@ static void recv_generator(char *fname,
+ if (statret == 0) {
+ char *t;
+ if (IS_DEVICE(file->mode)) {
+- if (!IS_DEVICE(st.st_mode))
++ if (!IS_DEVICE(sx.st.st_mode))
+ statret = -1;
+ t = "device file";
+ } else {
+- if (!IS_SPECIAL(st.st_mode))
++ if (!IS_SPECIAL(sx.st.st_mode))
+ statret = -1;
+ t = "special file";
+ }
+ if (statret == 0
+- && BITS_EQUAL(st.st_mode, file->mode, _S_IFMT)
+- && st.st_rdev == rdev) {
++ && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT)
++ && sx.st.st_rdev == rdev) {
+ /* The device or special file is identical. */
+- if (itemizing)
+- itemize(file, ndx, 0, &st, 0, 0, NULL);
+- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
++ if (itemizing) {
++#ifdef SUPPORT_ACLS
++ if (preserve_acls)
++ get_acl(fname, &sx);
++#endif
++ itemize(file, ndx, 0, &sx, 0, 0, NULL);
++ }
++ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_IS_HLINKED(file))
+- finish_hard_link(file, fname, &st, itemizing, code, -1);
++ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
+ #endif
+ if (remove_source_files == 1)
+ goto return_with_success;
+- return;
++ goto cleanup;
+ }
+- if (delete_item(fname, st.st_mode, t, del_opts) != 0)
+- return;
++ if (delete_item(fname, sx.st.st_mode, t, del_opts) != 0)
++ goto cleanup;
+ } else if (basis_dir[0] != NULL) {
+- int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
++ int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
+ itemizing, code);
+ if (j == -2) {
+ #ifndef CAN_HARDLINK_SPECIAL
+@@ -1364,7 +1424,7 @@ static void recv_generator(char *fname,
+ } else
+ #endif
+ if (!copy_dest)
+- return;
++ goto cleanup;
+ itemizing = 0;
+ code = FNONE;
+ } else if (j >= 0)
+@@ -1372,7 +1432,7 @@ static void recv_generator(char *fname,
+ }
+ #ifdef SUPPORT_HARD_LINKS
+ if (preserve_hard_links && F_HLINK_NOT_LAST(file))
+- return;
++ goto cleanup;
+ #endif
+ if (verbose > 2) {
+ rprintf(FINFO, "mknod(%s, 0%o, [%ld,%ld])\n",
+@@ -1385,7 +1445,11 @@ static void recv_generator(char *fname,
+ } else {
+ set_file_attrs(fname, file, NULL, 0);
+ if (itemizing) {
+- itemize(file, ndx, statret, &st,