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
12 based-on: patch/master/fileflags
13 diff --git a/compat.c b/compat.c
16 @@ -47,6 +47,7 @@ extern int force_change;
17 extern int protect_args;
18 extern int preserve_uid;
19 extern int preserve_gid;
20 +extern int preserve_crtimes;
21 extern int preserve_fileflags;
22 extern int preserve_acls;
23 extern int preserve_xattrs;
24 @@ -65,7 +66,7 @@ extern char *iconv_opt;
27 /* These index values are for the file-list's extra-attribute array. */
28 -int uid_ndx, gid_ndx, fileflags_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
29 +int uid_ndx, gid_ndx, crtimes_ndx, fileflags_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
31 int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
32 int sender_symlink_iconv = 0; /* sender should convert symlink content */
33 @@ -142,6 +143,8 @@ void setup_protocol(int f_out,int f_in)
34 uid_ndx = ++file_extra_cnt;
36 gid_ndx = ++file_extra_cnt;
37 + if (preserve_crtimes)
38 + crtimes_ndx = (file_extra_cnt += TIME_EXTRA_CNT);
39 if (preserve_fileflags || (force_change && !am_sender))
40 fileflags_ndx = ++file_extra_cnt;
41 if (preserve_acls && !am_sender)
42 diff --git a/flist.c b/flist.c
45 @@ -54,6 +54,7 @@ extern int preserve_fileflags;
46 extern int delete_during;
47 extern int missing_args;
49 +extern int crtimes_ndx;
50 extern int relative_paths;
51 extern int implied_dirs;
52 extern int ignore_perishable;
53 @@ -397,7 +398,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
55 int ndx, int first_ndx)
57 - static time_t modtime;
58 + static time_t modtime, crtime;
60 #ifdef SUPPORT_FILEFLAGS
61 static uint32 fileflags;
62 @@ -508,6 +509,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
63 modtime = file->modtime;
64 if (NSEC_BUMP(file) && protocol_version >= 31)
65 xflags |= XMIT_MOD_NSEC;
67 + time_t file_crtime = f_crtime(file);
68 + if (file_crtime == modtime)
69 + xflags |= XMIT_CRTIME_EQ_MTIME;
71 + crtime = file_crtime;
74 #ifdef SUPPORT_HARD_LINKS
76 @@ -592,6 +600,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
78 if (xflags & XMIT_MOD_NSEC)
79 write_varint(f, F_MOD_NSEC(file));
80 + if (crtimes_ndx && !(xflags & XMIT_CRTIME_EQ_MTIME))
81 + write_varlong(f, crtime, 4);
82 if (!(xflags & XMIT_SAME_MODE))
83 write_int(f, to_wire_mode(mode));
84 #ifdef SUPPORT_FILEFLAGS
85 @@ -685,7 +695,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
87 static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
89 - static int64 modtime;
90 + static int64 modtime, crtime;
92 #ifdef SUPPORT_FILEFLAGS
93 static uint32 fileflags;
94 @@ -834,6 +844,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
95 modtime_nsec = read_varint(f);
99 + if (!(xflags & XMIT_CRTIME_EQ_MTIME)) {
100 + crtime = read_varlong(f, 4);
101 +#if SIZEOF_TIME_T < SIZEOF_INT64
102 + if (!am_generator && (int64)(time_t)crtime != crtime) {
103 + rprintf(FERROR_XFER,
104 + "Create time value of %s truncated on receiver.\n",
111 if (!(xflags & XMIT_SAME_MODE))
112 mode = from_wire_mode(read_int(f));
114 @@ -1004,6 +1027,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
116 file->flags |= gid_flags;
119 + f_crtime_set(file, (time_t)crtime);
121 F_NDX(file) = flist->used + flist->ndx_start;
123 @@ -1405,6 +1430,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
124 F_GROUP(file) = st.st_gid;
125 if (am_generator && st.st_uid == our_uid)
126 file->flags |= FLAG_OWNED_BY_US;
128 + f_crtime_set(file, get_create_time(fname));
130 if (basename != thisname)
131 file->dirname = lastdir;
132 diff --git a/generator.c b/generator.c
135 @@ -40,6 +40,7 @@ extern int preserve_xattrs;
136 extern int preserve_links;
137 extern int preserve_devices;
138 extern int preserve_specials;
139 +extern int preserve_fileflags;
140 extern int preserve_hard_links;
141 extern int preserve_executability;
142 extern int preserve_fileflags;
143 @@ -379,8 +380,15 @@ static void do_delete_pass(void)
144 rprintf(FINFO, " \r");
147 -static inline int time_differs(struct file_struct *file, stat_x *sxp)
148 +static inline int time_differs(struct file_struct *file, stat_x *sxp, const char *fname)
151 + if (sxp->crtime == 0)
152 + sxp->crtime = get_create_time(fname);
153 + if (cmp_time(sxp->crtime, f_crtime(file)) != 0)
157 return cmp_time(sxp->st.st_mtime, file->modtime);
160 @@ -438,7 +446,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
162 if (S_ISLNK(file->mode)) {
163 #ifdef CAN_SET_SYMLINK_TIMES
164 - if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
165 + if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp, fname))
168 #ifdef CAN_CHMOD_SYMLINK
169 @@ -458,7 +466,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
173 - if (preserve_times && time_differs(file, sxp))
174 + if (preserve_times && time_differs(file, sxp, fname))
176 if (perms_differ(file, sxp))
178 @@ -501,6 +509,12 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
179 : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
180 && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
181 iflags |= ITEM_REPORT_TIME;
183 + if (sxp->crtime == 0)
184 + sxp->crtime = get_create_time(fnamecmp);
185 + if (cmp_time(sxp->crtime, f_crtime(file)) != 0)
186 + iflags |= ITEM_REPORT_CRTIME;
188 #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
189 if (S_ISLNK(file->mode)) {
191 @@ -1076,6 +1090,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
192 static void list_file_entry(struct file_struct *f)
194 char permbuf[PERMSTRING_SIZE];
195 + time_t crtime = crtimes_ndx ? f_crtime(f) : 0;
197 int colwidth = human_readable ? 14 : 11;
199 @@ -1091,10 +1106,11 @@ static void list_file_entry(struct file_struct *f)
202 if (preserve_links && S_ISLNK(f->mode)) {
203 - rprintf(FINFO, "%s %*s %s %s -> %s\n",
204 + rprintf(FINFO, "%s %*s %s %s %s -> %s\n",
205 permbuf, colwidth, human_num(len),
206 - timestring(f->modtime), f_name(f, NULL),
208 + timestring(f->modtime),
209 + crtimes_ndx ? timestring(crtime) : "",
210 + f_name(f, NULL), F_SYMLINK(f));
213 if (missing_args == 2 && f->mode == 0) {
214 @@ -1102,9 +1118,11 @@ static void list_file_entry(struct file_struct *f)
215 colwidth + 31, "*missing",
218 - rprintf(FINFO, "%s %*s %s %s\n",
219 + rprintf(FINFO, "%s %*s %s %s %s\n",
220 permbuf, colwidth, human_num(len),
221 - timestring(f->modtime), f_name(f, NULL));
222 + timestring(f->modtime),
223 + crtimes_ndx ? timestring(crtime) : "",
228 @@ -1196,6 +1214,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
234 if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
235 parent_is_dry_missing:
236 diff --git a/ifuncs.h b/ifuncs.h
239 @@ -43,6 +43,28 @@ free_xbuf(xbuf *xb)
240 memset(xb, 0, sizeof (xbuf));
243 +static inline time_t
244 +f_crtime(struct file_struct *fp)
246 +#if SIZEOF_TIME_T > 4
248 + memcpy(&crtime, &REQ_EXTRA(fp, crtimes_ndx)->unum, SIZEOF_TIME_T);
251 + return REQ_EXTRA(fp, crtimes_ndx)->unum;
256 +f_crtime_set(struct file_struct *fp, time_t crtime)
258 +#if SIZEOF_TIME_T > 4
259 + memcpy(&REQ_EXTRA(fp, crtimes_ndx)->unum, &crtime, SIZEOF_TIME_T);
261 + REQ_EXTRA(fp, crtimes_ndx)->unum = (uint32)crtime;
266 to_wire_mode(mode_t mode)
268 diff --git a/log.c b/log.c
271 @@ -732,7 +732,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
272 c[8] = !(iflags & ITEM_REPORT_FFLAGS) ? '.' : 'f';
273 c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
274 c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
276 + c[11] = !(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 @@ -60,6 +60,7 @@ int preserve_specials = 0;
285 int preserve_uid = 0;
286 int preserve_gid = 0;
287 int preserve_times = 0;
288 +int preserve_crtimes = 0;
292 @@ -714,6 +715,7 @@ void usage(enum logcode F)
293 rprintf(F," --specials preserve special files\n");
294 rprintf(F," -D same as --devices --specials\n");
295 rprintf(F," -t, --times preserve modification times\n");
296 + rprintf(F," -N, --crtimes preserve create times (newness)\n");
297 rprintf(F," -O, --omit-dir-times omit directories from --times\n");
298 rprintf(F," -J, --omit-link-times omit symlinks from --times\n");
299 rprintf(F," --super receiver attempts super-user activities\n");
300 @@ -877,6 +879,9 @@ static struct poptOption long_options[] = {
301 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
302 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
303 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
304 + {"crtimes", 'N', POPT_ARG_VAL, &preserve_crtimes, 1, 0, 0 },
305 + {"no-crtimes", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
306 + {"no-N", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
307 {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 },
308 {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
309 {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
310 @@ -2394,6 +2399,8 @@ void server_options(char **args, int *argc_p)
314 + if (preserve_crtimes)
318 else if (preserve_executability && am_sender)
319 diff --git a/rsync.c b/rsync.c
322 @@ -525,6 +525,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
323 || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
324 || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
325 flags |= ATTRS_SKIP_MTIME;
326 + /* Don't set the creation date on the root folder of an HFS+ volume. */
327 + if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode))
328 + flags |= ATTRS_SKIP_CRTIME;
329 if (!(flags & ATTRS_SKIP_MTIME)
330 && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
331 int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode, ST_FLAGS(sxp->st));
332 @@ -538,6 +541,14 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
334 file->flags |= FLAG_TIME_FAILED;
336 + if (crtimes_ndx && !(flags & ATTRS_SKIP_CRTIME)) {
337 + time_t file_crtime = f_crtime(file);
338 + if (sxp->crtime == 0)
339 + sxp->crtime = get_create_time(fname);
340 + if (cmp_time(sxp->crtime, file_crtime) != 0
341 + && set_create_time(fname, file_crtime) == 0)
345 change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
346 change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
347 @@ -691,7 +702,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
348 /* Change permissions before putting the file into place. */
349 set_file_attrs(fnametmp, file, NULL, fnamecmp,
350 ATTRS_DELAY_IMMUTABLE
351 - | (ok_to_set_time ? 0 : ATTRS_SKIP_MTIME));
352 + | (ok_to_set_time ? 0 : ATTRS_SKIP_MTIME | ATTRS_SKIP_CRTIME));
354 /* move tmp file over real file */
355 if (DEBUG_GTE(RECV, 1))
356 @@ -720,7 +731,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
359 set_file_attrs(fnametmp, file, NULL, fnamecmp,
360 - ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
361 + ok_to_set_time ? 0 : ATTRS_SKIP_MTIME | ATTRS_SKIP_CRTIME);
363 if (temp_copy_name) {
364 if (do_rename(fnametmp, fname) < 0) {
365 diff --git a/rsync.h b/rsync.h
369 #define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */
370 #define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */
371 #define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */
372 -#define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */
373 +#define XMIT_CRTIME_EQ_MTIME (1<<14) /* protocols ?? - now */
374 +#define XMIT_SAME_FLAGS (1<<15) /* protocols ?? - now */
376 /* These flags are used in the live flist data. */
379 #define ATTRS_REPORT (1<<0)
380 #define ATTRS_SKIP_MTIME (1<<1)
381 #define ATTRS_DELAY_IMMUTABLE (1<<2)
382 +#define ATTRS_SKIP_CRTIME (1<<3)
385 #define NORMAL_FLUSH 0
387 #define FNAMECMP_FUZZY 0x83
389 /* For use by the itemize_changes code */
390 -#define ITEM_REPORT_ATIME (1<<0)
391 +#define ITEM_REPORT_CRTIME (1<<0)
392 #define ITEM_REPORT_CHANGE (1<<1)
393 #define ITEM_REPORT_SIZE (1<<2) /* regular files only */
394 #define ITEM_REPORT_TIMEFAIL (1<<2) /* symlinks only */
395 @@ -733,6 +735,7 @@ extern int file_extra_cnt;
396 extern int inc_recurse;
399 +extern int crtimes_ndx;
400 extern int fileflags_ndx;
402 extern int xattrs_ndx;
403 @@ -740,6 +743,7 @@ extern int xattrs_ndx;
404 #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename))
405 #define EXTRA_LEN (sizeof (union file_extras))
406 #define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN)
407 +#define TIME_EXTRA_CNT ((SIZEOF_TIME_T + EXTRA_LEN - 1) / EXTRA_LEN)
408 #define DEV_EXTRA_CNT 2
409 #define DIRNODE_EXTRA_CNT 3
410 #define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN)
411 @@ -1019,6 +1023,7 @@ typedef struct {
417 struct rsync_acl *acc_acl; /* access ACL */
418 struct rsync_acl *def_acl; /* default ACL */
419 diff --git a/rsync.yo b/rsync.yo
422 @@ -370,6 +370,7 @@ to the detailed description below for a complete description. verb(
423 --specials preserve special files
424 -D same as --devices --specials
425 -t, --times preserve modification times
426 + -N, --crtimes preserve create times (newness)
427 -O, --omit-dir-times omit directories from --times
428 -J, --omit-link-times omit symlinks from --times
429 --super receiver attempts super-user activities
430 @@ -1184,6 +1185,9 @@ cause the next transfer to behave as if it used bf(-I), causing all files to be
431 updated (though rsync's delta-transfer algorithm will make the update fairly efficient
432 if the files haven't actually changed, you're much better off using bf(-t)).
434 +dit(bf(-N, --crtimes)) This tells rsync to set the create times (newness) of
435 +the destination files to the same value as the source files.
437 dit(bf(-O, --omit-dir-times)) This tells rsync to omit directories when
438 it is preserving modification times (see bf(--times)). If NFS is sharing
439 the directories on the receiving side, it is a good idea to use bf(-O).
440 @@ -2035,7 +2039,7 @@ with older versions of rsync, but that also turns on the output of other
443 The "%i" escape has a cryptic output that is 11 letters long. The general
444 -format is like the string bf(YXcstpogfax), where bf(Y) is replaced by the
445 +format is like the string bf(YXcstpogfaxn), where bf(Y) is replaced by the
446 type of update being done, bf(X) is replaced by the file-type, and the
447 other letters represent attributes that may be output if they are being
449 @@ -2094,6 +2098,8 @@ quote(itemization(
450 it() The bf(f) means that the fileflags information changed.
451 it() The bf(a) means that the ACL information changed.
452 it() The bf(x) means that the extended attribute information changed.
453 + it() A bf(n) means the create time (newness) is different and is being
454 + updated to the sender's value (requires bf(--crtimes)).
457 One other output is possible: when deleting files, the "%i" will output
458 diff --git a/syscall.c b/syscall.c
461 @@ -42,6 +42,13 @@ extern int force_change;
462 extern int preserve_perms;
463 extern int preserve_executability;
465 +#pragma pack(push, 4)
466 +struct create_time {
468 + struct timespec crtime;
472 #define RETURN_ERROR_IF(x,e) \
475 @@ -460,6 +467,36 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
479 +time_t get_create_time(const char *path)
481 + static struct create_time attrBuf;
482 + struct attrlist attrList;
484 + memset(&attrList, 0, sizeof attrList);
485 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
486 + attrList.commonattr = ATTR_CMN_CRTIME;
487 + if (getattrlist(path, &attrList, &attrBuf, sizeof attrBuf, FSOPT_NOFOLLOW) < 0)
489 + return attrBuf.crtime.tv_sec;
492 +int set_create_time(const char *path, time_t crtime)
494 + struct attrlist attrList;
495 + struct timespec ts;
497 + if (dry_run) return 0;
498 + RETURN_ERROR_IF_RO_OR_LO;
500 + ts.tv_sec = crtime;
503 + memset(&attrList, 0, sizeof attrList);
504 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
505 + attrList.commonattr = ATTR_CMN_CRTIME;
506 + return setattrlist(path, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW);
509 #ifdef HAVE_UTIMENSAT
510 int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec)
512 diff --git a/testsuite/crtimes.test b/testsuite/crtimes.test
515 +++ b/testsuite/crtimes.test
519 +# Test rsync copying create times
521 +. "$suitedir/rsync.fns"
523 +# Setting an older time via touch sets the create time to the mtime.
524 +# Setting it to a newer time affects just the mtime.
527 +echo hiho "$fromdir/foo"
529 +touch -t 200101011111.11 "$fromdir"
530 +touch -t 200202022222.22 "$fromdir"
532 +touch -t 200111111111.11 "$fromdir/foo"
533 +touch -t 200212122222.22 "$fromdir/foo"
537 +checkit "$RSYNC -rtgvvv --crtimes \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
539 +# The script would have aborted on error, so getting here means we've won.
541 diff --git a/testsuite/rsync.fns b/testsuite/rsync.fns
542 --- a/testsuite/rsync.fns
543 +++ b/testsuite/rsync.fns
544 @@ -23,9 +23,9 @@ todir="$tmpdir/to"
547 # For itemized output:
548 -all_plus='+++++++++'
550 -dots='.....' # trailing dots after changes
551 +all_plus='++++++++++'
553 +dots='......' # trailing dots after changes
554 tab_ch=' ' # a single tab character
557 diff --git a/tls.c b/tls.c
560 @@ -110,6 +110,8 @@ static int stat_xattr(const char *fname, STRUCT_STAT *fst)
564 +static int display_crtimes = 0;
566 static void failed(char const *what, char const *where)
568 fprintf(stderr, PROGRAM ": %s %s: %s\n",
569 @@ -117,16 +119,44 @@ static void failed(char const *what, char const *where)
573 +static void storetime(char *dest, size_t destsize, time_t t, int nsecs)
577 + struct tm *mt = gmtime(&t);
579 + len = snprintf(dest, destsize,
580 + "%04d-%02d-%02d %02d:%02d:%02d",
581 + (int)mt->tm_year + 1900,
582 + (int)mt->tm_mon + 1,
588 + snprintf(datebuf + len, sizeof datebuf - len, ".%09d", nsecs);
591 + int has_nsecs = nsecs >= 0 ? 1 : 0;
592 + int len = MIN(19 + 9*nsec_times, (int)sizeof datebuf - 1);
593 + memset(datebuf, ' ', len);
594 + datebuf[len] = '\0';
598 static void list_file(const char *fname)
602 char permbuf[PERMSTRING_SIZE];
606 + char crtimebuf[50];
609 if (do_lstat(fname, &buf) < 0)
610 failed("stat", fname);
611 + if (display_crtimes && (crtime = get_create_time(fname)) == 0)
612 + failed("get_create_time", fname);
613 #ifdef SUPPORT_XATTRS
615 stat_xattr(fname, &buf);
616 @@ -161,29 +191,11 @@ static void list_file(const char *fname)
618 permstring(permbuf, buf.st_mode);
620 - if (buf.st_mtime) {
622 - mt = gmtime(&buf.st_mtime);
624 - len = snprintf(datebuf, sizeof datebuf,
625 - "%04d-%02d-%02d %02d:%02d:%02d",
626 - (int)mt->tm_year + 1900,
627 - (int)mt->tm_mon + 1,
632 -#ifdef ST_MTIME_NSEC
634 - snprintf(datebuf + len, sizeof datebuf - len,
635 - ".%09d", (int)buf.ST_MTIME_NSEC);
639 - int len = MIN(19 + 9*nsec_times, (int)sizeof datebuf - 1);
640 - memset(datebuf, ' ', len);
641 - datebuf[len] = '\0';
643 + storetime(mtimebuf, sizeof mtimebuf, buf.st_mtime, nsecs);
644 + if (display_crtimes)
645 + storetime(crtimebuf, sizeof crtimebuf, crtime, -1);
647 + crtimebuf[0] = '\0';
649 /* TODO: Perhaps escape special characters in fname? */
651 @@ -194,13 +206,14 @@ static void list_file(const char *fname)
652 (long)minor(buf.st_rdev));
654 printf("%15s", do_big_num(buf.st_size, 1, NULL));
655 - printf(" %6ld.%-6ld %6ld %s %s%s\n",
656 + printf(" %6ld.%-6ld %6ld %s%s%s%s\n",
657 (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
658 - datebuf, fname, linkbuf);
659 + mtimebuf, crtimebuf, fname, linkbuf);
662 static struct poptOption long_options[] = {
663 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
664 + {"crtimes", 'N', POPT_ARG_NONE, &display_crtimes, 0, 0, 0},
665 {"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 },
666 {"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 },
667 #ifdef SUPPORT_XATTRS
668 @@ -219,6 +232,7 @@ static void tls_usage(int ret)
669 fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n");
670 fprintf(F,"Trivial file listing program for portably checking rsync\n");
671 fprintf(F,"\nOptions:\n");
672 + fprintf(F," -N, --crtimes display create times (newness)\n");
673 fprintf(F," -l, --link-times display the time on a symlink\n");
674 fprintf(F," -L, --link-owner display the owner+group on a symlink\n");
675 #ifdef SUPPORT_XATTRS