Fixed failing hunks.
[rsync/rsync-patches.git] / atimes.diff
1 To use this patch, run these commands for a successful build:
2
3     patch -p1 <patches/atimes.diff
4     ./prepare-source
5     ./configure                      (optional if already run)
6     make
7
8 TODO:  need to fix this to handle 64-bit time_t values!
9
10 --- old/compat.c
11 +++ new/compat.c
12 @@ -43,6 +43,7 @@ extern int prune_empty_dirs;
13  extern int protocol_version;
14  extern int preserve_uid;
15  extern int preserve_gid;
16 +extern int preserve_atimes;
17  extern int preserve_acls;
18  extern int preserve_xattrs;
19  extern int preserve_hard_links;
20 @@ -57,7 +58,7 @@ extern char *dest_option;
21  extern struct filter_list_struct filter_list;
22  
23  /* These index values are for the file-list's extra-attribute array. */
24 -int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx;
25 +int uid_ndx, gid_ndx, atimes_ndx, acls_ndx, xattrs_ndx;
26  
27  /* The server makes sure that if either side only supports a pre-release
28   * version of a protocol, that both sides must speak a compatible version
29 @@ -98,6 +99,8 @@ void setup_protocol(int f_out,int f_in)
30                 uid_ndx = ++file_extra_cnt;
31         if (preserve_gid)
32                 gid_ndx = ++file_extra_cnt;
33 +       if (preserve_atimes)
34 +               atimes_ndx = ++file_extra_cnt;
35         if (preserve_acls && !am_sender)
36                 acls_ndx = ++file_extra_cnt;
37         if (preserve_xattrs)
38 --- old/flist.c
39 +++ new/flist.c
40 @@ -52,6 +52,7 @@ extern int preserve_devices;
41  extern int preserve_specials;
42  extern int uid_ndx;
43  extern int gid_ndx;
44 +extern int atimes_ndx;
45  extern int relative_paths;
46  extern int implied_dirs;
47  extern int file_extra_cnt;
48 @@ -158,6 +159,7 @@ void show_flist_stats(void)
49  static void list_file_entry(struct file_struct *f)
50  {
51         char permbuf[PERMSTRING_SIZE];
52 +       time_t atime = atimes_ndx ? F_ATIME(f) : 0;
53         double len;
54  
55         if (!F_IS_ACTIVE(f)) {
56 @@ -172,14 +174,16 @@ static void list_file_entry(struct file_
57  
58  #ifdef SUPPORT_LINKS
59         if (preserve_links && S_ISLNK(f->mode)) {
60 -               rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
61 +               rprintf(FINFO, "%s %11.0f %s %s %s -> %s\n",
62                         permbuf, len, timestring(f->modtime),
63 +                       atimes_ndx ? timestring(atime) : "",
64                         f_name(f, NULL), F_SYMLINK(f));
65         } else
66  #endif
67         {
68 -               rprintf(FINFO, "%s %11.0f %s %s\n",
69 +               rprintf(FINFO, "%s %11.0f %s %s %s\n",
70                         permbuf, len, timestring(f->modtime),
71 +                       atimes_ndx ? timestring(atime) : "",
72                         f_name(f, NULL));
73         }
74  }
75 @@ -347,6 +351,7 @@ int push_pathname(const char *dir, int l
76  static void send_file_entry(int f, struct file_struct *file, int ndx)
77  {
78         static time_t modtime;
79 +       static time_t atime;
80         static mode_t mode;
81         static int64 dev;
82         static dev_t rdev;
83 @@ -442,6 +447,13 @@ static void send_file_entry(int f, struc
84                 flags |= XMIT_SAME_TIME;
85         else
86                 modtime = file->modtime;
87 +       if (atimes_ndx && !S_ISDIR(mode)) {
88 +               time_t file_atime = F_ATIME(file);
89 +               if (file_atime == atime)
90 +                       flags |= XMIT_SAME_ATIME;
91 +               else
92 +                       atime = file_atime;
93 +       }
94  
95  #ifdef SUPPORT_HARD_LINKS
96         if (tmp_dev != 0) {
97 @@ -513,6 +525,8 @@ static void send_file_entry(int f, struc
98         }
99         if (!(flags & XMIT_SAME_MODE))
100                 write_int(f, to_wire_mode(mode));
101 +       if (atimes_ndx && !S_ISDIR(mode) && !(flags & XMIT_SAME_ATIME))
102 +               write_varlong(f, atime, 4);
103         if (uid_ndx && !(flags & XMIT_SAME_UID)) {
104                 if (protocol_version < 30)
105                         write_int(f, uid);
106 @@ -599,7 +613,7 @@ static void send_file_entry(int f, struc
107  static struct file_struct *recv_file_entry(struct file_list *flist,
108                                            int xflags, int f)
109  {
110 -       static int64 modtime;
111 +       static int64 modtime, atime;
112         static mode_t mode;
113         static int64 dev;
114         static dev_t rdev;
115 @@ -735,6 +749,16 @@ static struct file_struct *recv_file_ent
116         }
117         if (!(xflags & XMIT_SAME_MODE))
118                 mode = from_wire_mode(read_int(f));
119 +       if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME)) {
120 +               atime = read_varlong(f, 4);
121 +#if SIZEOF_TIME_T < SIZEOF_INT64
122 +               if ((atime > INT_MAX || atime < INT_MIN) && !am_generator) {
123 +                       rprintf(FERROR,
124 +                               "Access time value of %s truncated on receiver.\n",
125 +                               lastname);
126 +               }
127 +#endif
128 +       }
129  
130         if (chmod_modes && !S_ISLNK(mode))
131                 mode = tweak_mode(mode, chmod_modes);
132 @@ -863,6 +887,8 @@ static struct file_struct *recv_file_ent
133                 F_GROUP(file) = gid;
134                 file->flags |= gid_flags;
135         }
136 +       if (atimes_ndx)
137 +               F_ATIME(file) = (time_t)atime;
138  #ifdef ICONV_OPTION
139         if (ic_ndx)
140                 F_NDX(file) = flist->count + flist->ndx_start;
141 @@ -1182,6 +1208,8 @@ struct file_struct *make_file(const char
142                 F_OWNER(file) = st.st_uid;
143         if (gid_ndx)
144                 F_GROUP(file) = st.st_gid;
145 +       if (atimes_ndx)
146 +               F_ATIME(file) = st.st_atime;
147  
148         if (basename != thisname)
149                 file->dirname = lastdir;
150 --- old/generator.c
151 +++ new/generator.c
152 @@ -43,6 +43,7 @@ extern int preserve_specials;
153  extern int preserve_hard_links;
154  extern int preserve_perms;
155  extern int preserve_times;
156 +extern int preserve_atimes;
157  extern int omit_dir_times;
158  extern int uid_ndx;
159  extern int gid_ndx;
160 @@ -563,6 +564,9 @@ void itemize(const char *fnamecmp, struc
161                   && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
162                  || (keep_time && cmp_time(file->modtime, sxp->st.st_mtime) != 0))
163                         iflags |= ITEM_REPORT_TIME;
164 +               if (preserve_atimes && !S_ISDIR(file->mode) && !S_ISLNK(file->mode)
165 +                && cmp_time(F_ATIME(file), sxp->st.st_atime) != 0)
166 +                       iflags |= ITEM_REPORT_ATIME;
167                 if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
168                         iflags |= ITEM_REPORT_PERMS;
169                 if (uid_ndx && am_root && (uid_t)F_OWNER(file) != sxp->st.st_uid)
170 @@ -880,6 +884,8 @@ static int try_dests_reg(struct file_str
171                 if (link_dest) {
172                         if (!hard_link_one(file, fname, cmpbuf, 1))
173                                 goto try_a_copy;
174 +                       if (preserve_atimes)
175 +                               set_file_attrs(fname, file, sxp, NULL, 0);
176                         if (preserve_hard_links && F_IS_HLINKED(file))
177                                 finish_hard_link(file, fname, &sxp->st, itemizing, code, j);
178                         if (itemizing && (verbose > 1 || stdout_format_has_i > 1)) {
179 @@ -1749,7 +1755,7 @@ static void touch_up_dirs(struct file_li
180                 if (!(file->mode & S_IWUSR))
181                         do_chmod(fname, file->mode);
182                 if (need_retouch_dir_times)
183 -                       set_modtime(fname, file->modtime, file->mode);
184 +                       set_times(fname, file->modtime, file->modtime, file->mode);
185                 if (allowed_lull && !(counter % lull_mod))
186                         maybe_send_keepalive();
187                 else if (!(counter & 0xFF))
188 --- old/log.c
189 +++ new/log.c
190 @@ -631,7 +631,8 @@ static void log_formatted(enum logcode c
191                         c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
192                         c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
193                         c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
194 -                       c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
195 +                       c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.'
196 +                            : S_ISLNK(file->mode) ? 'U' : 'u';
197                         c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
198                         c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
199                         c[11] = '\0';
200 --- old/options.c
201 +++ new/options.c
202 @@ -56,6 +56,7 @@ int preserve_uid = 0;
203  int preserve_gid = 0;
204  int preserve_times = 0;
205  int omit_dir_times = 0;
206 +int preserve_atimes = 0;
207  int update_only = 0;
208  int cvs_exclude = 0;
209  int dry_run = 0;
210 @@ -335,8 +336,9 @@ void usage(enum logcode F)
211    rprintf(F,"     --devices               preserve device files (super-user only)\n");
212    rprintf(F,"     --specials              preserve special files\n");
213    rprintf(F," -D                          same as --devices --specials\n");
214 -  rprintf(F," -t, --times                 preserve times\n");
215 -  rprintf(F," -O, --omit-dir-times        omit directories when preserving times\n");
216 +  rprintf(F," -t, --times                 preserve modify times\n");
217 +  rprintf(F," -O, --omit-dir-times        omit directories when preserving modify times\n");
218 +  rprintf(F," -U, --atimes                preserve access (last-used) times\n");
219    rprintf(F,"     --super                 receiver attempts super-user activities\n");
220  #ifdef SUPPORT_XATTRS
221    rprintf(F,"     --fake-super            store/recover privileged attrs using xattrs\n");
222 @@ -471,6 +473,9 @@ static struct poptOption long_options[] 
223    {"times",           't', POPT_ARG_VAL,    &preserve_times, 1, 0, 0 },
224    {"no-times",         0,  POPT_ARG_VAL,    &preserve_times, 0, 0, 0 },
225    {"no-t",             0,  POPT_ARG_VAL,    &preserve_times, 0, 0, 0 },
226 +  {"atimes",          'U', POPT_ARG_VAL,    &preserve_atimes, 1, 0, 0 },
227 +  {"no-atimes",        0,  POPT_ARG_VAL,    &preserve_atimes, 0, 0, 0 },
228 +  {"no-U",             0,  POPT_ARG_VAL,    &preserve_atimes, 0, 0, 0 },
229    {"omit-dir-times",  'O', POPT_ARG_VAL,    &omit_dir_times, 2, 0, 0 },
230    {"modify-window",    0,  POPT_ARG_INT,    &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
231    {"super",            0,  POPT_ARG_VAL,    &am_root, 2, 0, 0 },
232 @@ -1668,6 +1673,8 @@ void server_options(char **args,int *arg
233                 argstr[x++] = 'D';
234         if (preserve_times)
235                 argstr[x++] = 't';
236 +       if (preserve_atimes)
237 +               argstr[x++] = 'U';
238         if (preserve_perms)
239                 argstr[x++] = 'p';
240         else if (preserve_executability && am_sender)
241 --- old/rsync.c
242 +++ new/rsync.c
243 @@ -32,6 +32,7 @@ extern int preserve_acls;
244  extern int preserve_xattrs;
245  extern int preserve_perms;
246  extern int preserve_executability;
247 +extern int preserve_atimes;
248  extern int preserve_times;
249  extern int omit_dir_times;
250  extern int am_root;
251 @@ -275,6 +276,7 @@ int set_file_attrs(const char *fname, st
252         int updated = 0;
253         statx sx2;
254         int change_uid, change_gid;
255 +       time_t atime, mtime;
256         mode_t new_mode = file->mode;
257  
258         if (!sxp) {
259 @@ -312,18 +314,36 @@ int set_file_attrs(const char *fname, st
260                 set_stat_xattr(fname, file);
261  #endif
262  
263 +       /* This code must be the first update in the function due to
264 +        * how it uses the "updated" variable. */
265         if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && omit_dir_times))
266                 flags |= ATTRS_SKIP_MTIME;
267 +       if (!preserve_atimes || S_ISDIR(sxp->st.st_mode))
268 +               flags |= ATTRS_SKIP_ATIME;
269         if (!(flags & ATTRS_SKIP_MTIME)
270             && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
271 -               int ret = set_modtime(fname, file->modtime, sxp->st.st_mode);
272 +               mtime = file->modtime;
273 +               updated = 1;
274 +       } else
275 +               mtime = sxp->st.st_mtime;
276 +       if (!(flags & ATTRS_SKIP_ATIME)) {
277 +               time_t file_atime = F_ATIME(file);
278 +               if (cmp_time(sxp->st.st_atime, file_atime) != 0) {
279 +                       atime = file_atime;
280 +                       updated = 1;
281 +               } else
282 +                       atime = sxp->st.st_atime;
283 +       } else
284 +               atime = sxp->st.st_atime;
285 +       if (updated) {
286 +               int ret = set_times(fname, mtime, atime, sxp->st.st_mode);
287                 if (ret < 0) {
288                         rsyserr(FERROR, errno, "failed to set times on %s",
289                                 full_fname(fname));
290                         goto cleanup;
291                 }
292 -               if (ret == 0) /* ret == 1 if symlink could not be set */
293 -                       updated = 1;
294 +               if (ret > 0) /* ret == 1 if symlink could not be set */
295 +                       updated = 0;
296         }
297  
298         change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
299 --- old/rsync.h
300 +++ new/rsync.h
301 @@ -56,6 +56,7 @@
302  #define XMIT_RDEV_MINOR_8_pre30 (1<<11)        /* protocols 28 - 29  */
303  #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - NOW */
304  #define XMIT_HLINK_FIRST (1<<12)       /* protocols 30 - NOW */
305 +#define XMIT_SAME_ATIME (1<<13)                /* protocols ?? - NOW */
306  
307  /* These flags are used in the live flist data. */
308  
309 @@ -143,6 +144,7 @@
310  
311  #define ATTRS_REPORT           (1<<0)
312  #define ATTRS_SKIP_MTIME       (1<<1)
313 +#define ATTRS_SKIP_ATIME       (1<<2)
314  
315  #define FULL_FLUSH     1
316  #define NORMAL_FLUSH   0
317 @@ -582,6 +584,7 @@ struct file_struct {
318  extern int file_extra_cnt;
319  extern int uid_ndx;
320  extern int gid_ndx;
321 +extern int atimes_ndx;
322  extern int acls_ndx;
323  extern int xattrs_ndx;
324  
325 @@ -616,6 +619,7 @@ extern int xattrs_ndx;
326  /* When the associated option is on, all entries will have these present: */
327  #define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum
328  #define F_GROUP(f) REQ_EXTRA(f, gid_ndx)->unum
329 +#define F_ATIME(f) REQ_EXTRA(f, atimes_ndx)->unum
330  #define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num
331  #define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
332  #define F_NDX(f) REQ_EXTRA(f, ic_ndx)->num
333 --- old/rsync.yo
334 +++ new/rsync.yo
335 @@ -336,8 +336,9 @@ to the detailed description below for a 
336       --devices               preserve device files (super-user only)
337       --specials              preserve special files
338   -D                          same as --devices --specials
339 - -t, --times                 preserve times
340 - -O, --omit-dir-times        omit directories when preserving times
341 + -t, --times                 preserve modify times
342 + -O, --omit-dir-times        omit directories when preserving mod-times
343 + -U, --atimes                preserve access (use) times
344       --super                 receiver attempts super-user activities
345       --fake-super            store/recover privileged attrs using xattrs
346   -S, --sparse                handle sparse files efficiently
347 @@ -916,6 +917,12 @@ it is preserving modification times (see
348  the directories on the receiving side, it is a good idea to use bf(-O).
349  This option is inferred if you use bf(--backup) without bf(--backup-dir).
350  
351 +dit(bf(-U, --atimes)) This tells rsync to set the access (use) times of the
352 +destination files to the same value as the source files.  Note that the
353 +reading of the source file may update the atime of the source files, so
354 +repeated rsync runs with --atimes may be needed if you want to force the
355 +access-time values to be 100% identical on the two systems.
356 +
357  dit(bf(--super)) This tells the receiving side to attempt super-user
358  activities even if the receiving rsync wasn't run by the super-user.  These
359  activities include: preserving users via the bf(--owner) option, preserving
360 @@ -1530,7 +1537,7 @@ quote(itemization(
361    by the file transfer.
362    it() A bf(t) means the modification time is different and is being updated
363    to the sender's value (requires bf(--times)).  An alternate value of bf(T)
364 -  means that the time will be set to the transfer time, which happens
365 +  means that the modify time will be set to the transfer time, which happens
366    anytime a symlink is transferred, or when a file or device is transferred
367    without bf(--times).
368    it() A bf(p) means the permissions are different and are being updated to
369 @@ -1539,8 +1546,10 @@ quote(itemization(
370    sender's value (requires bf(--owner) and super-user privileges).
371    it() A bf(g) means the group is different and is being updated to the
372    sender's value (requires bf(--group) and the authority to set the group).
373 -  it() The bf(u) slot is reserved for reporting update (access) time changes
374 -  (a feature that is not yet released).
375 +  it() A bf(u) means the access (use) time is different and is being updated to
376 +  the sender's value (requires bf(--atimes)).  An alternate value of bf(U)
377 +  means that the access time will be set to the transfer time, which happens
378 +  when a symlink or directory is updated.
379    it() The bf(a) means that the ACL information changed.
380    it() The bf(x) slot is reserved for reporting extended attribute changes
381    (a feature that is not yet released).
382 --- old/sender.c
383 +++ new/sender.c
384 @@ -43,6 +43,7 @@ extern int do_progress;
385  extern int inplace;
386  extern int batch_fd;
387  extern int write_batch;
388 +extern unsigned int file_struct_len;
389  extern struct stats stats;
390  extern struct file_list *cur_flist, *first_flist;
391  
392 --- old/testsuite/atimes.test
393 +++ new/testsuite/atimes.test
394 @@ -0,0 +1,19 @@
395 +#! /bin/sh
396 +
397 +# Test rsync copying atimes
398 +
399 +. "$suitedir/rsync.fns"
400 +
401 +set -x
402 +
403 +mkdir "$fromdir"
404 +
405 +touch "$fromdir/foo"
406 +touch -a -t 200102031717.42 "$fromdir/foo"
407 +
408 +TLS_ARGS=--atime
409 +
410 +checkit "$RSYNC -rtUgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
411 +
412 +# The script would have aborted on error, so getting here means we've won.
413 +exit 0
414 --- old/testsuite/rsync.fns
415 +++ new/testsuite/rsync.fns
416 @@ -186,6 +186,10 @@ checkit() {
417      # We can just write everything to stdout/stderr, because the
418      # wrapper hides it unless there is a problem.
419  
420 +    if test x$TLS_ARGS = x--atime; then
421 +       ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
422 +    fi
423 +
424      echo "Running: \"$1\""  
425      eval "$1" 
426      status=$?
427 @@ -193,10 +197,13 @@ checkit() {
428         failed="YES";
429      fi
430  
431 +    if test x$TLS_ARGS != x--atime; then
432 +       ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
433 +    fi
434 +
435      echo "-------------"
436      echo "check how the directory listings compare with diff:"
437      echo ""
438 -    ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
439      ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
440      diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
441  
442 --- old/tls.c
443 +++ new/tls.c
444 @@ -98,6 +98,8 @@ static int stat_xattr(const char *fname,
445  
446  #endif
447  
448 +static int display_atime = 0;
449
450  static void failed(char const *what, char const *where)
451  {
452         fprintf(stderr, PROGRAM ": %s %s: %s\n",
453 @@ -105,12 +107,29 @@ static void failed(char const *what, cha
454         exit(1);
455  }
456  
457 +static void storetime(char *dest, time_t t, size_t destsize)
458 +{
459 +       if (t) {
460 +               struct tm *mt = gmtime(&t);
461 +
462 +               snprintf(dest, destsize,
463 +                       "%04d-%02d-%02d %02d:%02d:%02d ",
464 +                       (int)mt->tm_year + 1900,
465 +                       (int)mt->tm_mon + 1,
466 +                       (int)mt->tm_mday,
467 +                       (int)mt->tm_hour,
468 +                       (int)mt->tm_min,
469 +                       (int)mt->tm_sec);
470 +       } else
471 +               strlcpy(dest, "                    ", destsize);
472 +}
473 +
474  static void list_file(const char *fname)
475  {
476         STRUCT_STAT buf;
477         char permbuf[PERMSTRING_SIZE];
478 -       struct tm *mt;
479 -       char datebuf[50];
480 +       char mtimebuf[50];
481 +       char atimebuf[50];
482         char linkbuf[4096];
483  
484         if (do_lstat(fname, &buf) < 0)
485 @@ -147,19 +166,8 @@ static void list_file(const char *fname)
486  
487         permstring(permbuf, buf.st_mode);
488  
489 -       if (buf.st_mtime) {
490 -               mt = gmtime(&buf.st_mtime);
491 -
492 -               snprintf(datebuf, sizeof datebuf,
493 -                       "%04d-%02d-%02d %02d:%02d:%02d",
494 -                       (int)mt->tm_year + 1900,
495 -                       (int)mt->tm_mon + 1,
496 -                       (int)mt->tm_mday,
497 -                       (int)mt->tm_hour,
498 -                       (int)mt->tm_min,
499 -                       (int)mt->tm_sec);
500 -       } else
501 -               strlcpy(datebuf, "                   ", sizeof datebuf);
502 +       storetime(mtimebuf, buf.st_mtime, sizeof mtimebuf);
503 +       storetime(atimebuf, buf.st_atime, sizeof atimebuf);
504  
505         /* TODO: Perhaps escape special characters in fname? */
506  
507 @@ -170,13 +178,15 @@ static void list_file(const char *fname)
508                     (long)minor(buf.st_rdev));
509         } else /* NB: use double for size since it might not fit in a long. */
510                 printf("%12.0f", (double)buf.st_size);
511 -       printf(" %6ld.%-6ld %6ld %s %s%s\n",
512 +       printf(" %6ld.%-6ld %6ld %s%s%s%s\n",
513                (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
514 -              datebuf, fname, linkbuf);
515 +              mtimebuf, display_atime && !S_ISDIR(buf.st_mode) ? atimebuf : "",
516 +              fname, linkbuf);
517  }
518  
519  static struct poptOption long_options[] = {
520    /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
521 +  {"atime",           'u', POPT_ARG_NONE,   &display_atime, 0, 0, 0},
522  #ifdef SUPPORT_XATTRS
523    {"fake-super",      'f', POPT_ARG_VAL,    &am_root, -1, 0, 0 },
524  #endif
525 @@ -190,6 +200,7 @@ static void tls_usage(int ret)
526    fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n");
527    fprintf(F,"Trivial file listing program for portably checking rsync\n");
528    fprintf(F,"\nOptions:\n");
529 +  rprintf(F," -U, --atimes                display access (last-used) times\n");
530  #ifdef SUPPORT_XATTRS
531    fprintf(F," -f, --fake-super            display attributes including fake-super xattrs\n");
532  #endif
533 --- old/util.c
534 +++ new/util.c
535 @@ -121,7 +121,7 @@ NORETURN void overflow_exit(const char *
536         exit_cleanup(RERR_MALLOC);
537  }
538  
539 -int set_modtime(const char *fname, time_t modtime, mode_t mode)
540 +int set_times(const char *fname, time_t modtime, time_t atime, mode_t mode)
541  {
542  #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
543         if (S_ISLNK(mode))
544 @@ -129,9 +129,13 @@ int set_modtime(const char *fname, time_
545  #endif
546  
547         if (verbose > 2) {
548 -               rprintf(FINFO, "set modtime of %s to (%ld) %s",
549 +               char mtimebuf[200];
550 +
551 +               strlcpy(mtimebuf, timestring(modtime), sizeof mtimebuf);
552 +               rprintf(FINFO,
553 +                       "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
554                         fname, (long)modtime,
555 -                       asctime(localtime(&modtime)));
556 +                       mtimebuf, (long)atime, timestring(atime));
557         }
558  
559         if (dry_run)
560 @@ -140,7 +144,7 @@ int set_modtime(const char *fname, time_
561         {
562  #ifdef HAVE_UTIMES
563                 struct timeval t[2];
564 -               t[0].tv_sec = time(NULL);
565 +               t[0].tv_sec = atime;
566                 t[0].tv_usec = 0;
567                 t[1].tv_sec = modtime;
568                 t[1].tv_usec = 0;
569 @@ -153,12 +157,12 @@ int set_modtime(const char *fname, time_
570                 return utimes(fname, t);
571  #elif defined HAVE_UTIMBUF
572                 struct utimbuf tbuf;
573 -               tbuf.actime = time(NULL);
574 +               tbuf.actime = atime;
575                 tbuf.modtime = modtime;
576                 return utime(fname,&tbuf);
577  #elif defined HAVE_UTIME
578                 time_t t[2];
579 -               t[0] = time(NULL);
580 +               t[0] = atime;
581                 t[1] = modtime;
582                 return utime(fname,t);
583  #else