Example #1
0
def validate_update(
        filepath: str, progress_callback: Callable[[float],
                                                   None]) -> Tuple[str, str]:
    """ Like otupdate.buildroot.file_actions.validate_update but moreso

    Checks for the rootfs, rootfs hash, bootfs, and bootfs hash.

    Returns the path to the rootfs and the path to the bootfs
    """
    filenames = [ROOTFS_NAME, ROOTFS_HASH_NAME, BOOT_NAME, BOOT_HASH_NAME]

    def zip_callback(progress):
        progress_callback(progress / 3.0)

    files, sizes = unzip_update(filepath, zip_callback, filenames, filenames)

    def rootfs_hash_callback(progress):
        progress_callback(progress / 3.0 + 0.33)

    rootfs = files.get(ROOTFS_NAME)
    assert rootfs
    rootfs_calc_hash = hash_file(rootfs,
                                 rootfs_hash_callback,
                                 file_size=sizes[ROOTFS_NAME])
    rootfs_hashfile = files.get(ROOTFS_HASH_NAME)
    assert rootfs_hashfile
    rootfs_packaged_hash = open(rootfs_hashfile, 'rb').read().strip()
    if rootfs_calc_hash != rootfs_packaged_hash:
        msg = f"Hash mismatch (rootfs): calculated {rootfs_calc_hash!r} != "\
            f"packaged {rootfs_packaged_hash!r}"
        LOG.error(msg)
        raise HashMismatch(msg)

    def bootfs_hash_callback(progress):
        progress_callback(progress / 3.0 + 0.66)

    bootfs = files.get(BOOT_NAME)
    assert bootfs
    bootfs_calc_hash = hash_file(bootfs,
                                 bootfs_hash_callback,
                                 file_size=sizes[BOOT_NAME])
    bootfs_hashfile = files.get(BOOT_HASH_NAME)
    assert bootfs_hashfile
    bootfs_packaged_hash = open(bootfs_hashfile, 'rb').read().strip()
    if bootfs_calc_hash != bootfs_packaged_hash:
        msg = f"Hash mismatch (bootfs): calculated {bootfs_calc_hash!r} != "\
            f"packged {bootfs_packaged_hash!r}"
        LOG.error(msg)
        raise HashMismatch(msg)

    return rootfs, bootfs
def test_unzip(downloaded_update_file):
    cb = mock.Mock()
    paths, sizes = file_actions.unzip_update(downloaded_update_file, cb,
                                             file_actions.UPDATE_FILES,
                                             file_actions.UPDATE_FILES)
    assert sorted(list(paths.keys())) == sorted(file_actions.UPDATE_FILES)
    for filename, path in paths.items():
        assert os.path.dirname(path) == os.path.dirname(downloaded_update_file)
    with zipfile.ZipFile(downloaded_update_file) as zf:
        for filename, size in sizes.items():
            assert zf.getinfo(filename).file_size == size
        for filename, path in paths.items():
            assert zf.read(filename) == open(path, 'rb').read()
    # We should have callback calls for
    # - every chunk (including the fractional one at the end) of rootfs
    calls = sizes[file_actions.ROOTFS_NAME] // 1024
    if calls * 1024 != sizes[file_actions.ROOTFS_NAME]:
        calls += 1
    # - the two files that are less than a chunk
    calls += 2
    assert cb.call_count == calls
def test_unzip_requires_sig(downloaded_update_file):
    cb = mock.Mock()
    with pytest.raises(file_actions.FileMissing):
        file_actions.unzip_update(downloaded_update_file, cb,
                                  file_actions.UPDATE_FILES,
                                  file_actions.UPDATE_FILES)
def test_unzip_does_not_require_sig(downloaded_update_file):
    cb = mock.Mock()
    file_actions.unzip_update(downloaded_update_file, cb,
                              file_actions.UPDATE_FILES,
                              [file_actions.ROOTFS_NAME,
                               file_actions.ROOTFS_HASH_NAME])