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