+ if (preserve_hard_links && F_IS_HLINKED(file))
+ finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1);
+ } else
+#endif
+ match_level = 2;
+ if (itemizing && stdout_format_has_i
+ && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) {
+ int chg = compare_dest && type != TYPE_DIR ? 0
+ : ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
+ char *lp = match_level == 3 ? "" : NULL;
+ itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
+ }
+ if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT) {
+ rprintf(FCLIENT, "%s%s is uptodate\n",
+ fname, type == TYPE_DIR ? "/" : "");
+ }
+ return -2;
+ }
+
+ return j;
+}
+
+static void list_file_entry(struct file_struct *f)
+{
+ char permbuf[PERMSTRING_SIZE];
+ int64 len;
+ int colwidth = human_readable ? 14 : 11;
+
+ if (!F_IS_ACTIVE(f)) {
+ /* this can happen if duplicate names were removed */
+ return;
+ }
+
+ permstring(permbuf, f->mode);
+ len = F_LENGTH(f);
+
+ /* TODO: indicate '+' if the entry has an ACL. */
+
+#ifdef SUPPORT_LINKS
+ if (preserve_links && S_ISLNK(f->mode)) {
+ rprintf(FINFO, "%s %*s %s %s -> %s\n",
+ permbuf, colwidth, human_num(len),
+ timestring(f->modtime), f_name(f, NULL),
+ F_SYMLINK(f));
+ } else
+#endif
+ if (missing_args == 2 && f->mode == 0) {
+ rprintf(FINFO, "%-*s %s\n",
+ colwidth + 31, "*missing",
+ f_name(f, NULL));
+ } else {
+ rprintf(FINFO, "%s %*s %s %s\n",
+ permbuf, colwidth, human_num(len),
+ timestring(f->modtime), f_name(f, NULL));
+ }
+}
+
+static int phase = 0;
+static int dflt_perms;
+
+static int implied_dirs_are_missing;
+/* Helper for recv_generator's skip_dir and dry_missing_dir tests. */
+static BOOL is_below(struct file_struct *file, struct file_struct *subtree)
+{
+ return F_DEPTH(file) > F_DEPTH(subtree)
+ && (!implied_dirs_are_missing || f_name_has_prefix(file, subtree));
+}
+
+/* Acts on the indicated item in cur_flist whose name is fname. If a dir,
+ * make sure it exists, and has the right permissions/timestamp info. For
+ * all other non-regular files (symlinks, etc.) we create them here. For
+ * regular files that have changed, we try to find a basis file and then
+ * start sending checksums. The ndx is the file's unique index value.
+ *
+ * The fname parameter must point to a MAXPATHLEN buffer! (e.g it gets
+ * passed to delete_item(), which can use it during a recursive delete.)
+ *
+ * Note that f_out is set to -1 when doing final directory-permission and
+ * modification-time repair. */
+static void recv_generator(char *fname, struct file_struct *file, int ndx,
+ int itemizing, enum logcode code, int f_out)
+{
+ static const char *parent_dirname = "";
+ /* Missing dir not created due to --dry-run; will still be scanned. */
+ static struct file_struct *dry_missing_dir = NULL;
+ /* Missing dir whose contents are skipped altogether due to
+ * --ignore-non-existing, daemon exclude, or mkdir failure. */
+ static struct file_struct *skip_dir = NULL;
+ static struct file_list *fuzzy_dirlist = NULL;
+ static int need_fuzzy_dirlist = 0;
+ struct file_struct *fuzzy_file = NULL;
+ int fd = -1, f_copy = -1;
+ stat_x sx, real_sx;
+ STRUCT_STAT partial_st;
+ struct file_struct *back_file = NULL;
+ int statret, real_ret, stat_errno;
+ char *fnamecmp, *partialptr, *backupptr = NULL;
+ char fnamecmpbuf[MAXPATHLEN];
+ uchar fnamecmp_type;
+ int del_opts = delete_mode || force_delete ? DEL_RECURSE : 0;
+ int is_dir = !S_ISDIR(file->mode) ? 0
+ : inc_recurse && ndx != cur_flist->ndx_start - 1 ? -1
+ : 1;
+
+ if (DEBUG_GTE(GENR, 1))
+ rprintf(FINFO, "recv_generator(%s,%d)\n", fname, ndx);
+
+ if (list_only) {
+ if (is_dir < 0
+ || (is_dir && !implied_dirs && file->flags & FLAG_IMPLIED_DIR))
+ return;
+ list_file_entry(file);
+ return;
+ }
+
+ if (skip_dir) {
+ if (is_below(file, skip_dir)) {
+ if (is_dir)
+ file->flags |= FLAG_MISSING_DIR;
+#ifdef SUPPORT_HARD_LINKS
+ else if (F_IS_HLINKED(file))
+ handle_skipped_hlink(file, itemizing, code, f_out);
+#endif