1 This patch adds a --crtimes (-N) option that will preserve
4 To use this patch, run these commands for a successful build:
6 patch -p1 <patches/fileflags.diff
7 patch -p1 <patches/crtimes.diff
8 ./configure (optional if already run)
11 based-on: patch/master/fileflags
12 diff --git a/compat.c b/compat.c
15 @@ -51,6 +51,7 @@ extern int protect_args;
16 extern int preserve_uid;
17 extern int preserve_gid;
18 extern int preserve_atimes;
19 +extern int preserve_crtimes;
20 extern int preserve_acls;
21 extern int preserve_xattrs;
22 extern int preserve_fileflags;
23 @@ -70,7 +71,7 @@ extern char *iconv_opt;
26 /* These index values are for the file-list's extra-attribute array. */
27 -int pathname_ndx, depth_ndx, atimes_ndx, uid_ndx, gid_ndx, fileflags_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
28 +int pathname_ndx, depth_ndx, atimes_ndx, crtimes_ndx, uid_ndx, gid_ndx, fileflags_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
30 int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
31 int sender_symlink_iconv = 0; /* sender should convert symlink content */
32 @@ -150,6 +151,8 @@ void setup_protocol(int f_out,int f_in)
33 * aligned for direct int64-pointer memory access. */
35 atimes_ndx = (file_extra_cnt += EXTRA64_CNT);
36 + if (preserve_crtimes)
37 + crtimes_ndx = (file_extra_cnt += EXTRA64_CNT);
38 if (am_sender) /* This is most likely in the in64 union as well. */
39 pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT);
41 @@ -303,6 +306,10 @@ void setup_protocol(int f_out,int f_in)
42 want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM);
43 proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0;
44 xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0;
45 + if (!xfer_flags_as_varint && preserve_crtimes) {
46 + fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --crtimes.\n");
47 + exit_cleanup(RERR_PROTOCOL);
49 if (!xfer_flags_as_varint && preserve_fileflags) {
50 fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --fileflags.\n");
51 exit_cleanup(RERR_PROTOCOL);
52 diff --git a/flist.c b/flist.c
55 @@ -57,6 +57,7 @@ extern int delete_during;
56 extern int missing_args;
58 extern int atimes_ndx;
59 +extern int crtimes_ndx;
60 extern int relative_paths;
61 extern int implied_dirs;
62 extern int ignore_perishable;
63 @@ -383,6 +384,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
64 int ndx, int first_ndx)
66 static time_t modtime, atime;
67 +#ifdef SUPPORT_CRTIMES
68 + static time_t crtime;
71 #ifdef SUPPORT_FILEFLAGS
72 static uint32 fileflags;
73 @@ -499,6 +503,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
75 atime = F_ATIME(file);
77 +#ifdef SUPPORT_CRTIMES
79 + crtime = F_CRTIME(file);
80 + if (crtime == modtime)
81 + xflags |= XMIT_CRTIME_EQ_MTIME;
85 #ifdef SUPPORT_HARD_LINKS
87 @@ -586,6 +597,10 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
89 if (xflags & XMIT_MOD_NSEC)
90 write_varint(f, F_MOD_NSEC(file));
91 +#ifdef SUPPORT_CRTIMES
92 + if (crtimes_ndx && !(xflags & XMIT_CRTIME_EQ_MTIME))
93 + write_varlong(f, crtime, 4);
95 if (!(xflags & XMIT_SAME_MODE))
96 write_int(f, to_wire_mode(mode));
97 #ifdef SUPPORT_FILEFLAGS
98 @@ -682,6 +697,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
99 static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
101 static int64 modtime, atime;
102 +#ifdef SUPPORT_CRTIMES
103 + static time_t crtime;
106 #ifdef SUPPORT_FILEFLAGS
107 static uint32 fileflags;
108 @@ -795,6 +813,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
110 if (atimes_ndx && !S_ISDIR(mode))
111 atime = F_ATIME(first);
112 +#ifdef SUPPORT_CRTIMES
114 + crtime = F_CRTIME(first);
116 #ifdef SUPPORT_FILEFLAGS
117 if (preserve_fileflags)
118 fileflags = F_FFLAGS(first);
119 @@ -835,6 +857,21 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
120 modtime_nsec = read_varint(f);
123 +#ifdef SUPPORT_CRTIMES
125 + if (xflags & XMIT_CRTIME_EQ_MTIME)
128 + crtime = read_varlong(f, 4);
129 +#if SIZEOF_TIME_T < SIZEOF_INT64
130 + if (!am_generator && (int64)(time_t)crtime != crtime) {
131 + rprintf(FERROR_XFER,
132 + "Create time value of %s truncated on receiver.\n",
138 if (!(xflags & XMIT_SAME_MODE))
139 mode = from_wire_mode(read_int(f));
140 if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME)) {
141 @@ -1024,6 +1061,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
143 if (atimes_ndx && !S_ISDIR(mode))
144 F_ATIME(file) = atime;
145 +#ifdef SUPPORT_CRTIMES
147 + F_CRTIME(file) = crtime;
150 F_NDX(file) = flist->used + flist->ndx_start;
152 @@ -1427,6 +1468,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
153 file->flags |= FLAG_OWNED_BY_US;
154 if (atimes_ndx && !S_ISDIR(file->mode))
155 F_ATIME(file) = st.st_atime;
156 +#ifdef SUPPORT_CRTIMES
158 + F_CRTIME(file) = get_create_time(fname);
161 if (basename != thisname)
162 file->dirname = lastdir;
163 diff --git a/generator.c b/generator.c
166 @@ -41,6 +41,7 @@ extern int preserve_links;
167 extern int preserve_devices;
168 extern int write_devices;
169 extern int preserve_specials;
170 +extern int preserve_fileflags;
171 extern int preserve_hard_links;
172 extern int preserve_executability;
173 extern int preserve_fileflags;
174 @@ -395,6 +396,19 @@ static inline int time_diff(STRUCT_STAT *stp, struct file_struct *file)
178 +static inline int all_time_diff(stat_x *sxp, struct file_struct *file, UNUSED(const char *fname))
180 + int diff = time_diff(&sxp->st, file);
181 +#ifdef SUPPORT_CRTIMES
182 + if (!diff && crtimes_ndx) {
183 + if (sxp->crtime == 0)
184 + sxp->crtime = get_create_time(fname);
185 + diff = cmp_time(sxp->crtime, 0, F_CRTIME(file), 0);
191 static inline int perms_differ(struct file_struct *file, stat_x *sxp)
194 @@ -449,7 +463,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
196 if (S_ISLNK(file->mode)) {
197 #ifdef CAN_SET_SYMLINK_TIMES
198 - if (preserve_times & PRESERVE_LINK_TIMES && time_diff(&sxp->st, file))
199 + if (preserve_times & PRESERVE_LINK_TIMES && all_time_diff(sxp, file, fname))
202 #ifdef CAN_CHMOD_SYMLINK
203 @@ -469,7 +483,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
207 - if (preserve_times && time_diff(&sxp->st, file))
208 + if (preserve_times && all_time_diff(sxp, file, fname))
210 if (perms_differ(file, sxp))
212 @@ -515,6 +529,14 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
213 if (atimes_ndx && !S_ISDIR(file->mode) && !S_ISLNK(file->mode)
214 && cmp_time(F_ATIME(file), 0, sxp->st.st_atime, 0) != 0)
215 iflags |= ITEM_REPORT_ATIME;
216 +#ifdef SUPPORT_CRTIMES
218 + if (sxp->crtime == 0)
219 + sxp->crtime = get_create_time(fnamecmp);
220 + if (cmp_time(sxp->crtime, 0L, F_CRTIME(file), 0L) != 0)
221 + iflags |= ITEM_REPORT_CRTIME;
224 #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
225 if (S_ISLNK(file->mode)) {
227 @@ -1140,6 +1162,7 @@ static void list_file_entry(struct file_struct *f)
228 int size_width = human_readable ? 14 : 11;
229 int mtime_width = 1 + strlen(mtime_str);
230 int atime_width = atimes_ndx ? mtime_width : 0;
231 + int crtime_width = crtimes_ndx ? mtime_width : 0;
233 if (!F_IS_ACTIVE(f)) {
234 /* this can happen if duplicate names were removed */
235 @@ -1150,10 +1173,11 @@ static void list_file_entry(struct file_struct *f)
237 if (missing_args == 2 && f->mode == 0) {
238 rprintf(FINFO, "%-*s %s\n",
239 - 10 + 1 + size_width + mtime_width + atime_width, "*missing",
240 + 10 + 1 + size_width + mtime_width + atime_width + crtime_width, "*missing",
243 const char *atime_str = atimes_ndx && !S_ISDIR(f->mode) ? timestring(F_ATIME(f)) : "";
244 + const char *crtime_str = crtimes_ndx ? timestring(F_CRTIME(f)) : "";
245 const char *arrow, *lnk;
247 permstring(permbuf, f->mode);
248 @@ -1166,9 +1190,9 @@ static void list_file_entry(struct file_struct *f)
252 - rprintf(FINFO, "%s %*s %s%*s %s%s%s\n",
253 + rprintf(FINFO, "%s %*s %s%*s%*s %s%s%s\n",
254 permbuf, size_width, human_num(F_LENGTH(f)),
255 - timestring(f->modtime), atime_width, atime_str,
256 + timestring(f->modtime), atime_width, atime_str, crtime_width, crtime_str,
257 f_name(f, NULL), arrow, lnk);
260 @@ -1264,6 +1288,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
266 if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
268 diff --git a/log.c b/log.c
271 @@ -720,7 +720,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
272 c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
273 c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
274 c[11] = !(iflags & ITEM_REPORT_FFLAGS) ? '.' : 'f';
276 + c[12] = !(iflags & ITEM_REPORT_CRTIME) ? '.' : 'n';
279 if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
280 char ch = iflags & ITEM_IS_NEW ? '+' : '?';
281 diff --git a/options.c b/options.c
284 @@ -65,6 +65,7 @@ int preserve_uid = 0;
285 int preserve_gid = 0;
286 int preserve_times = 0;
287 int preserve_atimes = 0;
288 +int preserve_crtimes = 0;
290 int open_noatime = 0;
292 @@ -582,6 +583,7 @@ static void print_rsync_version(enum logcode f)
293 char const *ipv6 = "no ";
294 char const *sse2 = "no ";
295 char const *fileflags = "no ";
296 + char const *crtimes = "no ";
297 STRUCT_STAT *dumstat;
299 #if SUBPROTOCOL_VERSION != 0
300 @@ -624,6 +626,9 @@ static void print_rsync_version(enum logcode f)
301 #ifdef SUPPORT_FILEFLAGS
304 +#ifdef SUPPORT_CRTIMES
308 rprintf(f, "%s version %s protocol version %d%s\n",
309 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
310 @@ -639,8 +644,8 @@ static void print_rsync_version(enum logcode f)
311 got_socketpair, hardlinks, links, ipv6, have_inplace);
312 rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc, %ssse2,\n",
313 have_inplace, acls, xattrs, iconv, symtimes, prealloc, sse2);
314 - rprintf(f, " %sfile-flags\n",
316 + rprintf(f, " %sfile-flags, %scrtimes\n",
317 + fileflags, crtimes);
319 #ifdef MAINTAINER_MODE
320 rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
321 @@ -730,6 +735,9 @@ void usage(enum logcode F)
322 rprintf(F," -t, --times preserve modification times\n");
323 rprintf(F," -U, --atimes preserve access (last-used) times\n");
324 rprintf(F," --open-noatime avoid changing the atime on opened files\n");
325 +#ifdef SUPPORT_CRTIMES
326 + rprintf(F," -N, --crtimes preserve create times (newness)\n");
328 rprintf(F," -O, --omit-dir-times omit directories from --times\n");
329 rprintf(F," -J, --omit-link-times omit symlinks from --times\n");
330 rprintf(F," --super receiver attempts super-user activities\n");
331 @@ -905,6 +913,11 @@ static struct poptOption long_options[] = {
332 {"no-U", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 },
333 {"open-noatime", 0, POPT_ARG_VAL, &open_noatime, 1, 0, 0 },
334 {"no-open-noatime", 0, POPT_ARG_VAL, &open_noatime, 0, 0, 0 },
335 +#ifdef SUPPORT_CRTIMES
336 + {"crtimes", 'N', POPT_ARG_VAL, &preserve_crtimes, 1, 0, 0 },
337 + {"no-crtimes", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
338 + {"no-N", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
340 {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 },
341 {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
342 {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
343 @@ -2604,6 +2617,10 @@ void server_options(char **args, int *argc_p)
344 if (preserve_atimes > 1)
347 +#ifdef SUPPORT_CRTIMES
348 + if (preserve_crtimes)
353 else if (preserve_executability && am_sender)
354 diff --git a/rsync.c b/rsync.c
357 @@ -604,6 +604,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
358 memcpy(&sx2.st, &sxp->st, sizeof (sx2.st));
359 if (!atimes_ndx || S_ISDIR(sxp->st.st_mode))
360 flags |= ATTRS_SKIP_ATIME;
361 + /* Don't set the creation date on the root folder of an HFS+ volume. */
362 + if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode))
363 + flags |= ATTRS_SKIP_CRTIME;
364 if (!(flags & ATTRS_SKIP_MTIME)
365 && (sxp->st.st_mtime != file->modtime
367 @@ -638,6 +641,16 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
368 file->flags |= FLAG_TIME_FAILED;
371 +#ifdef SUPPORT_CRTIMES
372 + if (crtimes_ndx && !(flags & ATTRS_SKIP_CRTIME)) {
373 + time_t file_crtime = F_CRTIME(file);
374 + if (sxp->crtime == 0)
375 + sxp->crtime = get_create_time(fname);
376 + if (cmp_time(sxp->crtime, 0L, file_crtime, 0L) != 0
377 + && set_create_time(fname, file_crtime) == 0)
383 /* It's OK to call set_acl() now, even for a dir, as the generator
384 @@ -757,7 +770,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
385 /* Change permissions before putting the file into place. */
386 set_file_attrs(fnametmp, file, NULL, fnamecmp,
387 ATTRS_DELAY_IMMUTABLE
388 - | (ok_to_set_time ? ATTRS_SET_NANO : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME));
389 + | (ok_to_set_time ? ATTRS_SET_NANO : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME));
391 /* move tmp file over real file */
392 if (DEBUG_GTE(RECV, 1))
393 @@ -786,7 +799,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
396 set_file_attrs(fnametmp, file, NULL, fnamecmp,
397 - ok_to_set_time ? ATTRS_SET_NANO : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME);
398 + ok_to_set_time ? ATTRS_SET_NANO : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME);
400 if (temp_copy_name) {
401 if (do_rename(fnametmp, fname) < 0) {
402 diff --git a/rsync.h b/rsync.h
406 /* The following XMIT flags require an rsync that uses a varint for the flag values */
408 #define XMIT_SAME_FLAGS (1<<16) /* any protocol - restricted by command-line option */
409 -#define XMIT_RESERVED_17 (1<<17) /* reserved for future crtimes use */
410 +#define XMIT_CRTIME_EQ_MTIME (1<<17) /* any protocol - restricted by command-line option */
412 /* These flags are used in the live flist data. */
415 #define ATTRS_SET_NANO (1<<2)
416 #define ATTRS_SKIP_ATIME (1<<3)
417 #define ATTRS_DELAY_IMMUTABLE (1<<4)
418 +#define ATTRS_SKIP_CRTIME (1<<5)
421 #define NORMAL_FLUSH 0
423 #define ITEM_REPORT_ACL (1<<7)
424 #define ITEM_REPORT_XATTR (1<<8)
425 #define ITEM_REPORT_FFLAGS (1<<9)
426 +#define ITEM_REPORT_CRTIME (1<<10)
427 #define ITEM_BASIS_TYPE_FOLLOWS (1<<11)
428 #define ITEM_XNAME_FOLLOWS (1<<12)
429 #define ITEM_IS_NEW (1<<13)
430 @@ -567,6 +569,10 @@ typedef unsigned int size_t;
431 #define ST_FLAGS(st) NO_FFLAGS
434 +#ifdef HAVE_GETATTRLIST
435 +#define SUPPORT_CRTIMES 1
438 /* Find a variable that is either exactly 32-bits or longer.
439 * If some code depends on 32-bit truncation, it will need to
440 * take special action in a "#if SIZEOF_INT32 > 4" section. */
441 @@ -773,6 +779,7 @@ struct file_struct {
442 extern int file_extra_cnt;
443 extern int inc_recurse;
444 extern int atimes_ndx;
445 +extern int crtimes_ndx;
446 extern int pathname_ndx;
447 extern int depth_ndx;
449 @@ -837,6 +844,7 @@ extern int xattrs_ndx;
450 #define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
451 #define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num
452 #define F_ATIME(f) REQ_EXTRA64(f, atimes_ndx)->num
453 +#define F_CRTIME(f) REQ_EXTRA64(f, crtimes_ndx)->num
455 /* These items are per-entry optional: */
456 #define F_HL_GNUM(f) OPT_EXTRA(f, START_BUMP(f))->num /* non-dirs */
457 @@ -1079,6 +1087,7 @@ typedef struct {
463 struct rsync_acl *acc_acl; /* access ACL */
464 struct rsync_acl *def_acl; /* default ACL */
465 diff --git a/rsync.yo b/rsync.yo
468 @@ -381,6 +381,7 @@ to the detailed description below for a complete description. verb(
469 -t, --times preserve modification times
470 -U, --atimes preserve access (use) times
471 --open-noatime avoid changing the atime on opened files
472 + -N, --crtimes preserve create times (newness)
473 -O, --omit-dir-times omit directories from --times
474 -J, --omit-link-times omit symlinks from --times
475 --super receiver attempts super-user activities
476 @@ -1289,6 +1290,9 @@ flag then rsync will silently ignore this option. Note also that some
477 filesystems are mounted to avoid updating the atime on read access even
478 without the O_NOATIME flag being set.
480 +dit(bf(-N, --crtimes)) This tells rsync to set the create times (newness) of
481 +the destination files to the same value as the source files.
483 dit(bf(-O, --omit-dir-times)) This tells rsync to omit directories when
484 it is preserving modification times (see bf(--times)). If NFS is sharing
485 the directories on the receiving side, it is a good idea to use bf(-O).
486 @@ -2261,7 +2265,7 @@ with older versions of rsync, but that also turns on the output of other
489 The "%i" escape has a cryptic output that is 11 letters long. The general
490 -format is like the string bf(YXcstpogfax), where bf(Y) is replaced by the
491 +format is like the string bf(YXcstpogfaxn), where bf(Y) is replaced by the
492 type of update being done, bf(X) is replaced by the file-type, and the
493 other letters represent attributes that may be output if they are being
495 @@ -2323,6 +2327,8 @@ quote(itemization(
496 when a symlink or directory is updated.
497 it() The bf(a) means that the ACL information changed.
498 it() The bf(x) means that the extended attribute information changed.
499 + it() A bf(n) means the create time (newness) is different and is being
500 + updated to the sender's value (requires bf(--crtimes)).
503 One other output is possible: when deleting files, the "%i" will output
504 diff --git a/syscall.c b/syscall.c
507 @@ -55,6 +55,13 @@ extern int open_noatime;
511 +#pragma pack(push, 4)
512 +struct create_time {
514 + struct timespec crtime;
518 #define RETURN_ERROR_IF(x,e) \
521 @@ -493,6 +500,40 @@ int do_setattrlist_times(const char *fname, STRUCT_STAT *stp)
525 +#ifdef SUPPORT_CRTIMES
526 +time_t get_create_time(const char *path)
528 + static struct create_time attrBuf;
529 + struct attrlist attrList;
531 + memset(&attrList, 0, sizeof attrList);
532 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
533 + attrList.commonattr = ATTR_CMN_CRTIME;
534 + if (getattrlist(path, &attrList, &attrBuf, sizeof attrBuf, FSOPT_NOFOLLOW) < 0)
536 + return attrBuf.crtime.tv_sec;
540 +#ifdef SUPPORT_CRTIMES
541 +int set_create_time(const char *path, time_t crtime)
543 + struct attrlist attrList;
544 + struct timespec ts;
546 + if (dry_run) return 0;
547 + RETURN_ERROR_IF_RO_OR_LO;
549 + ts.tv_sec = crtime;
552 + memset(&attrList, 0, sizeof attrList);
553 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
554 + attrList.commonattr = ATTR_CMN_CRTIME;
555 + return setattrlist(path, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW);
559 #ifdef HAVE_UTIMENSAT
560 int do_utimensat(const char *fname, STRUCT_STAT *stp)
562 diff --git a/testsuite/crtimes.test b/testsuite/crtimes.test
565 +++ b/testsuite/crtimes.test
569 +# Test rsync copying create times
571 +. "$suitedir/rsync.fns"
573 +$RSYNC --version | grep " crtimes" >/dev/null || test_skipped "Rsync is configured without crtimes support"
575 +# Setting an older time via touch sets the create time to the mtime.
576 +# Setting it to a newer time affects just the mtime.
579 +echo hiho "$fromdir/foo"
581 +touch -t 200101011111.11 "$fromdir"
582 +touch -t 200202022222.22 "$fromdir"
584 +touch -t 200111111111.11 "$fromdir/foo"
585 +touch -t 200212122222.22 "$fromdir/foo"
589 +checkit "$RSYNC -rtgvvv --crtimes \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
591 +# The script would have aborted on error, so getting here means we've won.
593 diff --git a/testsuite/rsync.fns b/testsuite/rsync.fns
594 --- a/testsuite/rsync.fns
595 +++ b/testsuite/rsync.fns
596 @@ -23,9 +23,9 @@ todir="$tmpdir/to"
599 # For itemized output:
600 -all_plus='++++++++++'
602 -dots='......' # trailing dots after changes
603 +all_plus='+++++++++++'
605 +dots='.......' # trailing dots after changes
606 tab_ch=' ' # a single tab character
609 diff --git a/tls.c b/tls.c
612 @@ -108,6 +108,9 @@ static int stat_xattr(const char *fname, STRUCT_STAT *fst)
615 static int display_atimes = 0;
616 +#ifdef SUPPORT_CRTIMES
617 +static int display_crtimes = 0;
620 static void failed(char const *what, char const *where)
622 @@ -143,14 +146,22 @@ static void storetime(char *dest, size_t destsize, time_t t, int nsecs)
623 static void list_file(const char *fname)
626 +#ifdef SUPPORT_CRTIMES
629 char permbuf[PERMSTRING_SIZE];
632 + char crtimebuf[50];
636 if (do_lstat(fname, &buf) < 0)
637 failed("stat", fname);
638 +#ifdef SUPPORT_CRTIMES
639 + if (display_crtimes && (crtime = get_create_time(fname)) == 0)
640 + failed("get_create_time", fname);
642 #ifdef SUPPORT_XATTRS
644 stat_xattr(fname, &buf);
645 @@ -195,6 +206,12 @@ static void list_file(const char *fname)
646 storetime(atimebuf, sizeof atimebuf, S_ISDIR(buf.st_mode) ? 0 : buf.st_atime, -1);
649 +#ifdef SUPPORT_CRTIMES
650 + if (display_crtimes)
651 + storetime(crtimebuf, sizeof crtimebuf, crtime, -1);
654 + crtimebuf[0] = '\0';
656 /* TODO: Perhaps escape special characters in fname? */
657 printf("%s ", permbuf);
658 @@ -206,14 +223,17 @@ static void list_file(const char *fname)
660 printf("%15s", do_big_num(buf.st_size, 1, NULL));
662 - printf(" %6ld.%-6ld %6ld%s%s %s%s\n",
663 + printf(" %6ld.%-6ld %6ld%s%s%s %s%s\n",
664 (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
665 - mtimebuf, atimebuf, fname, linkbuf);
666 + mtimebuf, atimebuf, crtimebuf, fname, linkbuf);
669 static struct poptOption long_options[] = {
670 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
671 {"atimes", 'U', POPT_ARG_NONE, &display_atimes, 0, 0, 0},
672 +#ifdef SUPPORT_CRTIMES
673 + {"crtimes", 'N', POPT_ARG_NONE, &display_crtimes, 0, 0, 0},
675 {"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 },
676 {"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 },
677 #ifdef SUPPORT_XATTRS
678 @@ -233,6 +253,9 @@ static void NORETURN tls_usage(int ret)
679 fprintf(F,"Trivial file listing program for portably checking rsync\n");
680 fprintf(F,"\nOptions:\n");
681 fprintf(F," -U, --atimes display access (last-used) times\n");
682 +#ifdef SUPPORT_CRTIMES
683 + fprintf(F," -N, --crtimes display create times (newness)\n");
685 fprintf(F," -l, --link-times display the time on a symlink\n");
686 fprintf(F," -L, --link-owner display the owner+group on a symlink\n");
687 #ifdef SUPPORT_XATTRS