Be more robust against some situation where archive is corrupted

This commit is contained in:
Alexandre Aubin 2020-04-24 03:08:31 +02:00
parent 34fd4e90bd
commit 176d0176db
2 changed files with 27 additions and 18 deletions

View file

@ -88,6 +88,8 @@
"backup_archive_name_exists": "A backup archive with this name already exists.",
"backup_archive_name_unknown": "Unknown local backup archive named '{name:s}'",
"backup_archive_open_failed": "Could not open the backup archive",
"backup_archive_cant_retrieve_info_json": "Could not load infos for archive '{archive}' ... The info.json cannot be retrieved (or is not a valid json).",
"backup_archive_corrupted": "It looks like the backup archive '{archive}' is corrupted : {error}",
"backup_archive_system_part_not_available": "System part '{part:s}' unavailable in this backup",
"backup_archive_writing_error": "Could not add the files '{source:s}' (named in the archive '{dest:s}') to be backed up into the compressed archive '{archive:s}'",
"backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily? (This way is used since some files could not be prepared using a more efficient method.)",
@ -105,7 +107,6 @@
"backup_delete_error": "Could not delete '{path:s}'",
"backup_deleted": "Backup deleted",
"backup_hook_unknown": "The backup hook '{hook:s}' is unknown",
"backup_invalid_archive": "This is not a backup archive",
"backup_method_borg_finished": "Backup into Borg finished",
"backup_method_copy_finished": "Backup copy finalized",
"backup_method_custom_finished": "Custom backup method '{method:s}' finished",

View file

@ -871,7 +871,7 @@ class RestoreManager():
Read the info file from inside an archive
Exceptions:
backup_invalid_archive -- Raised if we can't read the info
backup_archive_cant_retrieve_info_json -- Raised if we can't read the info
"""
# Retrieve backup info
info_file = os.path.join(self.work_dir, "info.json")
@ -884,7 +884,7 @@ class RestoreManager():
self.info["system"] = self.info["hooks"]
except IOError:
logger.debug("unable to load '%s'", info_file, exc_info=1)
raise YunohostError('backup_invalid_archive')
raise YunohostError('backup_archive_cant_retrieve_info_json', archive=self.archive_path)
else:
logger.debug("restoring from backup '%s' created on %s", self.name,
datetime.utcfromtimestamp(self.info['created_at']))
@ -892,10 +892,6 @@ class RestoreManager():
def _postinstall_if_needed(self):
"""
Post install yunohost if needed
Exceptions:
backup_invalid_archive -- Raised if the current_host isn't in the
archive
"""
# Check if YunoHost is installed
if not os.path.isfile('/etc/yunohost/installed'):
@ -907,7 +903,7 @@ class RestoreManager():
logger.debug("unable to retrieve current_host from the backup",
exc_info=1)
# FIXME include the current_host by default ?
raise YunohostError('backup_invalid_archive')
raise YunohostError("The main domain name cannot be retrieved from inside the archive, and is needed to perform the postinstall", raw_msg=True)
logger.debug("executing the post-install...")
tools_postinstall(domain, 'Yunohost', True)
@ -1924,6 +1920,12 @@ class TarBackupMethod(BackupMethod):
self._archive_file, exc_info=1)
raise YunohostError('backup_archive_open_failed')
try:
files_in_archive = tar.getnames()
print(files_in_archive)
except IOError as e:
raise YunohostError("backup_archive_corrupted", archive=self._archive_file, error=str(e))
# FIXME : Is this really useful to close the archive just to
# reopen it right after this with the same options ...?
tar.close()
@ -1932,21 +1934,21 @@ class TarBackupMethod(BackupMethod):
logger.debug(m18n.n("restore_extracting"))
tar = tarfile.open(self._archive_file, "r:gz")
if "info.json" in tar.getnames():
if "info.json" in files_in_archive:
leading_dot = ""
tar.extract('info.json', path=self.work_dir)
elif "./info.json" in tar.getnames():
elif "./info.json" in files_in_archive:
leading_dot = "./"
tar.extract('./info.json', path=self.work_dir)
else:
logger.debug("unable to retrieve 'info.json' inside the archive",
exc_info=1)
tar.close()
raise YunohostError('backup_invalid_archive')
raise YunohostError('backup_archive_cant_retrieve_info_json', archive=self._archive_file)
if "backup.csv" in tar.getnames():
if "backup.csv" in files_in_archive:
tar.extract('backup.csv', path=self.work_dir)
elif "./backup.csv" in tar.getnames():
elif "./backup.csv" in files_in_archive:
tar.extract('./backup.csv', path=self.work_dir)
else:
# Old backup archive have no backup.csv file
@ -2288,7 +2290,7 @@ def backup_list(with_info=False, human_readable=False):
try:
d[a] = backup_info(a, human_readable=human_readable)
except YunohostError as e:
logger.warning('%s: %s' % (a, e.strerror))
logger.warning(str(e))
result = d
@ -2325,17 +2327,23 @@ 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'
try:
if "info.json" in tar.getnames():
files_in_archive = tar.getnames()
except IOError as e:
raise YunohostError("backup_archive_corrupted", archive=archive_file, error=str(e))
try:
if "info.json" in files_in_archive:
tar.extract('info.json', path=info_dir)
elif "./info.json" in tar.getnames():
elif "./info.json" in files_in_archive:
tar.extract('./info.json', path=info_dir)
else:
raise KeyError
except KeyError:
logger.debug("unable to retrieve '%s' inside the archive",
info_file, exc_info=1)
raise YunohostError('backup_invalid_archive')
raise YunohostError('backup_archive_cant_retrieve_info_json', archive=archive_file)
else:
shutil.move(os.path.join(info_dir, 'info.json'), info_file)
finally:
@ -2348,7 +2356,7 @@ def backup_info(name, with_details=False, human_readable=False):
info = json.load(f)
except:
logger.debug("unable to load '%s'", info_file, exc_info=1)
raise YunohostError('backup_invalid_archive')
raise YunohostError('backup_archive_cant_retrieve_info_json', archive=archive_file)
# Retrieve backup size
size = info.get('size', 0)