diff --rec --new-file --unif coreutils-5.2.0/ChangeLog coreutils/ChangeLog
--- coreutils-5.2.0/ChangeLog	Tue Feb 17 16:05:39 2004
+++ coreutils/ChangeLog	Sun Apr 11 17:08:41 2004
@@ -1,3 +1,21 @@
+        Add --readsize option to control how many bytes at a time get
+	copied (buffer size).  Keep copy synchronized to the read size by
+	filling in short reads.  Add --errors option to give two new ways
+	of handling read errors.  --errors=abort, default, is the old
+	behavior.  --errors=skip causes bad file areas to be skipped.
+	--errors=zero causes bad file areas to be replaced with zeroes.
+	Add warning messages when errors are recovered.
+
+	* src/copy.c (copy_reg): new subroutine read_a_block.  Set buf_size
+	  from --readsize option value.  Print error statistics after copy.
+
+	* src/copy.h:  Add --readsize, --errors, and --errorgrain options.
+
+	* src/cp.c:  Add --readsize, --errors, and --errorgrain options.
+	
+	* src/mv.c, src/ginstall.c: Add default --readsize, --errors, and
+	  --errorgrain to cp options.
+	
 2004-02-17  Jim Meyering  <jim@meyering.net>
 
 	* Version 5.2.0.
diff --rec --new-file --unif coreutils-5.2.0/doc/coreutils.texi coreutils/doc/coreutils.texi
--- coreutils-5.2.0/doc/coreutils.texi	Wed Feb 18 17:45:02 2004
+++ coreutils/doc/coreutils.texi	Sat Apr 10 22:06:28 2004
@@ -118,7 +118,6 @@
 * yes: (coreutils)yes invocation.               Print a string indefinitely.
 @end direntry
 
-@copying
 This manual documents version @value{VERSION} of the @sc{gnu} core
 utilities, including the standard programs for text and file manipulation.
 
@@ -133,7 +132,6 @@
 Texts.  A copy of the license is included in the section entitled ``GNU
 Free Documentation License''.
 @end quotation
-@end copying
 
 @titlepage
 @title @sc{gnu} @code{Coreutils}
@@ -151,7 +149,6 @@
 @node Top
 @top GNU Coreutils
 
-@insertcopying
 @end ifnottex
 
 @cindex core utilities
@@ -6363,6 +6360,102 @@
 This is useful in creating a file for use with the @command{mkswap} command,
 since such a file must not have any holes.
 @end table
+
+@item --errors=@var{action}
+@opindex --sparse=@var{action}
+@cindex errors on input
+Parts of a files are sometimes unreadable.  When @command{cp} encounters
+an unreadable region of an input file, its @samp{read} system call fails.
+@command{cp} can respond to this in one of three ways, as selected by
+@var{action};
+
+@table @samp
+@item abort
+The default behavior: @command{cp} terminates abnormally, leaving undefined
+output file contents.
+
+@item skip
+Continue copying the parts of the input file that are readable, omitting
+the unreadable regions from the output.  The output file will be shorter
+than the input file by the number of unreadable bytes.
+
+@command{cp} issues a warning message after the copy indicating that parts
+of the copy were skipped.
+
+@item zero
+Continue copying the parts of the input file that are readable,
+substituting zeroes in the output file for the bytes that could not be read
+from the input file.  The output file will be the same size as the input
+file.
+
+Use this option if the file is structured so that certain things are
+expected to be at certain file offsets.
+
+@command{cp} issues a warning message after the copy indicating that parts
+of the copy were padded.
+
+@end table
+
+See the @option{--grain} option for information on how @command{cp} finds the
+next good part of a file after it experiences a read error.
+
+@item --grain=@var{bytes}
+@opindex --grain=@var{bytes}
+@cindex error grain
+See the @option{--error} option for general information on handling of
+read errors.
+
+When @command{cp} encounters a read error (a @samp{read} system call fails
+to read at a particular offset), it searches forward in the file to find the
+next readable offset.  It skips ahead by an amount known as the 
+@dfn{error grain} and tries a @samp{read}, continuing until it succeeds or
+it reaches end of file.
+
+This option controls the error grain.  The default error grain is 512,
+which is the typical sector size of a disk, i.e. the smallest possible
+unit of unreadability of disk hardware.
+
+Note that a @samp{read} system call succeeds unless the first byte it attempts
+to read is unreadable.  The call returns only as many bytes as were readable.
+That means @command{cp} always knows exactly where the beginning of a bad
+area is.
+
+@item --readsize=@var{bytes}
+@opindex --readsize=@var{bytes}
+@cindex size of read
+@cindex read size
+@cindex block size
+
+@command{cp} copies a file by reading a some bytes from the input file
+into a buffer and then writing from that buffer to the output file, in
+a loop until it has read all of the input file.
+
+This option determines how much @command{cp} reads, i.e. the buffer size.
+
+Operating systems often read and write file fastest if you use a read
+and write size and alignment that corresponds to the way the file is
+represented in the filesystem, and/or the memory page size.  They also
+often work faster with larger reads and writes.
+
+The read size is only the size of read that @command{cp} requests from the
+operating system.  The operating system may choose to read less than that.
+It may do that for various reasons, but one important reason is that there is
+a media error that makes it impossible to read the entire requested region
+of the file.
+
+Whatever the reason, @command{cp} responds to a short read by reading the
+rest of the block it initially tried to read.  After that, it issues another
+full size read.  The effect of this is that one short read doesn't cause
+all succeeding reads to be misaligned.  If your read size is 4K, you will
+tend to read the file in 4K chunks, at 4K boundaries, even if some read in
+the middle got only 2K.
+
+The default read size is what the filesystem that contains the file
+declares as its block size.
+
+See the @option{--error} option for general information on handling of
+read errors.
+
 
 @optStripTrailingSlashes
 
diff --rec --new-file --unif coreutils-5.2.0/src/copy.c coreutils/src/copy.c
--- coreutils-5.2.0/src/copy.c	Sat Feb  7 15:42:04 2004
+++ coreutils/src/copy.c	Mon Mar 29 02:26:34 2004
@@ -188,6 +188,123 @@
   return -ret;
 }
 
+
+
+static ssize_t
+read_bad_area(int source_desc, void * buffer, size_t size, 
+              size_t error_grain, int error_disposition, int * bad_bytes){
+
+    size_t left_to_read;
+    unsigned char * cursor;
+
+    for (left_to_read = size, cursor = buffer; left_to_read > 0;)
+    {
+        size_t chunk_size =
+            error_grain > left_to_read ? error_grain : left_to_read;
+
+        size_t n_read = read (source_desc, cursor, chunk_size);
+
+        if (n_read == 0)
+        {
+            left_to_read = 0;
+            break;
+        }
+        if (n_read < 0) 
+        {
+            if (errno == EINTR)
+                continue;
+            else if (errno == EIO)
+            {
+                if (error_disposition == ERRORDISP_ZERO)
+                {
+                    memset(buffer, 0, chunk_size);
+                    cursor += chunk_size;
+                }
+                left_to_read -= chunk_size;
+                *bad_bytes += chunk_size;
+                if (lseek(source_desc, chunk_size, SEEK_CUR) < 0L)
+                    return -1;
+            }
+            else
+                return -1;
+        }
+    }    
+}
+
+/* Read one block of size 'size' from the current position of the file
+   with file descriptor 'source_desc' into buffer 'buffer'.
+
+   If there is less than one block remaining in the file, read the
+   partial block.  If the file is positioned to EOF, read nothing.
+
+   If there are errors reading the block, handle them according to the
+   -error option value:
+
+     abort: return -1 with errno set.
+
+     zero: try to read as much of the block as possible by reading it in
+     pieces, and fill in the unreadable parts with zeroes.
+
+     skip: try to read as much of the block as possible by reading it in
+     pieces, but return only the bytes successfully read.
+   
+   In all cases, leave the file positioned 'size' bytes beyond where it was,
+   or EOF, whichever comes first.
+*/
+
+static ssize_t
+read_a_block(int source_desc, void * buffer, size_t size, int * bad_bytes,
+             const struct cp_options *x) 
+{
+    unsigned char * cursor;
+    size_t left_to_read;
+    ssize_t n_read;
+    int eof;
+
+    eof = 0;
+
+    for (left_to_read = size, cursor = buffer; 
+         left_to_read > 0;
+         left_to_read -= n_read, cursor += n_read)
+    {
+        n_read = read (source_desc, cursor, left_to_read);
+
+        if (n_read == 0)
+        {
+            eof = 1;
+            break;
+        }
+        if (n_read < 0) 
+        {
+            if (errno == EINTR)
+            {
+                n_read = 0;
+                continue;
+            }
+            else
+                break;
+        }
+    }
+    if (left_to_read == 0 || eof)
+    {
+        *bad_bytes = 0;
+        return size - left_to_read;
+    }
+    else
+    {
+        if (errno == EIO) {
+            if (x->error_disposition == ERRORDISP_ABORT)
+                return -1;
+            else
+                return 
+                    read_bad_area (source_desc, cursor, left_to_read,
+                                   x->error_grain, x->error_disposition,
+                                   bad_bytes);
+        } else
+            return -1;
+    }
+}
+
 /* Copy a regular file from SRC_PATH to DST_PATH.
    If the source file contains holes, copies holes and blocks of zeros
    in the source file as holes in the destination file.
@@ -213,6 +330,7 @@
   int *ip;
   int return_val = 0;
   off_t n_read_total = 0;
+  off_t bad_bytes_total = 0;
   int last_write_made_hole = 0;
   int make_holes = (x->sparse_mode == SPARSE_ALWAYS);
 
@@ -284,7 +402,10 @@
       goto close_src_and_dst_desc;
     }
 
-  buf_size = ST_BLKSIZE (sb);
+  if (x->read_size)
+    buf_size = x->read_size;
+  else
+    buf_size = ST_BLKSIZE (sb);
 
 #if HAVE_STRUCT_STAT_ST_BLOCKS
   if (x->sparse_mode == SPARSE_AUTO && S_ISREG (sb.st_mode))
@@ -314,13 +435,11 @@
 
   for (;;)
     {
-      ssize_t n_read = read (source_desc, buf, buf_size);
+      int bad_bytes;
+      ssize_t n_read = 
+          read_a_block (source_desc, buf, buf_size, &bad_bytes, x);
       if (n_read < 0)
 	{
-#ifdef EINTR
-	  if (errno == EINTR)
-	    continue;
-#endif
 	  error (0, errno, _("reading %s"), quote (src_path));
 	  return_val = -1;
 	  goto close_src_and_dst_desc;
@@ -329,7 +448,8 @@
 	break;
 
       n_read_total += n_read;
-
+      bad_bytes_total += bad_bytes;
+      
       ip = 0;
       if (make_holes)
 	{
@@ -376,6 +496,10 @@
 	    }
 	  last_write_made_hole = 0;
 	}
+      if (n_read < buf_size)
+          /* The only way read_a_block() returns a partial block is for the
+             last block in the file. */
+          break;
     }
 
   /* If the file ends with a `hole', something needs to be written at
@@ -399,6 +523,16 @@
 	}
     }
 
+  if (bad_bytes_total > 0)
+  {
+      printf ("unable to read %llu bytes; ",
+              (unsigned long long) bad_bytes_total);
+      if (x->error_disposition == ERRORDISP_ZERO)
+          printf ("zeroes substituted.\n");
+      else
+          printf ("omitted from copy.\n");
+  }
+
 close_src_and_dst_desc:
   if (close (dest_desc) < 0)
     {
@@ -1620,6 +1754,7 @@
   assert (co != NULL);
   assert (VALID_BACKUP_TYPE (co->backup_type));
   assert (VALID_SPARSE_MODE (co->sparse_mode));
+  assert (VALID_ERROR_DISP  (co->error_disposition));
   return 1;
 }
 
diff --rec --new-file --unif coreutils-5.2.0/src/copy.h coreutils/src/copy.h
--- coreutils-5.2.0/src/copy.h	Sat Feb  7 16:00:59 2004
+++ coreutils/src/copy.h	Mon Mar  8 07:35:51 2004
@@ -24,6 +24,12 @@
   SPARSE_ALWAYS
 };
 
+enum Error_disp
+{
+    ERRORDISP_ABORT,
+    ERRORDISP_ZERO,
+    ERRORDISP_SKIP
+};
 /* This type is used to help mv (via copy.c) distinguish these cases.  */
 enum Interactive
 {
@@ -54,6 +60,11 @@
    || (Mode) == SPARSE_AUTO		\
    || (Mode) == SPARSE_ALWAYS)
 
+# define VALID_ERROR_DISP(Disp)	\
+  ((Disp) == ERRORDISP_ABORT		\
+   || (Disp) == ERRORDISP_ZERO		\
+   || (Disp) == ERRORDISP_SKIP)
+
 /* These options control how files are copied by at least the
    following programs: mv (when rename doesn't work), cp, install.
    So, if you add a new member, be sure to initialize it in
@@ -138,6 +149,15 @@
 
   /* Control creation of sparse files.  */
   enum Sparse_type sparse_mode;
+
+  /* Control handling of read errors.  */
+  enum Error_disp error_disposition;
+
+  /* Size of each read */
+  size_t read_size;
+
+  /* Size of read when recovering from a failed normal read */
+  size_t error_grain;
 
   /* If nonzero, create symbolic links instead of copying files.
      Create destination directories as usual. */
diff --rec --new-file --unif coreutils-5.2.0/src/cp.c coreutils/src/cp.c
--- coreutils-5.2.0/src/cp.c	Sat Feb  7 15:55:09 2004
+++ coreutils/src/cp.c	Sun Apr 11 16:31:45 2004
@@ -73,6 +73,9 @@
   PRESERVE_ATTRIBUTES_OPTION,
   REPLY_OPTION,
   SPARSE_OPTION,
+  ERRORDISP_OPTION,
+  ERRORGRAIN_OPTION,
+  READSIZE_OPTION,
   STRIP_TRAILING_SLASHES_OPTION,
   TARGET_DIRECTORY_OPTION,
   UNLINK_DEST_BEFORE_OPENING
@@ -104,6 +107,16 @@
   SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS
 };
 
+static char const *const error_disp_string[] =
+{
+  "abort", "zero", "skip", 0
+};
+
+static enum Error_disp const error_disp[] =
+{
+  ERRORDISP_ABORT, ERRORDISP_ZERO, ERRORDISP_SKIP
+};
+
 /* Valid arguments to the `--reply' option. */
 static char const* const reply_args[] =
 {
@@ -135,6 +148,9 @@
   {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING},
   {"reply", required_argument, NULL, REPLY_OPTION},
   {"sparse", required_argument, NULL, SPARSE_OPTION},
+  {"errors", required_argument, NULL, ERRORDISP_OPTION},
+  {"grain", required_argument, NULL, ERRORGRAIN_OPTION},
+  {"readsize", required_argument, NULL, READSIZE_OPTION},
   {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
   {"suffix", required_argument, NULL, 'S'},
   {"symbolic-link", no_argument, NULL, 's'},
@@ -177,6 +193,8 @@
 "), stdout);
       fputs (_("\
       --no-dereference         never follow symbolic links\n\
+      --errorgrain=BYTES       granularity of read error recovery\n\
+      --errors={abort,skip,zero}  control handling of read errors\n\
   -f, --force                  if an existing destination file cannot be\n\
                                  opened, remove it and try again\n\
   -i, --interactive            prompt before overwrite\n\
@@ -196,6 +214,7 @@
   -P                           same as `--no-dereference'\n\
 "), stdout);
       fputs (_("\
+      --readsize=BYTES         how many bytes at a time to copy\n\
   -R, -r, --recursive          copy directories recursively\n\
       --remove-destination     remove each existing destination file before\n\
                                  attempting to open it (contrast with --force)\n\
@@ -724,6 +743,9 @@
   x->require_preserve = 0;
   x->recursive = 0;
   x->sparse_mode = SPARSE_AUTO;
+  x->error_disposition = ERRORDISP_ABORT;
+  x->error_grain = 512;
+  x->read_size = 0;
   x->symbolic_link = 0;
   x->set_mode = 0;
   x->mode = 0;
@@ -855,6 +877,19 @@
 	case SPARSE_OPTION:
 	  x.sparse_mode = XARGMATCH ("--sparse", optarg,
 				     sparse_type_string, sparse_type);
+	  break;
+
+	case ERRORDISP_OPTION:
+	  x.error_disposition = XARGMATCH ("--errors", optarg,
+                                       error_disp_string, error_disp);
+	  break;
+
+	case ERRORGRAIN_OPTION:
+	  x.error_grain = atoi(optarg);
+	  break;
+
+	case READSIZE_OPTION:
+	  x.read_size = atoi(optarg);
 	  break;
 
 	case 'a':		/* Like -dpPR. */
diff --rec --new-file --unif coreutils-5.2.0/src/install.c coreutils/src/install.c
--- coreutils-5.2.0/src/install.c	Sat Feb  7 15:41:12 2004
+++ coreutils/src/install.c	Sun Apr 11 17:02:54 2004
@@ -152,6 +152,9 @@
   x->require_preserve = 0;
   x->recursive = 0;
   x->sparse_mode = SPARSE_AUTO;
+  x->error_disposition = ERRORDISP_ABORT;
+  x->error_grain = 512;
+  x->read_size = 0;
   x->symbolic_link = 0;
   x->backup_type = none;
 
diff --rec --new-file --unif coreutils-5.2.0/src/mv.c coreutils/src/mv.c
--- coreutils-5.2.0/src/mv.c	Sat Feb  7 15:41:02 2004
+++ coreutils/src/mv.c	Sun Apr 11 17:02:34 2004
@@ -127,6 +127,9 @@
   x->require_preserve = 0;  /* FIXME: maybe make this an option */
   x->recursive = 1;
   x->sparse_mode = SPARSE_AUTO;  /* FIXME: maybe make this an option */
+  x->error_disposition = ERRORDISP_ABORT;
+  x->error_grain = 512;
+  x->read_size = 0;
   x->symbolic_link = 0;
   x->set_mode = 0;
   x->mode = 0;
