Allow mounting all volumes per device

This commit is contained in:
2Shirt 2018-11-26 18:12:24 -07:00
parent 8a86edb5bb
commit b3b821a868
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C

View file

@ -126,11 +126,11 @@ def cleanup_transfer(dest_path):
if not os.path.exists(dest_path): if not os.path.exists(dest_path):
# Bail if dest_path was empty and removed # Bail if dest_path was empty and removed
raise Exception raise Exception
# Fix attributes # Fix attributes
cmd = ['attrib', '-a', '-h', '-r', '-s', dest_path] cmd = ['attrib', '-a', '-h', '-r', '-s', dest_path]
run_program(cmd, check=False) run_program(cmd, check=False)
for root, dirs, files in os.walk(dest_path, topdown=False): for root, dirs, files in os.walk(dest_path, topdown=False):
for name in dirs: for name in dirs:
# Remove empty directories and junction points # Remove empty directories and junction points
@ -153,7 +153,7 @@ def cleanup_transfer(dest_path):
except Exception: except Exception:
pass pass
def find_core_storage_volumes(): def find_core_storage_volumes(device_path=None):
"""Try to create block devices for any Apple CoreStorage volumes.""" """Try to create block devices for any Apple CoreStorage volumes."""
corestorage_uuid = '53746f72-6167-11aa-aa11-00306543ecac' corestorage_uuid = '53746f72-6167-11aa-aa11-00306543ecac'
dmsetup_cmd_file = '{TmpDir}/dmsetup_command'.format(**global_vars) dmsetup_cmd_file = '{TmpDir}/dmsetup_command'.format(**global_vars)
@ -162,6 +162,8 @@ def find_core_storage_volumes():
cmd = [ cmd = [
'lsblk', '--json', '--list', '--paths', 'lsblk', '--json', '--list', '--paths',
'--output', 'NAME,PARTTYPE'] '--output', 'NAME,PARTTYPE']
if device_path:
cmd.append(device_path)
result = run_program(cmd) result = run_program(cmd)
json_data = json.loads(result.stdout.decode()) json_data = json.loads(result.stdout.decode())
devs = json_data.get('blockdevices', []) devs = json_data.get('blockdevices', [])
@ -248,7 +250,9 @@ def get_mounted_volumes():
mounted_volumes.extend(item.get('children', [])) mounted_volumes.extend(item.get('children', []))
return {item['source']: item for item in mounted_volumes} return {item['source']: item for item in mounted_volumes}
def mount_volumes(all_devices=True, device_path=None, read_write=False): def mount_volumes(
all_devices=True, device_path=None,
read_write=False, core_storage=True):
"""Mount all detected filesystems.""" """Mount all detected filesystems."""
report = {} report = {}
cmd = [ cmd = [
@ -257,9 +261,10 @@ def mount_volumes(all_devices=True, device_path=None, read_write=False):
if not all_devices and device_path: if not all_devices and device_path:
# Only mount volumes for specific device # Only mount volumes for specific device
cmd.append(device_path) cmd.append(device_path)
else:
# Check for Apple CoreStorage volumes first # Check for Apple CoreStorage volumes first
find_core_storage_volumes() if core_storage:
find_core_storage_volumes(device_path)
# Get list of block devices # Get list of block devices
result = run_program(cmd) result = run_program(cmd)
@ -269,11 +274,14 @@ def mount_volumes(all_devices=True, device_path=None, read_write=False):
# Get list of volumes # Get list of volumes
volumes = {} volumes = {}
for dev in devs: for dev in devs:
if not dev.get('children', []):
volumes.update({dev['name']: dev})
for child in dev.get('children', []): for child in dev.get('children', []):
volumes.update({child['name']: child}) if not child.get('children', []):
volumes.update({child['name']: child})
for grandchild in child.get('children', []): for grandchild in child.get('children', []):
volumes.update({grandchild['name']: grandchild}) volumes.update({grandchild['name']: grandchild})
# Get list of mounted volumes # Get list of mounted volumes
mounted_volumes = get_mounted_volumes() mounted_volumes = get_mounted_volumes()
@ -352,7 +360,7 @@ def mount_backup_shares(read_write=False):
if server['Mounted']: if server['Mounted']:
print_warning(mounted_str) print_warning(mounted_str)
continue continue
mount_network_share(server, read_write) mount_network_share(server, read_write)
def mount_network_share(server, read_write=False): def mount_network_share(server, read_write=False):
@ -414,12 +422,12 @@ def run_fast_copy(items, dest):
"""Copy items to dest using FastCopy.""" """Copy items to dest using FastCopy."""
if not items: if not items:
raise Exception raise Exception
cmd = [global_vars['Tools']['FastCopy'], *FAST_COPY_ARGS] cmd = [global_vars['Tools']['FastCopy'], *FAST_COPY_ARGS]
cmd.append(r'/logfile={}\FastCopy.log'.format(global_vars['LogDir'])) cmd.append(r'/logfile={LogDir}\Tools\FastCopy.log'.format(**global_vars))
cmd.extend(items) cmd.extend(items)
cmd.append('/to={}\\'.format(dest)) cmd.append('/to={}\\'.format(dest))
run_program(cmd) run_program(cmd)
def run_wimextract(source, items, dest): def run_wimextract(source, items, dest):
@ -486,7 +494,7 @@ def list_source_items(source_obj, rel_path=None):
def scan_source(source_obj, dest_path, rel_path='', interactive=True): def scan_source(source_obj, dest_path, rel_path='', interactive=True):
"""Scan source for files/folders to transfer, returns list. """Scan source for files/folders to transfer, returns list.
This will scan the root and (recursively) any Windows.old folders.""" This will scan the root and (recursively) any Windows.old folders."""
selected_items = [] selected_items = []
win_olds = [] win_olds = []
@ -563,7 +571,7 @@ def scan_source(source_obj, dest_path, rel_path='', interactive=True):
'{}{}{}'.format(dest_path, os.sep, old.name), '{}{}{}'.format(dest_path, os.sep, old.name),
rel_path=old.name, rel_path=old.name,
interactive=False)) interactive=False))
# Done # Done
return selected_items return selected_items
@ -707,7 +715,7 @@ def select_source(backup_prefix):
item.name, # Image file item.name, # Image file
), ),
'Source': item}) 'Source': item})
# Check for local sources # Check for local sources
print_standard('Scanning for local sources...') print_standard('Scanning for local sources...')
set_thread_error_mode(silent=True) # Prevents "No disk" popups set_thread_error_mode(silent=True) # Prevents "No disk" popups
@ -747,7 +755,7 @@ def select_source(backup_prefix):
' Local', d.mountpoint, item.name), ' Local', d.mountpoint, item.name),
'Sort': r'{}{}'.format(d.mountpoint, item.name), 'Sort': r'{}{}'.format(d.mountpoint, item.name),
'Source': item}) 'Source': item})
set_thread_error_mode(silent=False) # Return to normal set_thread_error_mode(silent=False) # Return to normal
# Build Menu # Build Menu
@ -775,7 +783,7 @@ def select_source(backup_prefix):
umount_backup_shares() umount_backup_shares()
pause("Press Enter to exit...") pause("Press Enter to exit...")
exit_script() exit_script()
# Sanity check # Sanity check
if selected_source.is_file(): if selected_source.is_file():
# Image-Based # Image-Based
@ -783,7 +791,7 @@ def select_source(backup_prefix):
print_error('ERROR: Unsupported image: {}'.format( print_error('ERROR: Unsupported image: {}'.format(
selected_source.path)) selected_source.path))
raise GenericError raise GenericError
# Done # Done
return selected_source return selected_source
@ -791,7 +799,7 @@ def select_volume(title='Select disk', auto_select=True):
"""Select disk from attached disks. returns dict.""" """Select disk from attached disks. returns dict."""
actions = [{'Name': 'Quit', 'Letter': 'Q'}] actions = [{'Name': 'Quit', 'Letter': 'Q'}]
disks = [] disks = []
# Build list of disks # Build list of disks
set_thread_error_mode(silent=True) # Prevents "No disk" popups set_thread_error_mode(silent=True) # Prevents "No disk" popups
for d in psutil.disk_partitions(): for d in psutil.disk_partitions():
@ -812,11 +820,11 @@ def select_volume(title='Select disk', auto_select=True):
info['Display Name'] = '{} ({})'.format(info['Name'], free) info['Display Name'] = '{} ({})'.format(info['Name'], free)
disks.append(info) disks.append(info)
set_thread_error_mode(silent=False) # Return to normal set_thread_error_mode(silent=False) # Return to normal
# Skip menu? # Skip menu?
if len(disks) == 1 and auto_select: if len(disks) == 1 and auto_select:
return disks[0] return disks[0]
# Show menu # Show menu
selection = menu_select(title, main_entries=disks, action_entries=actions) selection = menu_select(title, main_entries=disks, action_entries=actions)
if selection == 'Q': if selection == 'Q':
@ -826,12 +834,12 @@ def select_volume(title='Select disk', auto_select=True):
def set_thread_error_mode(silent=True): def set_thread_error_mode(silent=True):
"""Disable or Enable Windows error message dialogs. """Disable or Enable Windows error message dialogs.
Disable when scanning for disks to avoid popups for empty cardreaders, etc Disable when scanning for disks to avoid popups for empty cardreaders, etc
""" """
# Code borrowed from: https://stackoverflow.com/a/29075319 # Code borrowed from: https://stackoverflow.com/a/29075319
kernel32 = ctypes.WinDLL('kernel32') kernel32 = ctypes.WinDLL('kernel32')
if silent: if silent:
kernel32.SetThreadErrorMode(SEM_FAIL, ctypes.byref(SEM_NORMAL)) kernel32.SetThreadErrorMode(SEM_FAIL, ctypes.byref(SEM_NORMAL))
else: else: