home-backup/home_backup/sys_service/btrfs.py

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