Added size safety check to ddrescue TUI
This commit is contained in:
parent
bd3601e0c8
commit
fc0a37999b
1 changed files with 57 additions and 4 deletions
|
|
@ -16,6 +16,8 @@ import time
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
|
||||||
from wk import cfg, debug, exe, io, log, net, std, tmux
|
from wk import cfg, debug, exe, io, log, net, std, tmux
|
||||||
from wk.hw import obj as hw_obj
|
from wk.hw import obj as hw_obj
|
||||||
from wk.hw import sensors as hw_sensors
|
from wk.hw import sensors as hw_sensors
|
||||||
|
|
@ -36,6 +38,7 @@ Options:
|
||||||
CLONE_SETTINGS = {
|
CLONE_SETTINGS = {
|
||||||
'Source': None,
|
'Source': None,
|
||||||
'Destination': None,
|
'Destination': None,
|
||||||
|
'Create Boot Partition': False,
|
||||||
'First Run': True,
|
'First Run': True,
|
||||||
'Needs Format': False,
|
'Needs Format': False,
|
||||||
'Table Type': None,
|
'Table Type': None,
|
||||||
|
|
@ -175,7 +178,7 @@ class State():
|
||||||
settings = {}
|
settings = {}
|
||||||
|
|
||||||
# Clone settings
|
# Clone settings
|
||||||
settings = self.load_settings(working_dir)
|
settings = self.load_settings(working_dir, discard_unused_settings=True)
|
||||||
|
|
||||||
# Add pairs
|
# Add pairs
|
||||||
if settings['Partition Mapping']:
|
if settings['Partition Mapping']:
|
||||||
|
|
@ -196,10 +199,11 @@ class State():
|
||||||
self.add_block_pair(self.source, bp_dest, working_dir)
|
self.add_block_pair(self.source, bp_dest, working_dir)
|
||||||
else:
|
else:
|
||||||
# New run, use new settings file
|
# New run, use new settings file
|
||||||
|
settings['Needs Format'] = True
|
||||||
offset = 0
|
offset = 0
|
||||||
if std.ask('Create an empty Windows boot partition on the clone?'):
|
if std.ask('Create an empty Windows boot partition on the clone?'):
|
||||||
offset = 2
|
offset = 2
|
||||||
settings['Needs Format'] = True
|
settings['Create Boot Partition'] = True
|
||||||
settings['Table Type'] = 'GPT'
|
settings['Table Type'] = 'GPT'
|
||||||
if std.choice(['G', 'M'], 'GPT or MBR partition table?') == 'M':
|
if std.choice(['G', 'M'], 'GPT or MBR partition table?') == 'M':
|
||||||
offset = 1
|
offset = 1
|
||||||
|
|
@ -281,7 +285,7 @@ class State():
|
||||||
report.extend(
|
report.extend(
|
||||||
build_block_pair_report(
|
build_block_pair_report(
|
||||||
self.block_pairs,
|
self.block_pairs,
|
||||||
self.load_settings(working_dir, False) if mode == 'Clone' else {},
|
self.load_settings(working_dir) if mode == 'Clone' else {},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
report.append(' ')
|
report.append(' ')
|
||||||
|
|
@ -427,6 +431,9 @@ class State():
|
||||||
source_parts = select_disk_parts(mode, self.source)
|
source_parts = select_disk_parts(mode, self.source)
|
||||||
self.add_image_block_pairs(source_parts, working_dir)
|
self.add_image_block_pairs(source_parts, working_dir)
|
||||||
|
|
||||||
|
# Safety Check
|
||||||
|
self.safety_check(mode, working_dir)
|
||||||
|
|
||||||
# Confirmation #2
|
# Confirmation #2
|
||||||
self.confirm_selections(mode, 'Start recovery?', working_dir=working_dir)
|
self.confirm_selections(mode, 'Start recovery?', working_dir=working_dir)
|
||||||
|
|
||||||
|
|
@ -513,6 +520,52 @@ class State():
|
||||||
# Done
|
# Done
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
def safety_check(self, mode, working_dir):
|
||||||
|
"""Run safety check and abort if necessary."""
|
||||||
|
required_size = sum([pair.size for pair in self.block_pairs])
|
||||||
|
|
||||||
|
# Increase required_size if necessary
|
||||||
|
if mode == 'Clone' and settings['Needs Format']:
|
||||||
|
settings = self.load_settings(working_dir)
|
||||||
|
if settings['Table Type'] == 'GPT':
|
||||||
|
# Below is the size calculation for the GPT
|
||||||
|
# 1 LBA for the protective MBR
|
||||||
|
# 33 LBAs each for the primary and backup GPT tables
|
||||||
|
# Source: https://en.wikipedia.org/wiki/GUID_Partition_Table
|
||||||
|
required_size += (1 + 33 + 33) * self.destination.details['phy-sec']
|
||||||
|
if settings['Create Boot Partition']:
|
||||||
|
# 384MiB EFI System Partition and a 16MiB MS Reserved partition
|
||||||
|
required_size += (384 + 16) * 1024**2
|
||||||
|
else:
|
||||||
|
# MBR only requires one LBA but adding a full 4096 bytes anyway
|
||||||
|
required_size += 4096
|
||||||
|
if settings['Create Boot Partition']:
|
||||||
|
# 100MiB System Reserved partition
|
||||||
|
required_size += 100 * 1024**2
|
||||||
|
|
||||||
|
# Reduce required_size if necessary
|
||||||
|
if mode == 'Image':
|
||||||
|
for pair in self.block_pairs:
|
||||||
|
if pair.destination.exists():
|
||||||
|
# NOTE: This uses the "max space" of the destination
|
||||||
|
# i.e. not the apparent size which is smaller for sparse files
|
||||||
|
# While this can result in an out-of-space error it's better
|
||||||
|
# than nothing.
|
||||||
|
required_size -= pair.destination.stat().st_size
|
||||||
|
|
||||||
|
# Check destination size
|
||||||
|
if mode == 'Clone':
|
||||||
|
destination_size = self.destination.details['size']
|
||||||
|
error_msg = 'A larger destination disk is required'
|
||||||
|
else:
|
||||||
|
# NOTE: Adding an extra 5% here to better ensure it will fit
|
||||||
|
destination_size = psutil.disk_usage(self.destination).free
|
||||||
|
destination_size *= 1.05
|
||||||
|
error_msg = 'Not enough free space on the destination'
|
||||||
|
if required_size > destination_size:
|
||||||
|
std.print_error(error_msg)
|
||||||
|
raise std.GenericAbort()
|
||||||
|
|
||||||
def save_debug_reports(self):
|
def save_debug_reports(self):
|
||||||
"""Save debug reports to disk."""
|
"""Save debug reports to disk."""
|
||||||
LOG.info('Saving debug reports')
|
LOG.info('Saving debug reports')
|
||||||
|
|
@ -631,7 +684,7 @@ def build_block_pair_report(block_pairs, settings):
|
||||||
return report
|
return report
|
||||||
|
|
||||||
# Show block pair mapping
|
# Show block pair mapping
|
||||||
if settings and settings['Needs Format']:
|
if settings and settings['Create Boot Partition']:
|
||||||
if settings['Table Type'] == 'GPT':
|
if settings['Table Type'] == 'GPT':
|
||||||
report.append(f'{" —— ":<9} --> EFI System Partition')
|
report.append(f'{" —— ":<9} --> EFI System Partition')
|
||||||
report.append(f'{" —— ":<9} --> Microsoft Reserved Partition')
|
report.append(f'{" —— ":<9} --> Microsoft Reserved Partition')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue