[clug] using 'dd' in a pipeline

steve jenkin sjenkin at canb.auug.org.au
Sun Nov 23 19:56:45 MST 2014


I’ve been looking at deliberate MD5 collisions and went to write a simple script based on ‘dd’, only to fall flat on my face - detecting ‘end of file’ from STDIN.

‘dd’ doesn’t consider EOF as an error and returns “success”.

I could use dd’s “iseek”, but that ties me to named files in the file system :(
I’d prefer to use a pipeline - current script below, but it requires I first know the size of the file, exactly the same issue as ‘iseek’.

One option is to catch the output of ‘dd’ in a temporary file, then test for its size, ending when the temp file is zero length.

I tried using the bash ‘read’ with "-n 0”, but that reads an entire line [not good for a binary file]
‘IFS=“” read -r -n 1’ runs, but consumes a byte of the input and discards binary ‘\0’ bytes :(

The stat() and read() system calls either don’t report EOF, or return zero-length at EOF.

I could test if a program that does a read() of zero-length, then uses ‘select’ with a short timeout, would reliably detect EOF on STDIN if it was a pipe or file.
It doesn’t seem reliable & portable to me, but it may be.

ioctl() and fcntl() didn’t seem to have

Anyone got ideas that I can use in a shell script? I’d prefer not to have to write code :)
There may already be extended versions of ‘dd’ that do this (haven’t checked these: dc3dd dcfldd dd_rescue ddd)

Or suggestion on existing tools or how to implement a simple test for EOF on STDIN (pipe or file) in PERL, PHP or other scripting languages.

Thanks in Advance
steve

=====================
Two files with same MD5 hash (e06723d4961a0a3f950e7786f3766338)
<http://natmchugh.blogspot.co.at/2014/10/how-i-created-two-images-with-same-md5.html>

Files:
brown.jpg <http://www.fishtrap.co.uk/james.jpg.coll>
white.jpg <http://www.fishtrap.co.uk/barry.jpg.coll>
=====================

#!/bin/bash

bs=4096
count=1

 for file in white.jpg brown.jpg
do
  echo "$file blocksize=${bs}"
  size=$(ls -l $file | awk -v bs="$bs" '{print $5 / bs}')

  cat $file|\
  while [[ $size -gt 0 ]]
  do
    echo -n "$size "
    dd bs=$bs count=$blocks 2>/dev/null |md5sum -
    size=$(( $size - $blocks ))
  done
  echo
done

--
Steve Jenkin, IT Systems and Design 
0412 786 915 (+61 412 786 915)
PO Box 48, Kippax ACT 2615, AUSTRALIA

mailto:sjenkin at canb.auug.org.au http://members.tip.net.au/~sjenkin



More information about the linux mailing list