+ 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, 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,
+ int maybe_ATTRS_REPORT, enum logcode code)
+{
+ char lnk[MAXPATHLEN];
+ int best_match = -1;
+ int match_level = 0;
+ enum nonregtype type;
+ int len, j = 0;
+
+#ifndef SUPPORT_LINKS
+ if (S_ISLNK(file->mode))
+ return -1;
+#endif
+ if (S_ISDIR(file->mode)) {
+ type = TYPE_DIR;
+ } else if (IS_SPECIAL(file->mode))
+ type = TYPE_SPECIAL;
+ else if (IS_DEVICE(file->mode))
+ type = TYPE_DEVICE;
+#ifdef SUPPORT_LINKS
+ else if (S_ISLNK(file->mode))
+ type = TYPE_SYMLINK;
+#endif
+ else {
+ rprintf(FERROR,
+ "internal: try_dests_non() called with invalid mode (%o)\n",
+ (int)file->mode);
+ exit_cleanup(RERR_UNSUPPORTED);
+ }
+
+ do {
+ pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
+ if (link_stat(cmpbuf, stp, 0) < 0)
+ continue;
+ switch (type) {
+ case TYPE_DIR:
+ if (!S_ISDIR(stp->st_mode))
+ continue;
+ break;
+ case TYPE_SPECIAL:
+ if (!IS_SPECIAL(stp->st_mode))
+ continue;
+ break;
+ case TYPE_DEVICE:
+ if (!IS_DEVICE(stp->st_mode))
+ continue;
+ break;
+#ifdef SUPPORT_LINKS
+ case TYPE_SYMLINK:
+ if (!S_ISLNK(stp->st_mode))
+ continue;
+ break;
+#endif
+ }
+ if (match_level < 1) {
+ match_level = 1;
+ best_match = j;
+ }
+ switch (type) {
+ case TYPE_DIR:
+ break;
+ case TYPE_SPECIAL:
+ case TYPE_DEVICE:
+ if (stp->st_rdev != file->u.rdev)
+ continue;
+ break;
+#ifdef SUPPORT_LINKS
+ case TYPE_SYMLINK:
+ if ((len = readlink(cmpbuf, lnk, MAXPATHLEN-1)) <= 0)
+ continue;
+ lnk[len] = '\0';
+ if (strcmp(lnk, file->u.link) != 0)
+ continue;
+ break;
+#endif
+ }
+ if (match_level < 2) {
+ match_level = 2;
+ best_match = j;
+ }
+ if (unchanged_attrs(file, stp)) {
+ match_level = 3;
+ best_match = j;
+ break;
+ }
+ } while (basis_dir[++j] != NULL);
+
+ if (!match_level)
+ return -1;
+
+ if (j != best_match) {
+ j = best_match;
+ pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
+ if (link_stat(cmpbuf, stp, 0) < 0)
+ return -1;
+ }
+
+ if (match_level == 3) {
+#ifdef SUPPORT_HARD_LINKS
+ if (link_dest
+#ifndef CAN_HARDLINK_SYMLINK
+ && !S_ISLNK(file->mode)
+#endif
+#ifndef CAN_HARDLINK_SPECIAL
+ && !IS_SPECIAL(file->mode) && !IS_DEVICE(file->mode)
+#endif
+ && !S_ISDIR(file->mode)) {
+ if (do_link(cmpbuf, fname) < 0) {
+ rsyserr(FERROR, errno,
+ "failed to hard-link %s with %s",
+ cmpbuf, fname);
+ return j;
+ }
+ if (preserve_hard_links && file->link_u.links)
+ hard_link_cluster(file, ndx, itemizing, code);
+ } else
+#endif
+ match_level = 2;
+ if (itemizing && stdout_format_has_i
+ && (verbose > 1 || 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(file, ndx, 0, stp, chg + ITEM_MATCHED, 0, lp);
+ }
+ if (verbose > 1 && maybe_ATTRS_REPORT) {
+ rprintf(FCLIENT, "%s%s is uptodate\n",
+ fname, type == TYPE_DIR ? "/" : "");
+ }
+ return -2;
+ }
+
+ return j;
+}
+
+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.