core: Support --owner-uid and --owner-gid options for commit
This allows us to more easily import user-built tarballs into a root-owned OSTree repo.
This commit is contained in:
parent
a287274935
commit
11d57d63e3
|
|
@ -1342,10 +1342,30 @@ create_tree_variant_from_hashes (GHashTable *file_checksums,
|
||||||
return serialized_tree;
|
return serialized_tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GFileInfo *
|
||||||
|
create_modified_file_info (GFileInfo *info,
|
||||||
|
OstreeRepoCommitModifier *modifier)
|
||||||
|
{
|
||||||
|
GFileInfo *ret;
|
||||||
|
|
||||||
|
if (!modifier)
|
||||||
|
return (GFileInfo*)g_object_ref (info);
|
||||||
|
|
||||||
|
ret = g_file_info_dup (info);
|
||||||
|
|
||||||
|
if (modifier->uid >= 0)
|
||||||
|
g_file_info_set_attribute_uint32 (ret, "unix::uid", modifier->uid);
|
||||||
|
if (modifier->gid >= 0)
|
||||||
|
g_file_info_set_attribute_uint32 (ret, "unix::gid", modifier->gid);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
stage_directory_recurse (OstreeRepo *self,
|
stage_directory_recurse (OstreeRepo *self,
|
||||||
GFile *base,
|
GFile *base,
|
||||||
GFile *dir,
|
GFile *dir,
|
||||||
|
OstreeRepoCommitModifier *modifier,
|
||||||
GChecksum **out_contents_checksum,
|
GChecksum **out_contents_checksum,
|
||||||
GChecksum **out_metadata_checksum,
|
GChecksum **out_metadata_checksum,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
|
@ -1357,6 +1377,7 @@ stage_directory_recurse (OstreeRepo *self,
|
||||||
GChecksum *ret_contents_checksum = NULL;
|
GChecksum *ret_contents_checksum = NULL;
|
||||||
GFileEnumerator *dir_enum = NULL;
|
GFileEnumerator *dir_enum = NULL;
|
||||||
GFileInfo *child_info = NULL;
|
GFileInfo *child_info = NULL;
|
||||||
|
GFileInfo *modified_info = NULL;
|
||||||
GFile *child = NULL;
|
GFile *child = NULL;
|
||||||
GHashTable *file_checksums = NULL;
|
GHashTable *file_checksums = NULL;
|
||||||
GHashTable *dir_metadata_checksums = NULL;
|
GHashTable *dir_metadata_checksums = NULL;
|
||||||
|
|
@ -1372,15 +1393,18 @@ stage_directory_recurse (OstreeRepo *self,
|
||||||
if (!child_info)
|
if (!child_info)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
modified_info = create_modified_file_info (child_info, modifier);
|
||||||
|
|
||||||
xattrs = ostree_get_xattrs_for_file (dir, error);
|
xattrs = ostree_get_xattrs_for_file (dir, error);
|
||||||
if (!xattrs)
|
if (!xattrs)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!stage_directory_meta (self, child_info, xattrs, &ret_metadata_checksum,
|
if (!stage_directory_meta (self, modified_info, xattrs, &ret_metadata_checksum,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
g_clear_object (&child_info);
|
g_clear_object (&child_info);
|
||||||
|
g_clear_object (&modified_info);
|
||||||
|
|
||||||
dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO,
|
dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
|
|
@ -1400,6 +1424,9 @@ stage_directory_recurse (OstreeRepo *self,
|
||||||
{
|
{
|
||||||
const char *name = g_file_info_get_name (child_info);
|
const char *name = g_file_info_get_name (child_info);
|
||||||
|
|
||||||
|
g_clear_object (&modified_info);
|
||||||
|
modified_info = create_modified_file_info (child_info, modifier);
|
||||||
|
|
||||||
g_clear_object (&child);
|
g_clear_object (&child);
|
||||||
child = g_file_get_child (dir, name);
|
child = g_file_get_child (dir, name);
|
||||||
|
|
||||||
|
|
@ -1408,7 +1435,7 @@ stage_directory_recurse (OstreeRepo *self,
|
||||||
GChecksum *child_dir_metadata_checksum = NULL;
|
GChecksum *child_dir_metadata_checksum = NULL;
|
||||||
GChecksum *child_dir_contents_checksum = NULL;
|
GChecksum *child_dir_contents_checksum = NULL;
|
||||||
|
|
||||||
if (!stage_directory_recurse (self, base, child, &child_dir_contents_checksum,
|
if (!stage_directory_recurse (self, base, child, modifier, &child_dir_contents_checksum,
|
||||||
&child_dir_metadata_checksum, cancellable, error))
|
&child_dir_metadata_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -1425,7 +1452,7 @@ stage_directory_recurse (OstreeRepo *self,
|
||||||
ot_clear_gvariant (&xattrs);
|
ot_clear_gvariant (&xattrs);
|
||||||
g_clear_object (&file_input);
|
g_clear_object (&file_input);
|
||||||
|
|
||||||
if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_REGULAR)
|
if (g_file_info_get_file_type (modified_info) == G_FILE_TYPE_REGULAR)
|
||||||
{
|
{
|
||||||
file_input = (GInputStream*)g_file_read (child, cancellable, error);
|
file_input = (GInputStream*)g_file_read (child, cancellable, error);
|
||||||
if (!file_input)
|
if (!file_input)
|
||||||
|
|
@ -1437,7 +1464,7 @@ stage_directory_recurse (OstreeRepo *self,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!stage_object (self, OSTREE_OBJECT_TYPE_RAW_FILE,
|
if (!stage_object (self, OSTREE_OBJECT_TYPE_RAW_FILE,
|
||||||
child_info, xattrs, file_input, NULL,
|
modified_info, xattrs, file_input, NULL,
|
||||||
&child_file_checksum, cancellable, error))
|
&child_file_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -1468,6 +1495,7 @@ stage_directory_recurse (OstreeRepo *self,
|
||||||
out:
|
out:
|
||||||
g_clear_object (&dir_enum);
|
g_clear_object (&dir_enum);
|
||||||
g_clear_object (&child);
|
g_clear_object (&child);
|
||||||
|
g_clear_object (&modified_info);
|
||||||
g_clear_object (&child_info);
|
g_clear_object (&child_info);
|
||||||
g_clear_object (&file_input);
|
g_clear_object (&file_input);
|
||||||
if (file_checksums)
|
if (file_checksums)
|
||||||
|
|
@ -1492,6 +1520,7 @@ ostree_repo_commit_directory (OstreeRepo *self,
|
||||||
const char *body,
|
const char *body,
|
||||||
GVariant *metadata,
|
GVariant *metadata,
|
||||||
GFile *dir,
|
GFile *dir,
|
||||||
|
OstreeRepoCommitModifier *modifier,
|
||||||
GChecksum **out_commit,
|
GChecksum **out_commit,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
|
|
@ -1518,7 +1547,7 @@ ostree_repo_commit_directory (OstreeRepo *self,
|
||||||
if (!ostree_repo_resolve_rev (self, parent, TRUE, ¤t_head, error))
|
if (!ostree_repo_resolve_rev (self, parent, TRUE, ¤t_head, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!stage_directory_recurse (self, dir, dir, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
if (!stage_directory_recurse (self, dir, dir, modifier, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
|
if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
|
||||||
|
|
@ -1548,9 +1577,11 @@ propagate_libarchive_error (GError **error,
|
||||||
}
|
}
|
||||||
|
|
||||||
static GFileInfo *
|
static GFileInfo *
|
||||||
file_info_from_archive_entry (struct archive_entry *entry)
|
file_info_from_archive_entry_and_modifier (struct archive_entry *entry,
|
||||||
|
OstreeRepoCommitModifier *modifier)
|
||||||
{
|
{
|
||||||
GFileInfo *info = g_file_info_new ();
|
GFileInfo *info = g_file_info_new ();
|
||||||
|
GFileInfo *modified_info = NULL;
|
||||||
const struct stat *st;
|
const struct stat *st;
|
||||||
guint32 file_type;
|
guint32 file_type;
|
||||||
|
|
||||||
|
|
@ -1576,7 +1607,11 @@ file_info_from_archive_entry (struct archive_entry *entry)
|
||||||
g_file_info_set_attribute_uint32 (info, "unix::rdev", st->st_rdev);
|
g_file_info_set_attribute_uint32 (info, "unix::rdev", st->st_rdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
modified_info = create_modified_file_info (info, modifier);
|
||||||
|
|
||||||
|
g_object_unref (info);
|
||||||
|
|
||||||
|
return modified_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
@ -1742,6 +1777,7 @@ file_tree_import_recurse (OstreeRepo *self,
|
||||||
static gboolean
|
static gboolean
|
||||||
import_libarchive (OstreeRepo *self,
|
import_libarchive (OstreeRepo *self,
|
||||||
GFile *archive_f,
|
GFile *archive_f,
|
||||||
|
OstreeRepoCommitModifier *modifier,
|
||||||
char **out_contents_checksum,
|
char **out_contents_checksum,
|
||||||
char **out_metadata_checksum,
|
char **out_metadata_checksum,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
|
|
@ -1861,7 +1897,7 @@ import_libarchive (OstreeRepo *self,
|
||||||
}
|
}
|
||||||
|
|
||||||
g_clear_object (&file_info);
|
g_clear_object (&file_info);
|
||||||
file_info = file_info_from_archive_entry (entry);
|
file_info = file_info_from_archive_entry_and_modifier (entry, modifier);
|
||||||
|
|
||||||
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_UNKNOWN)
|
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_UNKNOWN)
|
||||||
{
|
{
|
||||||
|
|
@ -1969,6 +2005,7 @@ ostree_repo_commit_tarfile (OstreeRepo *self,
|
||||||
const char *body,
|
const char *body,
|
||||||
GVariant *metadata,
|
GVariant *metadata,
|
||||||
GFile *path,
|
GFile *path,
|
||||||
|
OstreeRepoCommitModifier *modifier,
|
||||||
GChecksum **out_commit,
|
GChecksum **out_commit,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
|
|
@ -1996,7 +2033,7 @@ ostree_repo_commit_tarfile (OstreeRepo *self,
|
||||||
if (!ostree_repo_resolve_rev (self, parent, TRUE, ¤t_head, error))
|
if (!ostree_repo_resolve_rev (self, parent, TRUE, ¤t_head, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!import_libarchive (self, path, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
if (!import_libarchive (self, path, modifier, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
|
if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
|
||||||
|
|
@ -2020,6 +2057,31 @@ ostree_repo_commit_tarfile (OstreeRepo *self,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OstreeRepoCommitModifier *
|
||||||
|
ostree_repo_commit_modifier_new (void)
|
||||||
|
{
|
||||||
|
OstreeRepoCommitModifier *modifier = g_new0 (OstreeRepoCommitModifier, 1);
|
||||||
|
modifier->uid = -1;
|
||||||
|
modifier->gid = -1;
|
||||||
|
|
||||||
|
modifier->refcount = 1;
|
||||||
|
|
||||||
|
return modifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier)
|
||||||
|
{
|
||||||
|
if (!modifier)
|
||||||
|
return;
|
||||||
|
if (!g_atomic_int_dec_and_test (&modifier->refcount))
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free (modifier);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
iter_object_dir (OstreeRepo *self,
|
iter_object_dir (OstreeRepo *self,
|
||||||
GFile *dir,
|
GFile *dir,
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,18 @@ gboolean ostree_repo_load_variant (OstreeRepo *self,
|
||||||
GVariant **out_variant,
|
GVariant **out_variant,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
volatile gint refcount;
|
||||||
|
gpointer reserved[3];
|
||||||
|
|
||||||
|
gint uid;
|
||||||
|
gint gid;
|
||||||
|
} OstreeRepoCommitModifier;
|
||||||
|
|
||||||
|
OstreeRepoCommitModifier *ostree_repo_commit_modifier_new (void);
|
||||||
|
|
||||||
|
void ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier);
|
||||||
|
|
||||||
gboolean ostree_repo_commit_directory (OstreeRepo *self,
|
gboolean ostree_repo_commit_directory (OstreeRepo *self,
|
||||||
const char *branch,
|
const char *branch,
|
||||||
const char *parent,
|
const char *parent,
|
||||||
|
|
@ -137,6 +149,7 @@ gboolean ostree_repo_commit_directory (OstreeRepo *self,
|
||||||
const char *body,
|
const char *body,
|
||||||
GVariant *metadata,
|
GVariant *metadata,
|
||||||
GFile *base,
|
GFile *base,
|
||||||
|
OstreeRepoCommitModifier *modifier,
|
||||||
GChecksum **out_commit,
|
GChecksum **out_commit,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
@ -148,6 +161,7 @@ gboolean ostree_repo_commit_tarfile (OstreeRepo *self,
|
||||||
const char *body,
|
const char *body,
|
||||||
GVariant *metadata,
|
GVariant *metadata,
|
||||||
GFile *base,
|
GFile *base,
|
||||||
|
OstreeRepoCommitModifier *modifier,
|
||||||
GChecksum **out_commit,
|
GChecksum **out_commit,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ static char *body;
|
||||||
static char *parent;
|
static char *parent;
|
||||||
static char *branch;
|
static char *branch;
|
||||||
static gboolean tar;
|
static gboolean tar;
|
||||||
|
static gint owner_uid = -1;
|
||||||
|
static gint owner_gid = -1;
|
||||||
|
|
||||||
static GOptionEntry options[] = {
|
static GOptionEntry options[] = {
|
||||||
{ "subject", 's', 0, G_OPTION_ARG_STRING, &subject, "One line subject", "subject" },
|
{ "subject", 's', 0, G_OPTION_ARG_STRING, &subject, "One line subject", "subject" },
|
||||||
|
|
@ -45,6 +47,8 @@ static GOptionEntry options[] = {
|
||||||
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
|
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
|
||||||
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
|
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
|
||||||
{ "tar", 0, 0, G_OPTION_ARG_NONE, &tar, "Given argument is a tar file", NULL },
|
{ "tar", 0, 0, G_OPTION_ARG_NONE, &tar, "Given argument is a tar file", NULL },
|
||||||
|
{ "owner-uid", 0, 0, G_OPTION_ARG_INT, &owner_uid, "Set file ownership user id", "UID" },
|
||||||
|
{ "owner-gid", 0, 0, G_OPTION_ARG_INT, &owner_gid, "Set file ownership group id", "GID" },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -60,6 +64,7 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||||
GVariant *metadata = NULL;
|
GVariant *metadata = NULL;
|
||||||
GMappedFile *metadata_mappedf = NULL;
|
GMappedFile *metadata_mappedf = NULL;
|
||||||
GFile *metadata_f = NULL;
|
GFile *metadata_f = NULL;
|
||||||
|
OstreeRepoCommitModifier *modifier = NULL;
|
||||||
|
|
||||||
context = g_option_context_new ("[ARG] - Commit a new revision");
|
context = g_option_context_new ("[ARG] - Commit a new revision");
|
||||||
g_option_context_add_main_entries (context, options, NULL);
|
g_option_context_add_main_entries (context, options, NULL);
|
||||||
|
|
@ -126,16 +131,23 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (owner_uid >= 0 || owner_gid >= 0)
|
||||||
|
{
|
||||||
|
modifier = ostree_repo_commit_modifier_new ();
|
||||||
|
modifier->uid = owner_uid;
|
||||||
|
modifier->gid = owner_gid;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tar)
|
if (!tar)
|
||||||
{
|
{
|
||||||
if (!ostree_repo_commit_directory (repo, branch, parent, subject, body, metadata,
|
if (!ostree_repo_commit_directory (repo, branch, parent, subject, body, metadata,
|
||||||
arg, &commit_checksum, NULL, error))
|
arg, modifier, &commit_checksum, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ostree_repo_commit_tarfile (repo, branch, parent, subject, body, metadata,
|
if (!ostree_repo_commit_tarfile (repo, branch, parent, subject, body, metadata,
|
||||||
arg, &commit_checksum, NULL, error))
|
arg, modifier, &commit_checksum, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,6 +160,8 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
|
||||||
g_mapped_file_unref (metadata_mappedf);
|
g_mapped_file_unref (metadata_mappedf);
|
||||||
if (context)
|
if (context)
|
||||||
g_option_context_free (context);
|
g_option_context_free (context);
|
||||||
|
if (modifier)
|
||||||
|
ostree_repo_commit_modifier_unref (modifier);
|
||||||
g_clear_object (&repo);
|
g_clear_object (&repo);
|
||||||
ot_clear_checksum (&commit_checksum);
|
ot_clear_checksum (&commit_checksum);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ set -e
|
||||||
|
|
||||||
. libtest.sh
|
. libtest.sh
|
||||||
|
|
||||||
echo '1..6'
|
echo '1..9'
|
||||||
|
|
||||||
setup_test_repository "archive"
|
setup_test_repository "archive"
|
||||||
echo "ok setup"
|
echo "ok setup"
|
||||||
|
|
@ -50,3 +50,15 @@ echo "ok local clone checkout"
|
||||||
|
|
||||||
$OSTREE checkout -U test2 checkout-user-test2
|
$OSTREE checkout -U test2 checkout-user-test2
|
||||||
echo "ok user checkout"
|
echo "ok user checkout"
|
||||||
|
|
||||||
|
cd ${test_tmpdir}/checkout-test2
|
||||||
|
$OSTREE commit -b test2-uid0 -s 'UID 0 test' --owner-uid=0 --owner-gid=0
|
||||||
|
echo "ok uid0 commit"
|
||||||
|
|
||||||
|
cd ${test_tmpdir}
|
||||||
|
$OSTREE ls test2-uid0 /firstfile > uid0-ls-output.txt
|
||||||
|
assert_file_has_content uid0-ls-output.txt "-00664 0 0 0 /firstfile"
|
||||||
|
echo "ok uid0 ls"
|
||||||
|
|
||||||
|
$OSTREE checkout -U test2-uid0 checkout-user-test2-uid0
|
||||||
|
echo "ok user checkout from uid 0"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue