GFile *path,
int dfd,
const char *dfd_subpath,
+ GVariant *source_xattrs,
GVariant **out_xattrs,
gboolean *out_modified,
GCancellable *cancellable,
g_autoptr(GVariant) original_xattrs = NULL;
if (!skip_xattrs && !self->disable_xattrs)
{
- if (path && OSTREE_IS_REPO_FILE (path))
+ if (source_xattrs)
+ original_xattrs = g_variant_ref (source_xattrs);
+ else if (path && OSTREE_IS_REPO_FILE (path))
{
if (!ostree_repo_file_get_xattrs (OSTREE_REPO_FILE (path), &original_xattrs,
cancellable, error))
{
g_assert (dir_enum != NULL || dfd_iter != NULL);
+ GFileType file_type = g_file_info_get_file_type (child_info);
+
const char *name = g_file_info_get_name (child_info);
g_ptr_array_add (path, (char*)name);
g_autofree char *child_relpath = ptrarray_path_join (path);
+ /* See if we have a devino hit; this is used below. Further, for bare-user
+ * repos we'll reload our file info from the object (specifically the
+ * ostreemeta xattr). The on-disk state is not normally what we want to
+ * commit. Basically we're making sure that we pick up "real" uid/gid and any
+ * xattrs there.
+ */
+ const char *loose_checksum = NULL;
+ g_autoptr(GVariant) source_xattrs = NULL;
+ if (dfd_iter != NULL && (file_type != G_FILE_TYPE_DIRECTORY))
+ {
+ guint32 dev = g_file_info_get_attribute_uint32 (child_info, "unix::device");
+ guint64 inode = g_file_info_get_attribute_uint64 (child_info, "unix::inode");
+ loose_checksum = devino_cache_lookup (self, modifier, dev, inode);
+ if (loose_checksum && self->mode == OSTREE_REPO_MODE_BARE_USER)
+ {
+ child_info = NULL;
+ if (!ostree_repo_load_file (self, loose_checksum, NULL, &child_info, &source_xattrs,
+ cancellable, error))
+ return FALSE;
+ }
+ }
+
g_autoptr(GFileInfo) modified_info = NULL;
OstreeRepoCommitFilterResult filter_result =
_ostree_repo_commit_modifier_apply (self, modifier, child_relpath, child_info, &modified_info);
return TRUE;
}
- GFileType file_type = g_file_info_get_file_type (child_info);
switch (file_type)
{
case G_FILE_TYPE_DIRECTORY:
if (dir_enum != NULL)
{
if (!get_final_xattrs (self, modifier, child_relpath, child_info, child,
- -1, name, &xattrs, &xattrs_were_modified,
+ -1, name, source_xattrs, &xattrs, &xattrs_were_modified,
cancellable, error))
return FALSE;
}
int xattr_fd_arg = (file_input_fd != -1) ? file_input_fd : dfd_iter->fd;
const char *xattr_path_arg = (file_input_fd != -1) ? NULL : name;
if (!get_final_xattrs (self, modifier, child_relpath, child_info, child,
- xattr_fd_arg, xattr_path_arg, &xattrs, &xattrs_were_modified,
+ xattr_fd_arg, xattr_path_arg, source_xattrs,
+ &xattrs, &xattrs_were_modified,
cancellable, error))
return FALSE;
}
- /* only check the devino cache if the file info & xattrs were not modified */
+ /* Used below to see whether we can do a fast path commit */
const gboolean modified_file_meta = child_info_was_modified || xattrs_were_modified;
- const char *loose_checksum = NULL;
- if (!modified_file_meta)
- {
- guint32 dev = g_file_info_get_attribute_uint32 (child_info, "unix::device");
- guint64 inode = g_file_info_get_attribute_uint64 (child_info, "unix::inode");
- loose_checksum = devino_cache_lookup (self, modifier, dev, inode);
- }
/* A big prerequisite list of conditions for whether or not we can
* "adopt", i.e. just checksum and rename() into place
gboolean did_adopt = FALSE;
/* The very fast path - we have a devino cache hit, nothing to write */
- if (loose_checksum)
+ if (loose_checksum && !modified_file_meta)
{
if (!ostree_mutable_tree_replace_file (mtree, name, loose_checksum,
error))
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
{
if (!get_final_xattrs (self, modifier, relpath, child_info, dir, -1, NULL,
- &xattrs, NULL, cancellable, error))
+ NULL, &xattrs, NULL, cancellable, error))
return FALSE;
g_autofree guchar *child_file_csum = NULL;
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
{
if (!get_final_xattrs (self, modifier, relpath, modified_info, NULL, src_dfd_iter->fd,
- NULL, &xattrs, NULL, cancellable, error))
+ NULL, NULL, &xattrs, NULL, cancellable, error))
return FALSE;
if (!_ostree_repo_write_directory_meta (self, modified_info, xattrs, &child_file_csum,
--- /dev/null
+#!/bin/bash
+
+# Tests of the "raw ostree" functionality using the host's ostree repo as uid 0.
+
+set -xeuo pipefail
+
+dn=$(dirname $0)
+. ${dn}/libinsttest.sh
+
+echo "1..1"
+
+prepare_tmpdir
+ostree --repo=repo init --mode=bare-user
+mkdir -p components/{dbus,systemd}/usr/{bin,lib}
+echo dbus binary > components/dbus/usr/bin/dbus-daemon
+chmod a+x components/dbus/usr/bin/dbus-daemon
+echo dbus lib > components/dbus/usr/lib/libdbus.so.1
+echo dbus helper > components/dbus/usr/lib/dbus-daemon-helper
+chmod a+x components/dbus/usr/lib/dbus-daemon-helper
+echo systemd binary > components/systemd/usr/bin/systemd
+chmod a+x components/systemd/usr/bin/systemd
+echo systemd lib > components/systemd/usr/lib/libsystemd.so.1
+
+# Make the gid on dbus 81 like fedora, also ensure no xattrs
+ostree --repo=repo commit --no-xattrs -b component-dbus --owner-uid 0 --owner-gid 81 --tree=dir=components/dbus
+ostree --repo=repo commit --no-xattrs -b component-systemd --owner-uid 0 --owner-gid 0 --tree=dir=components/systemd
+rm rootfs -rf
+for component in dbus systemd; do
+ ostree --repo=repo checkout -U -H component-${component} --union rootfs
+done
+echo 'some rootfs data' > rootfs/usr/lib/cache.txt
+# Commit using the host's selinux policy
+ostree --repo=repo commit --selinux-policy / -b rootfs --link-checkout-speedup --tree=dir=rootfs
+ostree --repo=repo ls rootfs /usr/bin/systemd >ls.txt
+assert_file_has_content ls.txt '^-007.. 0 0 .*/usr/bin/systemd'
+ostree --repo=repo ls -X rootfs /usr/lib/dbus-daemon-helper >ls.txt
+assert_file_has_content ls.txt '^-007.. 0 81 .*security.selinux.*/usr/lib/dbus-daemon-helper'
+assert_not_file_has_content ls.txt 'user.ostreemeta'
+echo "ok bare-user link-checkout-speedup with modified xattrs maintains uids"
setup_test_repository "bare-user"
-extra_basic_tests=4
+extra_basic_tests=5
. $(dirname $0)/basic-test.sh
# Reset things so we don't inherit a lot of state from earlier tests
$OSTREE checkout -U -H test2-unreadable test2-checkout
assert_file_has_mode test2-checkout/unreadable 400
echo "ok bare-user handled unreadable file"
+
+cd ${test_tmpdir}
+mkdir -p components/{dbus,systemd}/usr/{bin,lib}
+echo dbus binary > components/dbus/usr/bin/dbus-daemon
+chmod a+x components/dbus/usr/bin/dbus-daemon
+echo dbus lib > components/dbus/usr/lib/libdbus.so.1
+echo dbus helper > components/dbus/usr/lib/dbus-daemon-helper
+chmod a+x components/dbus/usr/lib/dbus-daemon-helper
+echo systemd binary > components/systemd/usr/bin/systemd
+chmod a+x components/systemd/usr/bin/systemd
+echo systemd lib > components/systemd/usr/lib/libsystemd.so.1
+
+# Make the gid on dbus 81 like fedora
+$OSTREE commit -b component-dbus --owner-uid 0 --owner-gid 81 --tree=dir=components/dbus
+$OSTREE commit -b component-systemd --owner-uid 0 --owner-gid 0 --tree=dir=components/systemd
+rm rootfs -rf
+for component in dbus systemd; do
+ $OSTREE checkout -U -H component-${component} --union rootfs
+done
+echo 'some rootfs data' > rootfs/usr/lib/cache.txt
+$OSTREE commit -b rootfs --link-checkout-speedup --tree=dir=rootfs
+$OSTREE ls rootfs /usr/bin/systemd >ls.txt
+assert_file_has_content ls.txt '^-007.. 0 0 .*/usr/bin/systemd'
+$OSTREE ls rootfs /usr/lib/dbus-daemon-helper >ls.txt
+assert_file_has_content ls.txt '^-007.. 0 81 .*/usr/lib/dbus-daemon-helper'
+echo "ok bare-user link-checkout-speedup maintains uids"