I have written a program to do something similar.  My strategy is:
 * use os.read() to read 512 bytes at a time
 * when os.read fails, seek to the next multiple of 512 bytes
   and write '\0' * 512 to the output
I notice this code doesn't deal properly with short reads, but in my experience
they never happen (because the disk error makes an entire block unreadable, and
a block is never less than 512 bytes)

I use this code on a unix-style system.

def dd(src, target, bs=512):
    src = os.open(src, os.O_RDONLY)
    if os.path.exists(target):
        target = os.open(target, os.O_WRONLY | os.O_APPEND, 0600)
        existing = os.lseek(target, 0, SEEK_END)
    else:
        existing = 0
        target = os.open(target, os.O_WRONLY | os.O_CREAT, 0600)

    total = os.lseek(src, 0, SEEK_END) / bs
    os.lseek(src, existing, SEEK_SET)
    os.lseek(target, existing, SEEK_SET)

    if existing: print "starting at", existing
    i = existing / bs
    f = 0
    lastrem = -1

    last = start = time.time()
    while 1:
        try:
            block = os.read(src, bs)
        except os.error, detail:
            if detail.errno == errno.EIO:
                block = "\0" * bs
                os.lseek(src, (i+1) * bs, SEEK_SET)
                f = f + 1
            else:
                raise  
        if block == "": break

        i = i + 1
        os.write(target, block)

        now = time.time()
        if i % 1000 or now - last < 1: continue
        last = now

        frac = i * 1. / total
        rem = int((now-start) * (1-frac) / frac)
        if rem < 60 or abs(rem - lastrem) > .5:
            rm, rs = divmod(rem, 60)
            lastrem = rem
        spd = i * 512. / (now - start) / 1024 / 1024
        sys.stderr.write("%8d %8d %8d %3.1f%% %6d:%02d %6.1fMB/s\r"
                        % (i, f, i-f, i * 100. / total, rm, rs, spd))
    sys.stderr.write("\n")

Attachment: pgpsinNQxCisS.pgp
Description: PGP signature

-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to