from mkosi.log import ARG_DEBUG, die
from mkosi.partition import finalize_root, find_partitions
from mkosi.run import AsyncioThread, find_binary, fork_and_wait, run, spawn, workdir
-from mkosi.tree import copy_tree, make_nocow, rmtree
+from mkosi.tree import copy_tree, maybe_make_nocow, rmtree
from mkosi.user import INVOKING_USER, become_root_in_subuid_range, become_root_in_subuid_range_cmd
from mkosi.util import (
PathString,
# at the same time.
d.mkdir(exist_ok=True, parents=True)
# Make sure COW is disabled so systemd-journal-remote doesn't complain on btrfs filesystems.
- make_nocow(d, sandbox=config.sandbox)
+ maybe_make_nocow(d)
INVOKING_USER.chown(d)
with tempfile.NamedTemporaryFile(mode="w", prefix="mkosi-journal-remote-config-") as f:
dir=drive.directory or "/var/tmp",
prefix=f"mkosi-drive-{drive.id}",
) as file:
- make_nocow(Path(file.name), sandbox=config.sandbox)
+ maybe_make_nocow(Path(file.name))
file.truncate(round_up(drive.size, resource.getpagesize()))
yield Path(file.name)
ENOSYS = 38
F_DUPFD = 0
F_GETFD = 1
+FS_IOC_GETFLAGS = 0x80086601
+FS_NOCOW_FL = 0x00800000
LINUX_CAPABILITY_U32S_3 = 2
LINUX_CAPABILITY_VERSION_3 = 0x20080522
MNT_DETACH = 2
libseccomp.seccomp_release(seccomp)
+def lsattr(path: str) -> int:
+ attr = ctypes.c_int()
+ r = 0
+
+ fd = os.open(path, os.O_CLOEXEC | os.O_RDONLY)
+
+ libc.ioctl.argtypes = (ctypes.c_int, ctypes.c_long, ctypes.c_void_p)
+ if libc.ioctl(fd, FS_IOC_GETFLAGS, ctypes.byref(attr)) < 0:
+ r = ctypes.get_errno()
+
+ os.close(fd)
+
+ if r != 0:
+ raise OSError(r, os.strerror(r), path)
+
+ return attr.value
+
+
+def chattr(path: str, attr: int) -> None:
+ cattr = ctypes.c_int(attr)
+ fd = os.open(path, os.O_CLOEXEC | os.O_RDONLY)
+ r = 0
+
+ libc.ioctl.argtypes = (ctypes.c_int, ctypes.c_long, ctypes.c_void_p)
+ if libc.ioctl(fd, FS_IOC_GETFLAGS, ctypes.byref(cattr)) < 0:
+ r = ctypes.get_errno()
+
+ os.close(fd)
+
+ if r != 0:
+ raise OSError(r, os.strerror(r), path)
+
+
def join_new_session_keyring() -> None:
libkeyutils = ctypes.CDLL("libkeyutils.so.1")
if libkeyutils is None:
from mkosi.config import ConfigFeature
from mkosi.log import ARG_DEBUG, die
from mkosi.run import SandboxProtocol, nosandbox, run, workdir
-from mkosi.sandbox import BTRFS_SUPER_MAGIC, OVERLAYFS_SUPER_MAGIC, statfs
+from mkosi.sandbox import BTRFS_SUPER_MAGIC, FS_NOCOW_FL, OVERLAYFS_SUPER_MAGIC, chattr, lsattr, statfs
from mkosi.util import PathString, flatten
from mkosi.versioncomp import GenericVersion
shutil.copystat(tmp / d, dst / d)
-def make_nocow(path: Path, *, sandbox: SandboxProtocol = nosandbox) -> None:
- run(
- ["chattr", "+C", workdir(path)],
- check=False,
- stderr=subprocess.DEVNULL if not ARG_DEBUG.get() else None,
- sandbox=sandbox(options=["--bind", path, workdir(path)]),
- )
+def maybe_make_nocow(path: Path) -> None:
+ try:
+ chattr(os.fspath(path), lsattr(os.fspath(path)))
+ except OSError as e:
+ if e.errno not in (errno.ENOTTY, errno.EOPNOTSUPP, errno.EINVAL):
+ raise
def copy_tree(
def copy() -> None:
if src.is_file():
- attr = run(
- ["lsattr", "-l", workdir(src)],
- sandbox=sandbox(options=["--ro-bind", src, workdir(src)]),
- stdout=subprocess.PIPE,
- ).stdout
+ try:
+ attr = lsattr(os.fspath(src))
+ except OSError:
+ attr = 0
- if "No_COW" in attr:
+ if attr & FS_NOCOW_FL:
fdst = dst / src.name if dst.is_dir() else dst
fdst.touch()
- make_nocow(fdst, sandbox=sandbox)
+ maybe_make_nocow(fdst)
cmdline: list[PathString] = [
"cp",