Fix typo in rsyncd.conf man page.
[rsync/rsync.git] / generator.c
index 2d5bd12..125b313 100644 (file)
@@ -27,7 +27,6 @@ extern int dry_run;
 extern int do_xfers;
 extern int stdout_format_has_i;
 extern int logfile_format_has_i;
-extern int receiver_symlink_times;
 extern int am_root;
 extern int am_server;
 extern int am_daemon;
@@ -136,8 +135,12 @@ enum delret {
     DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_NOT_EMPTY
 };
 
-/* Forward declaration for delete_item(). */
+/* Forward declarations. */
 static enum delret delete_dir_contents(char *fname, uint16 flags);
+#ifdef SUPPORT_HARD_LINKS
+static void handle_skipped_hlink(struct file_struct *file, int itemizing,
+                                enum logcode code, int f_out);
+#endif
 
 static int is_backup_file(char *fn)
 {
@@ -280,7 +283,7 @@ static enum delret delete_dir_contents(char *fname, uint16 flags)
        for (j = dirlist->used; j--; ) {
                struct file_struct *fp = dirlist->files[j];
 
-               if (fp->flags & FLAG_MOUNT_DIR) {
+               if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
                        if (verbose > 1) {
                                rprintf(FINFO,
                                    "mount point, %s, pins parent directory\n",
@@ -512,7 +515,7 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
                struct file_struct *fp = dirlist->files[i];
                if (!F_IS_ACTIVE(fp))
                        continue;
-               if (fp->flags & FLAG_MOUNT_DIR) {
+               if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
                        if (verbose > 1)
                                rprintf(FINFO, "cannot delete mount point: %s\n",
                                        f_name(fp, NULL));
@@ -1216,7 +1219,8 @@ static int dflt_perms;
  * 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.
  *
- * When fname is non-null, it must point to a MAXPATHLEN buffer!
+ * 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. */
@@ -1270,6 +1274,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                excluded_dir = file;
                        }
                  skipping:
+#ifdef SUPPORT_HARD_LINKS
+                       if (F_IS_HLINKED(file))
+                               handle_skipped_hlink(file, itemizing, code, f_out);
+#endif
                        rprintf(FERROR_XFER,
                                "skipping daemon-excluded file \"%s\"\n",
                                fname);
@@ -1286,6 +1294,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                } else if (!dry_run) {
                        if (is_dir)
                                file->flags |= FLAG_MISSING_DIR;
+#ifdef SUPPORT_HARD_LINKS
+                       if (F_IS_HLINKED(file))
+                               handle_skipped_hlink(file, itemizing, code, f_out);
+#endif
                        return;
                }
        }
@@ -1348,6 +1360,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        }
                        file->flags |= FLAG_MISSING_DIR;
                }
+#ifdef SUPPORT_HARD_LINKS
+               else if (F_IS_HLINKED(file))
+                       handle_skipped_hlink(file, itemizing, code, f_out);
+#endif
                if (verbose > 1) {
                        rprintf(FINFO, "not creating new %s \"%s\"\n",
                                is_dir ? "directory" : "file", fname);
@@ -1359,6 +1375,17 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
         && !am_root && sx.st.st_uid == our_uid)
                del_opts |= DEL_NO_UID_WRITE;
 
+       if (ignore_existing > 0 && statret == 0
+        && (!is_dir || !S_ISDIR(sx.st.st_mode))) {
+               if (verbose > 1 && is_dir >= 0)
+                       rprintf(FINFO, "%s exists\n", fname);
+#ifdef SUPPORT_HARD_LINKS
+               if (F_IS_HLINKED(file))
+                       handle_skipped_hlink(file, itemizing, code, f_out);
+#endif
+               goto cleanup;
+       }
+
        if (is_dir) {
                if (!implied_dirs && file->flags & FLAG_IMPLIED_DIR)
                        goto cleanup;
@@ -1664,16 +1691,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                goto cleanup;
        }
 
-       if (ignore_existing > 0 && statret == 0) {
-               if (verbose > 1)
-                       rprintf(FINFO, "%s exists\n", fname);
-               goto cleanup;
-       }
-
        if (update_only > 0 && statret == 0
            && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
                if (verbose > 1)
                        rprintf(FINFO, "%s is newer\n", fname);
+#ifdef SUPPORT_HARD_LINKS
+               if (F_IS_HLINKED(file))
+                       handle_skipped_hlink(file, itemizing, code, f_out);
+#endif
                goto cleanup;
        }
 
@@ -1743,9 +1768,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                goto cleanup;
        }
 
-       if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file))
-               goto cleanup;
-
        if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
                ;
        else if (fnamecmp_type == FNAMECMP_FUZZY)
@@ -1770,6 +1792,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                goto cleanup;
        }
 
+       if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file)) {
+#ifdef SUPPORT_HARD_LINKS
+               if (F_IS_HLINKED(file))
+                       handle_skipped_hlink(file, itemizing, code, f_out);
+#endif
+               goto cleanup;
+       }
+
   prepare_to_open:
        if (partialptr) {
                sx.st = partial_st;
@@ -1857,7 +1887,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                rprintf(FINFO, "generating and sending sums for %d\n", ndx);
 
   notify_others:
-       if (remove_source_files && !delay_updates && !phase)
+       if (remove_source_files && !delay_updates && !phase && !dry_run)
                increment_active_files(ndx, itemizing, code);
        if (inc_recurse && !dry_run)
                cur_flist->in_progress++;
@@ -1926,6 +1956,28 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
        return;
 }
 
+#ifdef SUPPORT_HARD_LINKS
+static void handle_skipped_hlink(struct file_struct *file, int itemizing,
+                                enum logcode code, int f_out)
+{
+       char fbuf[MAXPATHLEN];
+       int new_last_ndx;
+       struct file_list *save_flist = cur_flist;
+
+       /* If we skip the last item in a chain of links and there was a
+        * prior non-skipped hard-link waiting to finish, finish it now. */
+       if ((new_last_ndx = skip_hard_link(file, &cur_flist)) < 0)
+               return;
+
+       file = cur_flist->files[new_last_ndx - cur_flist->ndx_start];
+       cur_flist->in_progress--; /* undo prior increment */
+       f_name(file, fbuf);
+       recv_generator(fbuf, file, new_last_ndx, itemizing, code, f_out);
+
+       cur_flist = save_flist;
+}
+#endif
+
 static void touch_up_dirs(struct file_list *flist, int ndx)
 {
        static int counter = 0;
@@ -2081,7 +2133,7 @@ void generate_files(int f_out, const char *local_name)
        need_retouch_dir_times = preserve_times > 1;
        lull_mod = allowed_lull * 5;
        symlink_timeset_failed_flags = ITEM_REPORT_TIME
-                                    | (receiver_symlink_times ? ITEM_REPORT_TIMEFAIL : 0 );
+           | (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0);
 
        if (verbose > 2)
                rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid());