Sorry, got carried away and forgot to attach the patch...
Only in rsync-3.0.9: config.h.in
Only in rsync-3.0.9: configure.sh
diff -ur rsync-3.0.9/fileio.c rsync-3.0.9.1/fileio.c
--- rsync-3.0.9/fileio.c	2011-02-21 19:32:51.000000000 +0000
+++ rsync-3.0.9.1/fileio.c	2012-10-07 17:54:20.233482145 +0000
@@ -26,6 +26,9 @@
 #endif
 
 extern int sparse_files;
+extern int retry_errors;
+extern int retry_delay;
+extern int fill_byte;
 
 static OFF_T sparse_seek = 0;
 
@@ -180,10 +183,12 @@
 /* slide the read window in the file */
 char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
 {
-	int32 nread;
+	int32 nread, retry_count;
 	OFF_T window_start, read_start;
 	int32 window_size, read_size, read_offset;
 
+	retry_count = 0;
+
 	if (len == 0)
 		return NULL;
 	if (len < 0) {
@@ -245,16 +250,46 @@
 	map->p_offset = window_start;
 	map->p_len = window_size;
 
+	memset(map->p + read_offset, fill_byte, read_size);
+
 	while (read_size > 0) {
 		nread = read(map->fd, map->p + read_offset, read_size);
-		if (nread <= 0) {
-			if (!map->status)
-				map->status = nread ? errno : ENODATA;
-			/* The best we can do is zero the buffer -- the file
-			 * has changed mid transfer! */
-			memset(map->p + read_offset, 0, read_size);
+
+		if(nread == 0) {
+			rprintf(FERROR, "Unexpected EOF");
+			map->status = ENODATA;
 			break;
 		}
+
+		if(nread < read_size && errno) {
+			retry_count++;
+
+			map->status = errno;
+
+			if(retry_count > retry_errors) {
+				if(retry_errors > 0)
+					rprintf(FERROR, "Error retry finished after %d retries at offset %.0f.\n", retry_errors, (double)read_start);
+
+				break;
+			}
+
+			if(nread != -1) {
+				if(!map->status)
+					map->status = nread;
+				map->p_fd_offset += nread;
+				read_offset += nread;
+				read_size -= nread;
+			}
+
+			rprintf(FERROR, "Error reading %d bytes at offset %.0f, got %d.", read_size, (double)read_start, nread);
+			rprintf(FERROR, "Retrying in %d seconds.\n", retry_delay);
+
+			sleep(retry_delay);
+			errno = 0;
+			
+			continue;
+		}
+
 		map->p_fd_offset += nread;
 		read_offset += nread;
 		read_size -= nread;
diff -ur rsync-3.0.9/flist.c rsync-3.0.9.1/flist.c
--- rsync-3.0.9/flist.c	2011-08-27 21:58:04.000000000 +0000
+++ rsync-3.0.9.1/flist.c	2012-09-28 16:20:50.199950493 +0000
@@ -71,6 +71,9 @@
 extern struct stats stats;
 extern char *filesfrom_host;
 
+extern int retry_errors;
+extern int retry_delay;
+
 extern char curr_dir[MAXPATHLEN];
 
 extern struct chmod_mode_struct *chmod_modes;
@@ -188,12 +191,24 @@
 static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf)
 {
 #ifdef SUPPORT_LINKS
+	int	retry_count = 0;
+	int	llen;
+
 	if (link_stat(path, stp, copy_dirlinks) < 0)
 		return -1;
 	if (S_ISLNK(stp->st_mode)) {
-		int llen = readlink(path, linkbuf, MAXPATHLEN - 1);
-		if (llen < 0)
+l1:
+		llen = readlink(path, linkbuf, MAXPATHLEN - 1);
+		if (llen < 0) {
+			retry_count++;
+			if(retry_count < retry_errors) {
+				rprintf(FERROR, "Error reading link at %s, retrying in %d seconds.\n", path, retry_delay);
+				sleep(retry_delay);
+				goto l1;
+			}
 			return -1;
+		}
+
 		linkbuf[llen] = '\0';
 		if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) {
 			if (verbose > 1) {
diff -ur rsync-3.0.9/options.c rsync-3.0.9.1/options.c
--- rsync-3.0.9/options.c	2011-09-13 22:41:26.000000000 +0000
+++ rsync-3.0.9.1/options.c	2012-10-07 17:41:26.843409777 +0000
@@ -115,6 +115,9 @@
 OFF_T max_size = 0;
 OFF_T min_size = 0;
 int ignore_errors = 0;
+int retry_errors = 1;
+int retry_delay = 15;
+int fill_byte = 0;
 int modify_window = 0;
 int blocking_io = -1;
 int checksum_seed = 0;
@@ -374,6 +377,9 @@
   rprintf(F,"     --delete-after          receiver deletes after transfer, not during\n");
   rprintf(F,"     --delete-excluded       also delete excluded files from destination dirs\n");
   rprintf(F,"     --ignore-errors         delete even if there are I/O errors\n");
+  rprintf(F,"     --retry-errors=NUM      On encountering an I/O error, retry this many times (1)\n");
+  rprintf(F,"     --retry-delay=NUM       Delay this many seconds (15) before retrying errors\n");
+  rprintf(F,"     --fill-byte=NUM			Fill read buffers with this byte.  Default is 0x00.\n");
   rprintf(F,"     --force                 force deletion of directories even if not empty\n");
   rprintf(F,"     --max-delete=NUM        don't delete more than NUM files\n");
   rprintf(F,"     --max-size=SIZE         don't transfer any file larger than SIZE\n");
@@ -558,6 +564,9 @@
   {"force",            0,  POPT_ARG_VAL,    &force_delete, 1, 0, 0 },
   {"no-force",         0,  POPT_ARG_VAL,    &force_delete, 0, 0, 0 },
   {"ignore-errors",    0,  POPT_ARG_VAL,    &ignore_errors, 1, 0, 0 },
+  {"retry-errors",     0,  POPT_ARG_LONG,   &retry_errors, 0, 0, 0 },
+  {"retry-delay",      0,  POPT_ARG_LONG,   &retry_delay, 0, 0, 0 },
+  {"fill-byte",        0,  POPT_ARG_INT,    &fill_byte, 0, 0, 0 },
   {"no-ignore-errors", 0,  POPT_ARG_VAL,    &ignore_errors, 0, 0, 0 },
   {"max-delete",       0,  POPT_ARG_INT,    &max_delete, 0, 0, 0 },
   {0,                 'F', POPT_ARG_NONE,   0, 'F', 0, 0 },
@@ -1645,6 +1654,21 @@
 		}
 	}
 
+	if(retry_errors > 100 || retry_errors <0) {
+		snprintf(err_buf, sizeof err_buf, "--retry-errors=%d out of range (0 - 100)", retry_errors);
+		return(0);
+	}
+
+	if(retry_delay < 0 || retry_delay > 1600) {
+		snprintf(err_buf, sizeof err_buf, "--retry-delay=%d out of range (0 - 1600)", retry_delay);
+		return(0);
+	}
+
+	if(fill_byte < 0 || fill_byte > 255) {
+		snprintf(err_buf, sizeof err_buf, "--fill-byte=%d out of range (0 - 255)", fill_byte);
+		return(0);
+	}
+
 	if (files_from) {
 		char *h, *p;
 		int q;
Only in rsync-3.0.9: proto.h
Only in rsync-3.0.9: proto.h-tstamp
Only in rsync-3.0.9: rsync.1
Only in rsync-3.0.9: rsyncd.conf.5
Only in rsync-3.0.9.1: #rsync.yo~
diff -ur rsync-3.0.9/rsync.yo rsync-3.0.9.1/rsync.yo
--- rsync-3.0.9/rsync.yo	2011-09-23 16:13:53.000000000 +0000
+++ rsync-3.0.9.1/rsync.yo	2012-10-07 18:34:01.213715071 +0000
@@ -386,6 +386,9 @@
      --delete-after          receiver deletes after transfer, not during
      --delete-excluded       also delete excluded files from dest dirs
      --ignore-errors         delete even if there are I/O errors
+     --retry-errors=NUM      reads will be retried NUM times on error
+     --retry-delay=NUM       delay NUM seconds before retrying errors
+     --fill-byte=NUM         fill read buffer with NUM before reading
      --force                 force deletion of dirs even if not empty
      --max-delete=NUM        don't delete more than NUM files
      --max-size=SIZE         don't transfer any file larger than SIZE
@@ -1289,6 +1292,21 @@
 dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files
 even when there are I/O errors.
 
+dit(bf(--retry-errors=NUM)) A read error may be retried NUM times in
+the case of a media error.  Sections of a file that were not read will
+be filled with 0x00, or the byte specified with bf(--fill-byte).
+
+dit(bf(--retry-delay=NUM)) Before a failed read is retried, sleep for
+NUM seconds before retrying.  This helps some targets that go nuts
+when there are errors, allowing the head to seek to a known position
+after a period of no activity.
+
+dit(bf(--fill-byte=NUM)) Before attempting a read, fill the buffer
+with NUM.  Rsync attempts to read the whole file, regardless of the
+errors it encounters, leaving holes filled with 0x00 bytes unless this
+option is specfied.  Broken files are only left in the destination
+directory if bf(--ignore-errors) is also specified on the commandline.
+
 dit(bf(--force)) This option tells rsync to delete a non-empty directory
 when it is to be replaced by a non-directory.  This is only relevant if
 deletions are not active (see bf(--delete) for details).
-- 
Please use reply-all for most replies to avoid omitting the mailing list.
To unsubscribe or change options: https://lists.samba.org/mailman/listinfo/rsync
Before posting, read: http://www.catb.org/~esr/faqs/smart-questions.html

Reply via email to