diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 9bed264c6..12e2adeff 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -2193,7 +2193,11 @@ def backup_list(with_info=False, human_readable=False): if result and with_info: d = OrderedDict() for a in result: - d[a] = backup_info(a, human_readable=human_readable) + try: + d[a] = backup_info(a, human_readable=human_readable) + except MoulinetteError, e: + logger.warning('%s: %s' % (a, e.strerror)) + result = d return {'archives': result} @@ -2231,9 +2235,16 @@ def backup_info(name, with_details=False, human_readable=False): if not os.path.exists(info_file): tar = tarfile.open(archive_file, "r:gz") info_dir = info_file + '.d' - tar.extract('info.json', path=info_dir) - tar.close() - shutil.move(os.path.join(info_dir, 'info.json'), info_file) + try: + tar.extract('info.json', path=info_dir) + except KeyError: + logger.debug("unable to retrieve '%s' inside the archive", + info_file, exc_info=1) + raise MoulinetteError(errno.EIO, m18n.n('backup_invalid_archive')) + else: + shutil.move(os.path.join(info_dir, 'info.json'), info_file) + finally: + tar.close() os.rmdir(info_dir) try: @@ -2281,21 +2292,21 @@ def backup_delete(name): name -- Name of the local backup archive """ + if name not in backup_list()["archives"]: + raise MoulinetteError(errno.EIO, m18n.n('backup_archive_name_unknown', + name=name)) + hook_callback('pre_backup_delete', args=[name]) archive_file = '%s/%s.tar.gz' % (ARCHIVES_PATH, name) - info_file = "%s/%s.info.json" % (ARCHIVES_PATH, name) + for backup_file in [archive_file, info_file]: - if not os.path.isfile(backup_file) and not os.path.islink(backup_file): - raise MoulinetteError(errno.EIO, - m18n.n('backup_archive_name_unknown', name=backup_file)) try: os.remove(backup_file) except: logger.debug("unable to delete '%s'", backup_file, exc_info=1) - raise MoulinetteError(errno.EIO, - m18n.n('backup_delete_error', path=backup_file)) + logger.warning(m18n.n('backup_delete_error', path=backup_file)) hook_callback('post_backup_delete', args=[name]) diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py index 5fd1bd4a9..9132b9611 100644 --- a/src/yunohost/tests/test_backuprestore.py +++ b/src/yunohost/tests/test_backuprestore.py @@ -634,5 +634,21 @@ def _test_backup_and_restore_app(app): assert app_is_installed(app) +############################################################################### +# Some edge cases # +############################################################################### +def test_restore_archive_with_no_json(mocker): + + # Create a backup with no info.json associated + os.system("touch /tmp/afile") + os.system("tar -czvf /home/yunohost.backup/archives/badbackup.tar.gz /tmp/afile") + + assert "badbackup" in backup_list()["archives"] + + mocker.spy(m18n, "n") + with pytest.raises(MoulinetteError): + backup_restore(auth, name="badbackup", force=True, + ignore_system=False, ignore_apps=False) + m18n.n.assert_any_call('backup_invalid_archive')