read error produces null-byte-filled destination file

Wayne Davison wayned at samba.org
Tue May 11 20:39:24 GMT 2004


On Mon, May 10, 2004 at 02:45:15PM -0700, Todd Stansell wrote:
> Subsequent rsyncs will succeed without any errors as long as the -c
> option isn't used.  You'd never know the file was corrupted, since the
> size and timestamp are both correct on the destination file.

It's pretty easy to at least fix this file-is-up-to-date deception.  The
appended patch changes rsync to send a bogus whole-file-checksum to the
receiver if there was an error reading the file.  This will cause the
receiver to ask for a resend (which will handle the case where the read
error was temporary, such as the file getting shorter during the
transfer).  If the resend fails, the file's time is not preserved, thus
marking it as not being updated correctly (at least to rsync).  The file
would still be full of nulls, however.

What do you think?  Rsync has always moved a finished file into place,
even if it fails the full-file checksum.  I'm wondering if this is
really a good idea.  Perhaps that should only occur if the --partial
flag was specified (in which case we're telling rsync that we'll accept
a not-quite-finished file if it helps the next transfer to be more
optimal).

..wayne..
-------------- next part --------------
--- cleanup.c	27 Jan 2004 08:14:33 -0000	1.21
+++ cleanup.c	11 May 2004 20:20:10 -0000
@@ -116,7 +116,7 @@ void _exit_cleanup(int code, const char 
 		if (cleanup_buf) unmap_file(cleanup_buf);
 		if (cleanup_fd1 != -1) close(cleanup_fd1);
 		if (cleanup_fd2 != -1) close(cleanup_fd2);
-		finish_transfer(cleanup_new_fname, fname, cleanup_file);
+		finish_transfer(cleanup_new_fname, fname, cleanup_file, 0);
 	}
 	io_flush(FULL_FLUSH);
 	if (cleanup_fname)
--- generator.c	5 May 2004 17:15:03 -0000	1.81
+++ generator.c	11 May 2004 20:20:10 -0000
@@ -351,7 +351,8 @@ void recv_generator(char *fname, struct 
 				 * right place -- no further action
 				 * required. */
 				if (strcmp(lnk,file->u.link) == 0) {
-					set_perms(fname,file,&st,1);
+					set_perms(fname, file, &st,
+						  PERMS_REPORT);
 					return;
 				}
 			}
@@ -391,7 +392,7 @@ void recv_generator(char *fname, struct 
 					rprintf(FINFO,"%s\n",fname);
 			}
 		} else {
-			set_perms(fname,file,&st,1);
+			set_perms(fname, file, &st, PERMS_REPORT);
 		}
 		return;
 	}
@@ -473,7 +474,7 @@ void recv_generator(char *fname, struct 
 
 	if (skip_file(fname, file, &st)) {
 		if (fnamecmp == fname)
-			set_perms(fname,file,&st,1);
+			set_perms(fname, file, &st, PERMS_REPORT);
 		return;
 	}
 
--- match.c	3 Jan 2004 19:28:03 -0000	1.60
+++ match.c	11 May 2004 20:20:11 -0000
@@ -322,6 +322,9 @@ void match_sums(int f, struct sum_struct
 	}
 
 	sum_end(file_sum);
+	/* If we had a read error, send a bad checksum. */
+	if (buf && buf->status != 0)
+		file_sum[0]++;
 
 	if (verbose > 2)
 		rprintf(FINFO,"sending file_sum\n");
--- proto.h	22 Apr 2004 09:58:09 -0000	1.189
+++ proto.h	11 May 2004 20:20:11 -0000
@@ -192,9 +192,10 @@ int recv_files(int f_in,struct file_list
 void free_sums(struct sum_struct *s);
 int delete_file(char *fname);
 int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
-		int report);
+	      int flags);
 void sig_int(void);
-void finish_transfer(char *fname, char *fnametmp, struct file_struct *file);
+void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
+		     int ok_to_set_time);
 const char *who_am_i(void);
 void read_sum_head(int f, struct sum_struct *sum);
 void send_files(struct file_list *flist, int f_out, int f_in);
--- receiver.c	27 Apr 2004 19:51:33 -0000	1.76
+++ receiver.c	11 May 2004 20:20:11 -0000
@@ -467,7 +467,7 @@ int recv_files(int f_in,struct file_list
 		if (verbose > 2)
 			rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
 
-		finish_transfer(fname, fnametmp, file);
+		finish_transfer(fname, fnametmp, file, recv_ok);
 
 		cleanup_disable();
 
--- rsync.c	23 Mar 2004 16:16:15 -0000	1.135
+++ rsync.c	11 May 2004 20:20:12 -0000
@@ -123,7 +123,7 @@ int delete_file(char *fname)
 }
 
 int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
-		int report)
+	      int flags)
 {
 	int updated = 0;
 	STRUCT_STAT st2;
@@ -140,8 +140,10 @@ int set_perms(char *fname,struct file_st
 		st = &st2;
 	}
 
-	if (preserve_times && !S_ISLNK(st->st_mode) &&
-	    cmp_modtime(st->st_mtime, file->modtime) != 0) {
+	if (!preserve_times || S_ISLNK(st->st_mode))
+		flags |= PERMS_SKIP_TIME;
+	if (!(flags & PERMS_SKIP_TIME)
+	    && cmp_modtime(st->st_mtime, file->modtime) != 0) {
 		/* don't complain about not setting times on directories
 		 * because some filesystems can't do it */
 		if (set_modtime(fname,file->modtime) != 0 &&
@@ -201,7 +203,7 @@ int set_perms(char *fname,struct file_st
 	}
 #endif
 
-	if (verbose > 1 && report) {
+	if (verbose > 1 && flags & PERMS_REPORT) {
 		if (updated)
 			rprintf(FINFO,"%s\n",fname);
 		else
@@ -228,7 +230,8 @@ void sig_int(void)
 
 /* finish off a file transfer, renaming the file and setting the permissions
    and ownership */
-void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
+void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
+		     int ok_to_set_time)
 {
 	int ret;
 
@@ -243,7 +246,8 @@ void finish_transfer(char *fname, char *
 		    full_fname(fnametmp), fname, strerror(errno));
 		do_unlink(fnametmp);
 	} else {
-		set_perms(fname,file,NULL,0);
+		set_perms(fname, file, NULL,
+			  ok_to_set_time ? 0 : PERMS_SKIP_TIME);
 	}
 }
 
--- rsync.h	8 May 2004 18:48:09 -0000	1.201
+++ rsync.h	11 May 2004 20:20:12 -0000
@@ -109,6 +109,9 @@
 #define XFLG_WORDS_ONLY 	(1<<2)
 #define XFLG_WORD_SPLIT 	(1<<3)
 
+#define PERMS_REPORT	(1<<0)
+#define PERMS_SKIP_TIME	(1<<1)
+
 #define FULL_FLUSH	1
 #define NORMAL_FLUSH	0
 


More information about the rsync mailing list