+
+ if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
+ realname, itemizing, code) < 0)
+ return -1;
+
+ if (remove_source_files == 1 && do_xfers)
+ send_msg_int(MSG_SUCCESS, ndx);
+
+ return 1;
+}
+
+int hard_link_one(struct file_struct *file, const char *fname,
+ const char *oldname, int terse)
+{
+ if (do_link(oldname, fname) < 0) {
+ enum logcode code;
+ if (terse) {
+ if (!verbose)
+ return -1;
+ code = FINFO;
+ } else
+ code = FERROR;
+ rsyserr(code, errno, "link %s => %s failed",
+ full_fname(fname), oldname);
+ return 0;
+ }
+
+ file->flags |= FLAG_HLINK_DONE;
+
+ return 1;
+}
+
+void finish_hard_link(struct file_struct *file, const char *fname,
+ STRUCT_STAT *stp, int itemizing, enum logcode code,
+ int alt_dest)
+{
+ statx prev_sx;
+ STRUCT_STAT st;
+ char alt_name[MAXPATHLEN], *prev_name;
+ const char *our_name;
+ struct file_list *flist;
+ int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
+
+ if (stp == NULL && prev_ndx >= 0) {
+ if (link_stat(fname, &st, 0) < 0) {
+ rsyserr(FERROR, errno, "stat %s failed",
+ full_fname(fname));
+ return;
+ }
+ stp = &st;
+ }
+
+ /* FIRST combined with DONE means we were the first to get done. */
+ file->flags |= FLAG_HLINK_FIRST | FLAG_HLINK_DONE;
+ F_HL_PREV(file) = alt_dest;
+ if (alt_dest >= 0 && dry_run) {
+ pathjoin(alt_name, MAXPATHLEN, basis_dir[alt_dest],
+ f_name(file, NULL));
+ our_name = alt_name;
+ } else
+ our_name = fname;
+
+#ifdef SUPPORT_ACLS
+ prev_sx.acc_acl = prev_sx.def_acl = NULL;
+#endif
+
+ while ((ndx = prev_ndx) >= 0) {
+ int val;
+ flist = flist_for_ndx(ndx);
+ assert(flist != NULL);
+ file = flist->files[ndx - flist->ndx_start];
+ file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
+ prev_ndx = F_HL_PREV(file);
+ prev_name = f_name(file, NULL);
+ prev_statret = link_stat(prev_name, &prev_sx.st, 0);
+ val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
+ our_name, stp, fname, itemizing, code);
+ flist->in_progress--;
+#ifdef SUPPORT_ACLS
+ if (preserve_acls)
+ free_acl(&prev_sx);