From 4e48aeb3887aad5bf9262343f8305d9e5e4907a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Lebleu?= Date: Thu, 18 Feb 2016 16:17:04 +0100 Subject: [PATCH] [enh] Store backup size and check free space before restoring (bugfix #189) --- locales/en.json | 1 + src/yunohost/backup.py | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 46d2cf118..1f0f5c148 100644 --- a/locales/en.json +++ b/locales/en.json @@ -6,6 +6,7 @@ "installation_failed" : "Installation failed", "unexpected_error" : "An unexpected error occured", "action_invalid" : "Invalid action '{:s}'", + "not_enough_disk_space" : "Not enough free disk space on '{path:s}'", "license_undefined" : "undefined", "no_appslist_found" : "No apps list found", diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 0fe3a1baa..85724d437 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -227,6 +227,11 @@ def backup_create(name=None, description=None, output_directory=None, _clean_tmp_dir(1) raise MoulinetteError(errno.EINVAL, m18n.n('backup_nothings_done')) + # Calculate total size + size = subprocess.check_output( + ['du','-sb', tmp_dir]).split()[0].decode('utf-8') + info['size'] = int(size) + # Create backup info file with open("%s/info.json" % tmp_dir, 'w') as f: f.write(json.dumps(info)) @@ -311,6 +316,14 @@ def backup_restore(name, hooks=[], apps=[], ignore_apps=False, ignore_hooks=Fals tmp_dir) os.system('rm -rf %s' % tmp_dir) + # Check available disk space + statvfs = os.statvfs(backup_path) + free_space = statvfs.f_frsize * statvfs.f_bavail + if free_space < info['size']: + logger.debug("%dB left but %dB is needed", free_space, info['size']) + raise MoulinetteError( + errno.EIO, m18n.n('not_enough_disk_space', path=backup_path)) + def _clean_tmp_dir(retcode=0): ret = hook_callback('post_backup_restore', args=[tmp_dir, retcode]) if not ret['failed']: @@ -538,7 +551,13 @@ def backup_info(name, with_details=False, human_readable=False): logger.debug("unable to load '%s'", info_file, exc_info=1) raise MoulinetteError(errno.EIO, m18n.n('backup_invalid_archive')) - size = os.path.getsize(archive_file) + # Retrieve backup size + size = info.get('size', 0) + if not size: + tar = tarfile.open(archive_file, "r:gz") + size = reduce(lambda x,y: getattr(x, 'size', x)+getattr(y, 'size', y), + tar.getmembers()) + tar.close() if human_readable: size = binary_to_human(size) + 'B'