a023be9b8662b4cc4e0d701d8e9067bb2a36de84
[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-09-21 09:40:27
19 +++ flist.c     2004-07-03 20:15:41
20 @@ -59,6 +59,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 @@ -143,17 +144,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 @@ -334,6 +335,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 @@ -349,7 +351,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 @@ -398,6 +400,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 @@ -453,6 +461,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 @@ -526,6 +536,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 @@ -542,7 +553,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 @@ -597,6 +608,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 @@ -647,6 +660,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 @@ -868,6 +882,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-09-20 19:50:13
132 +++ generator.c 2004-07-03 20:15:41
133 @@ -92,7 +92,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 @@ -484,7 +484,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-09-20 05:10:48
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 @@ -946,6 +949,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-09-07 21:45:30
187 +++ rsync.c     2004-08-13 08:17:28
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,32 @@ 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 +           != (PERMS_SKIP_MTIME|PERMS_SKIP_ATIME)) {
206 +               time_t atime, mtime;
207 +
208 +               if (!(flags & PERMS_SKIP_ATIME)
209 +                   && cmp_time(st->st_atime, file->atime) != 0) {
210 +                       atime = file->atime;
211 +                       updated = 1;
212 +               } else
213 +                       atime = st->st_atime;
214 +               if (!(flags & PERMS_SKIP_MTIME)
215 +                   && cmp_time(st->st_mtime, file->modtime) != 0) {
216 +                       mtime = file->modtime;
217 +                       updated = 1;
218 +               } else
219 +                       mtime = st->st_mtime;
220                 /* don't complain about not setting times on directories
221                  * because some filesystems can't do it */
222 -               if (set_modtime(fname,file->modtime) != 0 &&
223 +               if (updated && set_times(fname, mtime, atime) != 0 &&
224                     !S_ISDIR(st->st_mode)) {
225                         rsyserr(FERROR, errno, "failed to set times on %s",
226                                 full_fname(fname));
227                         return 0;
228                 }
229 -               updated = 1;
230         }
231  
232         change_uid = am_root && preserve_uid && st->st_uid != file->uid;
233 --- orig/rsync.h        2004-08-03 15:41:32
234 +++ rsync.h     2004-07-03 20:15:41
235 @@ -54,6 +54,7 @@
236  #define XMIT_HAS_IDEV_DATA (1<<9)
237  #define XMIT_SAME_DEV (1<<10)
238  #define XMIT_RDEV_MINOR_IS_SMALL (1<<11)
239 +#define XMIT_SAME_ATIME (1<<12)
240  
241  /* These flags are used in the live flist data. */
242  
243 @@ -111,6 +112,7 @@
244  
245  #define PERMS_REPORT           (1<<0)
246  #define PERMS_SKIP_MTIME       (1<<1)
247 +#define PERMS_SKIP_ATIME       (1<<2)
248  
249  #define FULL_FLUSH     1
250  #define NORMAL_FLUSH   0
251 @@ -425,6 +427,7 @@ struct file_struct {
252                 struct hlink *links;
253         } link_u;
254         time_t modtime;
255 +       time_t atime;
256         uid_t uid;
257         gid_t gid;
258         mode_t mode;
259 --- orig/rsync.yo       2004-09-20 05:10:48
260 +++ rsync.yo    2004-07-03 20:15:41
261 @@ -330,6 +330,7 @@ verb(
262   -g, --group                 preserve group
263   -D, --devices               preserve devices (root only)
264   -t, --times                 preserve times
265 + -A, --copy-atimes           copy access times
266   -S, --sparse                handle sparse files efficiently
267   -n, --dry-run               show what would have been transferred
268   -W, --whole-file            copy whole files, no incremental checks
269 @@ -603,6 +604,11 @@ cause the next transfer to behave as if 
270  updated (though the rsync algorithm will make the update fairly efficient
271  if the files haven't actually changed, you're much better off using -t).
272  
273 +dit(bf(-A, --copy-atimes)) This tells rsync to transfer access times
274 +along with the files and update them on the remote system.  Note that
275 +reading the source file may update the atime and hence repeated rsync
276 +copies with --copy-atimes may copy files unnecessarily.
277 +
278  dit(bf(-n, --dry-run)) This tells rsync to not do any file transfers,
279  instead it will just report the actions it would have taken.
280  
281 --- orig/testsuite/copy-atimes.test     2004-06-30 00:06:23
282 +++ testsuite/copy-atimes.test  2004-06-30 00:06:23
283 @@ -0,0 +1,19 @@
284 +#! /bin/sh
285 +
286 +# Test rsync copying atimes
287 +
288 +. "$suitedir/rsync.fns"
289 +
290 +set -x
291 +
292 +mkdir "$fromdir"
293 +
294 +touch "$fromdir/foo"
295 +touch -a -t 200102031717.42 "$fromdir/foo"
296 +
297 +TLS_ARGS=--atime
298 +
299 +checkit "$RSYNC -rtAgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
300 +
301 +# The script would have aborted on error, so getting here means we've won.
302 +exit 0
303 --- orig/testsuite/rsync.fns    2004-09-18 01:49:34
304 +++ testsuite/rsync.fns 2004-07-03 20:15:41
305 @@ -50,7 +50,7 @@ printmsg() {
306  
307  
308  rsync_ls_lR() {
309 -    find "$@" -print | sort | xargs "$TOOLDIR/tls"
310 +    find "$@" -print | sort | xargs "$TOOLDIR/tls" $TLS_ARGS
311  }
312  
313  rsync_getgroups() { 
314 @@ -158,6 +158,8 @@ checkit() {
315      # We can just write everything to stdout/stderr, because the
316      # wrapper hides it unless there is a problem.
317  
318 +    ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
319 +
320      echo "Running: \"$1\""  
321      eval "$1" 
322      status=$?
323 @@ -166,6 +168,12 @@ checkit() {
324      fi
325  
326      echo "-------------"
327 +    echo "check how the directory listings compare with diff:"
328 +    echo ""
329 +    ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
330 +    diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
331 +
332 +    echo "-------------"
333      echo "check how the files compare with diff:"
334      echo ""
335      for f in `cd "$2"; find . -type f -print `
336 @@ -173,12 +181,6 @@ checkit() {
337          diff $diffopt "$2"/"$f" "$3"/"$f" || failed=YES
338      done
339  
340 -    echo "-------------"
341 -    echo "check how the directory listings compare with diff:"
342 -    echo ""
343 -    ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
344 -    ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
345 -    diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
346      if [ -z "$failed" ] ; then
347         return 0
348      else
349 --- orig/tls.c  2004-05-15 20:10:13
350 +++ tls.c       2004-07-03 20:15:41
351 @@ -39,6 +39,7 @@
352  
353  
354  #include "rsync.h"
355 +#include "popt.h"
356  
357  #define PROGRAM "tls"
358  
359 @@ -48,6 +49,7 @@ int read_only = 1;
360  int list_only = 0;
361  int preserve_perms = 0;
362  
363 +static int display_atime = 0;
364  
365  static void failed(char const *what, char const *where)
366  {
367 @@ -56,14 +58,29 @@ static void failed(char const *what, cha
368         exit(1);
369  }
370  
371 +static void storetime(char *dest, time_t t)
372 +{
373 +       if (t) {
374 +               struct tm *mt = gmtime(&t);
375  
376 +               sprintf(dest, "%04d-%02d-%02d %02d:%02d:%02d ",
377 +                       mt->tm_year + 1900,
378 +                       mt->tm_mon + 1,
379 +                       mt->tm_mday,
380 +                       mt->tm_hour,
381 +                       mt->tm_min,
382 +                       mt->tm_sec);
383 +       } else {
384 +               strcpy(dest, "                    ");
385 +       }
386 +}      
387  
388  static void list_file(const char *fname)
389  {
390         STRUCT_STAT buf;
391         char permbuf[PERMSTRING_SIZE];
392 -       struct tm *mt;
393 -       char datebuf[50];
394 +       char mtimebuf[50];
395 +       char atimebuf[50];
396         char linkbuf[4096];
397  
398         if (do_lstat(fname, &buf) == -1)
399 @@ -96,19 +113,8 @@ static void list_file(const char *fname)
400  
401         permstring(permbuf, buf.st_mode);
402  
403 -       if (buf.st_mtime) {
404 -               mt = gmtime(&buf.st_mtime);
405 -
406 -               sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d",
407 -                       mt->tm_year + 1900,
408 -                       mt->tm_mon + 1,
409 -                       mt->tm_mday,
410 -                       mt->tm_hour,
411 -                       mt->tm_min,
412 -                       mt->tm_sec);
413 -       } else {
414 -               strcpy(datebuf, "                   ");
415 -       }
416 +       storetime(mtimebuf, buf.st_mtime);
417 +       storetime(atimebuf, buf.st_atime);
418  
419         /* TODO: Perhaps escape special characters in fname? */
420  
421 @@ -119,24 +125,55 @@ static void list_file(const char *fname)
422                     (long)minor(buf.st_rdev));
423         } else /* NB: use double for size since it might not fit in a long. */
424                 printf("%12.0f", (double)buf.st_size);
425 -       printf(" %6ld.%-6ld %6ld %s %s%s\n",
426 +       printf(" %6ld.%-6ld %6ld %s%s%s%s\n",
427                (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
428 -              datebuf, fname, linkbuf);
429 +              mtimebuf, display_atime ? atimebuf : "",
430 +              fname, linkbuf);
431  }
432  
433 +static struct poptOption long_options[] = {
434 +  /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
435 +  {"atime",           'u', POPT_ARG_NONE,   &display_atime, 0,   0, 0},
436 +  {"help",            'h', POPT_ARG_NONE,   0,              'h', 0, 0},
437 +  {0,0,0,0,0,0,0}
438 +};
439 +
440 +static void tls_usage(int ret)
441 +{
442 +       fprintf(stderr, "usage: " PROGRAM " [--atime | -u] DIR ...\n"
443 +           "Trivial file listing program for portably checking rsync\n");
444 +       exit(ret);
445 +}
446  
447  int
448  main(int argc, char *argv[])
449  {
450 -       if (argc < 2) {
451 -               fprintf(stderr, "usage: " PROGRAM " DIR ...\n"
452 -                       "Trivial file listing program for portably checking rsync\n");
453 -               return 1;
454 +       poptContext pc;
455 +       const char **extra_args;
456 +       int opt;
457 +
458 +       pc = poptGetContext(PROGRAM, argc, (const char **)argv,
459 +                           long_options, 0);
460 +       while ((opt = poptGetNextOpt(pc)) != -1) {
461 +               switch (opt) {
462 +               case 'h':
463 +                       tls_usage(0);
464 +               default:
465 +                       fprintf(stderr,
466 +                               "%s: %s\n",
467 +                               poptBadOption(pc, POPT_BADOPTION_NOALIAS),
468 +                               poptStrerror(opt));
469 +                       tls_usage(1);
470 +               }
471         }
472  
473 -       for (argv++; *argv; argv++) {
474 -               list_file(*argv);
475 -       }
476 +       extra_args = poptGetArgs(pc);
477 +       if (*extra_args == NULL)
478 +               tls_usage(1);
479 +
480 +       for (; *extra_args; extra_args++)
481 +               list_file(*extra_args);
482 +       poptFreeContext(pc);
483  
484         return 0;
485  }
486 --- orig/util.c 2004-09-07 21:45:30
487 +++ util.c      2004-07-03 20:15:41
488 @@ -128,31 +128,39 @@ void overflow(char *str)
489  
490  
491  
492 -int set_modtime(char *fname, time_t modtime)
493 +int set_times(char *fname, time_t modtime, time_t atime)
494  {
495         if (dry_run)
496                 return 0;
497  
498         if (verbose > 2) {
499 -               rprintf(FINFO, "set modtime of %s to (%ld) %s",
500 +               char mtimebuf[200];
501 +               char atimebuf[200];
502 +
503 +               strlcpy(mtimebuf, timestring(modtime), sizeof mtimebuf);
504 +               strlcpy(atimebuf, timestring(atime), sizeof atimebuf);
505 +
506 +               rprintf(FINFO,
507 +                       "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
508                         fname, (long)modtime,
509 -                       asctime(localtime(&modtime)));
510 +                       mtimebuf,
511 +                       (long)atime, atimebuf);
512         }
513  
514         {
515  #ifdef HAVE_UTIMBUF
516                 struct utimbuf tbuf;
517 -               tbuf.actime = time(NULL);
518 +               tbuf.actime = atime;
519                 tbuf.modtime = modtime;
520                 return utime(fname,&tbuf);
521  #elif defined(HAVE_UTIME)
522                 time_t t[2];
523 -               t[0] = time(NULL);
524 +               t[0] = atime;
525                 t[1] = modtime;
526                 return utime(fname,t);
527  #else
528                 struct timeval t[2];
529 -               t[0].tv_sec = time(NULL);
530 +               t[0].tv_sec = atime;
531                 t[0].tv_usec = 0;
532                 t[1].tv_sec = modtime;
533                 t[1].tv_usec = 0;
534 @@ -1142,8 +1150,8 @@ int msleep(int t)
535  
536  
537  /**
538 - * Determine if two file modification times are equivalent (either
539 - * exact or in the modification timestamp window established by
540 + * Determine if two file  times are equivalent (either
541 + * exact or in the timestamp window established by
542   * --modify-window).
543   *
544   * @retval 0 if the times should be treated as the same
545 @@ -1152,7 +1160,7 @@ int msleep(int t)
546   *
547   * @retval -1 if the 2nd is later
548   **/
549 -int cmp_modtime(time_t file1, time_t file2)
550 +int cmp_time(time_t file1, time_t file2)
551  {
552         if (file2 > file1) {
553                 if (file2 - file1 <= modify_window)