lib/core: introduce 'bare-split-xattrs' mode

This commit is contained in:
Luca BRUNO 2022-03-02 16:45:00 +00:00
parent 2c60f302f9
commit 08e98e9042
No known key found for this signature in database
GPG Key ID: A9834A2252078E4E
8 changed files with 82 additions and 11 deletions

View File

@ -59,6 +59,7 @@ test_programs = \
$(NULL) $(NULL)
_installed_or_uninstalled_test_scripts = \ _installed_or_uninstalled_test_scripts = \
tests/test-basic.sh \ tests/test-basic.sh \
tests/test-basic-bare-split-xattrs.sh \
tests/test-basic-user.sh \ tests/test-basic-user.sh \
tests/test-basic-user-only.sh \ tests/test-basic-user-only.sh \
tests/test-basic-root.sh \ tests/test-basic-root.sh \

View File

@ -63,18 +63,32 @@ Other disadvantages of `archive`:
- One doesn't know the total size (compressed or uncompressed) of content - One doesn't know the total size (compressed or uncompressed) of content
before downloading everything before downloading everything
## Aside: the bare and bare-user formats ## Aside: bare formats
The most common operation is to pull from an `archive` repository The most common operation is to pull from a remote `archive` repository
into a `bare` or `bare-user` formatted repository. These latter two into a local one. This latter is not compressed on disk. In other
are not compressed on disk. In other words, pulling to them is words, pulling to a local repository is similar to unpacking (but not
similar to unpacking (but not installing) an RPM/deb package. installing) the content of an RPM/deb package.
The `bare` repository format is the simplest one. In this mode regular files
are directly stored to disk, and all metadata (e.g. uid/gid and xattrs) is
reflected to the filesystem.
It allows further direct access to content and metadata, but it may require
elevated privileges when writing objects to the repository.
The `bare-user` format is a bit special in that the uid/gid and xattrs The `bare-user` format is a bit special in that the uid/gid and xattrs
from the content are ignored. This is primarily useful if you want to from the content are ignored. This is primarily useful if you want to
have the same OSTree-managed content that can be run on a host system have the same OSTree-managed content that can be run on a host system
or an unprivileged container. or an unprivileged container.
Similarly, the `bare-split-xattrs` format is a special mode where xattrs
are stored as separate repository objects, and not directly reflected to
the filesystem.
This is primarily useful when transporting xattrs through lossy environments
(e.g. tar streams and containerized environments). It also allows carrying
security-sensitive xattrs (e.g. SELinux labels) out-of-band without involving
OS filesystem logic.
## Static deltas ## Static deltas
OSTree itself was originally focused on a continuous delivery model, where OSTree itself was originally focused on a continuous delivery model, where

View File

@ -81,15 +81,37 @@ warnings such as GNU Tar emitting "implausibly old time stamp" with 0; however,
until we have a mechanism to transition cleanly to 1, for compatibilty OSTree until we have a mechanism to transition cleanly to 1, for compatibilty OSTree
is reverted to use zero again. is reverted to use zero again.
### Xattrs objects
In some repository modes (e.g. `bare-split-xattrs`), xattrs are stored on the
side of the content objects they refer to. This is done via two dedicated
object types, `file-xattrs` and `file-xattrs-link`.
`file-xattrs` store xattrs data, encoded as GVariant. Each object is keyed by
the checksum of the xattrs content, allowing for multiple references.
`file-xattrs-link` are hardlinks which are associated to file objects.
Each object is keyed by the same checksum of the corresponding file
object. The target of the hardlink is an existing `file-xattrs` object.
In case of reaching the limit of too many links, this object could be
a plain file too.
# Repository types and locations # Repository types and locations
Also unlike git, an OSTree repository can be in one of four separate Also unlike git, an OSTree repository can be in one of five separate
modes: `bare`, `bare-user`, `bare-user-only`, and `archive`. A bare repository is modes: `bare`, `bare-split-xattrs, ``bare-user`, `bare-user-only`, and
one where content files are just stored as regular files; it's `archive`.
designed to be the source of a "hardlink farm", where each operating
system checkout is merely links into it. If you want to store files A `bare` repository is one where content files are just stored as regular
files; it's designed to be the source of a "hardlink farm", where each
operating system checkout is merely links into it. If you want to store files
owned by e.g. root in this mode, you must run OSTree as root. owned by e.g. root in this mode, you must run OSTree as root.
The `bare-split-xattrs` mode is similar to the above one, but it does store
xattrs as separate objects. This is meant to avoid conflicts with
kernel-enforced constraints (e.g. on SELinux labels) and with other softwares
that may perform ephemeral changes to xattrs (e.g. container runtimes).
The `bare-user` mode is a later addition that is like `bare` in that The `bare-user` mode is a later addition that is like `bare` in that
files are unpacked, but it can (and should generally) be created as files are unpacked, but it can (and should generally) be created as
non-root. In this mode, extended metadata such as owner uid, gid, and non-root. In this mode, extended metadata such as owner uid, gid, and

View File

@ -197,7 +197,8 @@ _ostree_repo_mode_is_bare (OstreeRepoMode mode)
return return
mode == OSTREE_REPO_MODE_BARE || mode == OSTREE_REPO_MODE_BARE ||
mode == OSTREE_REPO_MODE_BARE_USER || mode == OSTREE_REPO_MODE_BARE_USER ||
mode == OSTREE_REPO_MODE_BARE_USER_ONLY; mode == OSTREE_REPO_MODE_BARE_USER_ONLY ||
mode == OSTREE_REPO_MODE_BARE_SPLIT_XATTRS;
} }
#ifndef OSTREE_DISABLE_GPGME #ifndef OSTREE_DISABLE_GPGME

View File

@ -39,6 +39,7 @@ G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE_Z2 == 1);
G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE == OSTREE_REPO_MODE_ARCHIVE_Z2); G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE == OSTREE_REPO_MODE_ARCHIVE_Z2);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER == 2); G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER == 2);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER_ONLY == 3); G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER_ONLY == 3);
G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_SPLIT_XATTRS == 4);
static GBytes *variant_to_lenprefixed_buffer (GVariant *variant); static GBytes *variant_to_lenprefixed_buffer (GVariant *variant);

View File

@ -193,6 +193,7 @@ typedef enum {
* @OSTREE_REPO_MODE_ARCHIVE_Z2: Legacy alias for `OSTREE_REPO_MODE_ARCHIVE` * @OSTREE_REPO_MODE_ARCHIVE_Z2: Legacy alias for `OSTREE_REPO_MODE_ARCHIVE`
* @OSTREE_REPO_MODE_BARE_USER: Files are stored as themselves, except ownership; can be written by user. Hardlinks work only in user checkouts. * @OSTREE_REPO_MODE_BARE_USER: Files are stored as themselves, except ownership; can be written by user. Hardlinks work only in user checkouts.
* @OSTREE_REPO_MODE_BARE_USER_ONLY: Same as BARE_USER, but all metadata is not stored, so it can only be used for user checkouts. Does not need xattrs. * @OSTREE_REPO_MODE_BARE_USER_ONLY: Same as BARE_USER, but all metadata is not stored, so it can only be used for user checkouts. Does not need xattrs.
* @OSTREE_REPO_MODE_BARE_SPLIT_XATTRS: Same as BARE_USER, but xattrs are stored separately from file content, with dedicated object types.
* *
* See the documentation of #OstreeRepo for more information about the * See the documentation of #OstreeRepo for more information about the
* possible modes. * possible modes.
@ -203,6 +204,7 @@ typedef enum {
OSTREE_REPO_MODE_ARCHIVE_Z2 = OSTREE_REPO_MODE_ARCHIVE, OSTREE_REPO_MODE_ARCHIVE_Z2 = OSTREE_REPO_MODE_ARCHIVE,
OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER,
OSTREE_REPO_MODE_BARE_USER_ONLY, OSTREE_REPO_MODE_BARE_USER_ONLY,
OSTREE_REPO_MODE_BARE_SPLIT_XATTRS,
} OstreeRepoMode; } OstreeRepoMode;
/** /**

View File

@ -2704,6 +2704,9 @@ ostree_repo_mode_to_string (OstreeRepoMode mode,
/* Legacy alias */ /* Legacy alias */
ret_mode ="archive-z2"; ret_mode ="archive-z2";
break; break;
case OSTREE_REPO_MODE_BARE_SPLIT_XATTRS:
ret_mode = "bare-split-xattrs";
break;
default: default:
return glnx_throw (error, "Invalid mode '%d'", mode); return glnx_throw (error, "Invalid mode '%d'", mode);
} }
@ -2734,6 +2737,8 @@ ostree_repo_mode_from_string (const char *mode,
else if (strcmp (mode, "archive-z2") == 0 || else if (strcmp (mode, "archive-z2") == 0 ||
strcmp (mode, "archive") == 0) strcmp (mode, "archive") == 0)
ret_mode = OSTREE_REPO_MODE_ARCHIVE; ret_mode = OSTREE_REPO_MODE_ARCHIVE;
else if (strcmp (mode, "bare-split-xattrs") == 0)
ret_mode = OSTREE_REPO_MODE_BARE_SPLIT_XATTRS;
else else
return glnx_throw (error, "Invalid mode '%s' in repository configuration", mode); return glnx_throw (error, "Invalid mode '%s' in repository configuration", mode);

View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
#
# SPDX-License-Identifier: LGPL-2.0+
set -euo pipefail
. $(dirname $0)/libtest.sh
mode="bare-split-xattrs"
OSTREE="${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo"
cd ${test_tmpdir}
${OSTREE} init --mode "${mode}"
${OSTREE} config get core.mode > mode.txt
assert_file_has_content mode.txt "${mode}"
tap_ok "repo init"
rm -rf -- repo mode.txt
cd ${test_tmpdir}
${OSTREE} init --mode "${mode}"
${OSTREE} fsck --all
tap_ok "repo fsck"
rm -rf -- repo
tap_end