diff --git a/src/libostree/ostree-core-private.h b/src/libostree/ostree-core-private.h index fbd9490e..a66a068f 100644 --- a/src/libostree/ostree-core-private.h +++ b/src/libostree/ostree-core-private.h @@ -144,7 +144,8 @@ _ostree_repo_mode_is_bare (OstreeRepoMode mode) { return mode == OSTREE_REPO_MODE_BARE || - mode == OSTREE_REPO_MODE_BARE_USER; + mode == OSTREE_REPO_MODE_BARE_USER || + mode == OSTREE_REPO_MODE_BARE_USER_ONLY; } GVariant * diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h index bcade9db..b25112db 100644 --- a/src/libostree/ostree-core.h +++ b/src/libostree/ostree-core.h @@ -179,6 +179,7 @@ typedef enum { * @OSTREE_REPO_MODE_BARE: Files are stored as themselves; checkouts are hardlinks; can only be written as root * @OSTREE_REPO_MODE_ARCHIVE_Z2: Files are compressed, should be owned by non-root. Can be served via HTTP * @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. * * See the documentation of #OstreeRepo for more information about the * possible modes. @@ -186,7 +187,8 @@ typedef enum { typedef enum { OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_ARCHIVE_Z2, - OSTREE_REPO_MODE_BARE_USER + OSTREE_REPO_MODE_BARE_USER, + OSTREE_REPO_MODE_BARE_USER_ONLY, } OstreeRepoMode; _OSTREE_PUBLIC diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 5611e6e9..09966a94 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -473,7 +473,9 @@ checkout_one_file_at (OstreeRepo *repo, (current_repo->mode == OSTREE_REPO_MODE_BARE_USER && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER /* NOTE: bare-user symlinks are not stored as symlinks */ - && !is_symlink)); + && !is_symlink) || + (current_repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY + && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER)); gboolean current_can_cache = (options->enable_uncompressed_cache && current_repo->enable_uncompressed_cache); gboolean is_archive_z2_with_cache = (current_repo->mode == OSTREE_REPO_MODE_ARCHIVE_Z2 @@ -862,6 +864,9 @@ ostree_repo_checkout_tree (OstreeRepo *self, { OstreeRepoCheckoutAtOptions options = { 0, }; + if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY) + mode = OSTREE_REPO_CHECKOUT_MODE_USER; + options.mode = mode; options.overwrite_mode = overwrite_mode; /* Backwards compatibility */ @@ -948,6 +953,7 @@ ostree_repo_checkout_at (OstreeRepo *self, GError **error) { OstreeRepoCheckoutAtOptions default_options = { 0, }; + OstreeRepoCheckoutAtOptions real_options; if (!options) { @@ -955,6 +961,13 @@ ostree_repo_checkout_at (OstreeRepo *self, options = &default_options; } + /* Make a copy so we can modify the options */ + real_options = *options; + options = &real_options; + + if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY) + options->mode = OSTREE_REPO_CHECKOUT_MODE_USER; + g_autoptr(GFile) commit_root = (GFile*) _ostree_repo_file_new_for_commit (self, commit, error); if (!commit_root) return FALSE; diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 1308ef5c..80c35f44 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -227,7 +227,11 @@ commit_loose_object_trusted (OstreeRepo *self, } /* Special handling for symlinks in bare repositories */ - if (object_is_symlink && self->mode == OSTREE_REPO_MODE_BARE) + if (object_is_symlink && self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + { + /* We don't store the metadata in bare-user-only, so we're done. */ + } + else if (object_is_symlink && self->mode == OSTREE_REPO_MODE_BARE) { /* Now that we know the checksum is valid, apply uid/gid, mode bits, * and extended attributes. @@ -283,7 +287,8 @@ commit_loose_object_trusted (OstreeRepo *self, } } - if (objtype == OSTREE_OBJECT_TYPE_FILE && self->mode == OSTREE_REPO_MODE_BARE_USER) + if (objtype == OSTREE_OBJECT_TYPE_FILE && + (self->mode == OSTREE_REPO_MODE_BARE_USER || self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY)) { if (!object_is_symlink) { @@ -302,7 +307,8 @@ commit_loose_object_trusted (OstreeRepo *self, } } - if (!write_file_metadata_to_xattr (fd, uid, gid, mode, xattrs, error)) + if (self->mode == OSTREE_REPO_MODE_BARE_USER && + !write_file_metadata_to_xattr (fd, uid, gid, mode, xattrs, error)) goto out; } @@ -708,8 +714,10 @@ write_object (OstreeRepo *self, cancellable, error)) goto out; } - else if (repo_mode == OSTREE_REPO_MODE_BARE && temp_file_is_symlink) + else if (_ostree_repo_mode_is_bare (repo_mode) && temp_file_is_symlink) { + /* Note: This will not be hit for bare-user mode because its converted to a + regular file and take the branch above */ if (!_ostree_make_temporary_symlink_at (self->tmp_dir_fd, g_file_info_get_symlink_target (file_info), &temp_filename, @@ -959,6 +967,7 @@ scan_one_loose_devino (OstreeRepo *self, case OSTREE_REPO_MODE_ARCHIVE_Z2: case OSTREE_REPO_MODE_BARE: case OSTREE_REPO_MODE_BARE_USER: + case OSTREE_REPO_MODE_BARE_USER_ONLY: skip = !g_str_has_suffix (name, ".file"); break; default: diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index adc74c0e..5e0a93ec 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1754,6 +1754,9 @@ ostree_repo_mode_to_string (OstreeRepoMode mode, case OSTREE_REPO_MODE_BARE_USER: ret_mode = "bare-user"; break; + case OSTREE_REPO_MODE_BARE_USER_ONLY: + ret_mode = "bare-user-only"; + break; case OSTREE_REPO_MODE_ARCHIVE_Z2: ret_mode ="archive-z2"; break; @@ -1781,6 +1784,8 @@ ostree_repo_mode_from_string (const char *mode, ret_mode = OSTREE_REPO_MODE_BARE; else if (strcmp (mode, "bare-user") == 0) ret_mode = OSTREE_REPO_MODE_BARE_USER; + else if (strcmp (mode, "bare-user-only") == 0) + ret_mode = OSTREE_REPO_MODE_BARE_USER_ONLY; else if (strcmp (mode, "archive-z2") == 0 || strcmp (mode, "archive") == 0) ret_mode = OSTREE_REPO_MODE_ARCHIVE_Z2; @@ -2907,6 +2912,37 @@ ostree_repo_load_file (OstreeRepo *self, g_file_info_set_symlink_target (ret_file_info, targetbuf); } } + else if (repo_mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + { + glnx_fd_close int fd = -1; + + /* Canonical info is: uid/gid is 0 and no xattrs, which + might be wrong and thus not validate correctly, but + at least we report something consistent. */ + g_file_info_set_attribute_uint32 (ret_file_info, "unix::uid", 0); + g_file_info_set_attribute_uint32 (ret_file_info, "unix::gid", 0); + + if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR && + out_input) + { + fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC); + if (fd < 0) + { + glnx_set_error_from_errno (error); + goto out; + } + + ret_input = g_unix_input_stream_new (fd, TRUE); + fd = -1; /* Transfer ownership */ + } + + if (out_xattrs) + { + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)")); + ret_xattrs = g_variant_ref_sink (g_variant_builder_end (&builder)); + } + } else { g_assert (repo_mode == OSTREE_REPO_MODE_BARE);