def GetVolumeSize(self, uuid, readable=True): """Return the size of the volume with the given UUID. Args: uuid: str, ID of the volume in question readable: Optional boolean, default true: return a human-readable string when true, otherwise int number of bytes. Returns: str or int, see "readable" arg. Raises: Error: there was a problem getting volume info. InvalidUUIDError: The UUID is formatted incorrectly. """ if not util.UuidIsValid(uuid): raise storage.InvalidUUIDErrorError('Invalid UUID: ' + uuid) (volumes, containers) = self._GetAPFSVolumesAndContainers(uuid) num_bytes = 0 for volume in volumes: if volume.get('APFSVolumeUUID') == uuid: num_bytes = (containers[0].get('CapacityFree') + volume.get('CapacityInUse')) break if readable: return '%.2f GiB' % (num_bytes / (1 << 30)) else: return num_bytes
def GetVolumeSize(uuid, readable=True): """Return the size of the volume with the given UUID. Args: uuid: str, ID of the volume in question readable: Optional boolean, default true: return a human-readable string when true, otherwise int number of bytes. Returns: str or int, see "readable" arg. Raises: Error: there was a problem getting volume info. ValueError: The UUID is formatted incorrectly. """ if not util.UuidIsValid(uuid): raise ValueError('Invalid UUID: ' + uuid) try: plist = util.GetPlistFromExec( (DISKUTIL, 'corestorage', 'info', '-plist', uuid)) except util.ExecError: logging.exception('GetVolumeSize() failed to get volume info: %s', uuid) raise Error num_bytes = plist['CoreStorageLogicalVolumeSize'] if readable: return '%.2f GiB' % (num_bytes / (1 << 30)) else: return num_bytes
def GetStateAndVolumeIds(): """Determine the state of core storage and the volume IDs (if any). In the case that core storage is enabled, it is required that every present volume is encrypted, to return "encrypted" status (i.e. the entire drive is encrypted, for all present drives). Otherwise only "enabled" status is returned. Returns: tuple: (State, [list; str encrypted UUIDs], [list; str unencrypted UUIDs]) Raises: Error: there was a problem getting the corestorage list, or family info. """ try: cs_plist = util.GetPlistFromExec( (DISKUTIL, 'corestorage', 'list', '-plist')) except util.ExecError: logging.exception( 'GetStateAndVolumeIds() failed to get corestorage list.') raise Error state = State.none volume_ids = [] encrypted_volume_ids = [] groups = cs_plist.get('CoreStorageLogicalVolumeGroups', []) if groups: state = State.enabled for group in groups: for family in group.get('CoreStorageLogicalVolumeFamilies', []): family_id = family['CoreStorageUUID'] if not util.UuidIsValid(family_id): continue try: info_plist = util.GetPlistFromExec( (DISKUTIL, 'corestorage', 'info', '-plist', family_id)) except util.ExecError: logging.exception( 'GetStateAndVolumeIds() failed to get corestorage family info: %s', family_id) raise Error enc = info_plist.get( 'CoreStorageLogicalVolumeFamilyEncryptionType', '') for volume in family['CoreStorageLogicalVolumes']: volume_id = volume['CoreStorageUUID'] if enc == 'AES-XTS': encrypted_volume_ids.append(volume_id) else: volume_ids.append(volume_id) if encrypted_volume_ids and not volume_ids: state = State.encrypted return state, encrypted_volume_ids, volume_ids
def UnlockVolume(uuid, passphrase): """Unlock a core storage encrypted volume. Args: uuid: str, uuid of the volume to unlock. passphrase: str, passphrase to unlock the volume. Raises: CouldNotUnlockError: the volume cannot be unlocked. ValueError: The UUID is formatted incorrectly. """ if not util.UuidIsValid(uuid): raise ValueError('Invalid UUID: ' + uuid) returncode, _, stderr = util.Exec( (DISKUTIL, 'corestorage', 'unlockVolume', uuid, '-stdinpassphrase'), stdin=passphrase) if returncode != 0 and not 'volume is not locked' in stderr: raise CouldNotUnlockError('Could not unlock volume (%s).' % returncode)
def _GetAPFSVolumesAndContainers(self, uuid=None, disk=None): """Returns a tuple of volumes and containers from apfs list -plist. Args: uuid: str, optional, APFSVolume uuid. If no uuid is provided, this function returns a diskutil apfs list plist.. disk: str, optional, name of the disk to look at. Returns: A dict of diskutil cs info/list -plist output. Raises: Error: The given uuid was invalid or there was a diskutil error. """ if uuid: if not util.UuidIsValid(uuid): raise storage.Error if disk or not self._containers: cmd = [DISKUTIL, 'apfs', 'list', '-plist'] if disk: cmd.append(disk) try: plist = util.GetPlistFromExec(cmd) except util.ExecError: return ([], []) containers = plist.get('Containers', []) if containers: volumes = containers[0].get('Volumes', []) else: volumes = [] if not disk: # save the full list for future lookups self._containers = containers self._volumes = volumes else: containers = self._containers volumes = self._volumes if uuid: uuid_volumes = [] for volume in volumes: if volume.get('APFSVolumeUUID') == uuid: uuid_volumes.append(volume) return (uuid_volumes, containers) else: return (volumes, containers)
def UnlockVolume(self, uuid, passphrase): """Unlock an APFS encrypted volume. Args: uuid: str, uuid of the volume to unlock. passphrase: str, passphrase to unlock the volume. Raises: CouldNotUnlockError: the volume cannot be unlocked. InvalidUUIDError: The UUID is formatted incorrectly. """ if not util.UuidIsValid(uuid): raise storage.InvalidUUIDError('Invalid UUID: ' + uuid) returncode, _, stderr = util.Exec( (DISKUTIL, 'apfs', 'unlockVolume', uuid, '-stdinpassphrase'), stdin=passphrase) if (returncode != 0 and 'volume is not locked' not in stderr and 'is already unlocked' not in stderr): raise storage.CouldNotUnlockError('Could not unlock volume (%s).' % returncode)
def RevertVolume(uuid, passphrase): """Revert a core storage encrypted volume (to unencrypted state). Args: uuid: str, uuid of the volume to revert. passphrase: str, passphrase to unlock the volume. Raises: CouldNotRevertError: the volume was unlocked, but cannot be reverted. CouldNotUnlockError: the volume cannot be unlocked. ValueError: The UUID is formatted incorrectly. """ if not util.UuidIsValid(uuid): raise ValueError('Invalid UUID: ' + uuid) UnlockVolume(uuid, passphrase) returncode, _, _ = util.Exec( (DISKUTIL, 'corestorage', 'revert', uuid, '-stdinpassphrase'), stdin=passphrase) if returncode != 0: raise CouldNotRevertError('Could not revert volume (%s).' % returncode)
def RevertVolume(self, uuid, passphrase, passwd=''): """Disable encryption on an APFS system. Args: uuid: str, uuid of the volume to revert. passphrase: str, passphrase to unlock the volume. passwd: str, password for sudo Raises: CouldNotRevertError: the volume was unlocked, but cannot be reverted. CouldNotUnlockError: the volume cannot be unlocked. InvalidUUIDError: The UUID is formatted incorrectly. """ if not util.UuidIsValid(uuid): raise storage.InvalidUUIDError('Invalid UUID: ' + uuid) self.UnlockVolume(uuid, passphrase) returncode, _, _ = util.Exec(('sudo', '-k', '-S', FDESETUP, 'disable'), stdin=passwd + '\n') if returncode != 0: raise storage.CouldNotRevertError( 'Could not disable encryption (%s).' % (returncode))
def GetCoreStoragePlist(uuid=None): """Returns a dict of diskutil cs info plist for a given str CoreStorage uuid. Args: uuid: str, optional, CoreStorage uuid. If no uuid is provided, this function returns a diskutil cs list plist.. Returns: A dict of diskutil cs info/list -plist output. Raises: Error: The given uuid was invalid or there was a diskutil error. """ if uuid: if not util.UuidIsValid(uuid): raise Error cmd = [DISKUTIL, 'corestorage', 'info', '-plist', uuid] else: cmd = [DISKUTIL, 'corestorage', 'list', '-plist'] try: return util.GetPlistFromExec(cmd) except util.ExecError: raise Error