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