Allow mounting all volumes per device
This commit is contained in:
parent
8a86edb5bb
commit
b3b821a868
1 changed files with 32 additions and 24 deletions
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue