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