def test_subvolume_info(self): for arg in self.path_or_fd(self.mountpoint): with self.subTest(type=type(arg)): info = btrfsutil.subvolume_info(arg) self.assertEqual(info.id, 5) self.assertEqual(info.parent_id, 0) self.assertEqual(info.dir_id, 0) self.assertEqual(info.flags, 0) self.assertIsInstance(info.uuid, bytes) self.assertEqual(len(info.uuid), 16) self.assertEqual(info.parent_uuid, bytes(16)) self.assertEqual(info.received_uuid, bytes(16)) self.assertNotEqual(info.generation, 0) self.assertEqual(info.ctransid, 0) self.assertEqual(info.otransid, 0) self.assertEqual(info.stransid, 0) self.assertEqual(info.rtransid, 0) self.assertIsInstance(info.ctime, float) self.assertIsInstance(info.otime, float) self.assertEqual(info.stime, 0) self.assertEqual(info.rtime, 0) subvol = os.path.join(self.mountpoint, 'subvol') btrfsutil.create_subvolume(subvol) info = btrfsutil.subvolume_info(subvol) self.assertEqual(info.id, 256) self.assertEqual(info.parent_id, 5) self.assertEqual(info.dir_id, 256) self.assertEqual(info.flags, 0) self.assertIsInstance(info.uuid, bytes) self.assertEqual(len(info.uuid), 16) self.assertEqual(info.parent_uuid, bytes(16)) self.assertEqual(info.received_uuid, bytes(16)) self.assertNotEqual(info.generation, 0) self.assertNotEqual(info.ctransid, 0) self.assertNotEqual(info.otransid, 0) self.assertEqual(info.stransid, 0) self.assertEqual(info.rtransid, 0) self.assertNotEqual(info.ctime, 0) self.assertNotEqual(info.otime, 0) self.assertEqual(info.stime, 0) self.assertEqual(info.rtime, 0) subvol_uuid = info.uuid snapshot = os.path.join(self.mountpoint, 'snapshot') btrfsutil.create_snapshot(subvol, snapshot) info = btrfsutil.subvolume_info(snapshot) self.assertEqual(info.parent_uuid, subvol_uuid) # TODO: test received_uuid, stransid, rtransid, stime, and rtime for arg in self.path_or_fd(self.mountpoint): with self.subTest(type=type(arg)): with self.assertRaises(btrfsutil.BtrfsUtilError) as e: # BTRFS_EXTENT_TREE_OBJECTID btrfsutil.subvolume_info(arg, 2)
def test_subvolume_info_unprivileged(self): subvol = os.path.join(self.mountpoint, 'subvol') btrfsutil.create_subvolume(subvol) snapshot = os.path.join(self.mountpoint, 'snapshot') btrfsutil.create_snapshot(subvol, snapshot) with drop_privs(): try: btrfsutil.subvolume_info(self.mountpoint) except OSError as e: if e.errno == errno.ENOTTY: self.skipTest('BTRFS_IOC_GET_SUBVOL_INFO is not available') else: raise self._test_subvolume_info(subvol, snapshot)
def test_subvolume_info(self): subvol = os.path.join(self.mountpoint, 'subvol') btrfsutil.create_subvolume(subvol) snapshot = os.path.join(self.mountpoint, 'snapshot') btrfsutil.create_snapshot(subvol, snapshot) self._test_subvolume_info(subvol, snapshot) for arg in self.path_or_fd(self.mountpoint): with self.subTest(type=type(arg)): with self.assertRaises(btrfsutil.BtrfsUtilError) as e: # BTRFS_EXTENT_TREE_OBJECTID btrfsutil.subvolume_info(arg, 2) self.assertEqual(e.exception.btrfsutilerror, btrfsutil.ERROR_SUBVOLUME_NOT_FOUND)
def test_read_only(self): for arg in self.path_or_fd(self.mountpoint): with self.subTest(type=type(arg)): btrfsutil.set_subvolume_read_only(arg) self.assertTrue(btrfsutil.get_subvolume_read_only(arg)) self.assertTrue(btrfsutil.subvolume_info(arg).flags & 1) btrfsutil.set_subvolume_read_only(arg, False) self.assertFalse(btrfsutil.get_subvolume_read_only(arg)) self.assertFalse(btrfsutil.subvolume_info(arg).flags & 1) btrfsutil.set_subvolume_read_only(arg, True) self.assertTrue(btrfsutil.get_subvolume_read_only(arg)) self.assertTrue(btrfsutil.subvolume_info(arg).flags & 1) btrfsutil.set_subvolume_read_only(arg, False)
def _test_subvolume_info(self, subvol, snapshot): for arg in self.path_or_fd(self.mountpoint): with self.subTest(type=type(arg)): info = btrfsutil.subvolume_info(arg) self.assertEqual(info.id, 5) self.assertEqual(info.parent_id, 0) self.assertEqual(info.dir_id, 0) self.assertEqual(info.flags, 0) self.assertIsInstance(info.uuid, bytes) self.assertEqual(len(info.uuid), 16) self.assertEqual(info.parent_uuid, bytes(16)) self.assertEqual(info.received_uuid, bytes(16)) self.assertNotEqual(info.generation, 0) self.assertGreaterEqual(info.ctransid, 0) self.assertEqual(info.otransid, 0) self.assertEqual(info.stransid, 0) self.assertEqual(info.rtransid, 0) self.assertIsInstance(info.ctime, float) self.assertIsInstance(info.otime, float) self.assertEqual(info.stime, 0) self.assertEqual(info.rtime, 0) info = btrfsutil.subvolume_info(subvol) self.assertEqual(info.id, 256) self.assertEqual(info.parent_id, 5) self.assertEqual(info.dir_id, 256) self.assertEqual(info.flags, 0) self.assertIsInstance(info.uuid, bytes) self.assertEqual(len(info.uuid), 16) self.assertEqual(info.parent_uuid, bytes(16)) self.assertEqual(info.received_uuid, bytes(16)) self.assertNotEqual(info.generation, 0) self.assertNotEqual(info.ctransid, 0) self.assertNotEqual(info.otransid, 0) self.assertEqual(info.stransid, 0) self.assertEqual(info.rtransid, 0) self.assertNotEqual(info.ctime, 0) self.assertNotEqual(info.otime, 0) self.assertEqual(info.stime, 0) self.assertEqual(info.rtime, 0) subvol_uuid = info.uuid info = btrfsutil.subvolume_info(snapshot) self.assertEqual(info.parent_uuid, subvol_uuid)
def get_subvolume_from(self, filesystem_path: Path) -> Optional[Subvolume]: logger = self._logger if not filesystem_path.exists(): raise SubvolumeError( f"The '{filesystem_path}' path does not exist!") if not filesystem_path.is_dir(): raise SubvolumeError( f"The '{filesystem_path}' path does not represent a directory!" ) try: filesystem_path_str = str(filesystem_path) if btrfsutil.is_subvolume(filesystem_path_str): subvolume_id = btrfsutil.subvolume_id(filesystem_path_str) subvolume_path = btrfsutil.subvolume_path( filesystem_path_str, subvolume_id) subvolume_read_only = btrfsutil.get_subvolume_read_only( filesystem_path_str) subvolume_info = btrfsutil.subvolume_info( filesystem_path_str, subvolume_id) self_uuid = default_if_none( try_convert_bytes_to_uuid(subvolume_info.uuid), constants.EMPTY_UUID, ) parent_uuid = default_if_none( try_convert_bytes_to_uuid(subvolume_info.parent_uuid), constants.EMPTY_UUID, ) return Subvolume( filesystem_path, subvolume_path, datetime.fromtimestamp(subvolume_info.otime), UuidRelation(self_uuid, parent_uuid), NumIdRelation(subvolume_info.id, subvolume_info.parent_id), subvolume_read_only, ) except btrfsutil.BtrfsUtilError as e: logger.exception("btrfsutil call failed!") raise SubvolumeError( f"Could not initialize the subvolume for '{filesystem_path}'!" ) from e return None