bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

"dd skip=N of=unseekable" patch for POSIX conformance


From: Paul Eggert
Subject: "dd skip=N of=unseekable" patch for POSIX conformance
Date: Fri, 27 May 2005 22:57:22 -0700
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.4 (gnu/linux)

I installed this patch after a question came up about it on the Open
Group reflector.  Unfortunately I don't have any unseekable devices to
test it on.

2005-05-27  Paul Eggert  <address@hidden>

        * NEWS: dd seek=N now conforms to POSIX if the output isn't seekable.
        * src/dd.c (skip): Return the number of records that were not
        skipped due to encountering EOF.
        (dd_copy): If the file wasn't seekable and EOF was encountered,
        write zeros past EOF until the desired offset is reached.

Index: NEWS
===================================================================
RCS file: /fetish/cu/NEWS,v
retrieving revision 1.291
diff -p -u -r1.291 NEWS
--- NEWS        27 May 2005 20:31:59 -0000      1.291
+++ NEWS        28 May 2005 04:22:07 -0000
@@ -63,6 +63,10 @@ GNU coreutils NEWS                      
     On hosts lacking the INFO signal, dd no longer treats the USR1
     signal as if it were INFO when POSIXLY_CORRECT is set.
 
+    If the file F is non-seekable and contains fewer than N blocks,
+    then before copying "dd seek=N of=F" now extends F with zeroed
+    blocks until F contains N blocks.
+
   fold changes:
 
     When POSIXLY_CORRECT is set, "fold file -3" is now equivalent to
Index: src/dd.c
===================================================================
RCS file: /fetish/cu/src/dd.c,v
retrieving revision 1.182
diff -p -u -r1.182 dd.c
--- src/dd.c    14 May 2005 07:58:37 -0000      1.182
+++ src/dd.c    28 May 2005 04:22:07 -0000
@@ -1130,9 +1130,11 @@ skip_via_lseek (char const *filename, in
 /* Throw away RECORDS blocks of BLOCKSIZE bytes on file descriptor FDESC,
    which is open with read permission for FILE.  Store up to BLOCKSIZE
    bytes of the data at a time in BUF, if necessary.  RECORDS must be
-   nonzero.  If fdesc is STDIN_FILENO, advance the input offset.  */
+   nonzero.  If fdesc is STDIN_FILENO, advance the input offset.
+   Return the number of records remaining, i.e., that were not skipped
+   because EOF was reached.  */
 
-static void
+static uintmax_t
 skip (int fdesc, char const *file, uintmax_t records, size_t blocksize,
       char *buf)
 {
@@ -1148,11 +1150,13 @@ skip (int fdesc, char const *file, uintm
     {
       if (fdesc == STDIN_FILENO)
        advance_input_offset (offset);
+      return 0;
     }
   else
     {
       int lseek_errno = errno;
-      while (records--)
+
+      do
        {
          ssize_t nread = iread (fdesc, buf, blocksize);
          if (nread < 0)
@@ -1170,14 +1174,15 @@ skip (int fdesc, char const *file, uintm
                error (0, lseek_errno, _("%s: cannot seek"), quote (file));
              quit (EXIT_FAILURE);
            }
-         /* POSIX doesn't say what to do when dd detects it has been
-            asked to skip past EOF, so I assume it's non-fatal.
-            FIXME: maybe give a warning.  */
+
          if (nread == 0)
            break;
          if (fdesc == STDIN_FILENO)
            advance_input_offset (nread);
        }
+      while (records-- != 0);
+
+      return records;
     }
 }
 
@@ -1390,10 +1395,32 @@ dd_copy (void)
     }
 
   if (skip_records != 0)
-    skip (STDIN_FILENO, input_file, skip_records, input_blocksize, ibuf);
+    {
+      skip (STDIN_FILENO, input_file, skip_records, input_blocksize, ibuf);
+      /* POSIX doesn't say what to do when dd detects it has been
+        asked to skip past EOF, so I assume it's non-fatal if the
+        call to 'skip' returns nonzero.  FIXME: maybe give a warning.  */
+    }
 
   if (seek_records != 0)
-    skip (STDOUT_FILENO, output_file, seek_records, output_blocksize, obuf);
+    {
+      uintmax_t write_records = skip (STDOUT_FILENO, output_file,
+                                     seek_records, output_blocksize, obuf);
+
+      if (write_records != 0)
+       {
+         memset (obuf, 0, output_blocksize);
+
+         do
+           if (iwrite (STDOUT_FILENO, obuf, output_blocksize)
+               != output_blocksize)
+             {
+               error (0, errno, _("writing to %s"), quote (output_file));
+               quit (EXIT_FAILURE);
+             }
+         while (--write_records != 0);
+       }
+    }
 
   if (max_records == 0)
     return exit_status;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]