[Top][All Lists]
[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