+ if (j != best_match) {
+ j = best_match;
+ pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
+ if (link_stat(cmpbuf, stp, 0) < 0)
+ match_level = 0;
+ }
+
+#ifdef HAVE_LINK
+ if (match_level == 3 && !copy_dest) {
+ if (link_dest) {
+ if (hard_link_one(file, ndx, fname, 0, stp,
+ cmpbuf, 1,
+ itemizing && verbose > 1,
+ code) < 0)
+ goto try_a_copy;
+ if (preserve_hard_links && file->link_u.links)
+ hard_link_cluster(file, ndx, itemizing, code);
+ } else if (itemizing)
+ itemize(file, ndx, 0, stp, 0, 0, NULL);
+ if (verbose > 1 && maybe_ATTRS_REPORT) {
+ code = daemon_log_format_has_i || dry_run
+ ? FCLIENT : FINFO;
+ rprintf(code, "%s is uptodate\n", fname);
+ }
+ return -2;
+ }
+#endif
+
+ if (match_level >= 2) {
+ try_a_copy: /* Copy the file locally. */
+ if (copy_file(cmpbuf, fname, file->mode) < 0) {
+ if (verbose) {
+ rsyserr(FINFO, errno, "copy_file %s => %s",
+ full_fname(cmpbuf), fname);
+ }
+ return -1;
+ }
+ if (itemizing)
+ itemize(file, ndx, 0, stp, ITEM_LOCAL_CHANGE, 0, NULL);
+ set_file_attrs(fname, file, NULL, 0);
+ if (maybe_ATTRS_REPORT
+ && ((!itemizing && verbose && match_level == 2)
+ || (verbose > 1 && match_level == 3))) {
+ code = daemon_log_format_has_i || dry_run
+ ? FCLIENT : FINFO;
+ rprintf(code, "%s%s\n", fname,
+ match_level == 3 ? " is uptodate" : "");
+ }
+ if (preserve_hard_links && file->link_u.links)
+ hard_link_cluster(file, ndx, itemizing, code);
+ return -2;
+ }
+
+ return FNAMECMP_BASIS_DIR_LOW + j;
+}
+
+/* This is only called for non-regular files. We return -2 if we've finished
+ * handling the file, or -1 if no dest-linking occurred. */
+static int try_dests_non(struct file_struct *file, char *fname, int ndx,
+ int itemizing, int *possible_ptr,
+ int maybe_ATTRS_REPORT, enum logcode code)
+{
+ char fnamebuf[MAXPATHLEN], lnk[MAXPATHLEN];
+ STRUCT_STAT st;
+ int len, 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))
+ continue;
+ if (S_ISLNK(file->mode)) {
+#ifdef SUPPORT_LINKS
+ if ((len = readlink(fnamebuf, lnk, MAXPATHLEN-1)) <= 0)
+ continue;
+ lnk[len] = '\0';
+ if (strcmp(lnk, file->u.link) != 0)
+#endif
+ continue;
+ } else {
+ if (!IS_DEVICE(st.st_mode) || st.st_rdev != file->u.rdev)
+ continue;
+ }
+ if (link_dest) {
+ if (do_link(fnamebuf, fname) < 0) {
+ /* TODO improve this to be based on errno? */
+ *possible_ptr = 0;
+ break;
+ }
+ if (preserve_hard_links && file->link_u.links)
+ hard_link_cluster(file, ndx, itemizing, code);
+ }
+ if (itemizing && log_format_has_i && verbose > 1) {
+ 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);
+ }
+ if (verbose > 1 && maybe_ATTRS_REPORT) {
+ code = daemon_log_format_has_i || dry_run
+ ? FCLIENT : FINFO;
+ rprintf(code, "%s is uptodate\n", fname);
+ }
+ return -2;
+ } while (basis_dir[++i] != NULL);
+
+ return -1;
+}
+
+static int phase = 0;
+
+/* 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
+ * 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.