diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 1096b0b071..8631f357a7 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -86,15 +86,6 @@ symlink_at_replace (const char *oldpath, return TRUE; } -static GLnxFileCopyFlags -sysroot_flags_to_copy_flags (GLnxFileCopyFlags defaults, - OstreeSysrootDebugFlags sysrootflags) -{ - if (sysrootflags & OSTREE_SYSROOT_DEBUG_NO_XATTRS) - defaults |= GLNX_FILE_COPY_NOXATTRS; - return defaults; -} - /* Try a hardlink if we can, otherwise fall back to copying. Used * right now for kernels/initramfs/device trees in /boot, where we can just * hardlink if we're on the same partition. @@ -139,101 +130,6 @@ install_into_boot (OstreeSePolicy *sepolicy, return TRUE; } -/* Copy ownership, mode, and xattrs from source directory to destination */ -static gboolean -dirfd_copy_attributes_and_xattrs (int src_parent_dfd, - const char *src_name, - int src_dfd, - int dest_dfd, - OstreeSysrootDebugFlags flags, - GCancellable *cancellable, - GError **error) -{ - g_autoptr(GVariant) xattrs = NULL; - - /* Clone all xattrs first, so we get the SELinux security context - * right. This will allow other users access if they have ACLs, but - * oh well. - */ - if (!(flags & OSTREE_SYSROOT_DEBUG_NO_XATTRS)) - { - if (!glnx_dfd_name_get_all_xattrs (src_parent_dfd, src_name, - &xattrs, cancellable, error)) - return FALSE; - if (!glnx_fd_set_all_xattrs (dest_dfd, xattrs, - cancellable, error)) - return FALSE; - } - - struct stat src_stbuf; - if (!glnx_fstat (src_dfd, &src_stbuf, error)) - return FALSE; - if (fchown (dest_dfd, src_stbuf.st_uid, src_stbuf.st_gid) != 0) - return glnx_throw_errno_prefix (error, "fchown"); - if (fchmod (dest_dfd, src_stbuf.st_mode) != 0) - return glnx_throw_errno_prefix (error, "fchmod"); - - return TRUE; -} - -static gboolean -copy_dir_recurse (int src_parent_dfd, - int dest_parent_dfd, - const char *name, - OstreeSysrootDebugFlags flags, - GCancellable *cancellable, - GError **error) -{ - g_auto(GLnxDirFdIterator) src_dfd_iter = { 0, }; - glnx_autofd int dest_dfd = -1; - struct dirent *dent; - - if (!glnx_dirfd_iterator_init_at (src_parent_dfd, name, TRUE, &src_dfd_iter, error)) - return FALSE; - - /* Create with mode 0700, we'll fchmod/fchown later */ - if (!glnx_ensure_dir (dest_parent_dfd, name, 0700, error)) - return FALSE; - - if (!glnx_opendirat (dest_parent_dfd, name, TRUE, &dest_dfd, error)) - return FALSE; - - if (!dirfd_copy_attributes_and_xattrs (src_parent_dfd, name, src_dfd_iter.fd, dest_dfd, - flags, cancellable, error)) - return FALSE; - - while (TRUE) - { - struct stat child_stbuf; - - if (!glnx_dirfd_iterator_next_dent (&src_dfd_iter, &dent, cancellable, error)) - return FALSE; - if (dent == NULL) - break; - - if (!glnx_fstatat (src_dfd_iter.fd, dent->d_name, &child_stbuf, - AT_SYMLINK_NOFOLLOW, error)) - return FALSE; - - if (S_ISDIR (child_stbuf.st_mode)) - { - if (!copy_dir_recurse (src_dfd_iter.fd, dest_dfd, dent->d_name, - flags, cancellable, error)) - return FALSE; - } - else - { - if (!glnx_file_copy_at (src_dfd_iter.fd, dent->d_name, &child_stbuf, - dest_dfd, dent->d_name, - sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags), - cancellable, error)) - return FALSE; - } - } - - return TRUE; -} - /* If a chain of directories is added, this function will ensure * they're created. */ @@ -290,8 +186,8 @@ ensure_directory_from_template (int orig_etc_fd, if (!glnx_opendirat (new_etc_fd, path, TRUE, &target_dfd, error)) return FALSE; - if (!dirfd_copy_attributes_and_xattrs (modified_etc_fd, path, src_dfd, target_dfd, - flags, cancellable, error)) + if (!ot_dirfd_copy_attributes_and_xattrs (modified_etc_fd, path, src_dfd, target_dfd, + flags, cancellable, error)) return FALSE; if (out_dfd) @@ -365,15 +261,15 @@ copy_modified_config_file (int orig_etc_fd, if (S_ISDIR (modified_stbuf.st_mode)) { - if (!copy_dir_recurse (modified_etc_fd, new_etc_fd, path, flags, - cancellable, error)) + if (!ot_copy_dir_recurse (modified_etc_fd, new_etc_fd, path, flags, + cancellable, error)) return FALSE; } else if (S_ISLNK (modified_stbuf.st_mode) || S_ISREG (modified_stbuf.st_mode)) { if (!glnx_file_copy_at (modified_etc_fd, path, &modified_stbuf, new_etc_fd, path, - sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags), + ot_sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags), cancellable, error)) return FALSE; } diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index e4b2039e2f..eef50160ac 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -28,19 +28,6 @@ G_BEGIN_DECLS -typedef enum { - - /* Don't flag deployments as immutable. */ - OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS = 1 << 0, - /* See https://github.com/ostreedev/ostree/pull/759 */ - OSTREE_SYSROOT_DEBUG_NO_XATTRS = 1 << 1, - /* https://github.com/ostreedev/ostree/pull/1049 */ - OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE = 1 << 2, - /* This is a temporary flag until we fully drop the explicit `systemctl start - * ostree-finalize-staged.service` so that tests can exercise the new path unit. */ - OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH = 1 << 3, -} OstreeSysrootDebugFlags; - /** * OstreeSysroot: * Internal struct diff --git a/src/libotutil/ot-fs-utils.c b/src/libotutil/ot-fs-utils.c index c4fcd56f11..fac408a95e 100644 --- a/src/libotutil/ot-fs-utils.c +++ b/src/libotutil/ot-fs-utils.c @@ -247,3 +247,98 @@ ot_parse_file_by_line (const char *path, return TRUE; } + +/* Copy ownership, mode, and xattrs from source directory to destination */ +gboolean +ot_dirfd_copy_attributes_and_xattrs (int src_parent_dfd, + const char *src_name, + int src_dfd, + int dest_dfd, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) xattrs = NULL; + + /* Clone all xattrs first, so we get the SELinux security context + * right. This will allow other users access if they have ACLs, but + * oh well. + */ + if (!(flags & OSTREE_SYSROOT_DEBUG_NO_XATTRS)) + { + if (!glnx_dfd_name_get_all_xattrs (src_parent_dfd, src_name, + &xattrs, cancellable, error)) + return FALSE; + if (!glnx_fd_set_all_xattrs (dest_dfd, xattrs, + cancellable, error)) + return FALSE; + } + + struct stat src_stbuf; + if (!glnx_fstat (src_dfd, &src_stbuf, error)) + return FALSE; + if (fchown (dest_dfd, src_stbuf.st_uid, src_stbuf.st_gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + if (fchmod (dest_dfd, src_stbuf.st_mode) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + return TRUE; +} + +gboolean +ot_copy_dir_recurse (int src_parent_dfd, + int dest_parent_dfd, + const char *name, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) src_dfd_iter = { 0, }; + glnx_autofd int dest_dfd = -1; + struct dirent *dent; + + if (!glnx_dirfd_iterator_init_at (src_parent_dfd, name, TRUE, &src_dfd_iter, error)) + return FALSE; + + /* Create with mode 0700, we'll fchmod/fchown later */ + if (!glnx_ensure_dir (dest_parent_dfd, name, 0700, error)) + return FALSE; + + if (!glnx_opendirat (dest_parent_dfd, name, TRUE, &dest_dfd, error)) + return FALSE; + + if (!ot_dirfd_copy_attributes_and_xattrs (src_parent_dfd, name, src_dfd_iter.fd, dest_dfd, + flags, cancellable, error)) + return FALSE; + + while (TRUE) + { + struct stat child_stbuf; + + if (!glnx_dirfd_iterator_next_dent (&src_dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (!glnx_fstatat (src_dfd_iter.fd, dent->d_name, &child_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + if (S_ISDIR (child_stbuf.st_mode)) + { + if (!ot_copy_dir_recurse (src_dfd_iter.fd, dest_dfd, dent->d_name, + flags, cancellable, error)) + return FALSE; + } + else + { + if (!glnx_file_copy_at (src_dfd_iter.fd, dent->d_name, &child_stbuf, + dest_dfd, dent->d_name, + ot_sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags), + cancellable, error)) + return FALSE; + } + } + + return TRUE; +} diff --git a/src/libotutil/ot-fs-utils.h b/src/libotutil/ot-fs-utils.h index 74a0fed6d8..225676d833 100644 --- a/src/libotutil/ot-fs-utils.h +++ b/src/libotutil/ot-fs-utils.h @@ -26,6 +26,19 @@ G_BEGIN_DECLS +typedef enum { + + /* Don't flag deployments as immutable. */ + OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS = 1 << 0, + /* See https://github.com/ostreedev/ostree/pull/759 */ + OSTREE_SYSROOT_DEBUG_NO_XATTRS = 1 << 1, + /* https://github.com/ostreedev/ostree/pull/1049 */ + OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE = 1 << 2, + /* This is a temporary flag until we fully drop the explicit `systemctl start + * ostree-finalize-staged.service` so that tests can exercise the new path unit. */ + OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH = 1 << 3, +} OstreeSysrootDebugFlags; + /* A little helper to call unlinkat() as a cleanup * function. Mostly only necessary to handle * deletion of temporary symlinks. @@ -52,6 +65,15 @@ ot_cleanup_unlinkat (OtCleanupUnlinkat *cleanup) } G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OtCleanupUnlinkat, ot_cleanup_unlinkat) +static inline GLnxFileCopyFlags +ot_sysroot_flags_to_copy_flags (GLnxFileCopyFlags defaults, + OstreeSysrootDebugFlags sysrootflags) +{ + if (sysrootflags & OSTREE_SYSROOT_DEBUG_NO_XATTRS) + defaults |= GLNX_FILE_COPY_NOXATTRS; + return defaults; +} + GFile * ot_fdrel_to_gfile (int dfd, const char *path); gboolean ot_readlinkat_gfile_info (int dfd, @@ -97,4 +119,21 @@ ot_parse_file_by_line (const char *path, GCancellable *cancellable, GError **error); +gboolean +ot_dirfd_copy_attributes_and_xattrs (int src_parent_dfd, + const char *src_name, + int src_dfd, + int dest_dfd, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error); + +gboolean +ot_copy_dir_recurse (int src_parent_dfd, + int dest_parent_dfd, + const char *name, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error); + G_END_DECLS