[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
possible bug - output stream handling inconsistency in dd
From: |
Theodoros V. Kalamatianos |
Subject: |
possible bug - output stream handling inconsistency in dd |
Date: |
Mon, 31 Oct 2005 13:55:45 +0200 (EET) |
Hello,
While trying to implement the per-block seek/skip options I suggested I
encountered an inconsistency between the handling of regular files and
stdout in the following case:
dd if=/dev/zero count=0 seek=1
To reproduce the inconsistency:
# rm -f test; dd if=/dev/zero count=0 seek=1 of=test; ll test
0+0 records in
0+0 records out
0 bytes (0 B) copied, 3,9e-05 seconds, 0,0 kB/s
-rw-r--r-- 1 root root 512 Oct 31 13:37 test
# rm -f test; dd if=/dev/zero count=0 seek=1 > test; ll test
0+0 records in
0+0 records out
0 bytes (0 B) copied, 3,6e-05 seconds, 0,0 kB/s
-rw-r--r-- 1 root root 0 Oct 31 13:37 test
Note the difference in the resulting file sizes.
In detail:
- when the output is a regular file ftruncate() is used to truncate the
file. This means that if the file is smaller than obs*seek it is expanded
to that size.
- when the output is stdout ftruncate() is not used and no expansion
happens.
I think that the proper behaviour would be to ftruncate() the output file
only when it is larger than the requested seek size. The following patch
corrects this inconsistency:
--- dd.c.orig 2005-10-31 10:21:15.000000000 +0200
+++ dd.c.orig.cmp 2005-10-31 13:49:14.000000000 +0200
@@ -1651,6 +1651,7 @@
#if HAVE_FTRUNCATE
if (seek_records != 0 && !(conversions_mask & C_NOTRUNC))
{
+ struct stat stdout_stat;
uintmax_t size = seek_records * output_blocksize;
unsigned long int obs = output_blocksize;
@@ -1661,7 +1662,12 @@
" (%lu-byte) blocks"),
seek_records, obs);
- if (ftruncate (STDOUT_FILENO, size) != 0)
+ if (fstat (STDOUT_FILENO, &stdout_stat) != 0)
+ error (EXIT_FAILURE, errno, _("cannot fstat %s"),
+ quote (output_file));
+
+ if ((stdout_stat.st_size > size) &&
+ (ftruncate (STDOUT_FILENO, size) != 0))
{
/* Complain only when ftruncate fails on a regular file, a
directory, or a shared memory object, as POSIX
1003.1-2004
@@ -1669,10 +1675,6 @@
For example, do not complain when Linux 2.4 ftruncate
fails on /dev/fd0. */
int ftruncate_errno = errno;
- struct stat stdout_stat;
- if (fstat (STDOUT_FILENO, &stdout_stat) != 0)
- error (EXIT_FAILURE, errno, _("cannot fstat %s"),
- quote (output_file));
if (S_ISREG (stdout_stat.st_mode)
|| S_ISDIR (stdout_stat.st_mode)
|| S_TYPEISSHM (&stdout_stat))
Note that this may introduce a race condition if the file size increases
between the fstat and ftruncate calls, but I don't think that there is a
way to do this atomically. Any comments are welcome...
Regards,
Theodoros Kalamatianos
- possible bug - output stream handling inconsistency in dd,
Theodoros V. Kalamatianos <=