bug-coreutils
[Top][All Lists]
Advanced

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

Re: possible bug - output stream handling inconsistency in dd


From: Theodoros V. Kalamatianos
Subject: Re: possible bug - output stream handling inconsistency in dd
Date: Wed, 2 Nov 2005 04:11:57 +0200 (EET)

On Tue, 1 Nov 2005, Paul Eggert wrote:

"Theodoros V. Kalamatianos" <address@hidden> writes:

lseek is valid on e.g. /dev/hda and people
would not expect dd to null their data till it reached the desired
offset.

True.  I guess the algorithm should be to use lseek if possible, and
to write nulls otherwise.  Then ftruncate if possible.

I agree. I also think that ftruncate should happen regardless of the presence of of=. This would allow cases like `true | dd seek=1 >> file'
to work properly.

Perhaps dd should output null bytes only on FIFOs ?

I'd say it should output nulls if lseek fails for any reason.

Hmm, so all we need is some code in skip() to fall back to iwrite for STDOUT_FILENO.

On a relative matter, what should dd do in the following case:

$ echo -n AB > f
$ echo -n ab | dd bs=1 seek=1 >> f

What should the contents of `f' be ?

Just "ABab".  That's a tricky one, since the ">>f" means that stdout
is in append mode, which means all writes are appended to the end of
the file regardless of the current seek position.  So the "seek=1" is
ineffective.

Yes, I realised this when I read the whole Std-Info-Man documentation.

Anyway, I _think_ that following patch implements the desired behaviour:


diff -uNr coreutils-5.92/src/dd.c coreutils-5.92/src/dd.c
--- coreutils-5.92/src/dd.c     2005-10-01 08:54:57.000000000 +0300
+++ coreutils-5.92/src/dd.c     2005-11-02 04:00:34.000000000 +0200
@@ -1139,6 +1139,47 @@
        advance_input_offset (offset);
       return 0;
     }
+  /* Do not seek if offset is zero */
+  else if (offset == 0)
+    return 0;
+  else if (fdesc == STDOUT_FILENO)
+    {
+      memset(buf, 0, blocksize);
+
+      do
+       {
+         /* Try reading first */
+         ssize_t nseek = iread (fdesc, buf, blocksize);
+         if (nseek < 0)
+           {
+             /* Don't stop if the stream is open write-only
+                Q: What is the proper error handling here ? */
+             if (errno != EBADF) {
+               error (0, errno, _("%s: cannot seek"), quote (file));
+               quit (EXIT_FAILURE);
+             }
+             nseek = 0;
+           }
+
+         /* Use write() for the remaining bytes */
+         if (nseek < blocksize)
+           {
+             nseek = iwrite (fdesc, buf, blocksize - nseek);
+
+             /* writes to the output are expected to succeed */
+             if (nseek < 0)
+               {
+                 error (0, errno, _("%s: cannot seek"), quote (file));
+                 quit (EXIT_FAILURE);
+               }
+             if (nseek == 0)
+               break;
+           }
+       }
+      while (--records != 0);
+
+      return records;
+    }
   else
     {
       int lseek_errno = errno;
@@ -1647,6 +1688,7 @@
          && (fd_reopen (STDOUT_FILENO, output_file, O_WRONLY | opts, perms)
              < 0))
        error (EXIT_FAILURE, errno, _("opening %s"), quote (output_file));
+    }

 #if HAVE_FTRUNCATE
       if (seek_records != 0 && !(conversions_mask & C_NOTRUNC))
@@ -1682,7 +1724,6 @@
            }
        }
 #endif
-    }

   install_signal_handlers ();


One stupid question: what non-seekable stream types exist, apart from a pipe to a program ? Is there any stream type where lseek could fail, but there is stored data that could be overwritten ?


Regards,

Theodoros Kalamatianos




reply via email to

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