def file_md5sum(filename):
    '''Calculate and returns an MD5 checksum for the specified file.  Any file
    errors (non-existent file, read error, etc.) are not handled here but should
    be caught where this method is called.

    :param filename: full path to the file for which a checksum should be calculated
    :returns: hex-digest formatted MD5 checksum as a string
    '''
    # duplicated from keep.common.utils
    # possibly at some point this should be moved to a common codebase/library
    md5 = hashlib.md5()
    with open(filename, 'rb') as filedata:
        for chunk in iter(lambda: filedata.read(128 * md5.block_size), b''):
            md5.update(chunk)
    return md5.hexdigest()