Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dd: reports incorrect whole/partial records written #3042

Closed
jfinkels opened this issue Feb 3, 2022 · 3 comments
Closed

dd: reports incorrect whole/partial records written #3042

jfinkels opened this issue Feb 3, 2022 · 3 comments
Labels

Comments

@jfinkels
Copy link
Collaborator

jfinkels commented Feb 3, 2022

GNU dd:

$ mkfifo inpipe
$ dd ibs=3 obs=3 if=inpipe &
$ (printf 'ab'; sleep 1; printf 'cd') > inpipe
abcd0+2 records in
1+1 records out
4 bytes copied, 1.00373 s, 0.0 kB/s

uutils dd:

$ mkfifo inpipe
$ ./target/debug/dd ibs=3 obs=3 if=inpipe &
$ (printf 'ab'; sleep 1; printf 'cd') > inpipe
0+2 records in
2+0 records out
4 bytes (4 B, 4 B) copied, 1.0 s, 0 B/s
abcd

There's a couple of minor differences here, but this issue is about the difference in the number of "records out":
1+1 records out versus 2+0 records out. The number on the left of the + sign is the number of complete blocks written, and the number on the right is the number of partial blocks written. In this case, the input block size is 3 and the output block size is 3, so 1+1 records out means that 1 complete block was written ('abc') and 1 partial block was written ('d'). However, the uutils dd is reporting 2 complete blocks written (presumably 'ab' and 'cd'), which is incorrect.

I believe this is happening because we are not buffering the output appropriately. I'm thinking that by maintaining a buffer of size obs, only flushing it when full, and only incrementing the number of complete blocks on flush, then we can get the correct behavior.

One caveat: if bs=3 is given instead of ibs=3 obs=3 on the command-line, then the behavior is different, as described in https://www.gnu.org/software/coreutils/manual/html_node/dd-invocation.html :

This makes dd read and write bytes per block, overriding any ‘ibs’ and ‘obs’ settings. In addition, if no data-transforming conv operand is specified, input is copied to the output as soon as it’s read, even if it is smaller than the block size.

In that case:

$ mkfifo inpipe
$ dd bs=3 if=inpipe &
$ (printf 'ab'; sleep 1; printf 'cd') > inpipe
abcd0+2 records in
0+2 records out
4 bytes copied, 1.00381 s, 0.0 kB/s

and you can see when you run it that the first partial block 'ab' gets written, then there is a 1 second pause, then the second partial block 'cd' gets written.

@jfinkels
Copy link
Collaborator Author

jfinkels commented Feb 5, 2022

Here's a simpler demonstration:

GNU dd:

$ printf 'abc' | dd bs=2 status=noxfer > /dev/null
1+1 records in
1+1 records out

uutils dd:

$ printf 'abc' | ./target/debug/dd bs=2 status=noxfer > /dev/null
1+1 records in
2+0 records out

@jfinkels
Copy link
Collaborator Author

Pull request #3129 resolved the simpler test case $ printf 'abc' | dd bs=2 status=noxfer > /dev/null, but not the one I originally reported.

@jfinkels
Copy link
Collaborator Author

I can no longer reproduce the issue as originally reported, so I think this is fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants