feat: Improve encrypted backups and resize logic
This commit introduces several major improvements to the handling of encrypted incremental backups. 1. **Fix LUKS Container Resize:** The `encryption_helper.sh` script has been fixed to reliably resize LUKS containers. The `cryptsetup resize` command now correctly re-authenticates, resolving an issue where the script would fail because it was incorrectly trying to read a password from an empty stdin stream. 2. **Refactor Backup Directory Structure:** The storage path for encrypted user backups has been flattened. Backups are now stored directly in the encrypted mount point (e.g., `/backup/pybackup/encrypted_videos/BACKUP_NAME`) instead of a deeply nested folder (`.../user/SOURCE_NAME/BACKUP_NAME`). This simplifies the directory structure as requested. 3. **Correct Incremental Size Estimation:** The `estimate_incremental_size` function is now more robust. - The `rsync` command for user backups now correctly uses a trailing slash on the source path. - This ensures the `--link-dest` comparison works as intended against the new, flat directory structure, leading to an accurate calculation of the required incremental size. 4. **Refine Container Resize Trigger and Logic:** The logic for automatically resizing encrypted containers in `encryption_manager.py` has been completely overhauled to prevent excessive growth: - A resize is now only triggered if the projected free space after a backup would fall below a 4 GB buffer. - The calculation for the new size now correctly adds the required space plus the 4 GB buffer, ensuring sufficient space without over-provisioning.
This commit is contained in:
@@ -88,7 +88,11 @@ class BackupManager:
|
||||
|
||||
if is_system:
|
||||
return os.path.join(base_data_dir, "system")
|
||||
# For user backups, store them directly in the mount point if encrypted.
|
||||
elif is_encrypted:
|
||||
return base_data_dir
|
||||
else:
|
||||
# Keep old structure for unencrypted user backups
|
||||
return os.path.join(base_data_dir, "user", source_name)
|
||||
|
||||
def check_for_full_backup(self, dest_path: str, source_name: str, is_encrypted: bool) -> bool:
|
||||
@@ -201,7 +205,9 @@ class BackupManager:
|
||||
full_system_cmd = f"mkdir -p '{rsync_dest}' && {rsync_cmd_str}"
|
||||
command = ['pkexec', 'bash', '-c', full_system_cmd]
|
||||
else:
|
||||
rsync_command_parts.extend([source_path, rsync_dest])
|
||||
# Add a trailing slash to the source path to ensure rsync copies the content, not the directory itself.
|
||||
source_with_slash = source_path.rstrip('/') + '/'
|
||||
rsync_command_parts.extend([source_with_slash, rsync_dest])
|
||||
os.makedirs(rsync_dest, exist_ok=True)
|
||||
command = rsync_command_parts
|
||||
|
||||
@@ -273,7 +279,7 @@ class BackupManager:
|
||||
if is_system:
|
||||
command.extend(['pkexec', 'rsync', '-aAXHvn', '--stats'])
|
||||
else:
|
||||
command.extend(['rsync', '-avn', '--stats'])
|
||||
command.extend(['rsync', '-ain', '--dry-run', '--stats'])
|
||||
|
||||
command.append(f"--link-dest={latest_backup_path}")
|
||||
|
||||
@@ -283,6 +289,9 @@ class BackupManager:
|
||||
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as dummy_dest:
|
||||
# For user backups, add a trailing slash to copy contents, not the dir itself.
|
||||
if not is_system:
|
||||
source_path = source_path.rstrip('/') + '/'
|
||||
command.extend([source_path, dummy_dest])
|
||||
|
||||
self.logger.log(
|
||||
|
Reference in New Issue
Block a user