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/flist.c
10 +++ new/flist.c
11 @@ -46,6 +46,7 @@ extern int preserve_devices;
12  extern int preserve_specials;
13  extern int preserve_uid;
14  extern int preserve_gid;
15 +extern int preserve_atimes;
16  extern int relative_paths;
17  extern int implied_dirs;
18  extern int flist_extra_ndx;
19 @@ -135,6 +136,7 @@ void show_flist_stats(void)
20  static void list_file_entry(struct file_struct *f)
21  {
22         char permbuf[PERMSTRING_SIZE];
23 +       time_t atime = preserve_atimes ? F_ATIME(f) : 0;
24  
25         if (!f->basename) {
26                 /* this can happen if duplicate names were removed */
27 @@ -145,16 +147,18 @@ static void list_file_entry(struct file_
28  
29  #ifdef SUPPORT_LINKS
30         if (preserve_links && S_ISLNK(f->mode)) {
31 -               rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
32 +               rprintf(FINFO, "%s %11.0f %s %s %s -> %s\n",
33                         permbuf,
34                         (double)f->length, timestring(f->modtime),
35 +                       preserve_atimes ? timestring(atime) : "",
36                         f_name(f, NULL), F_SYMLINK(f));
37         } else
38  #endif
39         {
40 -               rprintf(FINFO, "%s %11.0f %s %s\n",
41 +               rprintf(FINFO, "%s %11.0f %s %s %s\n",
42                         permbuf,
43                         (double)f->length, timestring(f->modtime),
44 +                       preserve_atimes ? timestring(atime) : "",
45                         f_name(f, NULL));
46         }
47  }
48 @@ -312,6 +316,7 @@ static void send_file_entry(struct file_
49  {
50         unsigned short flags;
51         static time_t modtime;
52 +       static time_t atime;
53         static mode_t mode;
54         static int64 dev;
55         static dev_t rdev;
56 @@ -327,7 +332,7 @@ static void send_file_entry(struct file_
57  
58         if (!file) {
59                 write_byte(f, 0);
60 -               modtime = 0, mode = 0;
61 +               modtime = 0, atime = 0, mode = 0;
62                 dev = 0, rdev = MAKEDEV(0, 0);
63                 rdev_major = 0;
64                 uid = 0, gid = 0;
65 @@ -377,6 +382,13 @@ static void send_file_entry(struct file_
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_idev.dev != 0) {
79 @@ -429,6 +441,8 @@ static void send_file_entry(struct file_
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 (!numeric_ids)
87                         add_uid(uid);
88 @@ -495,7 +509,7 @@ static void send_file_entry(struct file_
89  static struct file_struct *recv_file_entry(struct file_list *flist,
90                                            unsigned short 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 @@ -515,7 +529,7 @@ static struct file_struct *recv_file_ent
98         struct file_struct *file;
99  
100         if (!flist) {
101 -               modtime = 0, mode = 0;
102 +               modtime = 0, atime = 0, mode = 0;
103                 dev = 0, rdev = MAKEDEV(0, 0);
104                 rdev_major = 0;
105                 uid = 0, gid = 0;
106 @@ -571,6 +585,8 @@ static struct file_struct *recv_file_ent
107                 modtime = (time_t)read_int(f);
108         if (!(flags & XMIT_SAME_MODE))
109                 mode = from_wire_mode(read_int(f));
110 +       if (preserve_atimes && !S_ISDIR(mode) && !(flags & XMIT_SAME_ATIME))
111 +               atime = (time_t)read_int(f);
112  
113         if (chmod_modes && !S_ISLNK(mode))
114                 mode = tweak_mode(mode, chmod_modes);
115 @@ -643,6 +659,8 @@ static struct file_struct *recv_file_ent
116                 F_UID(file) = uid;
117         if (preserve_gid)
118                 F_GID(file) = gid;
119 +       if (preserve_atimes)
120 +               F_ATIME(file) = atime;
121  
122         if (dirname_len) {
123                 file->dirname = lastdir = bp;
124 @@ -906,6 +924,8 @@ struct file_struct *make_file(const char
125                 F_UID(file) = st.st_uid;
126         if (preserve_gid)
127                 F_GID(file) = st.st_gid;
128 +       if (preserve_atimes)
129 +               F_ATIME(file) = st.st_atime;
130  
131         if (dirname_len) {
132                 file->dirname = lastdir = bp;
133 --- old/generator.c
134 +++ new/generator.c
135 @@ -43,6 +43,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 @@ -477,6 +478,9 @@ void itemize(struct file_struct *file, i
144                   && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
145                  || (keep_time && cmp_time(file->modtime, 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), st->st_atime) != 0)
149 +                       iflags |= ITEM_REPORT_ATIME;
150                 if ((file->mode & CHMOD_BITS) != (st->st_mode & CHMOD_BITS))
151                         iflags |= ITEM_REPORT_PERMS;
152                 if (preserve_uid && am_root && F_UID(file) != st->st_uid)
153 @@ -787,6 +791,8 @@ static int try_dests_reg(struct file_str
154                         if (hard_link_one(file, ndx, fname, 0, stp,
155                                           cmpbuf, 1, i, code) < 0)
156                                 goto try_a_copy;
157 +                       if (preserve_atimes)
158 +                               set_file_attrs(fname, file, stp, 0);
159                         if (preserve_hard_links && IS_HLINKED(file))
160                                 hard_link_cluster(file, ndx, itemizing, code, j);
161                 } else
162 --- old/log.c
163 +++ new/log.c
164 @@ -37,6 +37,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 flist_extra_ndx;
172 @@ -618,7 +619,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] = '.';
177 +                       c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.'
178 +                            : S_ISLNK(file->mode) ? 'U' : 'u';
179                         c[9] = '\0';
180  
181                         if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
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 @@ -307,8 +308,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 @@ -425,6 +427,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 @@ -1223,6 +1228,8 @@ int parse_arguments(int *argc, const cha
215                 preserve_uid = flist_extra_ndx++;
216         if (preserve_gid)
217                 preserve_gid = flist_extra_ndx++;
218 +       if (preserve_atimes)
219 +               preserve_atimes = flist_extra_ndx++;
220  
221         *argv = poptGetArgs(pc);
222         *argc = count_args(*argv);
223 @@ -1542,6 +1549,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 @@ -34,6 +34,7 @@ extern int verbose;
235  extern int dry_run;
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 @@ -182,6 +183,7 @@ int set_file_attrs(char *fname, struct f
243         int updated = 0;
244         STRUCT_STAT st2;
245         int change_uid, change_gid;
246 +       time_t atime, mtime;
247         mode_t new_mode = file->mode;
248  
249         if (!st) {
250 @@ -201,18 +203,36 @@ int set_file_attrs(char *fname, struct f
251                 }
252         }
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(st->st_mode) && omit_dir_times))
257                 flags |= ATTRS_SKIP_MTIME;
258 +       if (!preserve_atimes || S_ISDIR(st->st_mode))
259 +               flags |= ATTRS_SKIP_ATIME;
260         if (!(flags & ATTRS_SKIP_MTIME)
261             && cmp_time(st->st_mtime, file->modtime) != 0) {
262 -               int ret = set_modtime(fname, file->modtime, st->st_mode);
263 +               mtime = file->modtime;
264 +               updated = 1;
265 +       } else
266 +               mtime = st->st_mtime;
267 +       if (!(flags & ATTRS_SKIP_ATIME)) {
268 +               time_t file_atime = F_ATIME(file);
269 +               if (cmp_time(st->st_atime, file_atime) != 0) {
270 +                       atime = file_atime;
271 +                       updated = 1;
272 +               } else
273 +                       atime = st->st_atime;
274 +       } else
275 +               atime = st->st_atime;
276 +       if (updated) {
277 +               int ret = set_times(fname, mtime, atime, st->st_mode);
278                 if (ret < 0) {
279                         rsyserr(FERROR, errno, "failed to set times on %s",
280                                 full_fname(fname));
281                         return 0;
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 && st->st_uid != F_UID(file);
290 --- old/rsync.h
291 +++ new/rsync.h
292 @@ -54,6 +54,7 @@
293  #define XMIT_HAS_IDEV_DATA (1<<9)
294  #define XMIT_SAME_DEV (1<<10)
295  #define XMIT_RDEV_MINOR_IS_SMALL (1<<11)
296 +#define XMIT_SAME_ATIME (1<<12)
297  
298  /* These flags are used in the live flist data. */
299  
300 @@ -120,6 +121,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 @@ -532,6 +534,7 @@ union flist_extras {
309         struct idev *idev;      /* The hard-link info during matching */
310         struct hlist *hlist;    /* The hard-link info after matching */
311         int32 num;              /* A general-purpose number */
312 +       time_t time;            /* A time value */
313  };
314  
315  #define FLIST_EXTRA(f,j) ((union flist_extras *)(f))[-(j)]
316 @@ -540,6 +543,7 @@ union flist_extras {
317  /* When enabled, all entries have these: */
318  #define F_UID(f) FLIST_EXTRA(f, preserve_uid).uid
319  #define F_GID(f) FLIST_EXTRA(f, preserve_gid).gid
320 +#define F_ATIME(f) FLIST_EXTRA(f, preserve_atimes).time
321  
322  /* These are per-entry optional and mutally exclusive: */
323  #define F_IDEV(f) FLIST_EXTRA(f, flist_extra_ndx).idev
324 --- old/rsync.yo
325 +++ new/rsync.yo
326 @@ -328,8 +328,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   -S, --sparse                handle sparse files efficiently
337   -n, --dry-run               show what would have been transferred
338 @@ -870,6 +871,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 @@ -1403,7 +1410,7 @@ with older versions of rsync, but that a
352  verbose messages).
353  
354  The "%i" escape has a cryptic output that is 9 letters long.  The general
355 -format is like the string bf(YXcstpogz), where bf(Y) is replaced by the
356 +format is like the string bf(YXcstpogu), where bf(Y) is replaced by the
357  type of update being done, bf(X) is replaced by the file-type, and the
358  other letters represent attributes that may be output if they are being
359  modified.
360 @@ -1443,7 +1450,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 @@ -1452,7 +1459,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(z) slot is reserved for future use.
374 +  it() A bf(u) means the access (use) time is different and is being updated to
375 +  the sender's value (requires bf(--atimes)).  An alternate value of bf(U)
376 +  means that the access time will be set to the transfer time, which happens
377 +  when a symlink or directory is updated.
378  ))
379  
380  One other output is possible:  when deleting files, the "%i" will output
381 --- old/sender.c
382 +++ new/sender.c
383 @@ -41,6 +41,7 @@ extern int do_progress;
384  extern int inplace;
385  extern int batch_fd;
386  extern int write_batch;
387 +extern unsigned int file_struct_len;
388  extern struct stats stats;
389  extern struct file_list *the_file_list;
390  extern char *stdout_format;
391 --- old/testsuite/atimes.test
392 +++ new/testsuite/atimes.test
393 @@ -0,0 +1,19 @@
394 +#! /bin/sh
395 +
396 +# Test rsync copying atimes
397 +
398 +. "$suitedir/rsync.fns"
399 +
400 +set -x
401 +
402 +mkdir "$fromdir"
403 +
404 +touch "$fromdir/foo"
405 +touch -a -t 200102031717.42 "$fromdir/foo"
406 +
407 +TLS_ARGS=--atime
408 +
409 +checkit "$RSYNC -rtUgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
410 +
411 +# The script would have aborted on error, so getting here means we've won.
412 +exit 0
413 --- old/testsuite/rsync.fns
414 +++ new/testsuite/rsync.fns
415 @@ -66,7 +66,7 @@ printmsg() {
416  }
417  
418  rsync_ls_lR() {
419 -    find "$@" -print | sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls"
420 +    find "$@" -print | sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls" $TLS_ARGS
421  }
422  
423  check_perms() {
424 @@ -184,6 +184,10 @@ checkit() {
425      # We can just write everything to stdout/stderr, because the
426      # wrapper hides it unless there is a problem.
427  
428 +    if test x$TLS_ARGS = x--atime; then
429 +       ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
430 +    fi
431 +
432      echo "Running: \"$1\""  
433      eval "$1" 
434      status=$?
435 @@ -191,10 +195,13 @@ checkit() {
436         failed="YES";
437      fi
438  
439 +    if test x$TLS_ARGS != x--atime; then
440 +       ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
441 +    fi
442 +
443      echo "-------------"
444      echo "check how the directory listings compare with diff:"
445      echo ""
446 -    ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
447      ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
448      diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
449  
450 --- old/tls.c
451 +++ new/tls.c
452 @@ -34,6 +34,7 @@
453   * change. */
454  
455  #include "rsync.h"
456 +#include "popt.h"
457  
458  #define PROGRAM "tls"
459  
460 @@ -43,6 +44,8 @@ int read_only = 1;
461  int list_only = 0;
462  int preserve_perms = 0;
463  
464 +static int display_atime = 0;
465
466  static void failed(char const *what, char const *where)
467  {
468         fprintf(stderr, PROGRAM ": %s %s: %s\n",
469 @@ -50,12 +53,29 @@ static void failed(char const *what, cha
470         exit(1);
471  }
472  
473 +static void storetime(char *dest, time_t t, size_t destsize)
474 +{
475 +       if (t) {
476 +               struct tm *mt = gmtime(&t);
477 +
478 +               snprintf(dest, destsize,
479 +                       "%04d-%02d-%02d %02d:%02d:%02d ",
480 +                       (int)mt->tm_year + 1900,
481 +                       (int)mt->tm_mon + 1,
482 +                       (int)mt->tm_mday,
483 +                       (int)mt->tm_hour,
484 +                       (int)mt->tm_min,
485 +                       (int)mt->tm_sec);
486 +       } else
487 +               strlcpy(dest, "                    ", destsize);
488 +}
489 +
490  static void list_file(const char *fname)
491  {
492         STRUCT_STAT buf;
493         char permbuf[PERMSTRING_SIZE];
494 -       struct tm *mt;
495 -       char datebuf[50];
496 +       char mtimebuf[50];
497 +       char atimebuf[50];
498         char linkbuf[4096];
499  
500         if (do_lstat(fname, &buf) < 0)
501 @@ -88,19 +108,8 @@ static void list_file(const char *fname)
502  
503         permstring(permbuf, buf.st_mode);
504  
505 -       if (buf.st_mtime) {
506 -               mt = gmtime(&buf.st_mtime);
507 -
508 -               snprintf(datebuf, sizeof datebuf,
509 -                       "%04d-%02d-%02d %02d:%02d:%02d",
510 -                       (int)mt->tm_year + 1900,
511 -                       (int)mt->tm_mon + 1,
512 -                       (int)mt->tm_mday,
513 -                       (int)mt->tm_hour,
514 -                       (int)mt->tm_min,
515 -                       (int)mt->tm_sec);
516 -       } else
517 -               strlcpy(datebuf, "                   ", sizeof datebuf);
518 +       storetime(mtimebuf, buf.st_mtime, sizeof mtimebuf);
519 +       storetime(atimebuf, buf.st_atime, sizeof atimebuf);
520  
521         /* TODO: Perhaps escape special characters in fname? */
522  
523 @@ -111,23 +120,55 @@ static void list_file(const char *fname)
524                     (long)minor(buf.st_rdev));
525         } else /* NB: use double for size since it might not fit in a long. */
526                 printf("%12.0f", (double)buf.st_size);
527 -       printf(" %6ld.%-6ld %6ld %s %s%s\n",
528 +       printf(" %6ld.%-6ld %6ld %s%s%s%s\n",
529                (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
530 -              datebuf, fname, linkbuf);
531 +              mtimebuf, display_atime && !S_ISDIR(buf.st_mode) ? atimebuf : "",
532 +              fname, linkbuf);
533 +}
534 +
535 +static struct poptOption long_options[] = {
536 +  /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
537 +  {"atime",           'u', POPT_ARG_NONE,   &display_atime, 0,   0, 0},
538 +  {"help",            'h', POPT_ARG_NONE,   0,              'h', 0, 0},
539 +  {0,0,0,0,0,0,0}
540 +};
541 +
542 +static void tls_usage(int ret)
543 +{
544 +       fprintf(stderr, "usage: " PROGRAM " [--atime | -u] DIR ...\n"
545 +           "Trivial file listing program for portably checking rsync\n");
546 +       exit(ret);
547  }
548  
549  int
550  main(int argc, char *argv[])
551  {
552 -       if (argc < 2) {
553 -               fprintf(stderr, "usage: " PROGRAM " DIR ...\n"
554 -                       "Trivial file listing program for portably checking rsync\n");
555 -               return 1;
556 -       }
557 +       poptContext pc;
558 +       const char **extra_args;
559 +       int opt;
560  
561 -       for (argv++; *argv; argv++) {
562 -               list_file(*argv);
563 +       pc = poptGetContext(PROGRAM, argc, (const char **)argv,
564 +                           long_options, 0);
565 +       while ((opt = poptGetNextOpt(pc)) != -1) {
566 +               switch (opt) {
567 +               case 'h':
568 +                       tls_usage(0);
569 +               default:
570 +                       fprintf(stderr,
571 +                               "%s: %s\n",
572 +                               poptBadOption(pc, POPT_BADOPTION_NOALIAS),
573 +                               poptStrerror(opt));
574 +                       tls_usage(1);
575 +               }
576         }
577  
578 +       extra_args = poptGetArgs(pc);
579 +       if (*extra_args == NULL)
580 +               tls_usage(1);
581 +
582 +       for (; *extra_args; extra_args++)
583 +               list_file(*extra_args);
584 +       poptFreeContext(pc);
585 +
586         return 0;
587  }
588 --- old/util.c
589 +++ new/util.c
590 @@ -121,7 +121,7 @@ NORETURN void overflow_exit(const char *
591         exit_cleanup(RERR_MALLOC);
592  }
593  
594 -int set_modtime(const char *fname, time_t modtime, mode_t mode)
595 +int set_times(const char *fname, time_t modtime, time_t atime, mode_t mode)
596  {
597  #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
598         if (S_ISLNK(mode))
599 @@ -129,9 +129,13 @@ int set_modtime(const char *fname, time_
600  #endif
601  
602         if (verbose > 2) {
603 -               rprintf(FINFO, "set modtime of %s to (%ld) %s",
604 +               char mtimebuf[200];
605 +
606 +               strlcpy(mtimebuf, timestring(modtime), sizeof mtimebuf);
607 +               rprintf(FINFO,
608 +                       "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
609                         fname, (long)modtime,
610 -                       asctime(localtime(&modtime)));
611 +                       mtimebuf, (long)atime, timestring(atime));
612         }
613  
614         if (dry_run)
615 @@ -140,7 +144,7 @@ int set_modtime(const char *fname, time_
616         {
617  #ifdef HAVE_UTIMES
618                 struct timeval t[2];
619 -               t[0].tv_sec = time(NULL);
620 +               t[0].tv_sec = atime;
621                 t[0].tv_usec = 0;
622                 t[1].tv_sec = modtime;
623                 t[1].tv_usec = 0;
624 @@ -153,12 +157,12 @@ int set_modtime(const char *fname, time_
625                 return utimes(fname, t);
626  #elif defined HAVE_UTIMBUF
627                 struct utimbuf tbuf;
628 -               tbuf.actime = time(NULL);
629 +               tbuf.actime = atime;
630                 tbuf.modtime = modtime;
631                 return utime(fname,&tbuf);
632  #elif defined HAVE_UTIME
633                 time_t t[2];
634 -               t[0] = time(NULL);
635 +               t[0] = atime;
636                 t[1] = modtime;
637                 return utime(fname,t);
638  #else