Updated to apply cleanly.
[rsync/rsync-patches.git] / atimes.diff
1 After applying this patch and running configure, you MUST run this
2 command before "make":
3
4     make proto
5
6
7 --- orig/batch.c        2004-08-02 05:02:24
8 +++ batch.c     2004-07-03 20:15:41
9 @@ -184,6 +184,8 @@ void show_flist(int index, struct file_s
10                 rprintf(FINFO, "flist->flags=%#x\n", fptr[i]->flags);
11                 rprintf(FINFO, "flist->modtime=%#lx\n",
12                         (long unsigned) fptr[i]->modtime);
13 +               rprintf(FINFO, "flist->atime=%#lx\n",
14 +                       (long unsigned) fptr[i]->atime);
15                 rprintf(FINFO, "flist->length=%.0f\n",
16                         (double) fptr[i]->length);
17                 rprintf(FINFO, "flist->mode=%#o\n", (int) fptr[i]->mode);
18 --- orig/flist.c        2004-08-11 23:42:23
19 +++ flist.c     2004-07-03 20:15:41
20 @@ -58,6 +58,7 @@ extern int relative_paths;
21  extern int implied_dirs;
22  extern int copy_links;
23  extern int copy_unsafe_links;
24 +extern int copy_atimes;
25  extern int protocol_version;
26  extern int sanitize_paths;
27  extern int delete_excluded;
28 @@ -141,17 +142,17 @@ static void list_file_entry(struct file_
29  
30  #if SUPPORT_LINKS
31         if (preserve_links && S_ISLNK(f->mode)) {
32 -               rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
33 +               rprintf(FINFO, "%s %11.0f %s %s %s -> %s\n",
34                         perms,
35                         (double)f->length, timestring(f->modtime),
36 -                       f_name(f), f->u.link);
37 +                       timestring(f->atime), f_name(f), f->u.link);
38         } else
39  #endif
40         {
41 -               rprintf(FINFO, "%s %11.0f %s %s\n",
42 +               rprintf(FINFO, "%s %11.0f %s %s %s\n",
43                         perms,
44                         (double)f->length, timestring(f->modtime),
45 -                       f_name(f));
46 +                       timestring(f->atime), f_name(f));
47         }
48  }
49  
50 @@ -332,6 +333,7 @@ void send_file_entry(struct file_struct 
51  {
52         unsigned short flags;
53         static time_t modtime;
54 +       static time_t atime;
55         static mode_t mode;
56         static uint64 dev;
57         static dev_t rdev;
58 @@ -347,7 +349,7 @@ void send_file_entry(struct file_struct 
59  
60         if (!file) {
61                 write_byte(f, 0);
62 -               modtime = 0, mode = 0;
63 +               modtime = 0, atime = 0, mode = 0;
64                 dev = 0, rdev = makedev(0, 0);
65                 rdev_major = 0;
66                 uid = 0, gid = 0;
67 @@ -396,6 +398,12 @@ void send_file_entry(struct file_struct 
68                 flags |= XMIT_SAME_TIME;
69         else
70                 modtime = file->modtime;
71 +       if (copy_atimes && !S_ISDIR(mode)) {
72 +               if (file->atime == atime)
73 +                       flags |= XMIT_SAME_ATIME;
74 +               else
75 +                       atime = file->atime;
76 +       }
77  
78  #if SUPPORT_HARD_LINKS
79         if (file->link_u.idev) {
80 @@ -451,6 +459,8 @@ void send_file_entry(struct file_struct 
81                 write_int(f, modtime);
82         if (!(flags & XMIT_SAME_MODE))
83                 write_int(f, to_wire_mode(mode));
84 +       if (copy_atimes && !S_ISDIR(mode) && !(flags & XMIT_SAME_ATIME))
85 +               write_int(f, atime);
86         if (preserve_uid && !(flags & XMIT_SAME_UID)) {
87                 if (!numeric_ids)
88                         add_uid(uid);
89 @@ -524,6 +534,7 @@ void receive_file_entry(struct file_stru
90                         struct file_list *flist, int f)
91  {
92         static time_t modtime;
93 +       static time_t atime;
94         static mode_t mode;
95         static uint64 dev;
96         static dev_t rdev;
97 @@ -540,7 +551,7 @@ void receive_file_entry(struct file_stru
98         struct file_struct *file;
99  
100         if (!fptr) {
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 @@ -595,6 +606,8 @@ void receive_file_entry(struct file_stru
107                 modtime = (time_t)read_int(f);
108         if (!(flags & XMIT_SAME_MODE))
109                 mode = from_wire_mode(read_int(f));
110 +       if (copy_atimes && !S_ISDIR(mode) && !(flags & XMIT_SAME_ATIME))
111 +               atime = (time_t)read_int(f);
112  
113         if (preserve_uid && !(flags & XMIT_SAME_UID))
114                 uid = (uid_t)read_int(f);
115 @@ -645,6 +658,7 @@ void receive_file_entry(struct file_stru
116  
117         file->flags = flags & XMIT_TOP_DIR ? FLAG_TOP_DIR : 0;
118         file->modtime = modtime;
119 +       file->atime = atime;
120         file->length = file_length;
121         file->mode = mode;
122         file->uid = uid;
123 @@ -866,6 +880,7 @@ skip_excludes:
124  
125         file->flags = flags;
126         file->modtime = st.st_mtime;
127 +       file->atime = st.st_atime;
128         file->length = st.st_size;
129         file->mode = st.st_mode;
130         file->uid = st.st_uid;
131 --- orig/generator.c    2004-08-05 18:24:21
132 +++ generator.c 2004-07-03 20:15:41
133 @@ -90,7 +90,7 @@ static int skip_file(char *fname, struct
134         if (ignore_times)
135                 return 0;
136  
137 -       return cmp_modtime(st->st_mtime, file->modtime) == 0;
138 +       return cmp_time(st->st_mtime, file->modtime) == 0;
139  }
140  
141  
142 @@ -470,7 +470,7 @@ static void recv_generator(char *fname, 
143         }
144  
145         if (update_only && fnamecmp == fname
146 -           && cmp_modtime(st.st_mtime, file->modtime) > 0) {
147 +           && cmp_time(st.st_mtime, file->modtime) > 0) {
148                 if (verbose > 1)
149                         rprintf(FINFO, "%s is newer\n", safe_fname(fname));
150                 return;
151 --- orig/options.c      2004-08-11 23:42:23
152 +++ options.c   2004-07-03 20:15:41
153 @@ -48,6 +48,7 @@ int preserve_devices = 0;
154  int preserve_uid = 0;
155  int preserve_gid = 0;
156  int preserve_times = 0;
157 +int copy_atimes = 0;
158  int update_only = 0;
159  int cvs_exclude = 0;
160  int dry_run = 0;
161 @@ -253,6 +254,7 @@ void usage(enum logcode F)
162    rprintf(F," -g, --group                 preserve group\n");
163    rprintf(F," -D, --devices               preserve devices (root only)\n");
164    rprintf(F," -t, --times                 preserve times\n");
165 +  rprintf(F," -A, --copy-atimes           copy access times\n");
166    rprintf(F," -S, --sparse                handle sparse files efficiently\n");
167    rprintf(F," -n, --dry-run               show what would have been transferred\n");
168    rprintf(F," -W, --whole-file            copy whole files, no incremental checks\n");
169 @@ -362,6 +364,7 @@ static struct poptOption long_options[] 
170    {"group",           'g', POPT_ARG_NONE,   &preserve_gid, 0, 0, 0 },
171    {"devices",         'D', POPT_ARG_NONE,   &preserve_devices, 0, 0, 0 },
172    {"times",           't', POPT_ARG_NONE,   &preserve_times, 0, 0, 0 },
173 +  {"copy-atimes",     'A', POPT_ARG_NONE,   &copy_atimes, 0, 0, 0 },
174    {"checksum",        'c', POPT_ARG_NONE,   &always_checksum, 0, 0, 0 },
175    {"verbose",         'v', POPT_ARG_NONE,   0,               'v', 0, 0 },
176    {"quiet",           'q', POPT_ARG_NONE,   0,               'q', 0, 0 },
177 @@ -940,6 +943,8 @@ void server_options(char **args,int *arg
178                 argstr[x++] = 'D';
179         if (preserve_times)
180                 argstr[x++] = 't';
181 +       if (copy_atimes)
182 +               argstr[x++] = 'A';
183         if (preserve_perms)
184                 argstr[x++] = 'p';
185         if (recurse)
186 --- orig/rsync.c        2004-08-09 21:07:10
187 +++ rsync.c     2004-07-03 20:15:41
188 @@ -25,6 +25,7 @@
189  extern int verbose;
190  extern int dry_run;
191  extern int preserve_times;
192 +extern int copy_atimes;
193  extern int am_root;
194  extern int am_sender;
195  extern int am_generator;
196 @@ -145,17 +146,31 @@ int set_perms(char *fname,struct file_st
197         if (!preserve_times || S_ISLNK(st->st_mode)
198             || (make_backups && !backup_dir && S_ISDIR(st->st_mode)))
199                 flags |= PERMS_SKIP_MTIME;
200 -       if (!(flags & PERMS_SKIP_MTIME)
201 -           && cmp_modtime(st->st_mtime, file->modtime) != 0) {
202 +       if (!copy_atimes || S_ISLNK(st->st_mode) || S_ISDIR(st->st_mode))
203 +               flags |= PERMS_SKIP_ATIME;
204 +       if (!(flags & (PERMS_SKIP_MTIME|PERMS_SKIP_ATIME))) {
205 +               time_t atime, mtime;
206 +
207 +               if (!(flags & PERMS_SKIP_ATIME)
208 +                   && cmp_time(st->st_atime, file->atime) != 0) {
209 +                       atime = file->atime;
210 +                       updated = 1;
211 +               } else
212 +                       atime = st->st_atime;
213 +               if (!(flags & PERMS_SKIP_MTIME)
214 +                   && cmp_time(st->st_mtime, file->modtime) != 0) {
215 +                       mtime = file->modtime;
216 +                       updated = 1;
217 +               } else
218 +                       mtime = st->st_mtime;
219                 /* don't complain about not setting times on directories
220                  * because some filesystems can't do it */
221 -               if (set_modtime(fname,file->modtime) != 0 &&
222 +               if (updated && set_times(fname, mtime, atime) != 0 &&
223                     !S_ISDIR(st->st_mode)) {
224                         rsyserr(FERROR, errno, "failed to set times on %s",
225                                 full_fname(fname));
226                         return 0;
227                 }
228 -               updated = 1;
229         }
230  
231         change_uid = am_root && preserve_uid && st->st_uid != file->uid;
232 --- orig/rsync.h        2004-08-03 15:41:32
233 +++ rsync.h     2004-07-03 20:15:41
234 @@ -54,6 +54,7 @@
235  #define XMIT_HAS_IDEV_DATA (1<<9)
236  #define XMIT_SAME_DEV (1<<10)
237  #define XMIT_RDEV_MINOR_IS_SMALL (1<<11)
238 +#define XMIT_SAME_ATIME (1<<12)
239  
240  /* These flags are used in the live flist data. */
241  
242 @@ -111,6 +112,7 @@
243  
244  #define PERMS_REPORT           (1<<0)
245  #define PERMS_SKIP_MTIME       (1<<1)
246 +#define PERMS_SKIP_ATIME       (1<<2)
247  
248  #define FULL_FLUSH     1
249  #define NORMAL_FLUSH   0
250 @@ -425,6 +427,7 @@ struct file_struct {
251                 struct hlink *links;
252         } link_u;
253         time_t modtime;
254 +       time_t atime;
255         uid_t uid;
256         gid_t gid;
257         mode_t mode;
258 --- orig/rsync.yo       2004-08-11 17:26:27
259 +++ rsync.yo    2004-07-03 20:15:41
260 @@ -301,6 +301,7 @@ verb(
261   -g, --group                 preserve group
262   -D, --devices               preserve devices (root only)
263   -t, --times                 preserve times
264 + -A, --copy-atimes           copy access times
265   -S, --sparse                handle sparse files efficiently
266   -n, --dry-run               show what would have been transferred
267   -W, --whole-file            copy whole files, no incremental checks
268 @@ -574,6 +575,11 @@ cause the next transfer to behave as if 
269  updated (though the rsync algorithm will make the update fairly efficient
270  if the files haven't actually changed, you're much better off using -t).
271  
272 +dit(bf(-A, --copy-atimes)) This tells rsync to transfer access times
273 +along with the files and update them on the remote system.  Note that
274 +reading the source file may update the atime and hence repeated rsync
275 +copies with --copy-atimes may copy files unnecessarily.
276 +
277  dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
278  instead it will just report the actions it would have taken.
279  
280 --- orig/testsuite/copy-atimes.test     2004-06-30 00:06:23
281 +++ testsuite/copy-atimes.test  2004-06-30 00:06:23
282 @@ -0,0 +1,19 @@
283 +#! /bin/sh
284 +
285 +# Test rsync copying atimes
286 +
287 +. "$suitedir/rsync.fns"
288 +
289 +set -x
290 +
291 +mkdir "$fromdir"
292 +
293 +touch "$fromdir/foo"
294 +touch -a -t 200102031717.42 "$fromdir/foo"
295 +
296 +TLS_ARGS=--atime
297 +
298 +checkit "$RSYNC -rtAgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
299 +
300 +# The script would have aborted on error, so getting here means we've won.
301 +exit 0
302 --- orig/testsuite/rsync.fns    2004-07-23 17:16:13
303 +++ testsuite/rsync.fns 2004-07-03 20:15:41
304 @@ -50,7 +50,7 @@ printmsg() {
305  
306  
307  rsync_ls_lR() {
308 -    find "$@" -print | sort | xargs "$TOOLDIR/tls"
309 +    find "$@" -print | sort | xargs "$TOOLDIR/tls" $TLS_ARGS
310  }
311  
312  rsync_getgroups() { 
313 @@ -150,6 +150,8 @@ checkit() {
314      # We can just write everything to stdout/stderr, because the
315      # wrapper hides it unless there is a problem.
316  
317 +    ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
318 +
319      echo "Running: \"$1\""  
320      eval "$1" 
321      status=$?
322 @@ -158,6 +160,12 @@ checkit() {
323      fi
324  
325      echo "-------------"
326 +    echo "check how the directory listings compare with diff:"
327 +    echo ""
328 +    ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
329 +    diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
330 +
331 +    echo "-------------"
332      echo "check how the files compare with diff:"
333      echo ""
334      for f in `cd "$2"; find . -type f -print `
335 @@ -165,12 +173,6 @@ checkit() {
336          diff $diffopt "$2"/"$f" "$3"/"$f" || failed=YES
337      done
338  
339 -    echo "-------------"
340 -    echo "check how the directory listings compare with diff:"
341 -    echo ""
342 -    ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
343 -    ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
344 -    diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
345      if [ -z "$failed" ] ; then
346         return 0
347      else
348 --- orig/tls.c  2004-05-15 20:10:13
349 +++ tls.c       2004-07-03 20:15:41
350 @@ -39,6 +39,7 @@
351  
352  
353  #include "rsync.h"
354 +#include "popt.h"
355  
356  #define PROGRAM "tls"
357  
358 @@ -48,6 +49,7 @@ int read_only = 1;
359  int list_only = 0;
360  int preserve_perms = 0;
361  
362 +static int display_atime = 0;
363  
364  static void failed(char const *what, char const *where)
365  {
366 @@ -56,14 +58,29 @@ static void failed(char const *what, cha
367         exit(1);
368  }
369  
370 +static void storetime(char *dest, time_t t)
371 +{
372 +       if (t) {
373 +               struct tm *mt = gmtime(&t);
374  
375 +               sprintf(dest, "%04d-%02d-%02d %02d:%02d:%02d ",
376 +                       mt->tm_year + 1900,
377 +                       mt->tm_mon + 1,
378 +                       mt->tm_mday,
379 +                       mt->tm_hour,
380 +                       mt->tm_min,
381 +                       mt->tm_sec);
382 +       } else {
383 +               strcpy(dest, "                    ");
384 +       }
385 +}      
386  
387  static void list_file(const char *fname)
388  {
389         STRUCT_STAT buf;
390         char permbuf[PERMSTRING_SIZE];
391 -       struct tm *mt;
392 -       char datebuf[50];
393 +       char mtimebuf[50];
394 +       char atimebuf[50];
395         char linkbuf[4096];
396  
397         if (do_lstat(fname, &buf) == -1)
398 @@ -96,19 +113,8 @@ static void list_file(const char *fname)
399  
400         permstring(permbuf, buf.st_mode);
401  
402 -       if (buf.st_mtime) {
403 -               mt = gmtime(&buf.st_mtime);
404 -
405 -               sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d",
406 -                       mt->tm_year + 1900,
407 -                       mt->tm_mon + 1,
408 -                       mt->tm_mday,
409 -                       mt->tm_hour,
410 -                       mt->tm_min,
411 -                       mt->tm_sec);
412 -       } else {
413 -               strcpy(datebuf, "                   ");
414 -       }
415 +       storetime(mtimebuf, buf.st_mtime);
416 +       storetime(atimebuf, buf.st_atime);
417  
418         /* TODO: Perhaps escape special characters in fname? */
419  
420 @@ -119,24 +125,55 @@ static void list_file(const char *fname)
421                     (long)minor(buf.st_rdev));
422         } else /* NB: use double for size since it might not fit in a long. */
423                 printf("%12.0f", (double)buf.st_size);
424 -       printf(" %6ld.%-6ld %6ld %s %s%s\n",
425 +       printf(" %6ld.%-6ld %6ld %s%s%s%s\n",
426                (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
427 -              datebuf, fname, linkbuf);
428 +              mtimebuf, display_atime ? atimebuf : "",
429 +              fname, linkbuf);
430  }
431  
432 +static struct poptOption long_options[] = {
433 +  /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
434 +  {"atime",           'u', POPT_ARG_NONE,   &display_atime, 0,   0, 0},
435 +  {"help",            'h', POPT_ARG_NONE,   0,              'h', 0, 0},
436 +  {0,0,0,0,0,0,0}
437 +};
438 +
439 +static void tls_usage(int ret)
440 +{
441 +       fprintf(stderr, "usage: " PROGRAM " [--atime | -u] DIR ...\n"
442 +           "Trivial file listing program for portably checking rsync\n");
443 +       exit(ret);
444 +}
445  
446  int
447  main(int argc, char *argv[])
448  {
449 -       if (argc < 2) {
450 -               fprintf(stderr, "usage: " PROGRAM " DIR ...\n"
451 -                       "Trivial file listing program for portably checking rsync\n");
452 -               return 1;
453 +       poptContext pc;
454 +       const char **extra_args;
455 +       int opt;
456 +
457 +       pc = poptGetContext(PROGRAM, argc, (const char **)argv,
458 +                           long_options, 0);
459 +       while ((opt = poptGetNextOpt(pc)) != -1) {
460 +               switch (opt) {
461 +               case 'h':
462 +                       tls_usage(0);
463 +               default:
464 +                       fprintf(stderr,
465 +                               "%s: %s\n",
466 +                               poptBadOption(pc, POPT_BADOPTION_NOALIAS),
467 +                               poptStrerror(opt));
468 +                       tls_usage(1);
469 +               }
470         }
471  
472 -       for (argv++; *argv; argv++) {
473 -               list_file(*argv);
474 -       }
475 +       extra_args = poptGetArgs(pc);
476 +       if (*extra_args == NULL)
477 +               tls_usage(1);
478 +
479 +       for (; *extra_args; extra_args++)
480 +               list_file(*extra_args);
481 +       poptFreeContext(pc);
482  
483         return 0;
484  }
485 --- orig/util.c 2004-08-11 23:42:23
486 +++ util.c      2004-07-03 20:15:41
487 @@ -128,31 +128,39 @@ void overflow(char *str)
488  
489  
490  
491 -int set_modtime(char *fname, time_t modtime)
492 +int set_times(char *fname, time_t modtime, time_t atime)
493  {
494         if (dry_run)
495                 return 0;
496  
497         if (verbose > 2) {
498 -               rprintf(FINFO, "set modtime of %s to (%ld) %s",
499 +               char mtimebuf[200];
500 +               char atimebuf[200];
501 +
502 +               strlcpy(mtimebuf, timestring(modtime), sizeof mtimebuf);
503 +               strlcpy(atimebuf, timestring(atime), sizeof atimebuf);
504 +
505 +               rprintf(FINFO,
506 +                       "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
507                         fname, (long)modtime,
508 -                       asctime(localtime(&modtime)));
509 +                       mtimebuf,
510 +                       (long)atime, atimebuf);
511         }
512  
513         {
514  #ifdef HAVE_UTIMBUF
515                 struct utimbuf tbuf;
516 -               tbuf.actime = time(NULL);
517 +               tbuf.actime = atime;
518                 tbuf.modtime = modtime;
519                 return utime(fname,&tbuf);
520  #elif defined(HAVE_UTIME)
521                 time_t t[2];
522 -               t[0] = time(NULL);
523 +               t[0] = atime;
524                 t[1] = modtime;
525                 return utime(fname,t);
526  #else
527                 struct timeval t[2];
528 -               t[0].tv_sec = time(NULL);
529 +               t[0].tv_sec = atime;
530                 t[0].tv_usec = 0;
531                 t[1].tv_sec = modtime;
532                 t[1].tv_usec = 0;
533 @@ -1156,8 +1164,8 @@ int msleep(int t)
534  
535  
536  /**
537 - * Determine if two file modification times are equivalent (either
538 - * exact or in the modification timestamp window established by
539 + * Determine if two file  times are equivalent (either
540 + * exact or in the timestamp window established by
541   * --modify-window).
542   *
543   * @retval 0 if the times should be treated as the same
544 @@ -1166,7 +1174,7 @@ int msleep(int t)
545   *
546   * @retval -1 if the 2nd is later
547   **/
548 -int cmp_modtime(time_t file1, time_t file2)
549 +int cmp_time(time_t file1, time_t file2)
550  {
551         if (file2 > file1) {
552                 if (file2 - file1 <= modify_window)