53 lines
2.0 KiB
Python
53 lines
2.0 KiB
Python
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 |