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