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