1 After applying this patch and running configure, you MUST run this
7 --- orig/batch.c 2006-01-14 08:14:29
8 +++ batch.c 2006-01-24 19:18:36
9 @@ -23,6 +23,7 @@ extern int do_compression;
10 extern int def_compress_level;
11 extern int protocol_version;
12 extern char *batch_name;
13 +extern unsigned int file_struct_len;
15 extern struct filter_list_struct filter_list;
17 @@ -222,9 +223,11 @@ void show_flist(int index, struct file_s
20 for (i = 0; i < index; i++) {
21 - rprintf(FINFO, "flist->flags=%#x\n", fptr[i]->flags);
22 + rprintf(FINFO, "flist->flags=%#x\n", FFLAGS(fptr[i]));
23 rprintf(FINFO, "flist->modtime=%#lx\n",
24 (long unsigned) fptr[i]->modtime);
25 + rprintf(FINFO, "flist->atime=%#lx\n",
26 + (long unsigned) fptr[i]->atime);
27 rprintf(FINFO, "flist->length=%.0f\n",
28 (double) fptr[i]->length);
29 rprintf(FINFO, "flist->mode=%#o\n", (int) fptr[i]->mode);
30 --- orig/flist.c 2006-01-24 19:03:06
31 +++ flist.c 2006-01-24 19:32:19
32 @@ -50,6 +50,7 @@ extern int preserve_perms;
33 extern int preserve_devices;
34 extern int preserve_uid;
35 extern int preserve_gid;
36 +extern int preserve_atimes;
37 extern int relative_paths;
38 extern int implied_dirs;
39 extern int copy_links;
40 @@ -83,7 +84,11 @@ void init_flist(void)
43 /* Figure out how big the file_struct is without trailing padding */
44 - file_struct_len = offsetof(struct file_struct, flags) + sizeof f.flags;
45 + if (preserve_atimes)
46 + file_struct_len = offsetof(struct file_struct, flags);
48 + file_struct_len = offsetof(struct file_struct, atime);
49 + file_struct_len += sizeof f.flags;
50 checksum_len = protocol_version < 21 ? 2 : MD4_SUM_LENGTH;
53 @@ -139,16 +144,18 @@ static void list_file_entry(struct file_
56 if (preserve_links && S_ISLNK(f->mode)) {
57 - rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
58 + rprintf(FINFO, "%s %11.0f %s %s %s -> %s\n",
60 (double)f->length, timestring(f->modtime),
61 + preserve_atimes ? timestring(f->atime) : "",
62 f_name(f, NULL), f->u.link);
66 - rprintf(FINFO, "%s %11.0f %s %s\n",
67 + rprintf(FINFO, "%s %11.0f %s %s %s\n",
69 (double)f->length, timestring(f->modtime),
70 + preserve_atimes ? timestring(f->atime) : "",
74 @@ -310,6 +317,7 @@ static void send_file_entry(struct file_
77 static time_t modtime;
78 + static time_t atime;
82 @@ -325,7 +333,7 @@ static void send_file_entry(struct file_
86 - modtime = 0, mode = 0;
87 + modtime = 0, atime = 0, mode = 0;
88 dev = 0, rdev = makedev(0, 0);
91 @@ -337,7 +345,7 @@ static void send_file_entry(struct file_
95 - flags = file->flags & XMIT_TOP_DIR;
96 + flags = FFLAGS(file) & XMIT_TOP_DIR;
98 if (file->mode == mode)
99 flags |= XMIT_SAME_MODE;
100 @@ -374,6 +382,12 @@ static void send_file_entry(struct file_
101 flags |= XMIT_SAME_TIME;
103 modtime = file->modtime;
104 + if (preserve_atimes && !S_ISDIR(mode)) {
105 + if (file->atime == atime)
106 + flags |= XMIT_SAME_ATIME;
108 + atime = file->atime;
111 #ifdef SUPPORT_HARD_LINKS
112 if (file->link_u.idev) {
113 @@ -427,6 +441,8 @@ static void send_file_entry(struct file_
114 write_int(f, modtime);
115 if (!(flags & XMIT_SAME_MODE))
116 write_int(f, to_wire_mode(mode));
117 + if (preserve_atimes && !S_ISDIR(mode) && !(flags & XMIT_SAME_ATIME))
118 + write_int(f, atime);
119 if (preserve_uid && !(flags & XMIT_SAME_UID)) {
122 @@ -494,6 +510,7 @@ static struct file_struct *receive_file_
123 unsigned short flags, int f)
125 static time_t modtime;
126 + static time_t atime;
130 @@ -512,7 +529,7 @@ static struct file_struct *receive_file_
131 struct file_struct *file;
134 - modtime = 0, mode = 0;
135 + modtime = 0, atime = 0, mode = 0;
136 dev = 0, rdev = makedev(0, 0);
139 @@ -568,6 +585,8 @@ static struct file_struct *receive_file_
140 modtime = (time_t)read_int(f);
141 if (!(flags & XMIT_SAME_MODE))
142 mode = from_wire_mode(read_int(f));
143 + if (preserve_atimes && !S_ISDIR(mode) && !(flags & XMIT_SAME_ATIME))
144 + atime = (time_t)read_int(f);
146 if (chmod_modes && !S_ISLNK(mode))
147 mode = tweak_mode(mode, chmod_modes);
148 @@ -623,6 +642,8 @@ static struct file_struct *receive_file_
149 file->length = file_length;
151 file->ids = id_pair(uid, gid);
152 + if (preserve_atimes)
153 + file->atime = atime;
156 file->dirname = lastdir = bp;
157 @@ -648,12 +669,12 @@ static struct file_struct *receive_file_
158 && lastname[del_hier_name_len-1] == '.'
159 && lastname[del_hier_name_len-2] == '/')
160 del_hier_name_len -= 2;
161 - file->flags |= FLAG_TOP_DIR | FLAG_DEL_HERE;
162 + FFLAGS(file) |= FLAG_TOP_DIR | FLAG_DEL_HERE;
163 } else if (in_del_hier) {
164 if (!relative_paths || !del_hier_name_len
165 || (l1 >= del_hier_name_len
166 && lastname[del_hier_name_len] == '/'))
167 - file->flags |= FLAG_DEL_HERE;
168 + FFLAGS(file) |= FLAG_DEL_HERE;
172 @@ -874,11 +895,13 @@ struct file_struct *make_file(char *fnam
173 memset(bp, 0, file_struct_len);
174 bp += file_struct_len;
176 - file->flags = flags;
177 + FFLAGS(file) = flags;
178 file->modtime = st.st_mtime;
179 file->length = st.st_size;
180 file->mode = st.st_mode;
181 file->ids = id_pair(st.st_uid, st.st_gid);
182 + if (preserve_atimes)
183 + file->atime = st.st_atime;
185 #ifdef SUPPORT_HARD_LINKS
186 if (flist && flist->hlink_pool) {
187 @@ -989,7 +1012,7 @@ static void send_if_directory(int f, str
188 char is_dot_dir = fbuf[ol-1] == '.' && (ol == 1 || fbuf[ol-2] == '/');
190 if (S_ISDIR(file->mode)
191 - && !(file->flags & FLAG_MOUNT_POINT) && f_name(file, fbuf)) {
192 + && !(FFLAGS(file) & FLAG_MOUNT_POINT) && f_name(file, fbuf)) {
194 unsigned int len = strlen(fbuf);
195 if (len > 1 && fbuf[len-1] == '/')
196 @@ -1567,8 +1590,9 @@ static void clean_flist(struct file_list
198 /* Make sure that if we unduplicate '.', that we don't
199 * lose track of a user-specified top directory. */
200 - flist->files[keep]->flags |= flist->files[drop]->flags
201 - & (FLAG_TOP_DIR|FLAG_DEL_HERE);
202 + FFLAGS(flist->files[keep])
203 + |= FFLAGS(flist->files[drop])
204 + & (FLAG_TOP_DIR|FLAG_DEL_HERE);
206 clear_file(drop, flist);
208 @@ -1630,7 +1654,7 @@ static void output_flist(struct file_lis
209 file->dirname ? file->dirname : "",
210 file->dirname ? "/" : "", NS(file->basename),
211 S_ISDIR(file->mode) ? "/" : "", (int)file->mode,
212 - (double)file->length, uidbuf, gidbuf, file->flags);
213 + (double)file->length, uidbuf, gidbuf, FFLAGS(file));
217 --- orig/generator.c 2006-01-24 19:03:07
218 +++ generator.c 2006-01-24 19:19:42
219 @@ -44,6 +44,7 @@ extern int preserve_uid;
220 extern int preserve_gid;
221 extern int preserve_times;
222 extern int omit_dir_times;
223 +extern int preserve_atimes;
224 extern int delete_before;
225 extern int delete_during;
226 extern int delete_after;
227 @@ -89,6 +90,7 @@ extern dev_t filesystem_dev;
228 extern char *backup_dir;
229 extern char *backup_suffix;
230 extern int backup_suffix_len;
231 +extern unsigned int file_struct_len;
232 extern struct file_list *the_file_list;
233 extern struct filter_list_struct server_filter_list;
235 @@ -183,7 +185,7 @@ static int delete_item(char *fname, int
236 for (j = dirlist->count; j--; ) {
237 struct file_struct *fp = dirlist->files[j];
239 - if (fp->flags & FLAG_MOUNT_POINT)
240 + if (FFLAGS(fp) & FLAG_MOUNT_POINT)
243 strlcpy(p, fp->basename, remainder);
244 @@ -261,7 +263,7 @@ static void delete_in_dir(struct file_li
245 filt_array[cur_depth] = push_local_filters(fbuf, dlen);
247 if (one_file_system) {
248 - if (file->flags & FLAG_TOP_DIR)
249 + if (FFLAGS(file) & FLAG_TOP_DIR)
250 filesystem_dev = stp->st_dev;
251 else if (filesystem_dev != stp->st_dev)
253 @@ -273,7 +275,7 @@ static void delete_in_dir(struct file_li
254 * from the filesystem. */
255 for (i = dirlist->count; i--; ) {
256 struct file_struct *fp = dirlist->files[i];
257 - if (!fp->basename || fp->flags & FLAG_MOUNT_POINT)
258 + if (!fp->basename || FFLAGS(fp) & FLAG_MOUNT_POINT)
260 if (flist_find(flist, fp) < 0) {
262 @@ -300,11 +302,11 @@ static void do_delete_pass(struct file_l
263 for (j = 0; j < flist->count; j++) {
264 struct file_struct *file = flist->files[j];
266 - if (!(file->flags & FLAG_DEL_HERE))
267 + if (!(FFLAGS(file) & FLAG_DEL_HERE))
271 - if (verbose > 1 && file->flags & FLAG_TOP_DIR)
272 + if (verbose > 1 && FFLAGS(file) & FLAG_TOP_DIR)
273 rprintf(FINFO, "deleting in %s\n", fbuf);
275 if (link_stat(fbuf, &st, keep_dirlinks) < 0
276 @@ -344,10 +346,18 @@ void itemize(struct file_struct *file, i
278 if (S_ISREG(file->mode) && file->length != st->st_size)
279 iflags |= ITEM_REPORT_SIZE;
280 - if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
281 - && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
282 - || (keep_time && cmp_modtime(file->modtime, st->st_mtime) != 0))
283 + if (iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
284 + && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname)) {
285 iflags |= ITEM_REPORT_TIME;
286 + if (!preserve_atimes && !S_ISDIR(file->mode))
287 + iflags |= ITEM_REPORT_ATIME;
289 + if (keep_time && cmp_time(file->modtime, st->st_mtime) != 0)
290 + iflags |= ITEM_REPORT_TIME;
291 + if (preserve_atimes && !S_ISDIR(file->mode)
292 + && cmp_time(file->atime, st->st_atime) != 0)
293 + iflags |= ITEM_REPORT_ATIME;
296 && (file->mode & CHMOD_BITS) != (st->st_mode & CHMOD_BITS))
297 iflags |= ITEM_REPORT_PERMS;
298 @@ -396,7 +406,7 @@ int unchanged_file(char *fn, struct file
302 - return cmp_modtime(st->st_mtime, file->modtime) == 0;
303 + return cmp_time(st->st_mtime, file->modtime) == 0;
307 @@ -550,13 +560,13 @@ static int find_fuzzy(struct file_struct
310 if (!S_ISREG(fp->mode) || !fp->length
311 - || fp->flags & FLAG_NO_FUZZY)
312 + || FFLAGS(fp) & FLAG_NO_FUZZY)
317 if (fp->length == file->length
318 - && cmp_modtime(fp->modtime, file->modtime) == 0) {
319 + && cmp_time(fp->modtime, file->modtime) == 0) {
322 "fuzzy size/modtime match for %s\n",
323 @@ -632,7 +642,7 @@ static int try_dests_reg(struct file_str
324 if (!unchanged_attrs(file, stp))
326 if ((always_checksum || ignore_times)
327 - && cmp_modtime(stp->st_mtime, file->modtime))
328 + && cmp_time(stp->st_mtime, file->modtime))
332 @@ -894,7 +904,7 @@ static void recv_generator(char *fname,
333 && verbose && code && f_out != -1)
334 rprintf(code, "%s/\n", fname);
335 if (delete_during && f_out != -1 && !phase && dry_run < 2
336 - && (file->flags & FLAG_DEL_HERE))
337 + && (FFLAGS(file) & FLAG_DEL_HERE))
338 delete_in_dir(the_file_list, fname, file, &st);
341 @@ -1071,7 +1081,7 @@ static void recv_generator(char *fname,
344 if (update_only && statret == 0
345 - && cmp_modtime(st.st_mtime, file->modtime) > 0) {
346 + && cmp_time(st.st_mtime, file->modtime) > 0) {
348 rprintf(FINFO, "%s is newer\n", fname);
350 @@ -1174,7 +1184,7 @@ static void recv_generator(char *fname,
352 int j = flist_find(fuzzy_dirlist, file);
353 if (j >= 0) /* don't use changing file as future fuzzy basis */
354 - fuzzy_dirlist->files[j]->flags |= FLAG_NO_FUZZY;
355 + FFLAGS(fuzzy_dirlist->files[j]) |= FLAG_NO_FUZZY;
359 --- orig/hlink.c 2006-01-14 20:27:09
360 +++ hlink.c 2006-01-24 19:17:58
361 @@ -26,6 +26,7 @@ extern int link_dest;
362 extern int make_backups;
363 extern int log_format_has_i;
364 extern char *basis_dir[];
365 +extern unsigned int file_struct_len;
366 extern struct file_list *the_file_list;
368 #ifdef SUPPORT_HARD_LINKS
369 @@ -86,10 +87,10 @@ static void link_idev_data(void)
370 FPTR(cur)->link_u.links = pool_talloc(hlink_pool,
371 struct hlink, 1, "hlink_list");
373 - FPTR(head)->flags |= FLAG_HLINK_TOL;
374 + FFLAGS(FPTR(head)) |= FLAG_HLINK_TOL;
375 FPTR(cur)->F_HLINDEX = to;
376 FPTR(cur)->F_NEXT = head;
377 - FPTR(cur)->flags |= FLAG_HLINK_EOL;
378 + FFLAGS(FPTR(cur)) |= FLAG_HLINK_EOL;
379 hlink_list[to++] = head;
381 FPTR(cur)->link_u.links = NULL;
382 @@ -175,7 +176,7 @@ int hard_link_check(struct file_struct *
384 #ifdef SUPPORT_HARD_LINKS
386 - if (skip && !(file->flags & FLAG_HLINK_EOL))
387 + if (skip && !(FFLAGS(file) & FLAG_HLINK_EOL))
388 head = hlink_list[file->F_HLINDEX] = file->F_NEXT;
390 head = hlink_list[file->F_HLINDEX];
391 @@ -270,8 +271,8 @@ void hard_link_cluster(struct file_struc
392 file->F_HLINDEX = FINISHED_LINK;
393 if (link_stat(f_name(file, hlink1), &st1, 0) < 0)
395 - if (!(file->flags & FLAG_HLINK_TOL)) {
396 - while (!(file->flags & FLAG_HLINK_EOL)) {
397 + if (!(FFLAGS(file) & FLAG_HLINK_TOL)) {
398 + while (!(FFLAGS(file) & FLAG_HLINK_EOL)) {
402 @@ -286,6 +287,6 @@ void hard_link_cluster(struct file_struc
403 maybe_hard_link(file, ndx, hlink2, statret, &st2,
404 hlink1, &st1, itemizing, code);
405 file->F_HLINDEX = FINISHED_LINK;
406 - } while (!(file->flags & FLAG_HLINK_EOL));
407 + } while (!(FFLAGS(file) & FLAG_HLINK_EOL));
410 --- orig/log.c 2006-01-24 17:00:34
411 +++ log.c 2005-12-15 23:05:44
412 @@ -38,6 +38,7 @@ extern int module_id;
413 extern int msg_fd_out;
414 extern int protocol_version;
415 extern int preserve_times;
416 +extern int preserve_atimes;
417 extern int log_format_has_i;
418 extern int log_format_has_o_or_i;
419 extern int daemon_log_format_has_o_or_i;
420 @@ -543,11 +544,14 @@ static void log_formatted(enum logcode c
421 n[4] = !(iflags & ITEM_REPORT_TIME) ? '.'
422 : !preserve_times || IS_DEVICE(file->mode)
423 || S_ISLNK(file->mode) ? 'T' : 't';
424 - n[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
425 - n[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
426 - n[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
427 - n[8] = !(iflags & ITEM_REPORT_XATTRS) ? '.' : 'a';
429 + n[5] = !(iflags & ITEM_REPORT_ATIME) ? '.'
430 + : !preserve_atimes || IS_DEVICE(file->mode)
431 + || S_ISLNK(file->mode) ? 'A' : 'a';
432 + n[6] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
433 + n[7] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
434 + n[8] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
435 + n[9] = !(iflags & ITEM_REPORT_XATTRS) ? '.' : 'a';
438 if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
439 char ch = iflags & ITEM_IS_NEW ? '+' : '?';
440 --- orig/options.c 2006-01-23 18:48:23
441 +++ options.c 2005-11-07 04:32:19
442 @@ -50,6 +50,7 @@ int preserve_uid = 0;
443 int preserve_gid = 0;
444 int preserve_times = 0;
445 int omit_dir_times = 0;
446 +int preserve_atimes = 0;
450 @@ -291,8 +292,9 @@ void usage(enum logcode F)
451 rprintf(F," -o, --owner preserve owner (root only)\n");
452 rprintf(F," -g, --group preserve group\n");
453 rprintf(F," -D, --devices preserve devices (root only)\n");
454 - rprintf(F," -t, --times preserve times\n");
455 - rprintf(F," -O, --omit-dir-times omit directories when preserving times\n");
456 + rprintf(F," -t, --times preserve modify times\n");
457 + rprintf(F," -O, --omit-dir-times omit directories when preserving modify times\n");
458 + rprintf(F," -k, --atimes preserve (keep) access times\n");
459 rprintf(F," --chmod=CHMOD change destination permissions\n");
460 rprintf(F," -S, --sparse handle sparse files efficiently\n");
461 rprintf(F," -n, --dry-run show what would have been transferred\n");
462 @@ -400,6 +402,9 @@ static struct poptOption long_options[]
463 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
464 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
465 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
466 + {"atimes", 'k', POPT_ARG_VAL, &preserve_atimes, 1, 0, 0 },
467 + {"no-atimes", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 },
468 + {"no-k", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 },
469 {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 2, 0, 0 },
470 {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
471 {"owner", 'o', POPT_ARG_VAL, &preserve_uid, 1, 0, 0 },
472 @@ -1468,6 +1473,8 @@ void server_options(char **args,int *arg
476 + if (preserve_atimes)
478 if (omit_dir_times == 2 && am_sender)
481 --- orig/rsync.c 2006-01-24 19:03:07
482 +++ rsync.c 2005-07-28 00:17:37
483 @@ -27,6 +27,7 @@ extern int dry_run;
484 extern int daemon_log_format_has_i;
485 extern int preserve_times;
486 extern int omit_dir_times;
487 +extern int preserve_atimes;
489 extern int am_server;
490 extern int am_sender;
491 @@ -56,6 +57,7 @@ int set_perms(char *fname,struct file_st
494 int change_uid, change_gid;
495 + time_t atime, mtime;
499 @@ -70,16 +72,29 @@ int set_perms(char *fname,struct file_st
501 if (!preserve_times || (S_ISDIR(st->st_mode) && omit_dir_times))
502 flags |= PERMS_SKIP_MTIME;
503 + if (!preserve_atimes || S_ISDIR(st->st_mode))
504 + flags |= PERMS_SKIP_ATIME;
505 if (!(flags & PERMS_SKIP_MTIME)
506 - && cmp_modtime(st->st_mtime, file->modtime) != 0) {
507 - int ret = set_modtime(fname, file->modtime, st->st_mode);
508 + && cmp_time(st->st_mtime, file->modtime) != 0) {
509 + mtime = file->modtime;
512 + mtime = st->st_mtime;
513 + if (!(flags & PERMS_SKIP_ATIME)
514 + && cmp_time(st->st_atime, file->atime) != 0) {
515 + atime = file->atime;
518 + atime = st->st_atime;
520 + int ret = set_times(fname, mtime, atime, st->st_mode);
522 rsyserr(FERROR, errno, "failed to set times on %s",
526 - if (ret == 0) /* ret == 1 if symlink could not be set */
528 + if (ret > 0) /* ret == 1 if symlink could not be set */
532 change_uid = am_root && preserve_uid && st->st_uid != file->ids->uid;
533 --- orig/rsync.h 2006-01-24 19:03:07
534 +++ rsync.h 2006-01-24 19:32:22
536 #define XMIT_HAS_IDEV_DATA (1<<9)
537 #define XMIT_SAME_DEV (1<<10)
538 #define XMIT_RDEV_MINOR_IS_SMALL (1<<11)
539 +#define XMIT_SAME_ATIME (1<<12)
541 /* These flags are used in the live flist data. */
545 #define PERMS_REPORT (1<<0)
546 #define PERMS_SKIP_MTIME (1<<1)
547 +#define PERMS_SKIP_ATIME (1<<2)
550 #define NORMAL_FLUSH 0
552 #define FNAMECMP_FUZZY 0x83
554 /* For use by the itemize_changes code */
555 +#define ITEM_REPORT_ATIME (1<<0)
556 #define ITEM_REPORT_CHECKSUM (1<<1)
557 #define ITEM_REPORT_SIZE (1<<2)
558 #define ITEM_REPORT_TIME (1<<3)
559 @@ -524,9 +527,12 @@ struct file_struct {
563 + time_t atime; /* this MUST be second to last */
564 uchar flags; /* this item MUST remain last */
567 +#define FFLAGS(f) ((uchar*)(f))[file_struct_len-1]
570 * Start the flist array at FLIST_START entries and grow it
571 * by doubling until FLIST_LINEAR then grow by FLIST_LINEAR
572 --- orig/rsync.yo 2006-01-24 19:03:08
573 +++ rsync.yo 2005-11-07 04:34:55
574 @@ -319,8 +319,9 @@ to the detailed description below for a
575 -o, --owner preserve owner (root only)
576 -g, --group preserve group
577 -D, --devices preserve devices (root only)
578 - -t, --times preserve times
579 - -O, --omit-dir-times omit directories when preserving times
580 + -t, --times preserve modify times
581 + -O, --omit-dir-times omit directories when preserving mod-times
582 + -k, --atimes preserve access times
583 --chmod=CHMOD change destination permissions
584 -S, --sparse handle sparse files efficiently
585 -n, --dry-run show what would have been transferred
586 @@ -711,6 +712,12 @@ it is preserving modification times (see
587 the directories on the receiving side, it is a good idea to use bf(-O).
588 This option is inferred if you use bf(--backup) without bf(--backup-dir).
590 +dit(bf(-k, --atimes)) This tells rsync to keep the access times of the
591 +destination files the same value as the source files. Note that the
592 +reading of the source file may update the atime of the source files, so
593 +repeated rsync runs with --atimes may be needed if you want to force the
594 +access-time values to be 100% identical on the two systems.
596 dit(bf(--chmod)) This options tells rsync to apply the listed "chmod" pattern
597 to the permission of the files on the destination. In addition to the normal
598 parsing rules specified in the chmod manpage, you can specify an item that
599 @@ -1180,7 +1187,7 @@ with older versions of rsync, but that a
602 The "%i" escape has a cryptic output that is 9 letters long. The general
603 -format is like the string bf(UXcstpoga)), where bf(U) is replaced by the
604 +format is like the string bf(UXcstapogx)), where bf(U) is replaced by the
605 kind of update being done, bf(X) is replaced by the file-type, and the
606 other letters represent attributes that may be output if they are being
608 @@ -1219,17 +1226,22 @@ quote(itemize(
609 by the file transfer.
610 it() A bf(t) means the modification time is different and is being updated
611 to the sender's value (requires bf(--times)). An alternate value of bf(T)
612 - means that the time will be set to the transfer time, which happens
613 + means that the modify time will be set to the transfer time, which happens
614 anytime a symlink is transferred, or when a file or device is transferred
616 + it() A bf(a) means the access time is different and is being updated to
617 + the sender's value (requires bf(--atimes)). An alternate value of bf(A)
618 + means that the access time will be set to the transfer time, which happens
619 + anytime a symlink is transferred, or when a file or device is transferred
620 + without bf(--atimes).
621 it() A bf(p) means the permissions are different and are being updated to
622 the sender's value (requires bf(--perms)).
623 it() An bf(o) means the owner is different and is being updated to the
624 sender's value (requires bf(--owner) and root privileges).
625 it() A bf(g) means the group is different and is being updated to the
626 sender's value (requires bf(--group) and the authority to set the group).
627 - it() The bf(a) is reserved for a future enhanced version that supports
628 - extended file attributes, such as ACLs.
629 + it() The bf(x) is reserved for a future enhanced version that supports
630 + extended file attributes.
633 One other output is possible: when deleting files, the "%i" will output
634 --- orig/sender.c 2006-01-14 20:27:10
635 +++ sender.c 2006-01-24 18:10:23
636 @@ -38,6 +38,7 @@ extern int do_progress;
639 extern int write_batch;
640 +extern unsigned int file_struct_len;
641 extern struct stats stats;
642 extern struct file_list *the_file_list;
643 extern char *log_format;
644 @@ -126,7 +127,7 @@ void successful_send(int ndx)
646 file = the_file_list->files[ndx];
647 /* The generator might tell us about symlinks we didn't send. */
648 - if (!(file->flags & FLAG_SENT) && !S_ISLNK(file->mode))
649 + if (!(FFLAGS(file) & FLAG_SENT) && !S_ISLNK(file->mode))
651 if (file->dir.root) {
652 offset = stringjoin(fname, sizeof fname,
653 @@ -370,7 +371,7 @@ void send_files(struct file_list *flist,
654 rprintf(FINFO, "sender finished %s\n", fname);
656 /* Flag that we actually sent this entry. */
657 - file->flags |= FLAG_SENT;
658 + FFLAGS(file) |= FLAG_SENT;
660 make_backups = save_make_backups;
662 --- orig/testsuite/atimes.test 2006-01-24 19:30:25
663 +++ testsuite/atimes.test 2006-01-24 19:30:25
667 +# Test rsync copying atimes
669 +. "$suitedir/rsync.fns"
675 +touch "$fromdir/foo"
676 +touch -a -t 200102031717.42 "$fromdir/foo"
680 +checkit "$RSYNC -rtkgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
682 +# The script would have aborted on error, so getting here means we've won.
684 --- orig/testsuite/itemize.test 2005-12-15 23:00:49
685 +++ testsuite/itemize.test 2006-01-24 19:29:18
686 @@ -44,14 +44,14 @@ ln "$fromdir/foo/config1" "$fromdir/foo/
687 $RSYNC -iplr "$fromdir/" "$todir/" \
689 cat <<EOT >"$chkfile"
692 ->f+++++++ bar/baz/rsync
694 ->f+++++++ foo/config1
695 ->f+++++++ foo/config2
697 -cL+++++++ foo/sym -> ../bar/baz/rsync
700 +>f++++++++ bar/baz/rsync
702 +>f++++++++ foo/config1
703 +>f++++++++ foo/config2
704 +>f++++++++ foo/extra
705 +cL++++++++ foo/sym -> ../bar/baz/rsync
707 diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
709 @@ -63,10 +63,10 @@ chmod 601 "$fromdir/foo/config2"
710 $RSYNC -iplrH "$fromdir/" "$todir/" \
712 cat <<EOT >"$chkfile"
713 ->f..T.... bar/baz/rsync
714 ->f..T.... foo/config1
715 ->f.sTp... foo/config2
716 -hf..T.... foo/extra => foo/config1
717 +>f..TA.... bar/baz/rsync
718 +>f..TA.... foo/config1
719 +>f.sTAp... foo/config2
720 +hf..TA.... foo/extra => foo/config1
722 diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
724 @@ -83,11 +83,11 @@ chmod 777 "$todir/bar/baz/rsync"
725 $RSYNC -iplrtc "$fromdir/" "$todir/" \
727 cat <<EOT >"$chkfile"
728 -.f..tp... bar/baz/rsync
730 -.f..t.... foo/config1
731 ->fcstp... foo/config2
732 -cL..T.... foo/sym -> ../bar/baz/rsync
733 +.f..t.p... bar/baz/rsync
735 +.f..t..... foo/config1
736 +>fcst.p... foo/config2
737 +cL..TA.... foo/sym -> ../bar/baz/rsync
739 diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
741 @@ -112,15 +112,15 @@ $RSYNC -ivvplrtH "$fromdir/" "$todir/" \
744 cat <<EOT >"$chkfile"
748 -.f...p... bar/baz/rsync
751 ->f..t.... foo/config2
753 -.L foo/sym -> ../bar/baz/rsync
757 +.f....p... bar/baz/rsync
760 +>f..t..... foo/config2
762 +.L foo/sym -> ../bar/baz/rsync
764 diff $diffopt "$chkfile" "$outfile" || test_fail "test 5 failed"
766 @@ -139,8 +139,8 @@ touch "$todir/foo/config2"
767 $RSYNC -iplrtH "$fromdir/" "$todir/" \
769 cat <<EOT >"$chkfile"
770 -.f...p... foo/config1
771 ->f..t.... foo/config2
772 +.f....p... foo/config1
773 +>f..t..... foo/config2
775 diff $diffopt "$chkfile" "$outfile" || test_fail "test 7 failed"
777 @@ -149,15 +149,15 @@ $RSYNC -ivvplrtH --copy-dest="$lddir" "$
780 cat <<EOT >"$chkfile"
788 -hf foo/extra => foo/config1
789 -cL..T.... foo/sym -> ../bar/baz/rsync
797 +hf foo/extra => foo/config1
798 +cL..TA.... foo/sym -> ../bar/baz/rsync
800 diff $diffopt "$chkfile" "$outfile" || test_fail "test 8 failed"
802 @@ -165,11 +165,11 @@ rm -rf "$todir"
803 $RSYNC -iplrtH --copy-dest="$lddir" "$fromdir/" "$todir/" \
805 cat <<EOT >"$chkfile"
810 -hf foo/extra => foo/config1
815 +hf foo/extra => foo/config1
817 diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"
819 @@ -196,15 +196,15 @@ $RSYNC -ivvplrtH --link-dest="$lddir" "$
822 cat <<EOT >"$chkfile"
830 -hf foo/extra => foo/config1
831 -hL foo/sym -> ../bar/baz/rsync
839 +hf foo/extra => foo/config1
840 +hL foo/sym -> ../bar/baz/rsync
842 diff $diffopt "$chkfile" "$outfile" || test_fail "test 11 failed"
844 @@ -212,10 +212,10 @@ rm -rf "$todir"
845 $RSYNC -iplrtH --link-dest="$lddir" "$fromdir/" "$todir/" \
847 cat <<EOT >"$chkfile"
857 diff $diffopt "$chkfile" "$outfile" || test_fail "test 12 failed"
859 @@ -243,14 +243,14 @@ filter_outfile
860 # TODO fix really-old problem when combining -H with --compare-dest:
861 # missing output for foo/extra hard-link (and it might not be updated)!
862 cat <<EOT >"$chkfile"
870 -.L foo/sym -> ../bar/baz/rsync
878 +.L foo/sym -> ../bar/baz/rsync
880 diff $diffopt "$chkfile" "$outfile" || test_fail "test 14 failed"
882 @@ -258,10 +258,10 @@ rm -rf "$todir"
883 $RSYNC -iplrtH --compare-dest="$lddir" "$fromdir/" "$todir/" \
885 cat <<EOT >"$chkfile"
895 diff $diffopt "$chkfile" "$outfile" || test_fail "test 15 failed"
897 --- orig/testsuite/rsync.fns 2005-06-10 21:33:28
898 +++ testsuite/rsync.fns 2005-07-28 00:41:20
899 @@ -50,7 +50,7 @@ printmsg() {
903 - find "$@" -print | sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls"
904 + find "$@" -print | sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls" $TLS_ARGS
908 @@ -158,6 +158,10 @@ checkit() {
909 # We can just write everything to stdout/stderr, because the
910 # wrapper hides it unless there is a problem.
912 + if test x$TLS_ARGS = x--atime; then
913 + ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
916 echo "Running: \"$1\""
919 @@ -165,10 +169,13 @@ checkit() {
923 + if test x$TLS_ARGS != x--atime; then
924 + ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
928 echo "check how the directory listings compare with diff:"
930 - ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
931 ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
932 diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed=YES
934 --- orig/tls.c 2005-09-24 17:40:31
935 +++ tls.c 2005-03-23 17:49:48
942 #define PROGRAM "tls"
944 @@ -48,6 +49,7 @@ int read_only = 1;
946 int preserve_perms = 0;
948 +static int display_atime = 0;
950 static void failed(char const *what, char const *where)
952 @@ -56,14 +58,29 @@ static void failed(char const *what, cha
956 +static void storetime(char *dest, time_t t)
959 + struct tm *mt = gmtime(&t);
961 + sprintf(dest, "%04d-%02d-%02d %02d:%02d:%02d ",
962 + (int)mt->tm_year + 1900,
963 + (int)mt->tm_mon + 1,
973 static void list_file(const char *fname)
976 char permbuf[PERMSTRING_SIZE];
983 if (do_lstat(fname, &buf) < 0)
984 @@ -96,19 +113,8 @@ static void list_file(const char *fname)
986 permstring(permbuf, buf.st_mode);
988 - if (buf.st_mtime) {
989 - mt = gmtime(&buf.st_mtime);
991 - sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d",
992 - (int)mt->tm_year + 1900,
993 - (int)mt->tm_mon + 1,
999 - strcpy(datebuf, " ");
1001 + storetime(mtimebuf, buf.st_mtime);
1002 + storetime(atimebuf, buf.st_atime);
1004 /* TODO: Perhaps escape special characters in fname? */
1006 @@ -119,24 +125,55 @@ static void list_file(const char *fname)
1007 (long)minor(buf.st_rdev));
1008 } else /* NB: use double for size since it might not fit in a long. */
1009 printf("%12.0f", (double)buf.st_size);
1010 - printf(" %6ld.%-6ld %6ld %s %s%s\n",
1011 + printf(" %6ld.%-6ld %6ld %s%s%s%s\n",
1012 (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
1013 - datebuf, fname, linkbuf);
1014 + mtimebuf, display_atime && !S_ISDIR(buf.st_mode) ? atimebuf : "",
1018 +static struct poptOption long_options[] = {
1019 + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
1020 + {"atime", 'u', POPT_ARG_NONE, &display_atime, 0, 0, 0},
1021 + {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0},
1025 +static void tls_usage(int ret)
1027 + fprintf(stderr, "usage: " PROGRAM " [--atime | -u] DIR ...\n"
1028 + "Trivial file listing program for portably checking rsync\n");
1033 main(int argc, char *argv[])
1036 - fprintf(stderr, "usage: " PROGRAM " DIR ...\n"
1037 - "Trivial file listing program for portably checking rsync\n");
1040 + const char **extra_args;
1043 + pc = poptGetContext(PROGRAM, argc, (const char **)argv,
1045 + while ((opt = poptGetNextOpt(pc)) != -1) {
1052 + poptBadOption(pc, POPT_BADOPTION_NOALIAS),
1053 + poptStrerror(opt));
1058 - for (argv++; *argv; argv++) {
1061 + extra_args = poptGetArgs(pc);
1062 + if (*extra_args == NULL)
1065 + for (; *extra_args; extra_args++)
1066 + list_file(*extra_args);
1067 + poptFreeContext(pc);
1071 --- orig/util.c 2006-01-20 00:12:48
1072 +++ util.c 2006-01-14 08:20:29
1073 @@ -130,7 +130,7 @@ void overflow_exit(char *str)
1077 -int set_modtime(char *fname, time_t modtime, mode_t mode)
1078 +int set_times(char *fname, time_t modtime, time_t atime, mode_t mode)
1080 #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
1082 @@ -138,9 +138,13 @@ int set_modtime(char *fname, time_t modt
1086 - rprintf(FINFO, "set modtime of %s to (%ld) %s",
1087 + char mtimebuf[200];
1089 + strlcpy(mtimebuf, timestring(modtime), sizeof mtimebuf);
1091 + "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
1092 fname, (long)modtime,
1093 - asctime(localtime(&modtime)));
1094 + mtimebuf, (long)atime, timestring(atime));
1098 @@ -149,7 +153,7 @@ int set_modtime(char *fname, time_t modt
1101 struct timeval t[2];
1102 - t[0].tv_sec = time(NULL);
1103 + t[0].tv_sec = atime;
1105 t[1].tv_sec = modtime;
1107 @@ -160,12 +164,12 @@ int set_modtime(char *fname, time_t modt
1108 return utimes(fname, t);
1109 #elif defined HAVE_UTIMBUF
1110 struct utimbuf tbuf;
1111 - tbuf.actime = time(NULL);
1112 + tbuf.actime = atime;
1113 tbuf.modtime = modtime;
1114 return utime(fname,&tbuf);
1115 #elif defined HAVE_UTIME
1117 - t[0] = time(NULL);
1120 return utime(fname,t);
1122 @@ -1175,8 +1179,8 @@ int msleep(int t)
1126 - * Determine if two file modification times are equivalent (either
1127 - * exact or in the modification timestamp window established by
1128 + * Determine if two file times are equivalent (either
1129 + * exact or in the timestamp window established by
1132 * @retval 0 if the times should be treated as the same
1133 @@ -1185,7 +1189,7 @@ int msleep(int t)
1135 * @retval -1 if the 2nd is later
1137 -int cmp_modtime(time_t file1, time_t file2)
1138 +int cmp_time(time_t file1, time_t file2)
1140 if (file2 > file1) {
1141 if (file2 - file1 <= modify_window)