Resume session via map file(s)
* Read map file(s) and set progress, status, and current pass
This commit is contained in:
parent
f5994d851b
commit
2430ba5e00
1 changed files with 100 additions and 10 deletions
|
|
@ -21,11 +21,11 @@ DDRESCUE_SETTINGS = {
|
||||||
'--data-preview': {'Enabled': True, 'Hidden': True},
|
'--data-preview': {'Enabled': True, 'Hidden': True},
|
||||||
'--idirect': {'Enabled': True},
|
'--idirect': {'Enabled': True},
|
||||||
'--odirect': {'Enabled': True},
|
'--odirect': {'Enabled': True},
|
||||||
'--max-read-rate': {'Enabled': False, 'Value': '4MiB'},
|
'--max-read-rate': {'Enabled': False, 'Value': '32MiB'},
|
||||||
'--min-read-rate': {'Enabled': True, 'Value': '64KiB'},
|
'--min-read-rate': {'Enabled': True, 'Value': '64KiB'},
|
||||||
'--reopen-on-error': {'Enabled': True},
|
'--reopen-on-error': {'Enabled': True},
|
||||||
'--retry-passes=': {'Enabled': True, 'Value': '0'},
|
'--retry-passes=': {'Enabled': True, 'Value': '0'},
|
||||||
'--test-mode=': {'Enabled': False, 'Value': 'some.map'},
|
'--test-mode=': {'Enabled': False, 'Value': 'test.map'},
|
||||||
'--timeout=': {'Enabled': True, 'Value': '5m'},
|
'--timeout=': {'Enabled': True, 'Value': '5m'},
|
||||||
'-vvvv': {'Enabled': True, 'Hidden': True},
|
'-vvvv': {'Enabled': True, 'Hidden': True},
|
||||||
}
|
}
|
||||||
|
|
@ -256,6 +256,7 @@ def get_status_color(s, t_success=99, t_warn=90):
|
||||||
def mark_all_passes_pending(source):
|
def mark_all_passes_pending(source):
|
||||||
"""Mark all devs and passes as pending in preparation for retry."""
|
"""Mark all devs and passes as pending in preparation for retry."""
|
||||||
source['Current Pass'] = 'Pass 1'
|
source['Current Pass'] = 'Pass 1'
|
||||||
|
source['Started Recovery'] = False
|
||||||
for p_num in ['Pass 1', 'Pass 2', 'Pass 3']:
|
for p_num in ['Pass 1', 'Pass 2', 'Pass 3']:
|
||||||
source[p_num]['Status'] = 'Pending'
|
source[p_num]['Status'] = 'Pending'
|
||||||
source[p_num]['Done'] = False
|
source[p_num]['Done'] = False
|
||||||
|
|
@ -273,8 +274,9 @@ def menu_clone(source_path, dest_path):
|
||||||
source['Pass 1'] = {'Status': 'Pending', 'Done': False}
|
source['Pass 1'] = {'Status': 'Pending', 'Done': False}
|
||||||
source['Pass 2'] = {'Status': 'Pending', 'Done': False}
|
source['Pass 2'] = {'Status': 'Pending', 'Done': False}
|
||||||
source['Pass 3'] = {'Status': 'Pending', 'Done': False}
|
source['Pass 3'] = {'Status': 'Pending', 'Done': False}
|
||||||
source['Recovered Size'] = 0,
|
source['Recovered Size'] = 0
|
||||||
source['Total Size'] = 0,
|
source['Started Recovery'] = False
|
||||||
|
source['Total Size'] = 0
|
||||||
source['Type'] = 'Clone'
|
source['Type'] = 'Clone'
|
||||||
dest = select_device(
|
dest = select_device(
|
||||||
'destination', dest_path,
|
'destination', dest_path,
|
||||||
|
|
@ -283,9 +285,12 @@ def menu_clone(source_path, dest_path):
|
||||||
|
|
||||||
# Show selection details
|
# Show selection details
|
||||||
show_selection_details(source, dest)
|
show_selection_details(source, dest)
|
||||||
|
|
||||||
|
# Set status details
|
||||||
set_dest_image_paths(source, dest)
|
set_dest_image_paths(source, dest)
|
||||||
check_dest_paths(source)
|
|
||||||
get_recovery_scope_size(source)
|
get_recovery_scope_size(source)
|
||||||
|
check_dest_paths(source)
|
||||||
|
resume_from_map(source)
|
||||||
|
|
||||||
# Confirm
|
# Confirm
|
||||||
if not ask('Proceed with clone?'):
|
if not ask('Proceed with clone?'):
|
||||||
|
|
@ -340,8 +345,9 @@ def menu_image(source_path, dest_path):
|
||||||
source['Pass 1'] = {'Status': 'Pending', 'Done': False}
|
source['Pass 1'] = {'Status': 'Pending', 'Done': False}
|
||||||
source['Pass 2'] = {'Status': 'Pending', 'Done': False}
|
source['Pass 2'] = {'Status': 'Pending', 'Done': False}
|
||||||
source['Pass 3'] = {'Status': 'Pending', 'Done': False}
|
source['Pass 3'] = {'Status': 'Pending', 'Done': False}
|
||||||
source['Recovered Size'] = 0,
|
source['Recovered Size'] = 0
|
||||||
source['Total Size'] = 0,
|
source['Started Recovery'] = False
|
||||||
|
source['Total Size'] = 0
|
||||||
source['Type'] = 'Image'
|
source['Type'] = 'Image'
|
||||||
dest = select_dest_path(dest_path, skip_device=source['Details'])
|
dest = select_dest_path(dest_path, skip_device=source['Details'])
|
||||||
dest_safety_check(source, dest)
|
dest_safety_check(source, dest)
|
||||||
|
|
@ -349,8 +355,9 @@ def menu_image(source_path, dest_path):
|
||||||
# Select child device(s)
|
# Select child device(s)
|
||||||
source['Children'] = menu_select_children(source)
|
source['Children'] = menu_select_children(source)
|
||||||
set_dest_image_paths(source, dest)
|
set_dest_image_paths(source, dest)
|
||||||
check_dest_paths(source)
|
|
||||||
get_recovery_scope_size(source)
|
get_recovery_scope_size(source)
|
||||||
|
check_dest_paths(source)
|
||||||
|
resume_from_map(source)
|
||||||
|
|
||||||
# Show selection details
|
# Show selection details
|
||||||
show_selection_details(source, dest)
|
show_selection_details(source, dest)
|
||||||
|
|
@ -750,6 +757,84 @@ def read_map_file(map_path):
|
||||||
return map_data
|
return map_data
|
||||||
|
|
||||||
|
|
||||||
|
def resume_from_map(source):
|
||||||
|
"""Read map file(s) and set current progress to resume previous session."""
|
||||||
|
map_data_read = False
|
||||||
|
non_tried = 0
|
||||||
|
non_trimmed = 0
|
||||||
|
non_scraped = 0
|
||||||
|
|
||||||
|
# Read map data
|
||||||
|
if source['Type'] != 'Clone' and source['Children']:
|
||||||
|
# Imaging child device(s)
|
||||||
|
for child in source['Children']:
|
||||||
|
if os.path.exists(child['Dest Paths']['Map']):
|
||||||
|
map_data = read_map_file(child['Dest Paths']['Map'])
|
||||||
|
map_data_read = True
|
||||||
|
non_tried += map_data['non-tried']
|
||||||
|
non_trimmed += map_data['non-trimmed']
|
||||||
|
non_scraped += map_data['non-scraped']
|
||||||
|
child['Recovered Size'] = map_data['rescued']/100*child['Size']
|
||||||
|
|
||||||
|
# Get (dev) current pass
|
||||||
|
dev_current_pass = 1
|
||||||
|
if map_data['non-tried'] == 0:
|
||||||
|
if map_data['non-trimmed'] > 0:
|
||||||
|
dev_current_pass = 2
|
||||||
|
elif map_data['non-scraped'] > 0:
|
||||||
|
dev_current_pass = 3
|
||||||
|
elif map_data['rescued'] == 100:
|
||||||
|
dev_current_pass = 4
|
||||||
|
|
||||||
|
# Mark passes as skipped
|
||||||
|
for x in range(1, dev_current_pass):
|
||||||
|
p_num = 'Pass {}'.format(x)
|
||||||
|
child[p_num]['Done'] = True
|
||||||
|
child[p_num]['Status'] = 'Skipped'
|
||||||
|
|
||||||
|
elif map_data_read:
|
||||||
|
# No map but we've already read at least one map, force pass 1
|
||||||
|
non_tried = 1
|
||||||
|
elif os.path.exists(source['Dest Paths']['Map']):
|
||||||
|
# Cloning or Imaging whole device
|
||||||
|
map_data = read_map_file(source['Dest Paths']['Map'])
|
||||||
|
map_data_read = True
|
||||||
|
non_tried += map_data['non-tried']
|
||||||
|
non_trimmed += map_data['non-trimmed']
|
||||||
|
non_scraped += map_data['non-scraped']
|
||||||
|
|
||||||
|
# Bail
|
||||||
|
if not map_data_read:
|
||||||
|
# No map data found, assuming fresh start
|
||||||
|
return
|
||||||
|
|
||||||
|
# Set current pass
|
||||||
|
if non_tried > 0:
|
||||||
|
current_pass = 'Pass 1'
|
||||||
|
elif non_trimmed > 0:
|
||||||
|
current_pass = 'Pass 2'
|
||||||
|
source['Pass 1']['Done'] = True
|
||||||
|
source['Pass 1']['Status'] = 'Skipped'
|
||||||
|
elif non_scraped > 0:
|
||||||
|
current_pass = 'Pass 3'
|
||||||
|
source['Pass 1']['Done'] = True
|
||||||
|
source['Pass 1']['Status'] = 'Skipped'
|
||||||
|
source['Pass 2']['Done'] = True
|
||||||
|
source['Pass 2']['Status'] = 'Skipped'
|
||||||
|
else:
|
||||||
|
source['Current Pass'] = 'Done'
|
||||||
|
update_progress(source, end_run=True)
|
||||||
|
return
|
||||||
|
source['Current Pass'] = current_pass
|
||||||
|
|
||||||
|
# Update current pass
|
||||||
|
if not source['Children']:
|
||||||
|
if os.path.exists(source['Dest Paths']['Map']):
|
||||||
|
map_data = read_map_file(source['Dest Paths']['Map'])
|
||||||
|
source[current_pass]['Done'] = map_data['pass completed']
|
||||||
|
source['Recovered Size'] = map_data['rescued']/100*source['Size']
|
||||||
|
|
||||||
|
|
||||||
def run_ddrescue(source, dest, settings):
|
def run_ddrescue(source, dest, settings):
|
||||||
"""Run ddrescue pass."""
|
"""Run ddrescue pass."""
|
||||||
current_pass = source['Current Pass']
|
current_pass = source['Current Pass']
|
||||||
|
|
@ -763,6 +848,7 @@ def run_ddrescue(source, dest, settings):
|
||||||
|
|
||||||
# Set device(s) to clone/image
|
# Set device(s) to clone/image
|
||||||
source[current_pass]['Status'] = 'Working'
|
source[current_pass]['Status'] = 'Working'
|
||||||
|
source['Started Recovery'] = True
|
||||||
source_devs = [source]
|
source_devs = [source]
|
||||||
if source['Children']:
|
if source['Children']:
|
||||||
# Use only selected child devices
|
# Use only selected child devices
|
||||||
|
|
@ -1093,13 +1179,16 @@ def update_progress(source, end_run=False):
|
||||||
|
|
||||||
# Update children progress
|
# Update children progress
|
||||||
for child in source['Children']:
|
for child in source['Children']:
|
||||||
|
if current_pass == 'Done':
|
||||||
|
continue
|
||||||
if os.path.exists(child['Dest Paths']['Map']):
|
if os.path.exists(child['Dest Paths']['Map']):
|
||||||
map_data = read_map_file(child['Dest Paths']['Map'])
|
map_data = read_map_file(child['Dest Paths']['Map'])
|
||||||
if child['Dev Path'] == source.get('Current Device', ''):
|
if child['Dev Path'] == source.get('Current Device', ''):
|
||||||
# Current child device
|
# Current child device
|
||||||
r_size = map_data['rescued']/100 * child['Size']
|
r_size = map_data['rescued']/100 * child['Size']
|
||||||
child[current_pass]['Done'] = map_data['pass completed']
|
child[current_pass]['Done'] = map_data['pass completed']
|
||||||
child[current_pass]['Status'] = map_data['rescued']
|
if source['Started Recovery']:
|
||||||
|
child[current_pass]['Status'] = map_data['rescued']
|
||||||
child['Recovered Size'] = r_size
|
child['Recovered Size'] = r_size
|
||||||
|
|
||||||
# All child devices
|
# All child devices
|
||||||
|
|
@ -1127,7 +1216,8 @@ def update_progress(source, end_run=False):
|
||||||
map_data = read_map_file(source['Dest Paths']['Map'])
|
map_data = read_map_file(source['Dest Paths']['Map'])
|
||||||
if current_pass != 'Done':
|
if current_pass != 'Done':
|
||||||
source[current_pass]['Done'] = map_data['pass completed']
|
source[current_pass]['Done'] = map_data['pass completed']
|
||||||
source[current_pass]['Status'] = map_data['rescued']
|
if source['Started Recovery']:
|
||||||
|
source[current_pass]['Status'] = map_data['rescued']
|
||||||
try:
|
try:
|
||||||
source[current_pass]['Min Status'] = min(
|
source[current_pass]['Min Status'] = min(
|
||||||
source[current_pass]['Min Status'],
|
source[current_pass]['Min Status'],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue