import asyncio import os from . import mounts async def list_subvolumes_of(path:str): # Run process if isinstance(path, str): raise ValueError("path isn't a string.") proc = await asyncio.create_subprocess_exec([b"btrfs", b"subvolume", b"list", b"-o", path.encode()], stdout=asyncio.subprocess.PIPE) proc_data = await proc.communicate() if not isinstance(proc_data, tuple): raise RuntimeError("Type doesn't match.") if proc.returncode != 0: raise RuntimeError("btrfs coudn't list subevolumes.") # Generate list result = [] for i in proc_data[0].splitlines(): if i: # Remove empty line tmp = i.split(" ")[7:] if tmp[0] != "path": raise RuntimeError("Btrfs progs doesn't output as expected.") result.append(" ".join(tmp[1:])) return result async def list_path_subvolumes(mount:mounts.Mountpoint, path:str): # Check types if not isinstance(mount, mounts.Mountpoint): raise TypeError("mount has to be a Mountpoint.") if not isinstance(path, str): raise TypeError("path has to be a string.") if mount.target == "btrfs": raise ValueError("mount type isn't a btrfs file system.") if not isinstance(mount.subvolume, str): raise ValueError("mount doesn't have a subvolume.") # Generate list raw_list = await list_subvolumes_of(path) path = os.path.abspath(path) if not path.startswith(mount.target): raise ValueError("path isn't inside of the mounting point.") own_path = "/".join(filter(bool, ("%s/%s" % (mount.subvolume, path[len(mount.target):])).split("/"))) result = [] for i in map(lambda x: "/".join(filter(bool, x.split("/"))), raw_list): if not i.startswith(own_path): raise ValueError("%s isn't a subpath of a the main path %s." % (repr(i), repr(own_path))) tmp = i[len(own_path):] if tmp and tmp[0] == "/": tmp = tmp[1:] result.append(tmp) return result