+ 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 %11.0f %s %s -> %s\n",
+ permbuf, len, timestring(f->modtime),
+ f_name(f, NULL), F_SYMLINK(f));
+ } else
+#endif
+ {
+ rprintf(FINFO, "%s %11.0f %s %s\n",
+ permbuf, 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 (verbose > 2)
+ 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
+ return;
+ }
+ skip_dir = NULL;
+ }
+
+ if (daemon_filter_list.head && (*fname != '.' || fname[1])) {
+ if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) {
+ if (is_dir < 0)
+ return;
+#ifdef SUPPORT_HARD_LINKS
+ if (F_IS_HLINKED(file))
+ handle_skipped_hlink(file, itemizing, code, f_out);
+#endif
+ rprintf(FERROR_XFER,
+ "skipping daemon-excluded %s \"%s\"\n",
+ is_dir ? "directory" : "file", fname);
+ if (is_dir)
+ goto skipping_dir_contents;
+ return;
+ }
+ }
+
+#ifdef SUPPORT_ACLS
+ sx.acc_acl = sx.def_acl = NULL;
+#endif
+#ifdef SUPPORT_XATTRS
+ sx.xattr = NULL;
+#endif
+ if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
+ parent_is_dry_missing:
+ if (fuzzy_dirlist) {
+ flist_free(fuzzy_dirlist);
+ fuzzy_dirlist = NULL;
+ }
+ parent_dirname = "";
+ statret = -1;
+ stat_errno = ENOENT;
+ } else {
+ const char *dn = file->dirname ? file->dirname : ".";
+ dry_missing_dir = NULL;
+ if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
+ if (relative_paths && !implied_dirs
+ && do_stat(dn, &sx.st) < 0) {
+ if (dry_run)
+ goto parent_is_dry_missing;
+ if (create_directory_path(fname) < 0) {
+ rsyserr(FERROR_XFER, errno,
+ "recv_generator: mkdir %s failed",
+ full_fname(dn));
+ }
+ }
+ if (fuzzy_dirlist) {
+ flist_free(fuzzy_dirlist);
+ fuzzy_dirlist = NULL;
+ }
+ if (fuzzy_basis)
+ need_fuzzy_dirlist = 1;
+#ifdef SUPPORT_ACLS
+ if (!preserve_perms)
+ dflt_perms = default_perms_for_dir(dn);
+#endif
+ }
+ parent_dirname = dn;
+
+ if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
+ strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
+ fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, 1);
+ need_fuzzy_dirlist = 0;
+ }
+
+ statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir);
+ stat_errno = errno;
+ }
+
+ if (ignore_non_existing > 0 && statret == -1 && stat_errno == ENOENT) {
+ if (is_dir) {
+ if (is_dir < 0)
+ return;
+ skip_dir = file;
+ file->flags |= FLAG_MISSING_DIR;
+ }
+#ifdef SUPPORT_HARD_LINKS
+ else if (F_IS_HLINKED(file))
+ handle_skipped_hlink(file, itemizing, code, f_out);
+#endif