[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
inconsistent behaviour of dd with seek= and oflag=seek_bytes
From: |
Rasmus Villemoes |
Subject: |
inconsistent behaviour of dd with seek= and oflag=seek_bytes |
Date: |
Wed, 20 Sep 2023 10:09:40 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.15.1 |
Consider this:
$ echo aaa > x
$ echo aaa > y
$ echo bbb > b
$ dd if=b of=x seek=600 oflag=seek_bytes
0+1 records in
0+1 records out
4 bytes copied, 0,000187014 s, 21,4 kB/s
$ dd if=b of=y seek=100 oflag=seek_bytes
0+1 records in
0+1 records out
4 bytes copied, 0,000359168 s, 11,1 kB/s
$ hexdump -C x
00000000 61 61 61 0a 00 00 00 00 00 00 00 00 00 00 00 00
|aaa.............|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|................|
*
00000250 00 00 00 00 00 00 00 00 62 62 62 0a |........bbb.|
0000025c
$ hexdump -C y
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|................|
*
00000060 00 00 00 00 62 62 62 0a |....bbb.|
00000068
In the latter case, the old contents of y are gone. This is easily
traced to the code that decides whether to include O_TRUNC in the open
flags:
int opts
= (output_flags
| (conversions_mask & C_NOCREAT ? 0 : O_CREAT)
| (conversions_mask & C_EXCL ? O_EXCL : 0)
| (seek_records || (conversions_mask & C_NOTRUNC) ? 0 :
O_TRUNC));
So when the seek value is smaller than a block (so seek_records is 0 and
seek_bytes has seek= value), we end up passing O_TRUNC. That is, IMO,
quite unexpected and inconsistent.
So one could pass conv=notrunc to be explicit. However, another case
where this could hit is when one tries to use dd to extend a file to a
specific size, where passing conv=notrunc is not an option (because then
dd wouldn't do ftruncate). One could do
dd if=/dev/null of=file seek=$somevalue oflag=seek_bytes
and that will work fine for $somevalue large enough, but then break when
it happens to be < 512 (leaving the file empty). Of course, a more
portable way to do this is to write it
dd if=/dev/null of=file seek=$somevalue bs=1
but I think the current behavior of seek_bytes with wildly different
results depending on whether the seek= value is below the block size or
not is a footgun.
I suggest moving the computation and sanity checking of size above the
initialization of opts, and then in the three places where
'seek_records' is used as a boolean (opts, open logic, decision whether
to do ftruncate), replace with 'size'.
Rasmus
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- inconsistent behaviour of dd with seek= and oflag=seek_bytes,
Rasmus Villemoes <=