Add safety check for local --remove-source-files.
[rsync.git] / generator.c
index 2265f6023e5f15a5ee09a5dfe37ddb5a38329331..935c84f9c4bd8974c5e78477d80422ea4d8906d0 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2020 Wayne Davison
+ * Copyright (C) 2003-2022 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,16 +35,18 @@ extern int inc_recurse;
 extern int relative_paths;
 extern int implied_dirs;
 extern int keep_dirlinks;
+extern int write_devices;
 extern int preserve_acls;
 extern int preserve_xattrs;
 extern int preserve_links;
 extern int preserve_devices;
-extern int write_devices;
 extern int preserve_specials;
 extern int preserve_hard_links;
 extern int preserve_executability;
 extern int preserve_perms;
-extern int preserve_times;
+extern int preserve_mtimes;
+extern int omit_dir_times;
+extern int omit_link_times;
 extern int delete_mode;
 extern int delete_before;
 extern int delete_during;
@@ -182,7 +184,8 @@ static int remember_delete(struct file_struct *file, const char *fname, int flag
 static int read_delay_line(char *buf, int *flags_p)
 {
        static int read_pos = 0;
-       int j, len, mode;
+       unsigned int mode;
+       int j, len;
        char *bp, *past_space;
 
        while (1) {
@@ -266,7 +269,7 @@ static void do_delayed_deletions(char *delbuf)
  * MAXPATHLEN buffer with the name of the directory in it (the functions we
  * call will append names onto the end, but the old dir value will be restored
  * on exit). */
-static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
+static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t fs_dev)
 {
        static int already_warned = 0;
        static struct hashtable *dev_tbl;
@@ -301,12 +304,12 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
                if (!dev_tbl)
                        dev_tbl = hashtable_create(16, HT_KEY64);
                if (file->flags & FLAG_TOP_DIR) {
-                       hashtable_find(dev_tbl, *fs_dev+1, "");
-                       filesystem_dev = *fs_dev;
-               } else if (filesystem_dev != *fs_dev) {
-                       if (!hashtable_find(dev_tbl, *fs_dev+1, NULL))
+                       hashtable_find(dev_tbl, fs_dev+1, "");
+                       filesystem_dev = fs_dev;
+               } else if (filesystem_dev != fs_dev) {
+                       if (!hashtable_find(dev_tbl, fs_dev+1, NULL))
                                return;
-                       filesystem_dev = *fs_dev; /* it's a prior top-dir dev */
+                       filesystem_dev = fs_dev; /* it's a prior top-dir dev */
                }
        }
 
@@ -375,9 +378,9 @@ static void do_delete_pass(void)
                 || !S_ISDIR(st.st_mode))
                        continue;
 
-               delete_in_dir(fbuf, file, &st.st_dev);
+               delete_in_dir(fbuf, file, st.st_dev);
        }
-       delete_in_dir(NULL, NULL, &dev_zero);
+       delete_in_dir(NULL, NULL, dev_zero);
 
        if (INFO_GTE(FLIST, 2) && !am_server)
                rprintf(FINFO, "                    \r");
@@ -398,7 +401,7 @@ static inline int any_time_differs(stat_x *sxp, struct file_struct *file, UNUSED
 #ifdef SUPPORT_CRTIMES
        if (!differs && crtimes_ndx) {
                if (sxp->crtime == 0)
-                       sxp->crtime = get_create_time(fname);
+                       sxp->crtime = get_create_time(fname, &sxp->st);
                differs = !same_time(sxp->crtime, 0, F_CRTIME(file), 0);
        }
 #endif
@@ -459,7 +462,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
 {
        if (S_ISLNK(file->mode)) {
 #ifdef CAN_SET_SYMLINK_TIMES
-               if (preserve_times & PRESERVE_LINK_TIMES && any_time_differs(sxp, file, fname))
+               if (preserve_mtimes && !omit_link_times && any_time_differs(sxp, file, fname))
                        return 0;
 #endif
 #ifdef CAN_CHMOD_SYMLINK
@@ -479,7 +482,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
                        return 0;
 #endif
        } else {
-               if (preserve_times && any_time_differs(sxp, file, fname))
+               if (preserve_mtimes && any_time_differs(sxp, file, fname))
                        return 0;
                if (perms_differ(file, sxp))
                        return 0;
@@ -503,9 +506,9 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
             const char *xname)
 {
        if (statret >= 0) { /* A from-dest-dir statret can == 1! */
-               int keep_time = !preserve_times ? 0
-                   : S_ISDIR(file->mode) ? preserve_times & PRESERVE_DIR_TIMES
-                   : S_ISLNK(file->mode) ? preserve_times & PRESERVE_LINK_TIMES
+               int keep_time = !preserve_mtimes ? 0
+                   : S_ISDIR(file->mode) ? !omit_dir_times
+                   : S_ISLNK(file->mode) ? !omit_link_times
                    : 1;
 
                if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
@@ -524,12 +527,12 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
 #ifdef SUPPORT_CRTIMES
                if (crtimes_ndx) {
                        if (sxp->crtime == 0)
-                               sxp->crtime = get_create_time(fnamecmp);
+                               sxp->crtime = get_create_time(fnamecmp, &sxp->st);
                        if (!same_time(sxp->crtime, 0, F_CRTIME(file), 0))
                                iflags |= ITEM_REPORT_CRTIME;
                }
 #endif
-#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
+#ifndef CAN_CHMOD_SYMLINK
                if (S_ISLNK(file->mode)) {
                        ;
                } else
@@ -1268,7 +1271,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        return;
                }
        }
-       sx.crtime = 0;
 
        if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
                int i;
@@ -1378,15 +1380,17 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
        if (ignore_existing > 0 && statret == 0
         && (!is_dir || stype != FT_DIR)) {
                if (INFO_GTE(SKIP, 1) && is_dir >= 0) {
-                       const char *suf;
-                       if (ftype != stype)
-                               suf = " (type differs)";
-                       else if (ftype == FT_REG && always_checksum > 0 && !INFO_GTE(SKIP, 2))
-                               suf = ""; /* skip quick-check checksum unless SKIP2 was specified */
-                       else if (quick_check_ok(ftype, fname, file, &sx.st))
-                               suf = " (uptodate)";
-                       else
-                               suf = " (differs)";
+                       const char *suf = "";
+                       if (INFO_GTE(SKIP, 2)) {
+                               if (ftype != stype)
+                                       suf = " (type change)";
+                               else if (!quick_check_ok(ftype, fname, file, &sx.st))
+                                       suf = always_checksum ? " (sum change)" : " (file change)";
+                               else if (!unchanged_attrs(fname, file, &sx))
+                                       suf = " (attr change)";
+                               else
+                                       suf = " (uptodate)";
+                       }
                        rprintf(FINFO, "%s exists%s\n", fname, suf);
                }
 #ifdef SUPPORT_HARD_LINKS
@@ -1409,7 +1413,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                } else
                        added_perms = 0;
                if (is_dir < 0) {
-                       if (!(preserve_times & PRESERVE_DIR_TIMES))
+                       if (!preserve_mtimes || omit_dir_times)
                                goto cleanup;
                        /* In inc_recurse mode we want to make sure any missing
                         * directories get created while we're still processing
@@ -1513,7 +1517,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                else if (delete_during && f_out != -1 && !phase
                    && !(file->flags & FLAG_MISSING_DIR)) {
                        if (file->flags & FLAG_CONTENT_DIR)
-                               delete_in_dir(fname, file, &real_sx.st.st_dev);
+                               delete_in_dir(fname, file, real_sx.st.st_dev);
                        else
                                change_local_filter_dir(fname, strlen(fname), F_DEPTH(file));
                }
@@ -1674,9 +1678,11 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
        }
 
        if (ftype != FT_REG) {
-               if (solo_file)
-                       fname = f_name(file, NULL);
-               rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname);
+               if (INFO_GTE(NONREG, 1)) {
+                       if (solo_file)
+                               fname = f_name(file, NULL);
+                       rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname);
+               }
                goto cleanup;
        }
 
@@ -1787,6 +1793,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                goto cleanup;
        }
 
+       if (write_devices && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) {
+               /* This early open into fd skips the regular open below. */
+               if ((fd = do_open(fnamecmp, O_RDONLY, 0)) >= 0)
+                       real_sx.st.st_size = sx.st.st_size = get_device_size(fd, fnamecmp);
+       }
+
        if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
                ;
        else if (fnamecmp_type >= FNAMECMP_FUZZY)
@@ -1807,7 +1819,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        goto cleanup;
          return_with_success:
                if (!dry_run)
-                       send_msg_int(MSG_SUCCESS, ndx);
+                       send_msg_success(fname, ndx);
                goto cleanup;
        }
 
@@ -1852,7 +1864,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
        }
 
        /* open the file */
-       if ((fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
+       if (fd < 0 && (fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
                rsyserr(FERROR, errno, "failed to open %s, continuing",
                        full_fname(fnamecmp));
          pretend_missing:
@@ -1869,11 +1881,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 
        if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) {
                if (!(backupptr = get_backup_name(fname))) {
-                       close(fd);
                        goto cleanup;
                }
                if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) {
-                       close(fd);
                        goto pretend_missing;
                }
                if (robust_unlink(backupptr) && errno != ENOENT) {
@@ -1881,14 +1891,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                full_fname(backupptr));
                        unmake_file(back_file);
                        back_file = NULL;
-                       close(fd);
                        goto cleanup;
                }
                if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
                        rsyserr(FERROR_XFER, errno, "open %s", full_fname(backupptr));
                        unmake_file(back_file);
                        back_file = NULL;
-                       close(fd);
                        goto cleanup;
                }
                fnamecmp_type = FNAMECMP_BACKUP;
@@ -1939,7 +1947,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                write_sum_head(f_out, NULL);
        else if (sx.st.st_size <= 0) {
                write_sum_head(f_out, NULL);
-               close(fd);
        } else {
                if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) {
                        rprintf(FWARNING,
@@ -1947,10 +1954,11 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                fnamecmp);
                        write_sum_head(f_out, NULL);
                }
-               close(fd);
        }
 
   cleanup:
+       if (fd >= 0)
+               close(fd);
        if (back_file) {
                int save_preserve_xattrs = preserve_xattrs;
                if (f_copy >= 0)
@@ -2236,7 +2244,7 @@ void generate_files(int f_out, const char *local_name)
        }
        solo_file = local_name;
        dir_tweaking = !(list_only || solo_file || dry_run);
-       need_retouch_dir_times = preserve_times & PRESERVE_DIR_TIMES;
+       need_retouch_dir_times = preserve_mtimes && !omit_dir_times;
        loopchk_limit = allowed_lull ? allowed_lull * 5 : 200;
        symlink_timeset_failed_flags = ITEM_REPORT_TIME
            | (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0);
@@ -2289,7 +2297,7 @@ void generate_files(int f_out, const char *local_name)
                                                dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
                                        } else
                                                dirdev = MAKEDEV(0, 0);
-                                       delete_in_dir(fbuf, fp, &dirdev);
+                                       delete_in_dir(fbuf, fp, dirdev);
                                } else
                                        change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp));
                        }
@@ -2336,7 +2344,7 @@ void generate_files(int f_out, const char *local_name)
        } while ((cur_flist = cur_flist->next) != NULL);
 
        if (delete_during)
-               delete_in_dir(NULL, NULL, &dev_zero);
+               delete_in_dir(NULL, NULL, dev_zero);
        phase++;
        if (DEBUG_GTE(GENR, 1))
                rprintf(FINFO, "generate_files phase=%d\n", phase);