The branch, master has been updated via 974f49e2 Add --crtimes option. via 9f7506ac Improve --itemize-changes doc. via 8779d6c8 Switch to RSYNC_MAX_SKIPPED test setting. from 96be713f Update NEWS.
https://git.samba.org/?p=rsync.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 974f49e22ac9f62fcfd750768d0835b900524578 Author: Wayne Davison <wa...@opencoder.net> Date: Wed Jul 22 12:12:18 2020 -0700 Add --crtimes option. commit 9f7506ac1b48a17a65610ed4a1356c7432cf4da7 Author: Wayne Davison <wa...@opencoder.net> Date: Wed Jul 22 11:26:02 2020 -0700 Improve --itemize-changes doc. commit 8779d6c8bb23c643c805fc9aaa5873ee64a98cd7 Author: Wayne Davison <wa...@opencoder.net> Date: Wed Jul 22 10:59:15 2020 -0700 Switch to RSYNC_MAX_SKIPPED test setting. ----------------------------------------------------------------------- Summary of changes: .github/workflows/build.yml | 6 +++--- Makefile.in | 18 +++++++++--------- NEWS.md | 3 +++ compat.c | 9 ++++++++- flist.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ generator.c | 34 +++++++++++++++++++++++++++++----- log.c | 5 +++-- options.c | 16 ++++++++++++++++ packaging/auto-Makefile | 4 ++-- rsync.1.md | 33 +++++++++++++++++++++------------ rsync.c | 17 +++++++++++++++-- rsync.h | 11 ++++++++++- runtests.sh | 14 +++----------- syscall.c | 43 +++++++++++++++++++++++++++++++++++++++++++ testsuite/crtimes.test | 26 ++++++++++++++++++++++++++ tls.c | 27 +++++++++++++++++++++++++-- 16 files changed, 261 insertions(+), 50 deletions(-) create mode 100644 testsuite/crtimes.test Changeset truncated at 500 lines: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 812171dc..af45eead 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,11 +27,11 @@ jobs: - name: info run: rsync --version - name: check - run: sudo make strict_check + run: sudo RSYNC_MAX_SKIPPED=1 make check - name: check30 - run: sudo make strict_check30 + run: sudo RSYNC_MAX_SKIPPED=1 make check30 - name: check29 - run: sudo make strict_check29 + run: sudo RSYNC_MAX_SKIPPED=1 make check29 - name: ssl file list run: rsync-ssl --no-motd download.samba.org::rsyncftp/ || true - name: save artifact diff --git a/Makefile.in b/Makefile.in index 513b2f8c..a6ce0366 100644 --- a/Makefile.in +++ b/Makefile.in @@ -295,17 +295,17 @@ test: check # catch Bash-isms earlier even if we're running on GNU. Of course, we # might lose in the future where POSIX diverges from old sh. -.PHONY: check strict_check -check strict_check: all $(CHECK_PROGS) $(CHECK_SYMLINKS) - rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh $@ +.PHONY: check +check: all $(CHECK_PROGS) $(CHECK_SYMLINKS) + rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh -.PHONY: check29 strict_check29 -check29 strict_check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS) - rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh $@ --protocol=29 +.PHONY: check29 +check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS) + rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=29 -.PHONY: check30 strict_check30 -check30 strict_check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS) - rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh $@ --protocol=30 +.PHONY: check30 +check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS) + rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=30 wildtest.o: wildtest.c t_stub.o lib/wildmatch.c rsync.h config.h wildtest$(EXEEXT): wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@ diff --git a/NEWS.md b/NEWS.md index 3ae5f74c..36d79af9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -39,6 +39,9 @@ protocol (so if you used this patch in the past, be sure to update your converter script to use newlines instead of null chars). + - Added `--crtimes` (`-N`) option for preserving the file's create time (on + an OS that supports that, such as macOS). + - Added the ability to specify "@netgroup" names to the `hosts allow` and `hosts deny` daemon parameters. This is a finalized version of the netgroup-auth patch from the patches repo. diff --git a/compat.c b/compat.c index 4719ef56..bbabd117 100644 --- a/compat.c +++ b/compat.c @@ -43,6 +43,7 @@ extern int protect_args; extern int preserve_uid; extern int preserve_gid; extern int preserve_atimes; +extern int preserve_crtimes; extern int preserve_acls; extern int preserve_xattrs; extern int xfer_flags_as_varint; @@ -76,7 +77,7 @@ int do_negotiated_strings = 0; int xmit_id0_names = 0; /* These index values are for the file-list's extra-attribute array. */ -int pathname_ndx, depth_ndx, atimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx; +int pathname_ndx, depth_ndx, atimes_ndx, crtimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx; int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ int sender_symlink_iconv = 0; /* sender should convert symlink content */ @@ -555,6 +556,8 @@ void setup_protocol(int f_out,int f_in) * aligned for direct int64-pointer memory access. */ if (preserve_atimes) atimes_ndx = (file_extra_cnt += EXTRA64_CNT); + if (preserve_crtimes) + crtimes_ndx = (file_extra_cnt += EXTRA64_CNT); if (am_sender) /* This is most likely in the in64 union as well. */ pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT); else @@ -719,6 +722,10 @@ void setup_protocol(int f_out,int f_in) proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0; xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0; xmit_id0_names = compat_flags & CF_ID0_NAMES ? 1 : 0; + if (!xfer_flags_as_varint && preserve_crtimes) { + fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --crtimes.\n"); + exit_cleanup(RERR_PROTOCOL); + } if (am_sender) { receiver_symlink_times = am_server ? strchr(client_info, 'L') != NULL diff --git a/flist.c b/flist.c index 6c2543cd..feec96d4 100644 --- a/flist.c +++ b/flist.c @@ -56,6 +56,7 @@ extern int delete_during; extern int missing_args; extern int eol_nulls; extern int atimes_ndx; +extern int crtimes_ndx; extern int relative_paths; extern int implied_dirs; extern int ignore_perishable; @@ -378,6 +379,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx) { static time_t modtime, atime; +#ifdef SUPPORT_CRTIMES + static time_t crtime; +#endif static mode_t mode; #ifdef SUPPORT_HARD_LINKS static int64 dev; @@ -483,6 +487,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, else atime = F_ATIME(file); } +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx) { + crtime = F_CRTIME(file); + if (crtime == modtime) + xflags |= XMIT_CRTIME_EQ_MTIME; + } +#endif #ifdef SUPPORT_HARD_LINKS if (tmp_dev != -1) { @@ -570,6 +581,10 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, } if (xflags & XMIT_MOD_NSEC) write_varint(f, F_MOD_NSEC(file)); +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx && !(xflags & XMIT_CRTIME_EQ_MTIME)) + write_varlong(f, crtime, 4); +#endif if (!(xflags & XMIT_SAME_MODE)) write_int(f, to_wire_mode(mode)); if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME)) @@ -662,6 +677,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags) { static int64 modtime, atime; +#ifdef SUPPORT_CRTIMES + static time_t crtime; +#endif static mode_t mode; #ifdef SUPPORT_HARD_LINKS static int64 dev; @@ -776,6 +794,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x mode = first->mode; if (atimes_ndx && !S_ISDIR(mode)) atime = F_ATIME(first); +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx) + crtime = F_CRTIME(first); +#endif if (preserve_uid) uid = F_OWNER(first); if (preserve_gid) @@ -815,6 +837,21 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x modtime_nsec = read_varint(f); else modtime_nsec = 0; +#endif +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx) { + if (xflags & XMIT_CRTIME_EQ_MTIME) + crtime = modtime; + else + crtime = read_varlong(f, 4); +#if SIZEOF_TIME_T < SIZEOF_INT64 + if (!am_generator && (int64)(time_t)crtime != crtime) { + rprintf(FERROR_XFER, + "Create time value of %s truncated on receiver.\n", + lastname); + } +#endif + } #endif if (!(xflags & XMIT_SAME_MODE)) mode = from_wire_mode(read_int(f)); @@ -997,6 +1034,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x } if (atimes_ndx && !S_ISDIR(mode)) F_ATIME(file) = atime; +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx) + F_CRTIME(file) = crtime; +#endif if (unsort_ndx) F_NDX(file) = flist->used + flist->ndx_start; @@ -1394,6 +1435,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, file->flags |= FLAG_OWNED_BY_US; if (atimes_ndx && !S_ISDIR(file->mode)) F_ATIME(file) = st.st_atime; +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx) + F_CRTIME(file) = get_create_time(fname); +#endif if (basename != thisname) file->dirname = lastdir; diff --git a/generator.c b/generator.c index 1648db1c..f1780838 100644 --- a/generator.c +++ b/generator.c @@ -396,6 +396,19 @@ static inline int mtime_differs(STRUCT_STAT *stp, struct file_struct *file) #endif } +static inline int any_time_differs(stat_x *sxp, struct file_struct *file, UNUSED(const char *fname)) +{ + int differs = mtime_differs(&sxp->st, file); +#ifdef SUPPORT_CRTIMES + if (!differs && crtimes_ndx) { + if (sxp->crtime == 0) + sxp->crtime = get_create_time(fname); + differs = !same_time(sxp->crtime, 0, F_CRTIME(file), 0); + } +#endif + return differs; +} + static inline int perms_differ(struct file_struct *file, stat_x *sxp) { if (preserve_perms) @@ -450,7 +463,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 && mtime_differs(&sxp->st, file)) + if (preserve_times & PRESERVE_LINK_TIMES && any_time_differs(sxp, file, fname)) return 0; #endif #ifdef CAN_CHMOD_SYMLINK @@ -470,7 +483,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) return 0; #endif } else { - if (preserve_times && mtime_differs(&sxp->st, file)) + if (preserve_times && any_time_differs(sxp, file, fname)) return 0; if (perms_differ(file, sxp)) return 0; @@ -512,6 +525,14 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre if (atimes_ndx && !S_ISDIR(file->mode) && !S_ISLNK(file->mode) && !same_time(F_ATIME(file), 0, sxp->st.st_atime, 0)) iflags |= ITEM_REPORT_ATIME; +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx) { + if (sxp->crtime == 0) + sxp->crtime = get_create_time(fnamecmp); + if (!same_time(sxp->crtime, 0, F_CRTIME(file), 0)) + iflags |= ITEM_REPORT_CRTIME; + } +#endif #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST if (S_ISLNK(file->mode)) { ; @@ -1131,6 +1152,7 @@ static void list_file_entry(struct file_struct *f) int size_width = human_readable ? 14 : 11; int mtime_width = 1 + strlen(mtime_str); int atime_width = atimes_ndx ? mtime_width : 0; + int crtime_width = crtimes_ndx ? mtime_width : 0; if (!F_IS_ACTIVE(f)) { /* this can happen if duplicate names were removed */ @@ -1141,10 +1163,11 @@ static void list_file_entry(struct file_struct *f) if (missing_args == 2 && f->mode == 0) { rprintf(FINFO, "%-*s %s\n", - 10 + 1 + size_width + mtime_width + atime_width, "*missing", + 10 + 1 + size_width + mtime_width + atime_width + crtime_width, "*missing", f_name(f, NULL)); } else { const char *atime_str = atimes_ndx && !S_ISDIR(f->mode) ? timestring(F_ATIME(f)) : ""; + const char *crtime_str = crtimes_ndx ? timestring(F_CRTIME(f)) : ""; const char *arrow, *lnk; permstring(permbuf, f->mode); @@ -1157,9 +1180,9 @@ static void list_file_entry(struct file_struct *f) #endif arrow = lnk = ""; - rprintf(FINFO, "%s %*s %s%*s %s%s%s\n", + rprintf(FINFO, "%s %*s %s%*s%*s %s%s%s\n", permbuf, size_width, human_num(F_LENGTH(f)), - timestring(f->modtime), atime_width, atime_str, + timestring(f->modtime), atime_width, atime_str, crtime_width, crtime_str, f_name(f, NULL), arrow, lnk); } } @@ -1255,6 +1278,7 @@ 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; diff --git a/log.c b/log.c index 85eae3d5..0dc26331 100644 --- a/log.c +++ b/log.c @@ -720,8 +720,9 @@ static void log_formatted(enum logcode code, const char *format, const char *op, c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; - c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' - : S_ISLNK(file->mode) ? 'U' : 'u'; + c[8] = !(iflags & (ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME)) ? '.' + : BITS_SET(iflags, ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME) ? 'b' + : iflags & ITEM_REPORT_ATIME ? 'u' : 'n'; c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; c[11] = '\0'; diff --git a/options.c b/options.c index 0ecabe8d..59335269 100644 --- a/options.c +++ b/options.c @@ -64,6 +64,7 @@ int preserve_uid = 0; int preserve_gid = 0; int preserve_times = 0; int preserve_atimes = 0; +int preserve_crtimes = 0; int update_only = 0; int open_noatime = 0; int cvs_exclude = 0; @@ -670,6 +671,11 @@ static void print_info_flags(enum logcode f) #endif "stop-at", +#ifndef SUPPORT_CRTIMES + "no " +#endif + "crtimes", + "*Optimizations", #ifndef HAVE_SIMD @@ -838,6 +844,9 @@ static struct poptOption long_options[] = { {"no-U", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 }, {"open-noatime", 0, POPT_ARG_VAL, &open_noatime, 1, 0, 0 }, {"no-open-noatime", 0, POPT_ARG_VAL, &open_noatime, 0, 0, 0 }, + {"crtimes", 'N', POPT_ARG_VAL, &preserve_crtimes, 1, 0, 0 }, + {"no-crtimes", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 }, + {"no-N", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 }, {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 }, {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, @@ -1211,6 +1220,9 @@ static void set_refuse_options(void) #ifndef HAVE_SETVBUF parse_one_refuse_match(0, "outbuf", list_end); #endif +#ifndef SUPPORT_CRTIMES + parse_one_refuse_match(0, "crtimes", list_end); +#endif /* Now we use the descrip values to actually mark the options for refusal. */ for (op = long_options; op != list_end; op++) { @@ -2738,6 +2750,10 @@ void server_options(char **args, int *argc_p) if (preserve_atimes > 1) argstr[x++] = 'U'; } +#ifdef SUPPORT_CRTIMES + if (preserve_crtimes) + argstr[x++] = 'N'; +#endif if (preserve_perms) argstr[x++] = 'p'; else if (preserve_executability && am_sender) diff --git a/packaging/auto-Makefile b/packaging/auto-Makefile index 5e3322a2..e50277cb 100644 --- a/packaging/auto-Makefile +++ b/packaging/auto-Makefile @@ -1,6 +1,6 @@ TARGETS := all install install-ssl-daemon install-all install-strip conf gen gensend reconfigure restatus \ - proto man clean cleantests distclean test check check29 check30 strict_check strict_check29 strict_check30 \ - installcheck splint doxygen doxygen-upload + proto man clean cleantests distclean test check check29 check30 installcheck splint \ + doxygen doxygen-upload .PHONY: $(TARGETS) auto-prep diff --git a/rsync.1.md b/rsync.1.md index 91942873..dcf69e52 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -372,6 +372,7 @@ detailed description below for a complete description. --times, -t preserve modification times --atimes, -U preserve access (use) times --open-noatime avoid changing the atime on opened files +--crtimes, -N preserve create times (newness) --omit-dir-times, -O omit directories from --times --omit-link-times, -J omit symlinks from --times --super receiver attempts super-user activities @@ -1341,6 +1342,11 @@ your home directory (remove the '=' for that). mounted to avoid updating the atime on read access even without the O_NOATIME flag being set. +0. `--crtimes`, `-N,` + + This tells rsync to set the create times (newness) of +the destination + files to the same value as the source files. + 0. `--omit-dir-times`, `-O` This tells rsync to omit directories when it is preserving modification @@ -2642,12 +2648,14 @@ your home directory (remove the '=' for that). directory, an `L` for a symlink, a `D` for a device, and a `S` for a special file (e.g. named sockets and fifos). - The other letters in the string above are the actual letters that will be - output if the associated attribute for the item is being updated or a "." - for no change. Three exceptions to this are: (1) a newly created item - replaces each letter with a "+", (2) an identical item replaces the dots - with spaces, and (3) an unknown attribute replaces each letter with a "?" - (this can happen when talking to an older rsync). + The other letters in the string indicate if some attributes of the file + have changed, as follows: + + - "`.`" - the attribute is unchanged. + - "`+`" - the file is newly created. + - "`Â `" - all the attributes are unchanged (all dots turn to spaces). + - "`?`" - the change is unknown (when the remote rsync is old). + - A letter indicates an attribute is being updated. The attribute that is associated with each letter is as follows: @@ -2671,12 +2679,13 @@ your home directory (remove the '=' for that). value (requires `--owner` and super-user privileges). - A `g` means the group is different and is being updated to the sender's value (requires `--group` and the authority to set the group). - - A `u` means the access (use) time is different and is being updated to - the sender's value (requires `--atimes`). An alternate value of `U` - means that the access time will be set to the transfer time, which - happens when a symlink or directory is updated. - - The `a` means that the ACL information changed. - - The `x` means that the extended attribute information changed. + - A `u`|`n`|`b` indicates the following information: `u` means the access + (use) time is different and is being updated to the sender's value + (requires `--atimes`); `n` means the create time (newness) is different + and is being updated to the sender's value (requires `--crtimes`); `b` + means that both the access and create times are being updated. + - The `a` means that the ACL information is being changed. + - The `x` means that the extended attribute information is being changed. One other output is possible: when deleting files, the "%i" will output the string "`*deleting`" for each item that is being removed (assuming that you diff --git a/rsync.c b/rsync.c index e091cbef..e7f1f96a 100644 --- a/rsync.c +++ b/rsync.c @@ -584,6 +584,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, memcpy(&sx2.st, &sxp->st, sizeof (sx2.st)); if (!atimes_ndx || S_ISDIR(sxp->st.st_mode)) flags |= ATTRS_SKIP_ATIME; + /* Don't set the creation date on the root folder of an HFS+ volume. */ + if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode)) + flags |= ATTRS_SKIP_CRTIME; if (!(flags & ATTRS_SKIP_MTIME) && !same_mtime(file, &sxp->st, flags & ATTRS_ACCURATE_TIME)) { sx2.st.st_mtime = file->modtime; #ifdef ST_MTIME_NSEC @@ -613,6 +616,16 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, file->flags |= FLAG_TIME_FAILED; } } +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx && !(flags & ATTRS_SKIP_CRTIME)) { + time_t file_crtime = F_CRTIME(file); + if (sxp->crtime == 0) + sxp->crtime = get_create_time(fname); + if (!same_time(sxp->crtime, 0L, file_crtime, 0L) + && set_create_time(fname, file_crtime) == 0) + updated = 1; + } +#endif #ifdef SUPPORT_ACLS /* It's OK to call set_acl() now, even for a dir, as the generator @@ -718,7 +731,7 @@ int finish_transfer(const char *fname, const char *fnametmp, /* Change permissions before putting the file into place. */ set_file_attrs(fnametmp, file, NULL, fnamecmp, - ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME); -- The rsync repository.
_______________________________________________ rsync-cvs mailing list rsync-cvs@lists.samba.org https://lists.samba.org/mailman/listinfo/rsync-cvs