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/b3.0.x/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_specials;
46 extern int preserve_fileflags;
47 extern int delete_during;
49 +extern int crtimes_ndx;
50 extern int relative_paths;
51 extern int implied_dirs;
52 extern int ignore_perishable;
53 @@ -393,7 +394,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 @@ -488,6 +489,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
63 xflags |= XMIT_SAME_TIME;
65 modtime = file->modtime;
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 @@ -557,6 +565,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
78 write_int(f, modtime);
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 @@ -648,7 +658,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 @@ -758,6 +768,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
99 + crtime = f_crtime(first);
100 if (preserve_devices && IS_DEVICE(mode)) {
101 uint32 *devp = F_RDEV_P(first);
102 rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
103 @@ -786,6 +798,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
105 modtime = read_int(f);
108 + if (!(xflags & XMIT_CRTIME_EQ_MTIME)) {
109 + crtime = read_varlong(f, 4);
110 +#if SIZEOF_TIME_T < SIZEOF_INT64
111 + if (!am_generator && (int64)(time_t)crtime != crtime) {
112 + rprintf(FERROR_XFER,
113 + "Create time value of %s truncated on receiver.\n",
120 if (!(xflags & XMIT_SAME_MODE))
121 mode = from_wire_mode(read_int(f));
123 @@ -946,6 +971,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
125 file->flags |= gid_flags;
128 + f_crtime_set(file, (time_t)crtime);
130 F_NDX(file) = flist->used + flist->ndx_start;
132 @@ -1324,6 +1351,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
133 F_GROUP(file) = st.st_gid;
134 if (am_generator && st.st_uid == our_uid)
135 file->flags |= FLAG_OWNED_BY_US;
137 + f_crtime_set(file, get_create_time(fname));
139 if (basename != thisname)
140 file->dirname = lastdir;
141 diff --git a/generator.c b/generator.c
152 @@ -41,6 +42,7 @@ extern int preserve_xattrs;
153 extern int preserve_links;
154 extern int preserve_devices;
155 extern int preserve_specials;
156 +extern int preserve_fileflags;
157 extern int preserve_hard_links;
158 extern int preserve_executability;
159 extern int preserve_fileflags;
160 @@ -576,8 +578,15 @@ static void do_delete_pass(void)
161 rprintf(FINFO, " \r");
164 -static inline int time_differs(struct file_struct *file, stat_x *sxp)
165 +static inline int time_differs(struct file_struct *file, stat_x *sxp, const char *fname)
168 + if (sxp->crtime == 0)
169 + sxp->crtime = get_create_time(fname);
170 + if (cmp_time(sxp->crtime, f_crtime(file)) != 0)
174 return cmp_time(sxp->st.st_mtime, file->modtime);
177 @@ -635,7 +644,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
179 if (S_ISLNK(file->mode)) {
180 #ifdef CAN_SET_SYMLINK_TIMES
181 - if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
182 + if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp, fname))
185 #ifdef CAN_CHMOD_SYMLINK
186 @@ -655,7 +664,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)
190 - if (preserve_times && time_differs(file, sxp))
191 + if (preserve_times && time_differs(file, sxp, fname))
193 if (perms_differ(file, sxp))
195 @@ -698,6 +707,12 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
196 : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
197 && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
198 iflags |= ITEM_REPORT_TIME;
200 + if (sxp->crtime == 0)
201 + sxp->crtime = get_create_time(fnamecmp);
202 + if (cmp_time(sxp->crtime, f_crtime(file)) != 0)
203 + iflags |= ITEM_REPORT_CRTIME;
205 #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
206 if (S_ISLNK(file->mode)) {
208 @@ -1263,7 +1278,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
210 static void list_file_entry(struct file_struct *f)
212 - char permbuf[PERMSTRING_SIZE];
213 + char permbuf[PERMSTRING_SIZE], crtime_buf[32];
216 if (!F_IS_ACTIVE(f)) {
217 @@ -1274,19 +1289,24 @@ static void list_file_entry(struct file_struct *f)
218 permstring(permbuf, f->mode);
222 + snprintf(crtime_buf, sizeof crtime_buf, " %s", timestring(f_crtime(f)));
224 + *crtime_buf = '\0';
226 /* TODO: indicate '+' if the entry has an ACL. */
229 if (preserve_links && S_ISLNK(f->mode)) {
230 - rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
231 + rprintf(FINFO, "%s %11.0f %s%s %s -> %s\n",
232 permbuf, len, timestring(f->modtime),
233 - f_name(f, NULL), F_SYMLINK(f));
234 + crtime_buf, f_name(f, NULL), F_SYMLINK(f));
238 - rprintf(FINFO, "%s %11.0f %s %s\n",
239 + rprintf(FINFO, "%s %11.0f %s%s %s\n",
240 permbuf, len, timestring(f->modtime),
242 + crtime_buf, f_name(f, NULL));
246 @@ -1383,6 +1403,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
252 if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) {
253 parent_is_dry_missing:
254 diff --git a/hlink.c b/hlink.c
257 @@ -371,6 +371,7 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
258 char cmpbuf[MAXPATHLEN];
263 alt_sx.acc_acl = alt_sx.def_acl = NULL;
265 @@ -499,6 +500,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx,
269 + prev_sx.crtime = 0;
271 prev_sx.acc_acl = prev_sx.def_acl = NULL;
273 diff --git a/ifuncs.h b/ifuncs.h
276 @@ -67,6 +67,28 @@ d_name(struct dirent *di)
280 +static inline time_t
281 +f_crtime(struct file_struct *fp)
283 +#if SIZEOF_TIME_T > 4
285 + memcpy(&crtime, &REQ_EXTRA(fp, crtimes_ndx)->unum, SIZEOF_TIME_T);
288 + return REQ_EXTRA(fp, crtimes_ndx)->unum;
293 +f_crtime_set(struct file_struct *fp, time_t crtime)
295 +#if SIZEOF_TIME_T > 4
296 + memcpy(&REQ_EXTRA(fp, crtimes_ndx)->unum, &crtime, SIZEOF_TIME_T);
298 + REQ_EXTRA(fp, crtimes_ndx)->unum = (uint32)crtime;
303 isDigit(const char *ptr)
305 diff --git a/log.c b/log.c
308 @@ -661,7 +661,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
309 c[8] = !(iflags & ITEM_REPORT_FFLAGS) ? '.' : 'f';
310 c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
311 c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
313 + c[11] = !(iflags & ITEM_REPORT_CRTIME) ? '.' : 'n';
316 if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
317 char ch = iflags & ITEM_IS_NEW ? '+' : '?';
318 diff --git a/options.c b/options.c
321 @@ -60,6 +60,7 @@ int preserve_specials = 0;
322 int preserve_uid = 0;
323 int preserve_gid = 0;
324 int preserve_times = 0;
325 +int preserve_crtimes = 0;
329 @@ -361,6 +362,7 @@ void usage(enum logcode F)
330 rprintf(F," -D same as --devices --specials\n");
331 rprintf(F," -t, --times preserve modification times\n");
332 rprintf(F," -O, --omit-dir-times omit directories from --times\n");
333 + rprintf(F," -N, --crtimes preserve create times (newness)\n");
334 rprintf(F," --super receiver attempts super-user activities\n");
335 #ifdef SUPPORT_XATTRS
336 rprintf(F," --fake-super store/recover privileged attrs using xattrs\n");
337 @@ -507,6 +509,9 @@ static struct poptOption long_options[] = {
338 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
339 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
340 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
341 + {"crtimes", 'N', POPT_ARG_VAL, &preserve_crtimes, 1, 0, 0 },
342 + {"no-crtimes", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
343 + {"no-N", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
344 {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 },
345 {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
346 {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
347 @@ -1810,6 +1815,8 @@ void server_options(char **args, int *argc_p)
351 + if (preserve_crtimes)
355 else if (preserve_executability && am_sender)
356 diff --git a/rsync.c b/rsync.c
359 @@ -464,6 +464,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
365 sx2.acc_acl = sx2.def_acl = NULL;
367 @@ -505,6 +506,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
368 || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
369 || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
370 flags |= ATTRS_SKIP_MTIME;
371 + /* Don't set the creation date on the root folder of an HFS+ volume. */
372 + if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode))
373 + flags |= ATTRS_SKIP_CRTIME;
374 if (!(flags & ATTRS_SKIP_MTIME)
375 && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
376 int ret = set_modtime(fname, file->modtime, sxp->st.st_mode, ST_FLAGS(sxp->st));
377 @@ -518,6 +522,14 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
379 file->flags |= FLAG_TIME_FAILED;
381 + if (crtimes_ndx && !(flags & ATTRS_SKIP_CRTIME)) {
382 + time_t file_crtime = f_crtime(file);
383 + if (sxp->crtime == 0)
384 + sxp->crtime = get_create_time(fname);
385 + if (cmp_time(sxp->crtime, file_crtime) != 0
386 + && set_create_time(fname, file_crtime) == 0)
390 change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
391 change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
392 @@ -675,7 +687,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
393 /* Change permissions before putting the file into place. */
394 set_file_attrs(fnametmp, file, NULL, fnamecmp,
395 ATTRS_DELAY_IMMUTABLE
396 - | (ok_to_set_time ? 0 : ATTRS_SKIP_MTIME));
397 + | (ok_to_set_time ? 0 : ATTRS_SKIP_MTIME | ATTRS_SKIP_CRTIME));
399 /* move tmp file over real file */
401 @@ -706,7 +718,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
404 set_file_attrs(fnametmp, file, NULL, fnamecmp,
405 - ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
406 + ok_to_set_time ? 0 : ATTRS_SKIP_MTIME | ATTRS_SKIP_CRTIME);
408 if (temp_copy_name) {
409 if (do_rename(fnametmp, fname) < 0) {
410 diff --git a/rsync.h b/rsync.h
414 #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */
415 #define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */
416 #define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */
417 +#define XMIT_CRTIME_EQ_MTIME (1<<13) /* protocols ?? - now */
418 #define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */
420 /* These flags are used in the live flist data. */
422 #define ATTRS_REPORT (1<<0)
423 #define ATTRS_SKIP_MTIME (1<<1)
424 #define ATTRS_DELAY_IMMUTABLE (1<<2)
425 +#define ATTRS_SKIP_CRTIME (1<<3)
428 #define NORMAL_FLUSH 0
430 #define FNAMECMP_FUZZY 0x83
432 /* For use by the itemize_changes code */
433 -#define ITEM_REPORT_ATIME (1<<0)
434 +#define ITEM_REPORT_CRTIME (1<<0)
435 #define ITEM_REPORT_CHANGE (1<<1)
436 #define ITEM_REPORT_SIZE (1<<2) /* regular files only */
437 #define ITEM_REPORT_TIMEFAIL (1<<2) /* symlinks only */
438 @@ -677,6 +679,7 @@ extern int file_extra_cnt;
439 extern int inc_recurse;
442 +extern int crtimes_ndx;
443 extern int fileflags_ndx;
445 extern int xattrs_ndx;
446 @@ -684,6 +687,7 @@ extern int xattrs_ndx;
447 #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename))
448 #define EXTRA_LEN (sizeof (union file_extras))
449 #define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN)
450 +#define TIME_EXTRA_CNT ((SIZEOF_TIME_T + EXTRA_LEN - 1) / EXTRA_LEN)
451 #define DEV_EXTRA_CNT 2
452 #define DIRNODE_EXTRA_CNT 3
453 #define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN)
454 @@ -951,6 +955,7 @@ typedef struct {
460 struct rsync_acl *acc_acl; /* access ACL */
461 struct rsync_acl *def_acl; /* default ACL */
462 diff --git a/rsync.yo b/rsync.yo
465 @@ -367,6 +367,7 @@ to the detailed description below for a complete description. verb(
466 -D same as --devices --specials
467 -t, --times preserve modification times
468 -O, --omit-dir-times omit directories from --times
469 + -N, --crtimes preserve create times (newness)
470 --super receiver attempts super-user activities
471 --fake-super store/recover privileged attrs using xattrs
472 -S, --sparse handle sparse files efficiently
473 @@ -1105,6 +1106,9 @@ it is preserving modification times (see bf(--times)). If NFS is sharing
474 the directories on the receiving side, it is a good idea to use bf(-O).
475 This option is inferred if you use bf(--backup) without bf(--backup-dir).
477 +dit(bf(-N, --crtimes)) This tells rsync to set the create times (newness) of
478 +the destination files to the same value as the source files.
480 dit(bf(--super)) This tells the receiving side to attempt super-user
481 activities even if the receiving rsync wasn't run by the super-user. These
482 activities include: preserving users via the bf(--owner) option, preserving
483 @@ -1811,7 +1815,7 @@ with older versions of rsync, but that also turns on the output of other
486 The "%i" escape has a cryptic output that is 11 letters long. The general
487 -format is like the string bf(YXcstpogfax), where bf(Y) is replaced by the
488 +format is like the string bf(YXcstpogfaxn), where bf(Y) is replaced by the
489 type of update being done, bf(X) is replaced by the file-type, and the
490 other letters represent attributes that may be output if they are being
492 @@ -1870,6 +1874,8 @@ quote(itemization(
493 it() The bf(f) means that the fileflags information changed.
494 it() The bf(a) means that the ACL information changed.
495 it() The bf(x) means that the extended attribute information changed.
496 + it() A bf(n) means the create time (newness) is different and is being
497 + updated to the sender's value (requires bf(--crtimes)).
500 One other output is possible: when deleting files, the "%i" will output
501 diff --git a/syscall.c b/syscall.c
504 @@ -37,6 +37,13 @@ extern int force_change;
505 extern int preserve_perms;
506 extern int preserve_executability;
508 +#pragma pack(push, 4)
509 +struct create_time {
511 + struct timespec crtime;
515 #define RETURN_ERROR_IF(x,e) \
518 @@ -529,6 +536,36 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
522 +time_t get_create_time(const char *path)
524 + static struct create_time attrBuf;
525 + struct attrlist attrList;
527 + memset(&attrList, 0, sizeof attrList);
528 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
529 + attrList.commonattr = ATTR_CMN_CRTIME;
530 + if (getattrlist(path, &attrList, &attrBuf, sizeof attrBuf, FSOPT_NOFOLLOW) < 0)
532 + return attrBuf.crtime.tv_sec;
535 +int set_create_time(const char *path, time_t crtime)
537 + struct attrlist attrList;
538 + struct timespec ts;
540 + if (dry_run) return 0;
541 + RETURN_ERROR_IF_RO_OR_LO;
543 + ts.tv_sec = crtime;
546 + memset(&attrList, 0, sizeof attrList);
547 + attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
548 + attrList.commonattr = ATTR_CMN_CRTIME;
549 + return setattrlist(path, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW);
552 #ifdef HAVE_UTIMENSAT
553 int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags)
555 diff --git a/testsuite/crtimes.test b/testsuite/crtimes.test
558 +++ b/testsuite/crtimes.test
562 +# Test rsync copying create times
564 +. "$suitedir/rsync.fns"
566 +# Setting an older time via touch sets the create time to the mtime.
567 +# Setting it to a newer time affects just the mtime.
570 +echo hiho "$fromdir/foo"
572 +touch -t 200101011111.11 "$fromdir"
573 +touch -t 200202022222.22 "$fromdir"
575 +touch -t 200111111111.11 "$fromdir/foo"
576 +touch -t 200212122222.22 "$fromdir/foo"
580 +checkit "$RSYNC -rtgvvv --crtimes \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
582 +# The script would have aborted on error, so getting here means we've won.
584 diff --git a/testsuite/rsync.fns b/testsuite/rsync.fns
585 --- a/testsuite/rsync.fns
586 +++ b/testsuite/rsync.fns
587 @@ -24,9 +24,9 @@ todir="$tmpdir/to"
590 # For itemized output:
591 -all_plus='+++++++++'
593 -dots='.....' # trailing dots after changes
594 +all_plus='++++++++++'
596 +dots='......' # trailing dots after changes
597 tab_ch=' ' # a single tab character
600 diff --git a/tls.c b/tls.c
603 @@ -107,6 +107,8 @@ static int stat_xattr(const char *fname, STRUCT_STAT *fst)
607 +static int display_crtimes = 0;
609 static void failed(char const *what, char const *where)
611 fprintf(stderr, PROGRAM ": %s %s: %s\n",
612 @@ -114,16 +116,36 @@ static void failed(char const *what, char const *where)
616 +static void storetime(char *dest, time_t t, size_t destsize)
619 + struct tm *mt = gmtime(&t);
621 + snprintf(dest, destsize,
622 + "%04d-%02d-%02d %02d:%02d:%02d ",
623 + (int)mt->tm_year + 1900,
624 + (int)mt->tm_mon + 1,
630 + strlcpy(dest, " ", destsize);
633 static void list_file(const char *fname)
637 char permbuf[PERMSTRING_SIZE];
641 + char crtimebuf[50];
644 if (do_lstat(fname, &buf) < 0)
645 failed("stat", fname);
646 + if (display_crtimes && (crtime = get_create_time(fname)) == 0)
647 + failed("get_create_time", fname);
648 #ifdef SUPPORT_XATTRS
650 stat_xattr(fname, &buf);
651 @@ -158,19 +180,11 @@ static void list_file(const char *fname)
653 permstring(permbuf, buf.st_mode);
655 - if (buf.st_mtime) {
656 - mt = gmtime(&buf.st_mtime);
658 - snprintf(datebuf, sizeof datebuf,
659 - "%04d-%02d-%02d %02d:%02d:%02d",
660 - (int)mt->tm_year + 1900,
661 - (int)mt->tm_mon + 1,
667 - strlcpy(datebuf, " ", sizeof datebuf);
668 + storetime(mtimebuf, buf.st_mtime, sizeof mtimebuf);
669 + if (display_crtimes)
670 + storetime(crtimebuf, crtime, sizeof crtimebuf);
672 + crtimebuf[0] = '\0';
674 /* TODO: Perhaps escape special characters in fname? */
676 @@ -181,13 +195,14 @@ static void list_file(const char *fname)
677 (long)minor(buf.st_rdev));
678 } else /* NB: use double for size since it might not fit in a long. */
679 printf("%12.0f", (double)buf.st_size);
680 - printf(" %6ld.%-6ld %6ld %s %s%s\n",
681 + printf(" %6ld.%-6ld %6ld %s%s%s%s\n",
682 (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
683 - datebuf, fname, linkbuf);
684 + mtimebuf, crtimebuf, fname, linkbuf);
687 static struct poptOption long_options[] = {
688 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
689 + {"crtimes", 'N', POPT_ARG_NONE, &display_crtimes, 0, 0, 0},
690 {"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 },
691 {"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 },
692 #ifdef SUPPORT_XATTRS
693 @@ -203,6 +218,7 @@ static void tls_usage(int ret)
694 fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n");
695 fprintf(F,"Trivial file listing program for portably checking rsync\n");
696 fprintf(F,"\nOptions:\n");
697 + fprintf(F," -N, --crtimes display create times (newness)\n");
698 fprintf(F," -l, --link-times display the time on a symlink\n");
699 fprintf(F," -L, --link-owner display the owner+group on a symlink\n");
700 #ifdef SUPPORT_XATTRS