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 @@ -43,6 +43,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 @@ -76,7 +77,7 @@ int inplace_partial = 0;
24 int do_negotiated_strings = 0;
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 @@ -505,6 +506,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 @@ -670,6 +673,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 @@ -378,6 +379,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 @@ -494,6 +498,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 @@ -581,6 +592,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 @@ -677,6 +692,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 @@ -790,6 +808,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 @@ -830,6 +852,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 @@ -1019,6 +1056,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 @@ -1420,6 +1461,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 @@ -398,6 +399,19 @@ static inline int mtime_differs(STRUCT_STAT *stp, struct file_struct *file)
178 +static inline int any_time_differs(stat_x *sxp, struct file_struct *file, UNUSED(const char *fname))
180 + int differs = mtime_differs(&sxp->st, file);
181 +#ifdef SUPPORT_CRTIMES
182 + if (!differs && crtimes_ndx) {
183 + if (sxp->crtime == 0)
184 + sxp->crtime = get_create_time(fname);
185 + differs = !same_time(sxp->crtime, 0, F_CRTIME(file), 0);
191 static inline int perms_differ(struct file_struct *file, stat_x *sxp)
194 @@ -452,7 +466,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 && mtime_differs(&sxp->st, file))
199 + if (preserve_times & PRESERVE_LINK_TIMES && any_time_differs(sxp, file, fname))
202 #ifdef CAN_CHMOD_SYMLINK
203 @@ -472,7 +486,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
207 - if (preserve_times && mtime_differs(&sxp->st, file))
208 + if (preserve_times && any_time_differs(sxp, file, fname))
210 if (perms_differ(file, sxp))
212 @@ -518,6 +532,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 && !same_time(F_ATIME(file), 0, sxp->st.st_atime, 0))
215 iflags |= ITEM_REPORT_ATIME;
216 +#ifdef SUPPORT_CRTIMES
218 + if (sxp->crtime == 0)
219 + sxp->crtime = get_create_time(fnamecmp);
220 + if (!same_time(sxp->crtime, 0, F_CRTIME(file), 0))
221 + iflags |= ITEM_REPORT_CRTIME;
224 #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
225 if (S_ISLNK(file->mode)) {
227 @@ -1142,6 +1164,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 @@ -1152,10 +1175,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 @@ -1168,9 +1192,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 @@ -1266,6 +1290,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 @@ -721,7 +721,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 @@ -668,6 +669,11 @@ static void print_capabilities(enum logcode f)
296 +#ifndef SUPPORT_CRTIMES
301 "*" /* All options after this point are hidden w/o -V -V */
304 @@ -846,6 +852,9 @@ static struct poptOption long_options[] = {
305 {"no-U", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 },
306 {"open-noatime", 0, POPT_ARG_VAL, &open_noatime, 1, 0, 0 },
307 {"no-open-noatime", 0, POPT_ARG_VAL, &open_noatime, 0, 0, 0 },
308 + {"crtimes", 'N', POPT_ARG_VAL, &preserve_crtimes, 1, 0, 0 },
309 + {"no-crtimes", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
310 + {"no-N", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
311 {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 },
312 {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
313 {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
314 @@ -1227,6 +1236,9 @@ static void set_refuse_options(void)
315 parse_one_refuse_match(0, "force-uchange", list_end);
316 parse_one_refuse_match(0, "force-schange", list_end);
318 +#ifndef SUPPORT_CRTIMES
319 + parse_one_refuse_match(0, "crtimes", list_end);
322 /* Now we use the descrip values to actually mark the options for refusal. */
323 for (op = long_options; op != list_end; op++) {
324 @@ -2570,6 +2582,10 @@ void server_options(char **args, int *argc_p)
325 if (preserve_atimes > 1)
328 +#ifdef SUPPORT_CRTIMES
329 + if (preserve_crtimes)
334 else if (preserve_executability && am_sender)
335 diff --git a/rsync.1.md b/rsync.1.md
338 @@ -373,6 +373,7 @@ detailed description below for a complete description.
339 --times, -t preserve modification times
340 --atimes, -U preserve access (use) times
341 --open-noatime avoid changing the atime on opened files
342 +--crtimes, -N preserve create times (newness)
343 --omit-dir-times, -O omit directories from --times
344 --omit-link-times, -J omit symlinks from --times
345 --super receiver attempts super-user activities
346 @@ -1371,6 +1372,11 @@ your home directory (remove the '=' for that).
347 mounted to avoid updating the atime on read access even without the
348 O_NOATIME flag being set.
350 +0. `--crtimes`, `-N,`
352 + This tells rsync to set the create times (newness) of +the destination
353 + files to the same value as the source files.
355 0. `--omit-dir-times`, `-O`
357 This tells rsync to omit directories when it is preserving modification
358 @@ -2633,7 +2639,7 @@ your home directory (remove the '=' for that).
359 output of other verbose messages).
361 The "%i" escape has a cryptic output that is 11 letters long. The general
362 - format is like the string `YXcstpoguaxf`, where **Y** is replaced by the type
363 + format is like the string `YXcstpoguaxfn`, where **Y** is replaced by the type
364 of update being done, **X** is replaced by the file-type, and the other
365 letters represent attributes that may be output if they are being modified.
367 @@ -2690,6 +2696,8 @@ your home directory (remove the '=' for that).
368 happens when a symlink or directory is updated.
369 - The `a` means that the ACL information changed.
370 - The `x` means that the extended attribute information changed.
371 + - A `n` means the create time (newness) is different and is being updated
372 + to the sender's value (requires `--crtimes`).
374 One other output is possible: when deleting files, the "%i" will output the
375 string "`*deleting`" for each item that is being removed (assuming that you
376 diff --git a/rsync.c b/rsync.c
379 @@ -618,6 +618,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
380 memcpy(&sx2.st, &sxp->st, sizeof (sx2.st));
381 if (!atimes_ndx || S_ISDIR(sxp->st.st_mode))
382 flags |= ATTRS_SKIP_ATIME;
383 + /* Don't set the creation date on the root folder of an HFS+ volume. */
384 + if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode))
385 + flags |= ATTRS_SKIP_CRTIME;
386 if (!(flags & ATTRS_SKIP_MTIME) && !same_mtime(file, &sxp->st, flags & ATTRS_ACCURATE_TIME)) {
387 sx2.st.st_mtime = file->modtime;
389 @@ -647,6 +650,16 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
390 file->flags |= FLAG_TIME_FAILED;
393 +#ifdef SUPPORT_CRTIMES
394 + if (crtimes_ndx && !(flags & ATTRS_SKIP_CRTIME)) {
395 + time_t file_crtime = F_CRTIME(file);
396 + if (sxp->crtime == 0)
397 + sxp->crtime = get_create_time(fname);
398 + if (!same_time(sxp->crtime, 0L, file_crtime, 0L)
399 + && set_create_time(fname, file_crtime) == 0)
405 /* It's OK to call set_acl() now, even for a dir, as the generator
406 @@ -766,7 +779,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
407 /* Change permissions before putting the file into place. */
408 set_file_attrs(fnametmp, file, NULL, fnamecmp,
409 ATTRS_DELAY_IMMUTABLE
410 - | (ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME));
411 + | (ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME));
413 /* move tmp file over real file */
414 if (DEBUG_GTE(RECV, 1))
415 @@ -795,7 +808,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
418 set_file_attrs(fnametmp, file, NULL, fnamecmp,
419 - ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME);
420 + ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME);
422 if (temp_copy_name) {
423 if (do_rename(fnametmp, fname) < 0) {
424 diff --git a/rsync.h b/rsync.h
428 /* The following XMIT flags require an rsync that uses a varint for the flag values */
430 #define XMIT_SAME_FLAGS (1<<16) /* any protocol - restricted by command-line option */
431 -#define XMIT_RESERVED_17 (1<<17) /* reserved for future crtimes use */
432 +#define XMIT_CRTIME_EQ_MTIME (1<<17) /* any protocol - restricted by command-line option */
434 /* These flags are used in the live flist data. */
437 #define ATTRS_ACCURATE_TIME (1<<2)
438 #define ATTRS_SKIP_ATIME (1<<3)
439 #define ATTRS_DELAY_IMMUTABLE (1<<4)
440 +#define ATTRS_SKIP_CRTIME (1<<5)
445 #define ITEM_REPORT_ACL (1<<7)
446 #define ITEM_REPORT_XATTR (1<<8)
447 #define ITEM_REPORT_FFLAGS (1<<9)
448 +#define ITEM_REPORT_CRTIME (1<<10)
449 #define ITEM_BASIS_TYPE_FOLLOWS (1<<11)
450 #define ITEM_XNAME_FOLLOWS (1<<12)
451 #define ITEM_IS_NEW (1<<13)
452 @@ -575,6 +577,10 @@ typedef unsigned int size_t;
453 #define ST_FLAGS(st) NO_FFLAGS
456 +#ifdef HAVE_GETATTRLIST
457 +#define SUPPORT_CRTIMES 1
460 /* Find a variable that is either exactly 32-bits or longer.
461 * If some code depends on 32-bit truncation, it will need to
462 * take special action in a "#if SIZEOF_INT32 > 4" section. */
463 @@ -784,6 +790,7 @@ struct file_struct {
464 extern int file_extra_cnt;
465 extern int inc_recurse;
466 extern int atimes_ndx;
467 +extern int crtimes_ndx;
468 extern int pathname_ndx;
469 extern int depth_ndx;
471 @@ -848,6 +855,7 @@ extern int xattrs_ndx;
472 #define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
473 #define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num
474 #define F_ATIME(f) REQ_EXTRA64(f, atimes_ndx)->num
475 +#define F_CRTIME(f) REQ_EXTRA64(f, crtimes_ndx)->num
477 /* These items are per-entry optional: */
478 #define F_HL_GNUM(f) OPT_EXTRA(f, START_BUMP(f))->num /* non-dirs */
479 @@ -1090,6 +1098,7 @@ typedef struct {
485 struct rsync_acl *acc_acl; /* access ACL */
486 struct rsync_acl *def_acl; /* default ACL */
487 diff --git a/syscall.c b/syscall.c
490 @@ -55,6 +55,13 @@ extern int open_noatime;
494 +#pragma pack(push, 4)
495 +struct create_time {
497 + struct timespec crtime;
501 #define RETURN_ERROR_IF(x,e) \
504 @@ -493,6 +500,40 @@ int do_setattrlist_times(const char *fname, STRUCT_STAT *stp)
508 +#ifdef SUPPORT_CRTIMES
509 +time_t get_create_time(const char *path)
511 + static struct create_time attrBuf;
512 + struct attrlist attrList;
514 + memset(&attrList, 0, sizeof attrList);
515 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
516 + attrList.commonattr = ATTR_CMN_CRTIME;
517 + if (getattrlist(path, &attrList, &attrBuf, sizeof attrBuf, FSOPT_NOFOLLOW) < 0)
519 + return attrBuf.crtime.tv_sec;
523 +#ifdef SUPPORT_CRTIMES
524 +int set_create_time(const char *path, time_t crtime)
526 + struct attrlist attrList;
527 + struct timespec ts;
529 + if (dry_run) return 0;
530 + RETURN_ERROR_IF_RO_OR_LO;
532 + ts.tv_sec = crtime;
535 + memset(&attrList, 0, sizeof attrList);
536 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
537 + attrList.commonattr = ATTR_CMN_CRTIME;
538 + return setattrlist(path, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW);
542 #ifdef HAVE_UTIMENSAT
543 int do_utimensat(const char *fname, STRUCT_STAT *stp)
545 diff --git a/testsuite/crtimes.test b/testsuite/crtimes.test
548 +++ b/testsuite/crtimes.test
552 +# Test rsync copying create times
554 +. "$suitedir/rsync.fns"
556 +$RSYNC --version | grep " crtimes" >/dev/null || test_skipped "Rsync is configured without crtimes support"
558 +# Setting an older time via touch sets the create time to the mtime.
559 +# Setting it to a newer time affects just the mtime.
562 +echo hiho "$fromdir/foo"
564 +touch -t 200101011111.11 "$fromdir"
565 +touch -t 200202022222.22 "$fromdir"
567 +touch -t 200111111111.11 "$fromdir/foo"
568 +touch -t 200212122222.22 "$fromdir/foo"
572 +checkit "$RSYNC -rtgvvv --crtimes \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
574 +# The script would have aborted on error, so getting here means we've won.
576 diff --git a/testsuite/rsync.fns b/testsuite/rsync.fns
577 --- a/testsuite/rsync.fns
578 +++ b/testsuite/rsync.fns
579 @@ -23,9 +23,9 @@ todir="$tmpdir/to"
582 # For itemized output:
583 -all_plus='++++++++++'
585 -dots='......' # trailing dots after changes
586 +all_plus='+++++++++++'
588 +dots='.......' # trailing dots after changes
589 tab_ch=' ' # a single tab character
592 diff --git a/tls.c b/tls.c
595 @@ -108,6 +108,9 @@ static int stat_xattr(const char *fname, STRUCT_STAT *fst)
598 static int display_atimes = 0;
599 +#ifdef SUPPORT_CRTIMES
600 +static int display_crtimes = 0;
603 static void failed(char const *what, char const *where)
605 @@ -143,14 +146,22 @@ static void storetime(char *dest, size_t destsize, time_t t, int nsecs)
606 static void list_file(const char *fname)
609 +#ifdef SUPPORT_CRTIMES
612 char permbuf[PERMSTRING_SIZE];
615 + char crtimebuf[50];
619 if (do_lstat(fname, &buf) < 0)
620 failed("stat", fname);
621 +#ifdef SUPPORT_CRTIMES
622 + if (display_crtimes && (crtime = get_create_time(fname)) == 0)
623 + failed("get_create_time", fname);
625 #ifdef SUPPORT_XATTRS
627 stat_xattr(fname, &buf);
628 @@ -195,6 +206,12 @@ static void list_file(const char *fname)
629 storetime(atimebuf, sizeof atimebuf, S_ISDIR(buf.st_mode) ? 0 : buf.st_atime, -1);
632 +#ifdef SUPPORT_CRTIMES
633 + if (display_crtimes)
634 + storetime(crtimebuf, sizeof crtimebuf, crtime, -1);
637 + crtimebuf[0] = '\0';
639 /* TODO: Perhaps escape special characters in fname? */
640 printf("%s ", permbuf);
641 @@ -204,14 +221,17 @@ static void list_file(const char *fname)
643 printf("%15s", do_big_num(buf.st_size, 1, NULL));
645 - printf(" %6ld.%-6ld %6ld%s%s %s%s\n",
646 + printf(" %6ld.%-6ld %6ld%s%s%s %s%s\n",
647 (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
648 - mtimebuf, atimebuf, fname, linkbuf);
649 + mtimebuf, atimebuf, crtimebuf, fname, linkbuf);
652 static struct poptOption long_options[] = {
653 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
654 {"atimes", 'U', POPT_ARG_NONE, &display_atimes, 0, 0, 0},
655 +#ifdef SUPPORT_CRTIMES
656 + {"crtimes", 'N', POPT_ARG_NONE, &display_crtimes, 0, 0, 0},
658 {"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 },
659 {"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 },
660 #ifdef SUPPORT_XATTRS
661 @@ -231,6 +251,9 @@ static void NORETURN tls_usage(int ret)
662 fprintf(F,"Trivial file listing program for portably checking rsync\n");
663 fprintf(F,"\nOptions:\n");
664 fprintf(F," -U, --atimes display access (last-used) times\n");
665 +#ifdef SUPPORT_CRTIMES
666 + fprintf(F," -N, --crtimes display create times (newness)\n");
668 fprintf(F," -l, --link-times display the time on a symlink\n");
669 fprintf(F," -L, --link-owner display the owner+group on a symlink\n");
670 #ifdef SUPPORT_XATTRS