patches for copying atimes

Assar assar at permabit.com
Sat Apr 10 23:30:29 GMT 2004


Hi.

Here's a patch for copying the atimes of files when -t/--times is
given.  I bumped the protocol to 29 since it sends more data over the
wire.  It obviously does not send the atime if it's sending data to an
older rsync version.

It passes all the tests (including the added atime.test) for me on a:

Linux Debian/3.0 gcc 2.95.4 (debian), glibc 2.2.5 system.

Any questions/feedback?  I certainly think that this functionality
would be useful for others.  Note that this is orthogonal to updating
(or not) the atimes on the source tree.

/assar

-------------- next part --------------
Index: backup.c
===================================================================
RCS file: /cvsroot/rsync/backup.c,v
retrieving revision 1.28
diff -u -w -r1.28 backup.c
--- backup.c	13 Mar 2004 20:18:03 -0000	1.28
+++ backup.c	10 Apr 2004 23:28:35 -0000
@@ -101,7 +101,7 @@
 				    "make_bak_dir stat %s failed: %s\n",
 				    full_fname(rel), strerror(errno));
 			} else {
-				set_modtime(fullpath, st.st_mtime);
+				set_times(fullpath, st.st_mtime, time(NULL));
 				do_lchown(fullpath, st.st_uid, st.st_gid);
 				do_chmod(fullpath, st.st_mode);
 			}
Index: batch.c
===================================================================
RCS file: /cvsroot/rsync/batch.c,v
retrieving revision 1.31
diff -u -w -r1.31 batch.c
--- batch.c	6 Mar 2004 07:45:52 -0000	1.31
+++ batch.c	10 Apr 2004 23:28:35 -0000
@@ -342,6 +342,8 @@
 		rprintf(FINFO, "flist->flags=%#x\n", fptr[i]->flags);
 		rprintf(FINFO, "flist->modtime=%#lx\n",
 			(long unsigned) fptr[i]->modtime);
+		rprintf(FINFO, "flist->atime=%#lx\n",
+			(long unsigned) fptr[i]->atime);
 		rprintf(FINFO, "flist->length=%.0f\n",
 			(double) fptr[i]->length);
 		rprintf(FINFO, "flist->mode=%#o\n", (int) fptr[i]->mode);
Index: flist.c
===================================================================
RCS file: /cvsroot/rsync/flist.c,v
retrieving revision 1.209
diff -u -w -r1.209 flist.c
--- flist.c	8 Apr 2004 23:15:39 -0000	1.209
+++ flist.c	10 Apr 2004 23:28:35 -0000
@@ -140,16 +140,16 @@
 
 #if SUPPORT_LINKS
 	if (preserve_links && S_ISLNK(f->mode)) {
-		rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
+		rprintf(FINFO, "%s %11.0f %s %s %s -> %s\n",
 			perms,
 			(double) f->length, timestring(f->modtime),
-			f_name(f), f->u.link);
+			timestring(f->atime), f_name(f), f->u.link);
 	} else
 #endif
-		rprintf(FINFO, "%s %11.0f %s %s\n",
+		rprintf(FINFO, "%s %11.0f %s %s %s\n",
 			perms,
 			(double) f->length, timestring(f->modtime),
-			f_name(f));
+			timestring(f->atime), f_name(f));
 }
 
 
@@ -323,6 +323,7 @@
 {
 	unsigned short flags;
 	static time_t modtime;
+	static time_t atime;
 	static mode_t mode;
 	static DEV64_T rdev, rdev_high;
 	static DEV64_T dev;
@@ -337,7 +338,7 @@
 
 	if (!file) {
 		write_byte(f, 0);
-		modtime = 0, mode = 0;
+		modtime = 0, atime = 0, mode = 0;
 		rdev = 0, rdev_high = 0, dev = 0;
 		uid = 0, gid = 0;
 		*lastname = '\0';
@@ -386,6 +387,12 @@
 		flags |= XMIT_SAME_TIME;
 	else
 		modtime = file->modtime;
+        if (protocol_version > 28) {
+                if (file->atime == atime)
+                        flags |= XMIT_SAME_ATIME;
+                else
+                        atime = file->atime;
+        }
 
 #if SUPPORT_HARD_LINKS
 	if (file->link_u.idev) {
@@ -439,6 +446,8 @@
 	write_longint(f, file->length);
 	if (!(flags & XMIT_SAME_TIME))
 		write_int(f, modtime);
+	if (protocol_version > 28 && !(flags & XMIT_SAME_ATIME))
+		write_int(f, atime);
 	if (!(flags & XMIT_SAME_MODE))
 		write_int(f, to_wire_mode(mode));
 	if (preserve_uid && !(flags & XMIT_SAME_UID)) {
@@ -509,6 +518,7 @@
     struct file_list *flist, int f)
 {
 	static time_t modtime;
+	static time_t atime;
 	static mode_t mode;
 	static DEV64_T rdev, rdev_high;
 	static DEV64_T dev;
@@ -524,7 +534,7 @@
 	struct file_struct *file;
 
 	if (!fptr) {
-		modtime = 0, mode = 0;
+		modtime = 0, atime = 0, mode = 0;
 		rdev = 0, rdev_high = 0, dev = 0;
 		uid = 0, gid = 0;
 		*lastname = '\0';
@@ -575,6 +585,11 @@
 	file_length = read_longint(f);
 	if (!(flags & XMIT_SAME_TIME))
 		modtime = (time_t)read_int(f);
+	if (protocol_version > 28) {
+                if (!(flags & XMIT_SAME_ATIME))
+                        atime = (time_t)read_int(f);
+        } else
+                atime = time(NULL);
 	if (!(flags & XMIT_SAME_MODE))
 		mode = from_wire_mode(read_int(f));
 
@@ -624,6 +639,7 @@
 
 	file->flags = flags & XMIT_TOP_DIR ? FLAG_TOP_DIR : 0;
 	file->modtime = modtime;
+        file->atime = atime;
 	file->length = file_length;
 	file->mode = mode;
 	file->uid = uid;
@@ -838,6 +854,7 @@
 
 	file->flags = flags;
 	file->modtime = st.st_mtime;
+	file->atime = st.st_atime;
 	file->length = st.st_size;
 	file->mode = st.st_mode;
 	file->uid = st.st_uid;
Index: generator.c
===================================================================
RCS file: /cvsroot/rsync/generator.c,v
retrieving revision 1.77
diff -u -w -r1.77 generator.c
--- generator.c	7 Mar 2004 20:29:59 -0000	1.77
+++ generator.c	10 Apr 2004 23:28:35 -0000
@@ -43,6 +43,7 @@
 extern int always_checksum;
 extern char *compare_dest;
 extern int link_dest;
+extern int preserve_times;
 
 
 /* choose whether to skip a particular file */
@@ -90,7 +91,11 @@
 		return 0;
 	}
 
-	return (cmp_modtime(st->st_mtime,file->modtime) == 0);
+        if (preserve_times && cmp_time(st->st_atime,file->atime) != 0) {
+                return 0;
+        }
+
+	return (cmp_time(st->st_mtime,file->modtime) == 0);
 }
 
 
@@ -466,7 +471,7 @@
 		return;
 	}
 
-	if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
+	if (update_only && cmp_time(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
 		if (verbose > 1)
 			rprintf(FINFO,"%s is newer\n",fname);
 		return;
Index: proto.h
===================================================================
RCS file: /cvsroot/rsync/proto.h,v
retrieving revision 1.185
diff -u -w -r1.185 proto.h
--- proto.h	27 Mar 2004 09:44:34 -0000	1.185
+++ proto.h	10 Apr 2004 23:28:35 -0000
@@ -244,7 +244,7 @@
 void print_child_argv(char **cmd);
 void out_of_memory(char *str);
 void overflow(char *str);
-int set_modtime(char *fname, time_t modtime);
+int set_times(char *fname, time_t modtime, time_t atime);
 int create_directory_path(char *fname, int base_umask);
 int copy_file(char *source, char *dest, mode_t mode);
 int robust_unlink(char *fname);
@@ -268,7 +268,7 @@
 int unsafe_symlink(const char *dest, const char *src);
 char *timestring(time_t t);
 int msleep(int t);
-int cmp_modtime(time_t file1, time_t file2);
+int cmp_time(time_t file1, time_t file2);
 int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6);
 void *_new_array(unsigned int size, unsigned long num);
 void *_realloc_array(void *ptr, unsigned int size, unsigned long num);
Index: rsync.c
===================================================================
RCS file: /cvsroot/rsync/rsync.c,v
retrieving revision 1.135
diff -u -w -r1.135 rsync.c
--- rsync.c	23 Mar 2004 16:16:15 -0000	1.135
+++ rsync.c	10 Apr 2004 23:28:35 -0000
@@ -141,10 +141,11 @@
 	}
 
 	if (preserve_times && !S_ISLNK(st->st_mode) &&
-	    cmp_modtime(st->st_mtime, file->modtime) != 0) {
+	    (cmp_time(st->st_mtime, file->modtime) != 0
+             || cmp_time(st->st_atime, file->atime) != 0)) {
 		/* don't complain about not setting times on directories
 		 * because some filesystems can't do it */
-		if (set_modtime(fname,file->modtime) != 0 &&
+		if (set_times(fname,file->modtime,file->atime) != 0 &&
 		    !S_ISDIR(st->st_mode)) {
 			rprintf(FERROR, "failed to set times on %s: %s\n",
 				full_fname(fname), strerror(errno));
Index: rsync.h
===================================================================
RCS file: /cvsroot/rsync/rsync.h,v
retrieving revision 1.193
diff -u -w -r1.193 rsync.h
--- rsync.h	9 Apr 2004 22:25:33 -0000	1.193
+++ rsync.h	10 Apr 2004 23:28:36 -0000
@@ -53,6 +53,7 @@
 #define XMIT_SAME_HIGH_RDEV (1<<8)
 #define XMIT_HAS_IDEV_DATA (1<<9)
 #define XMIT_SAME_DEV (1<<10)
+#define XMIT_SAME_ATIME (1<<11)
 
 /* These flags are used in the live flist data. */
 
@@ -61,7 +62,7 @@
 #define FLAG_MOUNT_POINT (1<<2)	/* sender only */
 
 /* update this if you make incompatible changes */
-#define PROTOCOL_VERSION 28
+#define PROTOCOL_VERSION 29
 
 /* We refuse to interoperate with versions that are not in this range.
  * Note that we assume we'll work with later versions: the onus is on
@@ -427,6 +428,7 @@
 		struct hlink *links;
 	} link_u;
 	time_t modtime;
+	time_t atime;
 	uid_t uid;
 	gid_t gid;
 	mode_t mode;
Index: tls.c
===================================================================
RCS file: /cvsroot/rsync/tls.c,v
retrieving revision 1.19
diff -u -w -r1.19 tls.c
--- tls.c	9 Apr 2004 20:22:44 -0000	1.19
+++ tls.c	10 Apr 2004 23:28:36 -0000
@@ -39,6 +39,7 @@
 
 
 #include "rsync.h"
+#include "popt.h"
 
 #define PROGRAM "tls"
 
@@ -48,6 +49,7 @@
 int list_only = 0;
 int preserve_perms = 0;
 
+static int display_atime = 0;
 
 static void failed (char const *what,
 		    char const *where)
@@ -57,14 +59,30 @@
 	exit (1);
 }
 
+static void storetime(char *dest,
+                      time_t t)
+{
+	if (t) {
+		struct tm *mt = gmtime(&t);
 
+		sprintf(dest, "%04d-%02d-%02d %02d:%02d:%02d",
+			mt->tm_year + 1900,
+			mt->tm_mon + 1,
+			mt->tm_mday,
+			mt->tm_hour,
+			mt->tm_min,
+			mt->tm_sec);
+	} else {
+		strcpy(dest, "                   ");
+	}
+}	
 
 static void list_file (const char *fname)
 {
 	STRUCT_STAT buf;
 	char permbuf[PERMSTRING_SIZE];
-	struct tm *mt;
-	char datebuf[50];
+	char mtimebuf[50];
+	char atimebuf[50];
 	char linkbuf[4096];
 
 	if (do_lstat(fname, &buf) == -1)
@@ -97,19 +115,8 @@
 
 	permstring(permbuf, buf.st_mode);
 
-	if (buf.st_mtime) {
-		mt = gmtime(&buf.st_mtime);
-
-		sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d",
-			mt->tm_year + 1900,
-			mt->tm_mon + 1,
-			mt->tm_mday,
-			mt->tm_hour,
-			mt->tm_min,
-			mt->tm_sec);
-	} else {
-		strcpy(datebuf, "                   ");
-	}
+        storetime(mtimebuf, buf.st_mtime);
+        storetime(atimebuf, buf.st_atime);
 
 	/* TODO: Perhaps escape special characters in fname? */
 
@@ -120,24 +127,58 @@
 		    (long)minor(buf.st_rdev));
 	} else /* NB: use double for size since it might not fit in a long. */
 		printf("%12.0f", (double)buf.st_size);
-	printf(" %6ld.%-6ld %6ld %s %s%s\n",
+        printf(" %6ld.%-6ld %6ld %s %s%s%s%s\n",
 	       (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
-	       datebuf, fname, linkbuf);
+ 	       mtimebuf,
+               display_atime ? atimebuf : "",
+               display_atime ? "" : " ",
+               fname, linkbuf);
 }
 
+static struct poptOption long_options[] = {
+  /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+  {"atime",           'u', POPT_ARG_NONE,   &display_atime, 0,   0, 0},
+  {"help",            'h', POPT_ARG_NONE,   0,              'h', 0, 0}
+};
+
+static void tls_usage()
+{
+        fprintf (stderr, "usage: " PROGRAM " [--atime | -u] DIR ...\n"
+                 "Trivial file listing program for portably checking rsync\n");
+}
 
 int
 main(int argc, char *argv[])
 {
-	if (argc < 2) {
-		fprintf (stderr, "usage: " PROGRAM " DIR ...\n"
-			 "Trivial file listing program for portably checking rsync\n");
+        poptContext pc;
+        const char **extra_args;
+        char err_buf[100];
+        int opt;
+
+        pc = poptGetContext(PROGRAM, argc, (const char **)argv,
+                            long_options, 0);
+        while ((opt = poptGetNextOpt(pc)) != -1) {
+                switch (opt) {
+                case 'h':
+                        tls_usage();
+                        return 0;
+                default :
+                        snprintf(err_buf, sizeof err_buf,
+                                 "%s: %s\n",
+                                 poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+                                 poptStrerror(opt));
 		return 1;
 	}
-
-	for (argv++; *argv; argv++) {
-		list_file (*argv);
 	}
 
+        extra_args = poptGetArgs(pc);
+        if (*extra_args == NULL) {
+                tls_usage();
+                return 1;
+        }
+        for (; *extra_args; extra_args++) {
+                list_file (*extra_args);
+        }
+        poptFreeContext(pc);
 	return 0;
 }
Index: util.c
===================================================================
RCS file: /cvsroot/rsync/util.c,v
retrieving revision 1.133
diff -u -w -r1.133 util.c
--- util.c	27 Mar 2004 09:44:49 -0000	1.133
+++ util.c	10 Apr 2004 23:28:36 -0000
@@ -123,32 +123,40 @@
 
 
 
-int set_modtime(char *fname, time_t modtime)
+int set_times(char *fname, time_t modtime, time_t atime)
 {
 	extern int dry_run;
 	if (dry_run)
 		return 0;
 
 	if (verbose > 2) {
-		rprintf(FINFO, "set modtime of %s to (%ld) %s",
+                char mtimebuf[200];
+                char atimebuf[200];
+
+                strlcpy(mtimebuf, timestring(modtime), sizeof(mtimebuf));
+                strlcpy(atimebuf, timestring(atime), sizeof(atimebuf));
+
+		rprintf(FINFO,
+                        "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
 			fname, (long) modtime,
-			asctime(localtime(&modtime)));
+                        mtimebuf,
+                        (long) atime, atimebuf);
 	}
 
 	{
 #ifdef HAVE_UTIMBUF
 		struct utimbuf tbuf;
-		tbuf.actime = time(NULL);
+		tbuf.actime = atime;
 		tbuf.modtime = modtime;
 		return utime(fname,&tbuf);
 #elif defined(HAVE_UTIME)
 		time_t t[2];
-		t[0] = time(NULL);
+		t[0] = atime;
 		t[1] = modtime;
 		return utime(fname,t);
 #else
 		struct timeval t[2];
-		t[0].tv_sec = time(NULL);
+		t[0].tv_sec = atime;
 		t[0].tv_usec = 0;
 		t[1].tv_sec = modtime;
 		t[1].tv_usec = 0;
@@ -1045,8 +1053,8 @@
 
 
 /**
- * Determine if two file modification times are equivalent (either
- * exact or in the modification timestamp window established by
+ * Determine if two file  times are equivalent (either
+ * exact or in the timestamp window established by
  * --modify-window).
  *
  * @retval 0 if the times should be treated as the same
@@ -1055,7 +1063,7 @@
  *
  * @retval -1 if the 2nd is later
  **/
-int cmp_modtime(time_t file1, time_t file2)
+int cmp_time(time_t file1, time_t file2)
 {
 	extern int modify_window;
 
Index: testsuite/atime.test
===================================================================
RCS file: testsuite/atime.test
diff -N testsuite/atime.test
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/atime.test	10 Apr 2004 23:28:36 -0000
@@ -0,0 +1,22 @@
+#! /bin/sh
+
+# Test rsync copying atimes
+
+. $srcdir/testsuite/rsync.fns
+
+set -x
+
+fromdir="$scratchdir/from"
+todir="$scratchdir/to"
+
+mkdir "$fromdir"
+
+touch "$fromdir/foo"
+touch -a -t 200102031717.42 "$fromdir/foo"
+
+TLS_ARGS=--atime
+
+checkit "$RSYNC -rtgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
+
+# The script would have aborted on error, so getting here means we've won.
+exit 0
Index: testsuite/rsync.fns
===================================================================
RCS file: /cvsroot/rsync/testsuite/rsync.fns,v
retrieving revision 1.59
diff -u -w -r1.59 rsync.fns
--- testsuite/rsync.fns	4 Feb 2004 07:32:48 -0000	1.59
+++ testsuite/rsync.fns	10 Apr 2004 23:28:36 -0000
@@ -51,7 +51,7 @@
 
 
 rsync_ls_lR() {
-    find "$@" -print | sort | xargs "$TOOLDIR/tls"
+    find "$@" -print | sort | xargs "$TOOLDIR/tls" $TLS_ARGS
 }
 
 rsync_getgroups() { 
@@ -151,6 +151,8 @@
     # We can just write everything to stdout/stderr, because the
     # wrapper hides it unless there is a problem.
 
+    ( cd "$2" && rsync_ls_lR . ) > ${TMP}/ls-from 
+
     echo "Running: \"$1\""  
     eval "$1" 
     status=$?
@@ -159,6 +161,12 @@
     fi
 
     echo "-------------"
+    echo "check how the directory listings compare with diff:"
+    echo ""
+    ( cd "$3" && rsync_ls_lR . ) > ${TMP}/ls-to 
+    diff $diffopt ${TMP}/ls-from ${TMP}/ls-to || failed=YES
+
+    echo "-------------"
     echo "check how the files compare with diff:"
     echo ""
     for f in `cd "$2"; find . -type f -print `
@@ -166,12 +174,6 @@
         diff $diffopt "$2"/"$f" "$3"/"$f" || failed=YES
     done
 
-    echo "-------------"
-    echo "check how the directory listings compare with diff:"
-    echo ""
-    ( cd "$2" && rsync_ls_lR . ) > ${TMP}/ls-from 
-    ( cd "$3" && rsync_ls_lR . ) > ${TMP}/ls-to 
-    diff $diffopt ${TMP}/ls-from ${TMP}/ls-to || failed=YES
     if [ -z "${failed}" ] ; then
 	return 0
     else


More information about the rsync mailing list