rprintf(FINFO, " \r");
}
-static inline int time_differs(struct file_struct *file, stat_x *sxp)
+static inline int time_diff(STRUCT_STAT *stp, struct file_struct *file)
{
- return cmp_time(sxp->st.st_mtime, file->modtime);
+#ifdef ST_MTIME_NSEC
+ return cmp_time(stp->st_mtime, stp->ST_MTIME_NSEC, file->modtime, F_MOD_NSEC(file));
+#else
+ return cmp_time(stp->st_mtime, 0L, file->modtime, 0L);
+#endif
}
static inline int perms_differ(struct file_struct *file, stat_x *sxp)
{
if (S_ISLNK(file->mode)) {
#ifdef CAN_SET_SYMLINK_TIMES
- if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
+ if (preserve_times & PRESERVE_LINK_TIMES && time_diff(&sxp->st, file))
return 0;
#endif
#ifdef CAN_CHMOD_SYMLINK
return 0;
#endif
} else {
- if (preserve_times && time_differs(file, sxp))
+ if (preserve_times && time_diff(&sxp->st, file))
return 0;
if (perms_differ(file, sxp))
return 0;
if (iflags & ITEM_LOCAL_CHANGE)
iflags |= symlink_timeset_failed_flags;
} else if (keep_time
- ? cmp_time(file->modtime, sxp->st.st_mtime) != 0
+ ? time_diff(&sxp->st, file)
: iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
&& (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
iflags |= ITEM_REPORT_TIME;
if (ignore_times)
return 0;
- return cmp_time(st->st_mtime, file->modtime) == 0;
+ return time_diff(st, file) == 0;
}
if (!S_ISREG(fp->mode) || !F_LENGTH(fp) || fp->flags & FLAG_FILE_SENT)
continue;
- if (F_LENGTH(fp) == F_LENGTH(file) && cmp_time(fp->modtime, file->modtime) == 0) {
+ if (F_LENGTH(fp) == F_LENGTH(file) && cmp_time(fp->modtime, 0L, file->modtime, 0L) == 0) {
if (DEBUG_GTE(FUZZY, 2))
rprintf(FINFO, "fuzzy size/modtime match for %s\n", f_name(fp, NULL));
*fnamecmp_type_ptr = FNAMECMP_FUZZY + i;
goto cleanup;
}
- if (update_only > 0 && statret == 0
- && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
+ if (update_only > 0 && statret == 0 && time_diff(&sx.st, file) > 0) {
if (INFO_GTE(SKIP, 1))
rprintf(FINFO, "%s is newer\n", fname);
#ifdef SUPPORT_HARD_LINKS
do_chmod(fname, file->mode);
if (need_retouch_dir_times) {
STRUCT_STAT st;
- if (link_stat(fname, &st, 0) == 0
- && cmp_time(st.st_mtime, file->modtime) != 0)
+ if (link_stat(fname, &st, 0) == 0 && time_diff(&st, file))
set_modtime(fname, file->modtime, F_MOD_NSEC(file), file->mode);
}
if (counter >= loopchk_limit) {
rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n");
rprintf(F," -M, --remote-option=OPTION send OPTION to the remote side only\n");
rprintf(F," --size-only skip files that match in size\n");
- rprintf(F," --modify-window=NUM compare mod-times with reduced accuracy\n");
+ rprintf(F," -@, --modify-window=NUM set the accuracy for mod-time comparisons\n");
rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," -y, --fuzzy find similar file for basis if no dest file\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
{"omit-link-times", 'J', POPT_ARG_VAL, &omit_link_times, 1, 0, 0 },
{"no-omit-link-times",0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 },
{"no-J", 0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 },
- {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
+ {"modify-window", '@', POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
{"super", 0, POPT_ARG_VAL, &am_root, 2, 0, 0 },
{"no-super", 0, POPT_ARG_VAL, &am_root, 0, 0, 0 },
{"fake-super", 0, POPT_ARG_VAL, &am_root, -1, 0, 0 },
else if (missing_args == 1 && !am_sender)
args[ac++] = "--ignore-missing-args";
- if (modify_window_set) {
- if (asprintf(&arg, "--modify-window=%d", modify_window) < 0)
+ if (modify_window_set && am_sender) {
+ char *fmt = modify_window < 0 ? "-@%d" : "--modify-window=%d";
+ if (asprintf(&arg, fmt, modify_window) < 0)
goto oom;
args[ac++] = arg;
}
--contimeout=SECONDS set daemon connection timeout in seconds
-I, --ignore-times don't skip files that match size and time
--size-only skip files that match in size
- --modify-window=NUM compare mod-times with reduced accuracy
+ -@, --modify-window=NUM set the accuracy for mod-time comparisons
-T, --temp-dir=DIR create temporary files in directory DIR
-y, --fuzzy find similar file for basis if no dest file
--compare-dest=DIR also compare received files relative to DIR
when starting to use rsync after using another mirroring system which may
not preserve timestamps exactly.
-dit(bf(--modify-window)) When comparing two timestamps, rsync treats the
+dit(bf(-@, --modify-window)) When comparing two timestamps, rsync treats the
timestamps as being equal if they differ by no more than the modify-window
-value. This is normally 0 (for an exact match), but you may find it useful
-to set this to a larger value in some situations. In particular, when
-transferring to or from an MS Windows FAT filesystem (which represents
-times with a 2-second resolution), bf(--modify-window=1) is useful
-(allowing times to differ by up to 1 second).
+value. The default is 0, which matches just integer seconds. If you specify a
+negative value (and the receiver is at least version 3.1.3) then nanoseconds
+will also be taken into account. Specifying 1 is useful for copies to/from MS
+Windows FAT filesystems, because FAT represents times with a 2-second
+resolution (allowing times to differ from the original by up to 1 second).
+
+If you want all your transfers to default to comparing nanoseconds, you can
+create a ~/.popt file and put these lines in it:
+
+quote(tt( rsync alias -a -a@-1))
+quote(tt( rsync alias -t -t@-1))
+
+With that as the default, you'd need to specify bf(--modify-window=0) (aka
+bf(-@0)) to override it and ignore nanoseconds, e.g. if you're copying between
+ext3 and ext4, or if the receiving rsync is older than 3.1.3.
dit(bf(-c, --checksum)) This changes the way rsync checks if the files have
been changed and are in need of a transfer. Without this option, rsync
*
* @retval -1 if the 2nd is later
**/
-int cmp_time(time_t file1, time_t file2)
+int cmp_time(time_t f1_sec, unsigned long f1_nsec, time_t f2_sec, unsigned long f2_nsec)
{
- if (file2 > file1) {
+ if (f2_sec > f1_sec) {
/* The final comparison makes sure that modify_window doesn't overflow a
- * time_t, which would mean that file2 must be in the equality window. */
- if (!modify_window || (file2 > file1 + modify_window && file1 + modify_window > file1))
+ * time_t, which would mean that f2_sec must be in the equality window. */
+ if (modify_window <= 0 || (f2_sec > f1_sec + modify_window && f1_sec + modify_window > f1_sec))
return -1;
- } else if (file1 > file2) {
- if (!modify_window || (file1 > file2 + modify_window && file2 + modify_window > file2))
+ } else if (f1_sec > f2_sec) {
+ if (modify_window <= 0 || (f1_sec > f2_sec + modify_window && f2_sec + modify_window > f2_sec))
+ return 1;
+ } else if (modify_window < 0) {
+ if (f2_nsec > f1_nsec)
+ return -1;
+ else if (f1_nsec > f2_nsec)
return 1;
}
return 0;