From efe680e8138aa06926eb8665f72b5b656e9c03e9 Mon Sep 17 00:00:00 2001 From: timeshifter Date: Thu, 2 Dec 2021 16:53:39 +0100 Subject: [PATCH] add: skip decrypt if already decrypted --- zfs-backup.py | 57 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/zfs-backup.py b/zfs-backup.py index 1dcca33..6ef6279 100755 --- a/zfs-backup.py +++ b/zfs-backup.py @@ -47,7 +47,6 @@ def main(): # TODO tests # TODO docstrings # TODO first backup -# TODO --skip-decrypt # TODO --skip-import # TODO --skip-post-backup-scrub # TODO print time estimation while scrub is in progress @@ -362,25 +361,16 @@ class Time: class Disk: def __init__(self, uuid: UUID, name: str): self.uuid = uuid - self._decrypted = False + self._decrypted: bool = False + self._was_already_decrypted: bool = False self._name = name def decrypt(self) -> None: if self._decrypted: raise ValueError(ALREADY_DECRYPTED, self._name) - self._verify_mapper_entry_not_in_use() - self._decrypt_with_cryptsetup() + self._was_already_decrypted = Cryptsetup.decrypt(self._path, self._mapper_entry) self._decrypted = True - def _decrypt_with_cryptsetup(self): - Command.run([config.CRYPTSETUP, "open", self._path, self._mapper_entry]) - - def _verify_mapper_entry_not_in_use(self): - for item in MAPPER_PATH.iterdir(): - if self._mapper_entry == item.name: - print(MAPPER_ENTRY_ALREADY_EXISTS, self._mapper_entry) - exit(EXIT_ERROR) - @property def _path(self) -> Path: return DISK_BY_UUID / str(self.uuid) @@ -392,10 +382,51 @@ class Disk: def encrypt(self): if not self._decrypted: raise ValueError(NOT_DECRYPTED, self._name) + if self._was_already_decrypted: + return Command.run([config.CRYPTSETUP, "close", self._mapper_entry]) self._decrypted = False +class Cryptsetup: + @classmethod + def _status(cls, name: str) -> str: + return Command.get_output([config.CRYPTSETUP, "status", name]) + + @classmethod + def decrypt(cls, path: Path, mapper_entry: str) -> bool: + if cls._mapper_entry_in_use(mapper_entry): + if cls._already_decrypted(path, mapper_entry): + return True + print(MAPPER_ENTRY_ALREADY_EXISTS) + exit(EXIT_ERROR) + Command.run([config.CRYPTSETUP, "open", str(path), mapper_entry]) + return False + + @classmethod + def _mapper_entry_in_use(cls, mapper_entry: str) -> bool: + return (MAPPER_PATH / mapper_entry).exists() + + @classmethod + def _get_device_from_status(cls, status: str) -> Path: + for line in status.split("\n"): + if line.startswith(" device:"): + device = Path(line.split(":")[-1].strip()) + break + else: + print("panic") + exit(EXIT_ERROR) + for item in DISK_BY_UUID.iterdir(): + # noinspection PyUnboundLocalVariable + if item.readlink() == device: + return item + + @classmethod + def _already_decrypted(cls, path: Path, mapper_entry: str) -> bool: + decrypted_disk_path = cls._get_device_from_status(cls._status(mapper_entry)) + return decrypted_disk_path == path + + class Pool: def __init__(self, name: str): self._name = name