def calculate_md5(filename, length):
    """Calculate the MD5 hash of a file, up to length bytes.

    Returns the MD5 in its binary form, as an 8-byte string. Raises IOError
    or OSError in case of error.

    """
    assert length >= 0

    # shortcut: MD5 of an empty string is 'd41d8cd98f00b204e9800998ecf8427e',
    # represented here in binary
    if length == 0:
        return '\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\t\x98\xec\xf8\x42\x7e'

    md5_summer = hashlib.md5()

    f = open(filename, 'rb')

    try:
        bytes_read = 0

        while bytes_read < length:
            chunk_size = min(MD5_CHUNK_SIZE, length - bytes_read)

            chunk = f.read(chunk_size)

            if not chunk:
                # found EOF: means length was larger than the file size, or
                # file was truncated while reading -- print warning?
                break

            md5_summer.update(chunk)

            bytes_read += len(chunk)

    finally:
        f.close()

    md5 = md5_summer.digest()

    return md5
Calculate the MD5 hash of a file, up to length bytes.

    Returns the MD5 in its binary form, as an 8-byte string. Raises IOError
    or OSError in case of error.