New upstream version 2018.5
This commit is contained in:
commit
144d8ab093
74 files changed
+2347
-4165
No files matched your search
@@ -18,8 +18,6 @@
|
||||
***/
|
||||
|
||||
/* Add new symbols here. Release commits should copy this section into -released.sym. */
|
||||
LIBOSTREE_2018.5 {
|
||||
} LIBOSTREE_2018.3;
|
||||
|
||||
/* Stub section for the stable release *after* this development one; don't
|
||||
* edit this other than to update the last number. This is just a copy/paste
|
||||
|
||||
@@ -94,8 +94,4 @@ LIBOSTREE_2017.14_EXPERIMENTAL {
|
||||
global:
|
||||
ostree_remote_get_type;
|
||||
ostree_remote_get_url;
|
||||
ostree_repo_auto_lock_cleanup;
|
||||
ostree_repo_auto_lock_push;
|
||||
ostree_repo_lock_pop;
|
||||
ostree_repo_lock_push;
|
||||
} LIBOSTREE_2017.13_EXPERIMENTAL;
|
||||
@@ -464,6 +464,15 @@ LIBOSTREE_2018.3 {
|
||||
ostree_deployment_is_pinned;
|
||||
} LIBOSTREE_2018.2;
|
||||
|
||||
LIBOSTREE_2018.5 {
|
||||
ostree_sysroot_stage_tree;
|
||||
ostree_sysroot_get_staged_deployment;
|
||||
ostree_deployment_is_staged;
|
||||
ostree_repo_traverse_new_parents;
|
||||
ostree_repo_traverse_parents_get_commits;
|
||||
ostree_repo_traverse_commit_union_with_parents;
|
||||
} LIBOSTREE_2018.3;
|
||||
|
||||
/* NOTE: Only add more content here in release commits! See the
|
||||
* comments at the top of this file.
|
||||
*/
|
||||
@@ -61,7 +61,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSysrootUpgrader, g_object_unref)
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (OstreeRepoCommitTraverseIter, ostree_repo_commit_traverse_iter_clear)
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, ostree_repo_auto_lock_cleanup)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeCollectionRef, ostree_collection_ref_free)
|
||||
G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeCollectionRefv, ostree_collection_ref_freev, NULL)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRemote, ostree_remote_unref)
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-repo-pull-private.h"
|
||||
#include "ostree-repo-static-delta-private.h"
|
||||
#include "ostree-sysroot.h"
|
||||
#include "ostree-sysroot-private.h"
|
||||
#include "ostree-bootloader-grub2.h"
|
||||
|
||||
#include "otutil.h"
|
||||
@@ -52,7 +52,8 @@ ostree_cmd__private__ (void)
|
||||
_ostree_repo_static_delta_dump,
|
||||
_ostree_repo_static_delta_query_exists,
|
||||
_ostree_repo_static_delta_delete,
|
||||
_ostree_repo_verify_bindings
|
||||
_ostree_repo_verify_bindings,
|
||||
_ostree_sysroot_finalize_staged,
|
||||
};
|
||||
|
||||
return &table;
|
||||
|
||||
@@ -34,6 +34,7 @@ typedef struct {
|
||||
gboolean (* ostree_static_delta_query_exists) (OstreeRepo *repo, const char *delta_id, gboolean *out_exists, GCancellable *cancellable, GError **error);
|
||||
gboolean (* ostree_static_delta_delete) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error);
|
||||
gboolean (* ostree_repo_verify_bindings) (const char *collection_id, const char *ref_name, GVariant *commit, GError **error);
|
||||
gboolean (* ostree_finalize_staged) (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
|
||||
} OstreeCmdPrivateVTable;
|
||||
|
||||
/* Note this not really "public", we just export the symbol, but not the header */
|
||||
|
||||
@@ -36,6 +36,7 @@ G_BEGIN_DECLS
|
||||
* @bootconfig: Bootloader configuration
|
||||
* @origin: How to construct an upgraded version of this tree
|
||||
* @unlocked: The unlocked state
|
||||
* @staged: TRUE iff this deployment is staged
|
||||
*/
|
||||
struct _OstreeDeployment
|
||||
{
|
||||
@@ -50,6 +51,7 @@ struct _OstreeDeployment
|
||||
OstreeBootconfigParser *bootconfig;
|
||||
GKeyFile *origin;
|
||||
OstreeDeploymentUnlockedState unlocked;
|
||||
gboolean staged;
|
||||
};
|
||||
|
||||
void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum);
|
||||
|
||||
@@ -339,3 +339,16 @@ ostree_deployment_is_pinned (OstreeDeployment *self)
|
||||
return FALSE;
|
||||
return g_key_file_get_boolean (self->origin, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_deployment_is_staged:
|
||||
* @self: Deployment
|
||||
*
|
||||
* Returns: `TRUE` if deployment should be "finalized" at shutdown time
|
||||
* Since: 2018.3
|
||||
*/
|
||||
gboolean
|
||||
ostree_deployment_is_staged (OstreeDeployment *self)
|
||||
{
|
||||
return self->staged;
|
||||
}
|
||||
@@ -73,7 +73,8 @@ OstreeBootconfigParser *ostree_deployment_get_bootconfig (OstreeDeployment *self
|
||||
_OSTREE_PUBLIC
|
||||
GKeyFile *ostree_deployment_get_origin (OstreeDeployment *self);
|
||||
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_deployment_is_staged (OstreeDeployment *self);
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_deployment_is_pinned (OstreeDeployment *self);
|
||||
|
||||
|
||||
@@ -598,27 +598,26 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_check_support_reflink (OstreeRepo *self, gboolean *supported, GError **error)
|
||||
_check_support_reflink (OstreeRepo *dest, gboolean *supported, GError **error)
|
||||
{
|
||||
/* We have not checked yet if the file system supports reflinks, do it here */
|
||||
if (g_atomic_int_get (&self->fs_support_reflink) == 0)
|
||||
/* We have not checked yet if the destination file system supports reflinks, do it here */
|
||||
if (g_atomic_int_get (&dest->fs_support_reflink) == 0)
|
||||
{
|
||||
g_auto(GLnxTmpfile) src_tmpf = { 0, };
|
||||
glnx_autofd int src_fd = -1;
|
||||
g_auto(GLnxTmpfile) dest_tmpf = { 0, };
|
||||
|
||||
if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_RDWR|O_CLOEXEC,
|
||||
&src_tmpf, error))
|
||||
if (!glnx_openat_rdonly (dest->repo_dir_fd, "config", TRUE, &src_fd, error))
|
||||
return FALSE;
|
||||
if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_WRONLY|O_CLOEXEC,
|
||||
if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (dest), ".", O_WRONLY|O_CLOEXEC,
|
||||
&dest_tmpf, error))
|
||||
return FALSE;
|
||||
|
||||
if (ioctl (dest_tmpf.fd, FICLONE, src_tmpf.fd) == 0)
|
||||
g_atomic_int_set (&self->fs_support_reflink, 1);
|
||||
if (ioctl (dest_tmpf.fd, FICLONE, src_fd) == 0)
|
||||
g_atomic_int_set (&dest->fs_support_reflink, 1);
|
||||
else if (errno == EOPNOTSUPP) /* Ignore other kind of errors as they might be temporary failures */
|
||||
g_atomic_int_set (&self->fs_support_reflink, -1);
|
||||
g_atomic_int_set (&dest->fs_support_reflink, -1);
|
||||
}
|
||||
*supported = g_atomic_int_get (&self->fs_support_reflink) >= 0;
|
||||
*supported = g_atomic_int_get (&dest->fs_support_reflink) >= 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -631,6 +630,7 @@ _create_payload_link (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean reflinks_supported = FALSE;
|
||||
|
||||
if (!_check_support_reflink (self, &reflinks_supported, error))
|
||||
return FALSE;
|
||||
|
||||
@@ -664,8 +664,8 @@ _create_payload_link (OstreeRepo *self,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_import_payload_link (OstreeRepo *self,
|
||||
OstreeRepo *source,
|
||||
_import_payload_link (OstreeRepo *dest_repo,
|
||||
OstreeRepo *src_repo,
|
||||
const char *checksum,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@@ -676,20 +676,24 @@ _import_payload_link (OstreeRepo *self,
|
||||
glnx_unref_object OtChecksumInstream *checksum_payload = NULL;
|
||||
g_autoptr(GFileInfo) file_info = NULL;
|
||||
|
||||
if (!_check_support_reflink (self, &reflinks_supported, error))
|
||||
/* The two repositories are on different devices */
|
||||
if (src_repo->device != dest_repo->device)
|
||||
return TRUE;
|
||||
|
||||
if (!_check_support_reflink (dest_repo, &reflinks_supported, error))
|
||||
return FALSE;
|
||||
|
||||
if (!reflinks_supported)
|
||||
return TRUE;
|
||||
|
||||
if (!G_IN_SET(self->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY))
|
||||
if (!G_IN_SET(dest_repo->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY))
|
||||
return TRUE;
|
||||
|
||||
if (!ostree_repo_load_file (source, checksum, &is, &file_info, NULL, cancellable, error))
|
||||
if (!ostree_repo_load_file (src_repo, checksum, &is, &file_info, NULL, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR
|
||||
|| g_file_info_get_size (file_info) < self->payload_link_threshold)
|
||||
|| g_file_info_get_size (file_info) < dest_repo->payload_link_threshold)
|
||||
return TRUE;
|
||||
|
||||
checksum_payload = ot_checksum_instream_new (is, G_CHECKSUM_SHA256);
|
||||
@@ -706,11 +710,12 @@ _import_payload_link (OstreeRepo *self,
|
||||
}
|
||||
payload_checksum = ot_checksum_instream_get_string (checksum_payload);
|
||||
|
||||
return _create_payload_link (self, checksum, payload_checksum, file_info, cancellable, error);
|
||||
return _create_payload_link (dest_repo, checksum, payload_checksum, file_info, cancellable, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_try_clone_from_payload_link (OstreeRepo *self,
|
||||
OstreeRepo *dest_repo,
|
||||
const char *payload_checksum,
|
||||
GFileInfo *file_info,
|
||||
GLnxTmpfile *tmpf,
|
||||
@@ -722,7 +727,11 @@ _try_clone_from_payload_link (OstreeRepo *self,
|
||||
if (self->commit_stagedir.initialized)
|
||||
dfd_searches[0] = self->commit_stagedir.fd;
|
||||
|
||||
if (!_check_support_reflink (self, &reflinks_supported, error))
|
||||
/* The two repositories are on different devices */
|
||||
if (self->device != dest_repo->device)
|
||||
return TRUE;
|
||||
|
||||
if (!_check_support_reflink (dest_repo, &reflinks_supported, error))
|
||||
return FALSE;
|
||||
|
||||
if (!reflinks_supported)
|
||||
@@ -778,7 +787,7 @@ _try_clone_from_payload_link (OstreeRepo *self,
|
||||
}
|
||||
}
|
||||
if (self->parent_repo)
|
||||
return _try_clone_from_payload_link (self->parent_repo, payload_checksum, file_info, tmpf, cancellable, error);
|
||||
return _try_clone_from_payload_link (self->parent_repo, dest_repo, payload_checksum, file_info, tmpf, cancellable, error);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1073,7 +1082,7 @@ write_content_object (OstreeRepo *self,
|
||||
|
||||
/* Check if a file with the same payload is present in the repository,
|
||||
and in case try to reflink it */
|
||||
if (actual_payload_checksum && !_try_clone_from_payload_link (self, actual_payload_checksum, file_info, &tmpf, cancellable, error))
|
||||
if (actual_payload_checksum && !_try_clone_from_payload_link (self, self, actual_payload_checksum, file_info, &tmpf, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
/* This path is for regular files */
|
||||
@@ -1246,7 +1255,7 @@ write_metadata_object (OstreeRepo *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
OtChecksum checksum = { 0, };
|
||||
g_auto(OtChecksum) checksum = { 0, };
|
||||
ot_checksum_init (&checksum);
|
||||
gsize len;
|
||||
const guint8*bufdata = g_bytes_get_data (buf, &len);
|
||||
@@ -1440,7 +1449,8 @@ scan_loose_devino (OstreeRepo *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (self->mode == OSTREE_REPO_MODE_ARCHIVE)
|
||||
if (self->mode == OSTREE_REPO_MODE_ARCHIVE &&
|
||||
self->uncompressed_objects_dir_fd != -1)
|
||||
{
|
||||
if (!scan_one_loose_devino (self, self->uncompressed_objects_dir_fd, devino_cache,
|
||||
cancellable, error))
|
||||
@@ -1500,7 +1510,7 @@ devino_cache_lookup (OstreeRepo *self,
|
||||
* There is an upfront cost to creating this mapping, as this will scan the
|
||||
* entire objects directory. If your commit is composed of mostly hardlinks to
|
||||
* existing ostree objects, then this will speed up considerably, so call it
|
||||
* before you call ostree_write_directory_to_mtree() or similar. However,
|
||||
* before you call ostree_repo_write_directory_to_mtree() or similar. However,
|
||||
* ostree_repo_devino_cache_new() is better as it avoids scanning all objects.
|
||||
*
|
||||
* Multithreading: This function is *not* MT safe.
|
||||
@@ -1541,10 +1551,9 @@ ostree_repo_scan_hardlinks (OstreeRepo *self,
|
||||
* on a single `OstreeRepo` instance as long as their lifetime is bounded by the
|
||||
* transaction.
|
||||
*
|
||||
* Locking: Acquires a `shared` lock; release via commit or abort
|
||||
* Multithreading: This function is *not* MT safe; only one transaction can be
|
||||
* active at a time.
|
||||
*
|
||||
* This function takes a shared lock on the @self repository.
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_prepare_transaction (OstreeRepo *self,
|
||||
@@ -1557,8 +1566,8 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
|
||||
|
||||
memset (&self->txn.stats, 0, sizeof (OstreeRepoTransactionStats));
|
||||
|
||||
self->txn_locked = ostree_repo_lock_push (self, OSTREE_REPO_LOCK_SHARED,
|
||||
cancellable, error);
|
||||
self->txn_locked = _ostree_repo_lock_push (self, OSTREE_REPO_LOCK_SHARED,
|
||||
cancellable, error);
|
||||
if (!self->txn_locked)
|
||||
return FALSE;
|
||||
|
||||
@@ -2070,6 +2079,7 @@ ostree_repo_set_collection_ref_immediate (OstreeRepo *self,
|
||||
* Note that if multiple threads are performing writes, all such threads must
|
||||
* have terminated before this function is invoked.
|
||||
*
|
||||
* Locking: Releases `shared` lock acquired by `ostree_repo_prepare_transaction()`
|
||||
* Multithreading: This function is *not* MT safe; only one transaction can be
|
||||
* active at a time.
|
||||
*/
|
||||
@@ -2126,7 +2136,7 @@ ostree_repo_commit_transaction (OstreeRepo *self,
|
||||
|
||||
if (self->txn_locked)
|
||||
{
|
||||
if (!ostree_repo_lock_pop (self, cancellable, error))
|
||||
if (!_ostree_repo_lock_pop (self, cancellable, error))
|
||||
return FALSE;
|
||||
self->txn_locked = FALSE;
|
||||
}
|
||||
@@ -2179,7 +2189,7 @@ ostree_repo_abort_transaction (OstreeRepo *self,
|
||||
|
||||
if (self->txn_locked)
|
||||
{
|
||||
if (!ostree_repo_lock_pop (self, cancellable, error))
|
||||
if (!_ostree_repo_lock_pop (self, cancellable, error))
|
||||
return FALSE;
|
||||
self->txn_locked = FALSE;
|
||||
}
|
||||
@@ -2216,7 +2226,7 @@ metadata_size_valid (OstreeObjectType objtype,
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Store the metadata object @variant. Return the checksum
|
||||
* Store the metadata object @object. Return the checksum
|
||||
* as @out_csum.
|
||||
*
|
||||
* If @expected_checksum is not %NULL, verify it against the
|
||||
|
||||
@@ -844,7 +844,7 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService
|
||||
}
|
||||
|
||||
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, OSTREE_REPO_FINDER (finder),
|
||||
priority, supported_ref_to_checksum,
|
||||
priority, supported_ref_to_checksum, NULL,
|
||||
GUINT64_FROM_BE (g_variant_get_uint64 (summary_timestamp))));
|
||||
}
|
||||
}
|
||||
@@ -1437,9 +1437,15 @@ ostree_repo_finder_avahi_start (OstreeRepoFinderAvahi *self,
|
||||
|
||||
if (client == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Failed to create finder client: %s",
|
||||
avahi_strerror (failure));
|
||||
if (failure == AVAHI_ERR_NO_DAEMON)
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"Avahi daemon is not running: %s",
|
||||
avahi_strerror (failure));
|
||||
else
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Failed to create finder client: %s",
|
||||
avahi_strerror (failure));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
|
||||
continue;
|
||||
}
|
||||
|
||||
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
|
||||
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
|
||||
}
|
||||
|
||||
g_ptr_array_sort (results, results_compare_cb);
|
||||
|
||||
@@ -434,7 +434,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
g_array_sort (repos_refs, repo_and_refs_compare);
|
||||
|
||||
/* Also check the well-known special-case directories in the mount.
|
||||
* Add them after sorting, so they’re always last. */
|
||||
* Add them after sorting, so they’re always last.
|
||||
* NOTE: If you change these, update the man page. */
|
||||
const gchar * const well_known_repos[] =
|
||||
{
|
||||
".ostree/repo",
|
||||
@@ -545,7 +546,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
* the code in ostree_repo_pull_from_remotes_async() will be able to
|
||||
* check it just as quickly as we can here; so don’t duplicate the
|
||||
* code. */
|
||||
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
|
||||
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ ostree_repo_finder_override_resolve_async (OstreeRepoFinder *fi
|
||||
g_hash_table_iter_init (&iter, repo_remote_to_refs);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &remote, (gpointer *) &supported_ref_to_checksum))
|
||||
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
|
||||
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
|
||||
|
||||
g_ptr_array_sort (results, results_compare_cb);
|
||||
|
||||
|
||||
@@ -132,8 +132,8 @@ static void resolve_cb (GObject *obj,
|
||||
* which the result provides. If the result provides the latest commit for a ref
|
||||
* across all of the results, the checksum will be set. Otherwise, if the
|
||||
* result provides an outdated commit, or doesn’t provide a given ref at all,
|
||||
* the ref will not be set. Results which provide none of the requested @refs
|
||||
* may be listed with an empty refs map.
|
||||
* the checksum will not be set. Results which provide none of the requested
|
||||
* @refs may be listed with an empty refs map.
|
||||
*
|
||||
* Pass the results to ostree_repo_pull_from_remotes_async() to pull the given
|
||||
* @refs from those remotes.
|
||||
@@ -436,6 +436,9 @@ G_DEFINE_BOXED_TYPE (OstreeRepoFinderResult, ostree_repo_finder_result,
|
||||
* priority
|
||||
* @ref_to_checksum: (element-type OstreeCollectionRef utf8) (transfer none):
|
||||
* map of collection–ref pairs to checksums provided by this result
|
||||
* @ref_to_timestamp: (element-type OstreeCollectionRef guint64) (nullable)
|
||||
* (transfer none): map of collection–ref pairs to timestamps provided by this
|
||||
* result
|
||||
* @summary_last_modified: Unix timestamp (seconds since the epoch, UTC) when
|
||||
* the summary file for the result was last modified, or `0` if this is unknown
|
||||
*
|
||||
@@ -450,6 +453,7 @@ ostree_repo_finder_result_new (OstreeRemote *remote,
|
||||
OstreeRepoFinder *finder,
|
||||
gint priority,
|
||||
GHashTable *ref_to_checksum,
|
||||
GHashTable *ref_to_timestamp,
|
||||
guint64 summary_last_modified)
|
||||
{
|
||||
g_autoptr(OstreeRepoFinderResult) result = NULL;
|
||||
@@ -463,6 +467,7 @@ ostree_repo_finder_result_new (OstreeRemote *remote,
|
||||
result->finder = g_object_ref (finder);
|
||||
result->priority = priority;
|
||||
result->ref_to_checksum = g_hash_table_ref (ref_to_checksum);
|
||||
result->ref_to_timestamp = ref_to_timestamp != NULL ? g_hash_table_ref (ref_to_timestamp) : NULL;
|
||||
result->summary_last_modified = summary_last_modified;
|
||||
|
||||
return g_steal_pointer (&result);
|
||||
@@ -484,7 +489,7 @@ ostree_repo_finder_result_dup (OstreeRepoFinderResult *result)
|
||||
|
||||
return ostree_repo_finder_result_new (result->remote, result->finder,
|
||||
result->priority, result->ref_to_checksum,
|
||||
result->summary_last_modified);
|
||||
result->ref_to_timestamp, result->summary_last_modified);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -554,6 +559,7 @@ ostree_repo_finder_result_free (OstreeRepoFinderResult *result)
|
||||
/* This may be NULL iff the result is freed half-way through find_remotes_cb()
|
||||
* in ostree-repo-pull.c, and at no other time. */
|
||||
g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref);
|
||||
g_clear_pointer (&result->ref_to_timestamp, g_hash_table_unref);
|
||||
g_object_unref (result->finder);
|
||||
ostree_remote_unref (result->remote);
|
||||
g_free (result);
|
||||
|
||||
@@ -99,6 +99,8 @@ GPtrArray *ostree_repo_finder_resolve_all_finish (GAsyncResult *result,
|
||||
* @ref_to_checksum: (element-type OstreeCollectionRef utf8): map of collection–ref
|
||||
* pairs to checksums provided by this remote; values may be %NULL to
|
||||
* indicate this remote doesn’t provide that ref
|
||||
* @ref_to_timestamp: (element-type OstreeCollectionRef guint64) (nullable): map of
|
||||
* collection–ref pairs to timestamps; values may be 0 for various reasons
|
||||
* @summary_last_modified: Unix timestamp (seconds since the epoch, UTC) when
|
||||
* the summary file on the remote was last modified, or `0` if unknown
|
||||
*
|
||||
@@ -122,6 +124,15 @@ GPtrArray *ostree_repo_finder_resolve_all_finish (GAsyncResult *result,
|
||||
* should be available locally, so the details for each checksum can be looked
|
||||
* up using ostree_repo_load_commit().
|
||||
*
|
||||
* @ref_to_timestamp provides timestamps for the set of refs in
|
||||
* @ref_to_checksum. The refs are keys (of type #OstreeCollectionRef) and the
|
||||
* values are guint64 pointers with the timestamp associated with the checksum
|
||||
* provided in @ref_to_checksum. @ref_to_timestamp can be %NULL, and when it's
|
||||
* not, the timestamps are zero when any of the following conditions are met:
|
||||
* (1) the override-commit-ids option was used on
|
||||
* ostree_repo_find_remotes_async (2) there was an error in trying to get the
|
||||
* commit metadata (3) the checksum for this ref is %NULL in @ref_to_checksum.
|
||||
*
|
||||
* Since: 2017.8
|
||||
*/
|
||||
typedef struct
|
||||
@@ -131,9 +142,10 @@ typedef struct
|
||||
gint priority;
|
||||
GHashTable *ref_to_checksum;
|
||||
guint64 summary_last_modified;
|
||||
GHashTable *ref_to_timestamp;
|
||||
|
||||
/*< private >*/
|
||||
gpointer padding[4];
|
||||
gpointer padding[3];
|
||||
} OstreeRepoFinderResult;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
@@ -144,6 +156,7 @@ OstreeRepoFinderResult *ostree_repo_finder_result_new (OstreeRemote *remote,
|
||||
OstreeRepoFinder *finder,
|
||||
gint priority,
|
||||
GHashTable *ref_to_checksum,
|
||||
GHashTable *ref_to_timestamp,
|
||||
guint64 summary_last_modified);
|
||||
_OSTREE_PUBLIC
|
||||
OstreeRepoFinderResult *ostree_repo_finder_result_dup (OstreeRepoFinderResult *result);
|
||||
|
||||
@@ -435,34 +435,36 @@ _ostree_repo_get_remote_inherited (OstreeRepo *self,
|
||||
const char *name,
|
||||
GError **error);
|
||||
|
||||
#ifndef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
|
||||
/* All the locking APIs below are duplicated in ostree-repo.h. Remove the ones
|
||||
* here once it's no longer experimental.
|
||||
/* Locking APIs are currently private.
|
||||
* See https://github.com/ostreedev/ostree/pull/1555
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
OSTREE_REPO_LOCK_SHARED,
|
||||
OSTREE_REPO_LOCK_EXCLUSIVE
|
||||
} OstreeRepoLockType;
|
||||
|
||||
gboolean ostree_repo_lock_push (OstreeRepo *self,
|
||||
gboolean _ostree_repo_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean ostree_repo_lock_pop (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean _ostree_repo_lock_pop (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
typedef OstreeRepo OstreeRepoAutoLock;
|
||||
|
||||
OstreeRepoAutoLock * ostree_repo_auto_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
void ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, ostree_repo_auto_lock_cleanup)
|
||||
OstreeRepoAutoLock * _ostree_repo_auto_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
void _ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, _ostree_repo_auto_lock_cleanup)
|
||||
|
||||
#ifndef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
|
||||
/* These APIs are duplicated in the public headers when doing an
|
||||
* experimental-API build.
|
||||
*/
|
||||
const gchar * ostree_repo_get_collection_id (OstreeRepo *self);
|
||||
gboolean ostree_repo_set_collection_id (OstreeRepo *self,
|
||||
const gchar *collection_id,
|
||||
|
||||
@@ -193,7 +193,7 @@ _ostree_repo_prune_tmp (OstreeRepo *self,
|
||||
* targeting that commit; otherwise any static delta of non existing commits are
|
||||
* deleted.
|
||||
*
|
||||
* This function takes an exclusive lock on the @self repository.
|
||||
* Locking: exclusive
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
|
||||
@@ -201,8 +201,7 @@ ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(OstreeRepoAutoLock) lock =
|
||||
ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable,
|
||||
error);
|
||||
_ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
|
||||
if (!lock)
|
||||
return FALSE;
|
||||
|
||||
@@ -327,7 +326,7 @@ repo_prune_internal (OstreeRepo *self,
|
||||
* statistics on objects that would be deleted, without actually
|
||||
* deleting them.
|
||||
*
|
||||
* This function takes an exclusive lock on the @self repository.
|
||||
* Locking: exclusive
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_prune (OstreeRepo *self,
|
||||
@@ -340,8 +339,7 @@ ostree_repo_prune (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(OstreeRepoAutoLock) lock =
|
||||
ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable,
|
||||
error);
|
||||
_ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
|
||||
if (!lock)
|
||||
return FALSE;
|
||||
|
||||
@@ -440,7 +438,7 @@ ostree_repo_prune (OstreeRepo *self,
|
||||
* The %OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE flag may be specified to just determine
|
||||
* statistics on objects that would be deleted, without actually deleting them.
|
||||
*
|
||||
* This function takes an exclusive lock on the @self repository.
|
||||
* Locking: exclusive
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_prune_from_reachable (OstreeRepo *self,
|
||||
@@ -452,8 +450,7 @@ ostree_repo_prune_from_reachable (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(OstreeRepoAutoLock) lock =
|
||||
ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable,
|
||||
error);
|
||||
_ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
|
||||
if (!lock)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -2913,6 +2913,7 @@ repo_remote_fetch_summary (OstreeRepo *self,
|
||||
GVariant *options,
|
||||
GBytes **out_summary,
|
||||
GBytes **out_signatures,
|
||||
gboolean *out_from_cache,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
@@ -3015,32 +3016,13 @@ repo_remote_fetch_summary (OstreeRepo *self,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!from_cache && *out_summary && *out_signatures)
|
||||
{
|
||||
g_autoptr(GError) temp_error = NULL;
|
||||
|
||||
if (!_ostree_repo_cache_summary (self,
|
||||
name,
|
||||
*out_summary,
|
||||
*out_signatures,
|
||||
cancellable,
|
||||
&temp_error))
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
|
||||
g_debug ("No permissions to save summary cache");
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, g_steal_pointer (&temp_error));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (mainctx)
|
||||
g_main_context_pop_thread_default (mainctx);
|
||||
|
||||
*out_from_cache = from_cache;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4704,7 +4686,20 @@ ostree_repo_find_remotes_async (OstreeRepo *self,
|
||||
|
||||
if (local_error != NULL)
|
||||
{
|
||||
g_warning ("Avahi finder failed; removing it: %s", local_error->message);
|
||||
/* See ostree-repo-finder-avahi.c:ostree_repo_finder_avahi_start, we
|
||||
* intentionally throw this so as to distinguish between the Avahi
|
||||
* finder failing because the Avahi daemon wasn't running and
|
||||
* the Avahi finder failing because of some actual error.
|
||||
*
|
||||
* We need to distinguish between g_debug and g_warning here because
|
||||
* unit tests that use this code may set G_DEBUG=fatal-warnings which
|
||||
* would cause client code to abort if a warning were emitted.
|
||||
*/
|
||||
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
g_debug ("Avahi finder failed under normal operation; removing it: %s", local_error->message);
|
||||
else
|
||||
g_warning ("Avahi finder failed abnormally; removing it: %s", local_error->message);
|
||||
|
||||
default_finders[2] = NULL;
|
||||
g_clear_object (&finder_avahi);
|
||||
}
|
||||
@@ -4764,7 +4759,7 @@ find_remotes_process_refs (OstreeRepo *self,
|
||||
for (j = 0, n = g_variant_n_children (summary_refs); j < n; j++)
|
||||
{
|
||||
const guchar *csum_bytes;
|
||||
g_autoptr(GVariant) ref_v = NULL, csum_v = NULL, commit_metadata_v = NULL, stored_commit_metadata_v = NULL;
|
||||
g_autoptr(GVariant) ref_v = NULL, csum_v = NULL, commit_metadata_v = NULL, stored_commit_v = NULL;
|
||||
guint64 commit_size, commit_timestamp;
|
||||
gchar tmp_checksum[OSTREE_SHA256_STRING_LEN + 1];
|
||||
gsize ref_index;
|
||||
@@ -4801,9 +4796,9 @@ find_remotes_process_refs (OstreeRepo *self,
|
||||
if (!collection_refv_contains (refs, summary_collection_id, ref_name, &ref_index))
|
||||
continue;
|
||||
|
||||
/* Load the commit metadata from disk if possible, for verification. */
|
||||
if (!ostree_repo_load_commit (self, tmp_checksum, &stored_commit_metadata_v, NULL, NULL))
|
||||
stored_commit_metadata_v = NULL;
|
||||
/* Load the commit from disk if possible, for verification. */
|
||||
if (!ostree_repo_load_commit (self, tmp_checksum, &stored_commit_v, NULL, NULL))
|
||||
stored_commit_v = NULL;
|
||||
|
||||
/* Check the additional metadata. */
|
||||
if (!g_variant_lookup (commit_metadata_v, OSTREE_COMMIT_TIMESTAMP, "t", &commit_timestamp))
|
||||
@@ -4826,7 +4821,7 @@ find_remotes_process_refs (OstreeRepo *self,
|
||||
if (commit_metadata == NULL)
|
||||
{
|
||||
commit_metadata = commit_metadata_new (tmp_checksum, commit_size,
|
||||
(stored_commit_metadata_v != NULL) ? ostree_commit_get_timestamp (stored_commit_metadata_v) : 0,
|
||||
(stored_commit_v != NULL) ? ostree_commit_get_timestamp (stored_commit_v) : 0,
|
||||
NULL);
|
||||
g_hash_table_insert (commit_metadatas, commit_metadata->checksum,
|
||||
commit_metadata /* transfer */);
|
||||
@@ -4880,6 +4875,7 @@ find_remotes_cb (GObject *obj,
|
||||
g_autoptr(GHashTable) commit_metadatas = NULL; /* (element-type commit-checksum CommitMetadata) */
|
||||
g_autoptr(OstreeFetcher) fetcher = NULL;
|
||||
g_autofree const gchar **ref_to_latest_commit = NULL; /* indexed as @refs; (element-type commit-checksum) */
|
||||
g_autofree guint64 *ref_to_latest_timestamp = NULL; /* indexed as @refs; (element-type commit-timestamp) */
|
||||
gsize n_refs;
|
||||
g_autofree char **override_commit_ids = NULL;
|
||||
g_autoptr(GPtrArray) remotes_to_remove = NULL; /* (element-type OstreeRemote) */
|
||||
@@ -5035,6 +5031,7 @@ find_remotes_cb (GObject *obj,
|
||||
* it’s been moved to @refs_and_remotes_table and is now potentially out
|
||||
* of date. */
|
||||
g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref);
|
||||
g_clear_pointer (&result->ref_to_timestamp, g_hash_table_unref);
|
||||
result->summary_last_modified = summary_last_modified;
|
||||
}
|
||||
|
||||
@@ -5171,8 +5168,12 @@ find_remotes_cb (GObject *obj,
|
||||
*
|
||||
* @ref_to_latest_commit is indexed by @ref_index, and its values are the
|
||||
* latest checksum for each ref. If override-commit-ids was used,
|
||||
* @ref_to_latest_commit won't be initialized or used.*/
|
||||
* @ref_to_latest_commit won't be initialized or used.
|
||||
*
|
||||
* @ref_to_latest_timestamp is also indexed by @ref_index, and its values are
|
||||
* the latest timestamp for each ref, when available.*/
|
||||
ref_to_latest_commit = g_new0 (const gchar *, n_refs);
|
||||
ref_to_latest_timestamp = g_new0 (guint64, n_refs);
|
||||
|
||||
for (i = 0; i < n_refs; i++)
|
||||
{
|
||||
@@ -5213,6 +5214,11 @@ find_remotes_cb (GObject *obj,
|
||||
* the summary or commit metadata files above. */
|
||||
ref_to_latest_commit[i] = latest_checksum;
|
||||
|
||||
if (latest_checksum != NULL && latest_commit_metadata != NULL)
|
||||
ref_to_latest_timestamp[i] = latest_commit_metadata->timestamp;
|
||||
else
|
||||
ref_to_latest_timestamp[i] = 0;
|
||||
|
||||
if (latest_commit_metadata != NULL)
|
||||
{
|
||||
latest_commit_timestamp_str = uint64_secs_to_iso8601 (latest_commit_metadata->timestamp);
|
||||
@@ -5235,7 +5241,8 @@ find_remotes_cb (GObject *obj,
|
||||
for (i = 0; i < results->len; i++)
|
||||
{
|
||||
OstreeRepoFinderResult *result = g_ptr_array_index (results, i);
|
||||
g_autoptr(GHashTable) validated_ref_to_checksum = NULL; /* (element-type utf8 utf8) */
|
||||
g_autoptr(GHashTable) validated_ref_to_checksum = NULL; /* (element-type OstreeCollectionRef utf8) */
|
||||
g_autoptr(GHashTable) validated_ref_to_timestamp = NULL; /* (element-type OstreeCollectionRef guint64) */
|
||||
gsize j, n_latest_refs;
|
||||
|
||||
/* Previous error processing this result? */
|
||||
@@ -5249,11 +5256,24 @@ find_remotes_cb (GObject *obj,
|
||||
(GDestroyNotify) ostree_collection_ref_free,
|
||||
g_free);
|
||||
|
||||
validated_ref_to_timestamp = g_hash_table_new_full (ostree_collection_ref_hash,
|
||||
ostree_collection_ref_equal,
|
||||
(GDestroyNotify) ostree_collection_ref_free,
|
||||
g_free);
|
||||
if (override_commit_ids)
|
||||
{
|
||||
for (j = 0; refs[j] != NULL; j++)
|
||||
g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
|
||||
g_strdup (override_commit_ids[j]));
|
||||
{
|
||||
guint64 *timestamp_ptr;
|
||||
|
||||
g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
|
||||
g_strdup (override_commit_ids[j]));
|
||||
|
||||
timestamp_ptr = g_malloc (sizeof (guint64));
|
||||
*timestamp_ptr = 0;
|
||||
g_hash_table_insert (validated_ref_to_timestamp, ostree_collection_ref_dup (refs[j]),
|
||||
timestamp_ptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5262,6 +5282,7 @@ find_remotes_cb (GObject *obj,
|
||||
for (j = 0; refs[j] != NULL; j++)
|
||||
{
|
||||
const gchar *latest_commit_for_ref = ref_to_latest_commit[j];
|
||||
guint64 *timestamp_ptr;
|
||||
|
||||
if (pointer_table_get (refs_and_remotes_table, j, i) != latest_commit_for_ref)
|
||||
latest_commit_for_ref = NULL;
|
||||
@@ -5270,6 +5291,14 @@ find_remotes_cb (GObject *obj,
|
||||
|
||||
g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
|
||||
g_strdup (latest_commit_for_ref));
|
||||
|
||||
timestamp_ptr = g_malloc (sizeof (guint64));
|
||||
if (latest_commit_for_ref != NULL)
|
||||
*timestamp_ptr = GUINT64_TO_BE (ref_to_latest_timestamp[j]);
|
||||
else
|
||||
*timestamp_ptr = 0;
|
||||
g_hash_table_insert (validated_ref_to_timestamp, ostree_collection_ref_dup (refs[j]),
|
||||
timestamp_ptr);
|
||||
}
|
||||
|
||||
if (n_latest_refs == 0)
|
||||
@@ -5282,6 +5311,7 @@ find_remotes_cb (GObject *obj,
|
||||
}
|
||||
|
||||
result->ref_to_checksum = g_steal_pointer (&validated_ref_to_checksum);
|
||||
result->ref_to_timestamp = g_steal_pointer (&validated_ref_to_timestamp);
|
||||
g_ptr_array_add (final_results, g_steal_pointer (&g_ptr_array_index (results, i)));
|
||||
}
|
||||
|
||||
@@ -5396,6 +5426,13 @@ copy_option (GVariantDict *master_options,
|
||||
* * `flags` (`i`): #OstreeRepoPullFlags to apply to the pull operation
|
||||
* * `inherit-transaction` (`b`): %TRUE to inherit an ongoing transaction on
|
||||
* the #OstreeRepo, rather than encapsulating the pull in a new one
|
||||
* * `depth` (`i`): How far in the history to traverse; default is 0, -1 means infinite
|
||||
* * `disable-static-deltas` (`b`): Do not use static deltas
|
||||
* * `http-headers` (`a(ss)`): Additional headers to add to all HTTP requests
|
||||
* * `subdirs` (`as`): Pull just these subdirectories
|
||||
* * `update-frequency` (`u`): Frequency to call the async progress callback in
|
||||
* milliseconds, if any; only values higher than 0 are valid
|
||||
* * `append-user-agent` (`s`): Additional string to append to the user agent
|
||||
*
|
||||
* Since: 2017.8
|
||||
*/
|
||||
@@ -5756,6 +5793,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
g_autoptr(GBytes) signatures = NULL;
|
||||
gboolean ret = FALSE;
|
||||
gboolean gpg_verify_summary;
|
||||
gboolean summary_is_from_cache;
|
||||
|
||||
g_return_val_if_fail (OSTREE_REPO (self), FALSE);
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
@@ -5770,6 +5808,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
options,
|
||||
&summary,
|
||||
&signatures,
|
||||
&summary_is_from_cache,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
@@ -5777,6 +5816,13 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
if (!ostree_repo_remote_get_gpg_verify_summary (self, name, &gpg_verify_summary, error))
|
||||
goto out;
|
||||
|
||||
if (gpg_verify_summary && summary == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"GPG verification enabled, but no summary found (check that the configured URL in remote config is correct)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gpg_verify_summary && signatures == NULL)
|
||||
{
|
||||
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
|
||||
@@ -5799,6 +5845,27 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!summary_is_from_cache && summary && signatures)
|
||||
{
|
||||
g_autoptr(GError) temp_error = NULL;
|
||||
|
||||
if (!_ostree_repo_cache_summary (self,
|
||||
name,
|
||||
summary,
|
||||
signatures,
|
||||
cancellable,
|
||||
&temp_error))
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
|
||||
g_debug ("No permissions to save summary cache");
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, g_steal_pointer (&temp_error));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (out_summary != NULL)
|
||||
*out_summary = g_steal_pointer (&summary);
|
||||
|
||||
|
||||
@@ -104,11 +104,6 @@ ostree_repo_list_static_delta_names (OstreeRepo *self,
|
||||
while (TRUE)
|
||||
{
|
||||
struct dirent *sub_dent;
|
||||
const char *name1;
|
||||
const char *name2;
|
||||
g_autofree char *superblock_subpath = NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&sub_dfd_iter, &sub_dent,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
@@ -117,39 +112,33 @@ ostree_repo_list_static_delta_names (OstreeRepo *self,
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
name1 = dent->d_name;
|
||||
name2 = sub_dent->d_name;
|
||||
const char *name1 = dent->d_name;
|
||||
const char *name2 = sub_dent->d_name;
|
||||
|
||||
superblock_subpath = g_strconcat (name2, "/superblock", NULL);
|
||||
if (fstatat (sub_dfd_iter.fd, superblock_subpath, &stbuf, 0) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autofree char *buf = g_strconcat (name1, name2, NULL);
|
||||
GString *out = g_string_new ("");
|
||||
char checksum[OSTREE_SHA256_STRING_LEN+1];
|
||||
guchar csum[OSTREE_SHA256_DIGEST_LEN];
|
||||
const char *dash = strchr (buf, '-');
|
||||
g_autofree char *superblock_subpath = g_strconcat (name2, "/superblock", NULL);
|
||||
if (!glnx_fstatat_allow_noent (sub_dfd_iter.fd, superblock_subpath, NULL, 0, error))
|
||||
return FALSE;
|
||||
if (errno == ENOENT)
|
||||
continue;
|
||||
|
||||
ostree_checksum_b64_inplace_to_bytes (buf, csum);
|
||||
g_autofree char *buf = g_strconcat (name1, name2, NULL);
|
||||
GString *out = g_string_new ("");
|
||||
char checksum[OSTREE_SHA256_STRING_LEN+1];
|
||||
guchar csum[OSTREE_SHA256_DIGEST_LEN];
|
||||
const char *dash = strchr (buf, '-');
|
||||
|
||||
ostree_checksum_b64_inplace_to_bytes (buf, csum);
|
||||
ostree_checksum_inplace_from_bytes (csum, checksum);
|
||||
g_string_append (out, checksum);
|
||||
if (dash)
|
||||
{
|
||||
g_string_append_c (out, '-');
|
||||
ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
|
||||
ostree_checksum_inplace_from_bytes (csum, checksum);
|
||||
g_string_append (out, checksum);
|
||||
if (dash)
|
||||
{
|
||||
g_string_append_c (out, '-');
|
||||
ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
|
||||
ostree_checksum_inplace_from_bytes (csum, checksum);
|
||||
g_string_append (out, checksum);
|
||||
}
|
||||
|
||||
g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
|
||||
}
|
||||
|
||||
g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,13 +309,10 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
|
||||
guint32 version;
|
||||
guint64 size;
|
||||
guint64 usize;
|
||||
const guchar *csum;
|
||||
char checksum[OSTREE_SHA256_STRING_LEN+1];
|
||||
gboolean have_all;
|
||||
g_autoptr(GVariant) csum_v = NULL;
|
||||
g_autoptr(GVariant) objects = NULL;
|
||||
g_autoptr(GVariant) part = NULL;
|
||||
g_autofree char *deltapart_path = NULL;
|
||||
OstreeStaticDeltaOpenFlags delta_open_flags =
|
||||
skip_validation ? OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM : 0;
|
||||
g_autoptr(GVariant) header = g_variant_get_child_value (headers, i);
|
||||
@@ -335,6 +321,7 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
|
||||
if (version > OSTREE_DELTAPART_VERSION)
|
||||
return glnx_throw (error, "Delta part has too new version %u", version);
|
||||
|
||||
gboolean have_all;
|
||||
if (!_ostree_repo_static_delta_part_have_all_objects (self, objects, &have_all,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
@@ -345,12 +332,12 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
|
||||
if (have_all)
|
||||
continue;
|
||||
|
||||
csum = ostree_checksum_bytes_peek_validate (csum_v, error);
|
||||
const guchar *csum = ostree_checksum_bytes_peek_validate (csum_v, error);
|
||||
if (!csum)
|
||||
return FALSE;
|
||||
ostree_checksum_inplace_from_bytes (csum, checksum);
|
||||
|
||||
deltapart_path =
|
||||
g_autofree char *deltapart_path =
|
||||
_ostree_get_relative_static_delta_part_path (from_checksum, to_checksum, i);
|
||||
|
||||
g_autoptr(GInputStream) part_in = NULL;
|
||||
@@ -410,16 +397,14 @@ _ostree_static_delta_part_open (GInputStream *part_in,
|
||||
{
|
||||
const gboolean trusted = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED) > 0;
|
||||
const gboolean skip_checksum = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM) > 0;
|
||||
gsize bytes_read;
|
||||
guint8 comptype;
|
||||
g_autoptr(GChecksum) checksum = NULL;
|
||||
g_autoptr(GInputStream) checksum_in = NULL;
|
||||
GInputStream *source_in;
|
||||
|
||||
/* We either take a fd or a GBytes reference */
|
||||
g_return_val_if_fail (G_IS_FILE_DESCRIPTOR_BASED (part_in) || inline_part_bytes != NULL, FALSE);
|
||||
g_return_val_if_fail (skip_checksum || expected_checksum != NULL, FALSE);
|
||||
|
||||
g_autoptr(GChecksum) checksum = NULL;
|
||||
g_autoptr(GInputStream) checksum_in = NULL;
|
||||
GInputStream *source_in;
|
||||
if (!skip_checksum)
|
||||
{
|
||||
checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
@@ -431,7 +416,9 @@ _ostree_static_delta_part_open (GInputStream *part_in,
|
||||
source_in = part_in;
|
||||
}
|
||||
|
||||
guint8 comptype;
|
||||
{ guint8 buf[1];
|
||||
gsize bytes_read;
|
||||
/* First byte is compression type */
|
||||
if (!g_input_stream_read_all (source_in, buf, sizeof(buf), &bytes_read,
|
||||
cancellable, error))
|
||||
@@ -511,7 +498,6 @@ show_one_part (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GVariant) part = NULL;
|
||||
g_autofree char *part_path = _ostree_get_relative_static_delta_part_path (from, to, i);
|
||||
|
||||
guint32 version;
|
||||
@@ -530,6 +516,7 @@ show_one_part (OstreeRepo *self,
|
||||
return glnx_throw_errno_prefix (error, "openat(%s)", part_path);
|
||||
g_autoptr(GInputStream) part_in = g_unix_input_stream_new (part_fd, FALSE);
|
||||
|
||||
g_autoptr(GVariant) part = NULL;
|
||||
if (!_ostree_static_delta_part_open (part_in, NULL,
|
||||
OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM,
|
||||
NULL,
|
||||
@@ -576,19 +563,13 @@ OstreeDeltaEndianness
|
||||
_ostree_delta_get_endianness (GVariant *superblock,
|
||||
gboolean *out_was_heuristic)
|
||||
{
|
||||
guint8 endianness_char;
|
||||
g_autoptr(GVariant) delta_meta = NULL;
|
||||
g_autoptr(GVariantDict) delta_metadict = NULL;
|
||||
guint64 total_size = 0;
|
||||
guint64 total_usize = 0;
|
||||
guint total_objects = 0;
|
||||
|
||||
delta_meta = g_variant_get_child_value (superblock, 0);
|
||||
delta_metadict = g_variant_dict_new (delta_meta);
|
||||
g_autoptr(GVariant) delta_meta = g_variant_get_child_value (superblock, 0);
|
||||
g_autoptr(GVariantDict) delta_metadict = g_variant_dict_new (delta_meta);
|
||||
|
||||
if (out_was_heuristic)
|
||||
*out_was_heuristic = FALSE;
|
||||
|
||||
guint8 endianness_char;
|
||||
if (g_variant_dict_lookup (delta_metadict, "ostree.endianness", "y", &endianness_char))
|
||||
{
|
||||
switch (endianness_char)
|
||||
@@ -605,15 +586,16 @@ _ostree_delta_get_endianness (GVariant *superblock,
|
||||
if (out_was_heuristic)
|
||||
*out_was_heuristic = TRUE;
|
||||
|
||||
guint64 total_size = 0;
|
||||
guint64 total_usize = 0;
|
||||
guint total_objects = 0;
|
||||
{ g_autoptr(GVariant) meta_entries = NULL;
|
||||
guint n_parts;
|
||||
guint i;
|
||||
gboolean is_byteswapped = FALSE;
|
||||
|
||||
g_variant_get_child (superblock, 6, "@a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT, &meta_entries);
|
||||
n_parts = g_variant_n_children (meta_entries);
|
||||
const guint n_parts = g_variant_n_children (meta_entries);
|
||||
|
||||
for (i = 0; i < n_parts; i++)
|
||||
for (guint i = 0; i < n_parts; i++)
|
||||
{
|
||||
g_autoptr(GVariant) objects = NULL;
|
||||
guint64 size, usize;
|
||||
@@ -631,7 +613,7 @@ _ostree_delta_get_endianness (GVariant *superblock,
|
||||
double ratio = ((double)size)/((double)usize);
|
||||
|
||||
/* This should really never happen where compressing things makes it more than 50% bigger.
|
||||
*/
|
||||
*/
|
||||
if (ratio > 1.2)
|
||||
{
|
||||
is_byteswapped = TRUE;
|
||||
@@ -724,26 +706,16 @@ _ostree_repo_static_delta_query_exists (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *from = NULL;
|
||||
g_autofree char *from = NULL;
|
||||
g_autofree char *to = NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
if (!_ostree_parse_delta_name (delta_id, &from, &to, error))
|
||||
return FALSE;
|
||||
|
||||
g_autofree char *superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to);
|
||||
if (!glnx_fstatat_allow_noent (self->repo_dir_fd, superblock_path, NULL, 0, error))
|
||||
return FALSE;
|
||||
|
||||
if (fstatat (self->repo_dir_fd, superblock_path, &stbuf, 0) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
*out_exists = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return glnx_throw_errno_prefix (error, "fstatat(%s)", superblock_path);
|
||||
}
|
||||
*out_exists = TRUE;
|
||||
*out_exists = (errno == 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -755,21 +727,15 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
|
||||
{
|
||||
g_autofree char *from = NULL;
|
||||
g_autofree char *to = NULL;
|
||||
g_autofree char *superblock_path = NULL;
|
||||
g_autoptr(GVariant) delta_superblock = NULL;
|
||||
guint64 total_size = 0, total_usize = 0;
|
||||
guint64 total_fallback_size = 0, total_fallback_usize = 0;
|
||||
OstreeDeltaEndianness endianness;
|
||||
gboolean swap_endian = FALSE;
|
||||
|
||||
if (!_ostree_parse_delta_name (delta_id, &from, &to, error))
|
||||
return FALSE;
|
||||
|
||||
superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to);
|
||||
g_autofree char *superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to);
|
||||
|
||||
glnx_autofd int superblock_fd = -1;
|
||||
if (!glnx_openat_rdonly (self->repo_dir_fd, superblock_path, TRUE, &superblock_fd, error))
|
||||
return FALSE;
|
||||
g_autoptr(GVariant) delta_superblock = NULL;
|
||||
if (!ot_variant_read_fd (superblock_fd, 0,
|
||||
(GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
|
||||
TRUE, &delta_superblock, error))
|
||||
@@ -777,6 +743,8 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
|
||||
|
||||
g_print ("Delta: %s\n", delta_id);
|
||||
|
||||
gboolean swap_endian = FALSE;
|
||||
OstreeDeltaEndianness endianness;
|
||||
{ const char *endianness_description;
|
||||
gboolean was_heuristic;
|
||||
|
||||
@@ -823,6 +791,8 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
|
||||
|
||||
g_print ("Number of fallback entries: %u\n", n_fallback);
|
||||
|
||||
guint64 total_size = 0, total_usize = 0;
|
||||
guint64 total_fallback_size = 0, total_fallback_usize = 0;
|
||||
for (guint i = 0; i < n_fallback; i++)
|
||||
{
|
||||
guint64 size, usize;
|
||||
|
||||
@@ -294,18 +294,141 @@ ostree_repo_traverse_new_reachable (void)
|
||||
NULL, (GDestroyNotify)g_variant_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_traverse_new_parents:
|
||||
*
|
||||
* This hash table is a mapping from #GVariant which can be accessed
|
||||
* via ostree_object_name_deserialize() to a #GVariant containing either
|
||||
* a similar #GVariant or and array of them, listing the parents of the key.
|
||||
*
|
||||
* Returns: (transfer container) (element-type GVariant GVariant): A new hash table
|
||||
*
|
||||
* Since: 2018.5
|
||||
*/
|
||||
GHashTable *
|
||||
ostree_repo_traverse_new_parents (void)
|
||||
{
|
||||
return g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
|
||||
(GDestroyNotify)g_variant_unref, (GDestroyNotify)g_variant_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
parents_get_commits (GHashTable *parents_ht, GVariant *object, GHashTable *res)
|
||||
{
|
||||
const char *checksum;
|
||||
OstreeObjectType type;
|
||||
|
||||
if (object == NULL)
|
||||
return;
|
||||
|
||||
ostree_object_name_deserialize (object, &checksum, &type);
|
||||
if (type == OSTREE_OBJECT_TYPE_COMMIT)
|
||||
g_hash_table_add (res, g_strdup (checksum));
|
||||
else
|
||||
{
|
||||
GVariant *parents = g_hash_table_lookup (parents_ht, object);
|
||||
|
||||
if (parents == NULL)
|
||||
g_debug ("Unexpected NULL parent");
|
||||
else if (g_variant_is_of_type (parents, G_VARIANT_TYPE_ARRAY))
|
||||
{
|
||||
gsize i, len = g_variant_n_children (parents);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
g_autoptr(GVariant) parent = g_variant_get_child_value (parents, i);
|
||||
parents_get_commits (parents_ht, parent, res);
|
||||
}
|
||||
}
|
||||
else
|
||||
parents_get_commits (parents_ht, parents, res);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_traverse_parents_get_commits:
|
||||
*
|
||||
* Gets all the commits that a certain object belongs to, as recorded
|
||||
* by a parents table gotten from ostree_repo_traverse_commit_union_with_parents.
|
||||
*
|
||||
* Returns: (transfer full) (array zero-terminated=1): An array of checksums for
|
||||
* the commits the key belongs to.
|
||||
*
|
||||
* Since: 2018.5
|
||||
*/
|
||||
char **
|
||||
ostree_repo_traverse_parents_get_commits (GHashTable *parents, GVariant *object)
|
||||
{
|
||||
g_autoptr(GHashTable) res = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
parents_get_commits (parents, object, res);
|
||||
|
||||
return (char **)g_hash_table_get_keys_as_array (res, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
traverse_dirtree (OstreeRepo *repo,
|
||||
const char *checksum,
|
||||
GVariant *parent_key,
|
||||
GHashTable *inout_reachable,
|
||||
GHashTable *inout_parents,
|
||||
gboolean ignore_missing_dirs,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
static void
|
||||
add_parent_ref (GHashTable *inout_parents,
|
||||
GVariant *key,
|
||||
GVariant *parent_key)
|
||||
{
|
||||
GVariant *old_parents;
|
||||
|
||||
if (inout_parents == NULL)
|
||||
return;
|
||||
|
||||
old_parents = g_hash_table_lookup (inout_parents, key);
|
||||
if (old_parents == NULL)
|
||||
{
|
||||
/* For the common case of a single pointer we skip using an array to save memory. */
|
||||
g_hash_table_insert (inout_parents, g_variant_ref (key), g_variant_ref (parent_key));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autofree GVariant **new_parents = NULL;
|
||||
gsize i, len = 0;
|
||||
|
||||
if (g_variant_is_of_type (old_parents, G_VARIANT_TYPE_ARRAY))
|
||||
{
|
||||
gsize old_parents_len = g_variant_n_children (old_parents);
|
||||
new_parents = g_new (GVariant *, old_parents_len + 1);
|
||||
for (i = 0; i < old_parents_len ; i++)
|
||||
{
|
||||
g_autoptr(GVariant) old_parent = g_variant_get_child_value (old_parents, i);
|
||||
if (!g_variant_equal (old_parent, parent_key))
|
||||
new_parents[len++] = g_steal_pointer (&old_parent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_parents = g_new (GVariant *, 2);
|
||||
if (!g_variant_equal (old_parents, parent_key))
|
||||
new_parents[len++] = g_variant_ref (old_parents);
|
||||
}
|
||||
new_parents[len++] = g_variant_ref (parent_key);
|
||||
g_hash_table_insert (inout_parents, g_variant_ref (key),
|
||||
g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(su)"), new_parents , len)));
|
||||
for (i = 0; i < len; i++)
|
||||
g_variant_unref (new_parents[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
traverse_iter (OstreeRepo *repo,
|
||||
OstreeRepoCommitTraverseIter *iter,
|
||||
GVariant *parent_key,
|
||||
GHashTable *inout_reachable,
|
||||
GHashTable *inout_parents,
|
||||
gboolean ignore_missing_dirs,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@@ -343,6 +466,7 @@ traverse_iter (OstreeRepo *repo,
|
||||
|
||||
g_debug ("Found file object %s", checksum);
|
||||
key = g_variant_ref_sink (ostree_object_name_serialize (checksum, OSTREE_OBJECT_TYPE_FILE));
|
||||
add_parent_ref (inout_parents, key, parent_key);
|
||||
g_hash_table_add (inout_reachable, g_steal_pointer (&key));
|
||||
}
|
||||
else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_DIR)
|
||||
@@ -357,16 +481,18 @@ traverse_iter (OstreeRepo *repo,
|
||||
g_debug ("Found dirtree object %s", content_checksum);
|
||||
g_debug ("Found dirmeta object %s", meta_checksum);
|
||||
key = g_variant_ref_sink (ostree_object_name_serialize (meta_checksum, OSTREE_OBJECT_TYPE_DIR_META));
|
||||
add_parent_ref (inout_parents, key, parent_key);
|
||||
g_hash_table_add (inout_reachable, g_steal_pointer (&key));
|
||||
|
||||
key = g_variant_ref_sink (ostree_object_name_serialize (content_checksum, OSTREE_OBJECT_TYPE_DIR_TREE));
|
||||
add_parent_ref (inout_parents, key, parent_key);
|
||||
if (!g_hash_table_lookup (inout_reachable, key))
|
||||
{
|
||||
g_hash_table_add (inout_reachable, g_steal_pointer (&key));
|
||||
|
||||
if (!traverse_dirtree (repo, content_checksum, inout_reachable,
|
||||
if (!traverse_dirtree (repo, content_checksum, key, inout_reachable, inout_parents,
|
||||
ignore_missing_dirs, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_hash_table_add (inout_reachable, g_steal_pointer (&key));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -379,7 +505,9 @@ traverse_iter (OstreeRepo *repo,
|
||||
static gboolean
|
||||
traverse_dirtree (OstreeRepo *repo,
|
||||
const char *checksum,
|
||||
GVariant *parent_key,
|
||||
GHashTable *inout_reachable,
|
||||
GHashTable *inout_parents,
|
||||
gboolean ignore_missing_dirs,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@@ -409,31 +537,39 @@ traverse_dirtree (OstreeRepo *repo,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
if (!traverse_iter (repo, &iter, inout_reachable, ignore_missing_dirs, cancellable, error))
|
||||
if (!traverse_iter (repo, &iter, parent_key, inout_reachable, inout_parents, ignore_missing_dirs, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_traverse_commit_union: (skip)
|
||||
* ostree_repo_traverse_commit_union_with_parents: (skip)
|
||||
* @repo: Repo
|
||||
* @commit_checksum: ASCII SHA256 checksum
|
||||
* @maxdepth: Traverse this many parent commits, -1 for unlimited
|
||||
* @inout_reachable: Set of reachable objects
|
||||
* @inout_parents: Map from object to parent object
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Update the set @inout_reachable containing all objects reachable
|
||||
* from @commit_checksum, traversing @maxdepth parent commits.
|
||||
*
|
||||
* Additionally this constructs a mapping from each object to the parents
|
||||
* of the object, which can be used to track which commits an object
|
||||
* belongs to.
|
||||
*
|
||||
* Since: 2018.5
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_traverse_commit_union (OstreeRepo *repo,
|
||||
const char *commit_checksum,
|
||||
int maxdepth,
|
||||
GHashTable *inout_reachable,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
ostree_repo_traverse_commit_union_with_parents (OstreeRepo *repo,
|
||||
const char *commit_checksum,
|
||||
int maxdepth,
|
||||
GHashTable *inout_reachable,
|
||||
GHashTable *inout_parents,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *tmp_checksum = NULL;
|
||||
|
||||
@@ -467,8 +603,7 @@ ostree_repo_traverse_commit_union (OstreeRepo *repo,
|
||||
if ((commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) != 0)
|
||||
ignore_missing_dirs = TRUE;
|
||||
|
||||
g_hash_table_add (inout_reachable, key);
|
||||
key = NULL;
|
||||
g_hash_table_add (inout_reachable, g_variant_ref (key));
|
||||
|
||||
g_debug ("Traversing commit %s", commit_checksum);
|
||||
ostree_cleanup_repo_commit_traverse_iter
|
||||
@@ -478,7 +613,7 @@ ostree_repo_traverse_commit_union (OstreeRepo *repo,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
if (!traverse_iter (repo, &iter, inout_reachable, ignore_missing_dirs, cancellable, error))
|
||||
if (!traverse_iter (repo, &iter, key, inout_reachable, inout_parents, ignore_missing_dirs, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
gboolean recurse = FALSE;
|
||||
@@ -501,6 +636,32 @@ ostree_repo_traverse_commit_union (OstreeRepo *repo,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_traverse_commit_union: (skip)
|
||||
* @repo: Repo
|
||||
* @commit_checksum: ASCII SHA256 checksum
|
||||
* @maxdepth: Traverse this many parent commits, -1 for unlimited
|
||||
* @inout_reachable: Set of reachable objects
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* Update the set @inout_reachable containing all objects reachable
|
||||
* from @commit_checksum, traversing @maxdepth parent commits.
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_traverse_commit_union (OstreeRepo *repo,
|
||||
const char *commit_checksum,
|
||||
int maxdepth,
|
||||
GHashTable *inout_reachable,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
return
|
||||
ostree_repo_traverse_commit_union_with_parents (repo, commit_checksum, maxdepth,
|
||||
inout_reachable, NULL,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_traverse_commit:
|
||||
* @repo: Repo
|
||||
|
||||
+37
-35
@@ -436,7 +436,7 @@ pop_repo_lock (OstreeRepo *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* ostree_repo_lock_push:
|
||||
* @self: a #OstreeRepo
|
||||
* @lock_type: the type of lock to acquire
|
||||
@@ -462,13 +462,12 @@ pop_repo_lock (OstreeRepo *self,
|
||||
* %TRUE is returned.
|
||||
*
|
||||
* Returns: %TRUE on success, otherwise %FALSE with @error set
|
||||
* Since: 2017.14
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
_ostree_repo_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
|
||||
@@ -531,8 +530,8 @@ ostree_repo_lock_push (OstreeRepo *self,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_lock_pop:
|
||||
/*
|
||||
* _ostree_repo_lock_pop:
|
||||
* @self: a #OstreeRepo
|
||||
* @cancellable: a #GCancellable
|
||||
* @error: a #GError
|
||||
@@ -553,12 +552,11 @@ ostree_repo_lock_push (OstreeRepo *self,
|
||||
* %TRUE is returned.
|
||||
*
|
||||
* Returns: %TRUE on success, otherwise %FALSE with @error set
|
||||
* Since: 2017.14
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_lock_pop (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
_ostree_repo_lock_pop (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
|
||||
@@ -621,8 +619,8 @@ ostree_repo_lock_pop (OstreeRepo *self,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_auto_lock_push: (skip)
|
||||
/*
|
||||
* _ostree_repo_auto_lock_push: (skip)
|
||||
* @self: a #OstreeRepo
|
||||
* @lock_type: the type of lock to acquire
|
||||
* @cancellable: a #GCancellable
|
||||
@@ -636,37 +634,34 @@ ostree_repo_lock_pop (OstreeRepo *self,
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* g_autoptr(OstreeRepoAutoLock) lock = NULL;
|
||||
* lock = ostree_repo_auto_lock_push (repo, lock_type, cancellable, error);
|
||||
* lock = _ostree_repo_auto_lock_push (repo, lock_type, cancellable, error);
|
||||
* if (!lock)
|
||||
* return FALSE;
|
||||
* ]|
|
||||
*
|
||||
* Returns: @self on success, otherwise %NULL with @error set
|
||||
* Since: 2017.14
|
||||
*/
|
||||
OstreeRepoAutoLock *
|
||||
ostree_repo_auto_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
_ostree_repo_auto_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
if (!ostree_repo_lock_push (self, lock_type, cancellable, error))
|
||||
if (!_ostree_repo_lock_push (self, lock_type, cancellable, error))
|
||||
return NULL;
|
||||
return (OstreeRepoAutoLock *)self;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_auto_lock_cleanup: (skip)
|
||||
/*
|
||||
* _ostree_repo_auto_lock_cleanup: (skip)
|
||||
* @lock: a #OstreeRepoAutoLock
|
||||
*
|
||||
* A cleanup handler for use with ostree_repo_auto_lock_push(). If @lock is
|
||||
* not %NULL, ostree_repo_lock_pop() will be called on it. If
|
||||
* ostree_repo_lock_pop() fails, a critical warning will be emitted.
|
||||
*
|
||||
* Since: 2017.14
|
||||
*/
|
||||
void
|
||||
ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock)
|
||||
_ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock)
|
||||
{
|
||||
OstreeRepo *repo = lock;
|
||||
if (repo)
|
||||
@@ -674,7 +669,7 @@ ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock)
|
||||
g_autoptr(GError) error = NULL;
|
||||
int errsv = errno;
|
||||
|
||||
if (!ostree_repo_lock_pop (repo, NULL, &error))
|
||||
if (!_ostree_repo_lock_pop (repo, NULL, &error))
|
||||
g_critical ("Cleanup repo lock failed: %s", error->message);
|
||||
|
||||
errno = errsv;
|
||||
@@ -2742,10 +2737,10 @@ reload_core_config (OstreeRepo *self,
|
||||
self->tmp_expiry_seconds = g_ascii_strtoull (tmp_expiry_seconds, NULL, 10);
|
||||
}
|
||||
|
||||
/* Disable locking by default for now */
|
||||
{ gboolean locking;
|
||||
/* Enabled by default in 2018.05 */
|
||||
if (!ot_keyfile_get_boolean_with_default (self->config, "core", "locking",
|
||||
FALSE, &locking, error))
|
||||
TRUE, &locking, error))
|
||||
return FALSE;
|
||||
if (!locking)
|
||||
{
|
||||
@@ -3550,6 +3545,9 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char *errprefix = glnx_strjoina ("Opening content object ", checksum);
|
||||
GLNX_AUTO_PREFIX_ERROR (errprefix, error);
|
||||
|
||||
struct stat stbuf;
|
||||
glnx_autofd int fd = -1;
|
||||
g_autofree char *ret_symlink = NULL;
|
||||
@@ -3590,7 +3588,7 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
|
||||
}
|
||||
|
||||
if (!(S_ISREG (stbuf.st_mode) || S_ISLNK (stbuf.st_mode)))
|
||||
return glnx_throw (error, "Not a regular file or symlink: %s", loose_path_buf);
|
||||
return glnx_throw (error, "Not a regular file or symlink");
|
||||
|
||||
/* In the non-bare-user case, gather symlink info if requested */
|
||||
if (self->mode != OSTREE_REPO_MODE_BARE_USER
|
||||
@@ -4642,6 +4640,10 @@ sign_data (OstreeRepo *self,
|
||||
if (gpgme_err_code (err) == GPG_ERR_EOF)
|
||||
return glnx_throw (error, "No gpg key found with ID %s (homedir: %s)", key_id,
|
||||
homedir ? homedir : "<default>");
|
||||
else if (gpgme_err_code (err) == GPG_ERR_AMBIGUOUS_NAME) {
|
||||
return glnx_throw (error, "gpg key id %s ambiguous (homedir: %s). Try the fingerprint instead", key_id,
|
||||
homedir ? homedir : "<default>");
|
||||
}
|
||||
else if (err != GPG_ERR_NO_ERROR)
|
||||
return ot_gpgme_throw (err, error, "Unable to lookup key ID %s", key_id);
|
||||
|
||||
@@ -5311,11 +5313,11 @@ summary_add_ref_entry (OstreeRepo *self,
|
||||
* `core/commit-update-summary` is set.
|
||||
*
|
||||
* If the `core/collection-id` key is set in the configuration, it will be
|
||||
* included as %OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs from the
|
||||
* `refs/mirrors` directory will be included in the generated summary file,
|
||||
* listed under the %OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs and refs
|
||||
* in %OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in lexicographic
|
||||
* order.
|
||||
* included as %OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs that
|
||||
* have associated collection IDs will be included in the generated summary
|
||||
* file, listed under the %OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs
|
||||
* and refs in %OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in
|
||||
* lexicographic order.
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_regenerate_summary (OstreeRepo *self,
|
||||
|
||||
+14
-42
@@ -109,48 +109,6 @@ OstreeRepo * ostree_repo_create_at (int dfd,
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
|
||||
/**
|
||||
* OstreeRepoLockType:
|
||||
* @OSTREE_REPO_LOCK_SHARED: A shared lock
|
||||
* @OSTREE_REPO_LOCK_EXCLUSIVE: An exclusive lock
|
||||
*
|
||||
* The type of repository lock to acquire.
|
||||
*
|
||||
* Since: 2017.14
|
||||
*/
|
||||
typedef enum {
|
||||
OSTREE_REPO_LOCK_SHARED,
|
||||
OSTREE_REPO_LOCK_EXCLUSIVE
|
||||
} OstreeRepoLockType;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_lock_pop (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* OstreeRepoAutoLock: (skip)
|
||||
*
|
||||
* This is simply an alias to #OstreeRepo used for automatic lock cleanup.
|
||||
* See ostree_repo_auto_lock_push() for its intended usage.
|
||||
*
|
||||
* Since: 2017.14
|
||||
*/
|
||||
typedef OstreeRepo OstreeRepoAutoLock;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
OstreeRepoAutoLock * ostree_repo_auto_lock_push (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
const gchar * ostree_repo_get_collection_id (OstreeRepo *self);
|
||||
_OSTREE_PUBLIC
|
||||
@@ -1112,6 +1070,12 @@ gboolean ostree_repo_static_delta_execute_offline (OstreeRepo
|
||||
_OSTREE_PUBLIC
|
||||
GHashTable *ostree_repo_traverse_new_reachable (void);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
GHashTable *ostree_repo_traverse_new_parents (void);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
char ** ostree_repo_traverse_parents_get_commits (GHashTable *parents, GVariant *object);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_traverse_commit (OstreeRepo *repo,
|
||||
const char *commit_checksum,
|
||||
@@ -1127,6 +1091,14 @@ gboolean ostree_repo_traverse_commit_union (OstreeRepo *repo,
|
||||
GHashTable *inout_reachable,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_traverse_commit_union_with_parents (OstreeRepo *repo,
|
||||
const char *commit_checksum,
|
||||
int maxdepth,
|
||||
GHashTable *inout_reachable,
|
||||
GHashTable *inout_parents,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
struct _OstreeRepoCommitTraverseIter {
|
||||
gboolean initialized;
|
||||
|
||||
@@ -239,6 +239,44 @@ cleanup_other_bootversions (OstreeSysroot *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Delete a deployment directory */
|
||||
gboolean
|
||||
_ostree_sysroot_rmrf_deployment (OstreeSysroot *self,
|
||||
OstreeDeployment *deployment,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *origin_relpath = ostree_deployment_get_origin_relpath (deployment);
|
||||
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
|
||||
struct stat stbuf;
|
||||
glnx_autofd int deployment_fd = -1;
|
||||
|
||||
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE,
|
||||
&deployment_fd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_fstat (deployment_fd, &stbuf, error))
|
||||
return FALSE;
|
||||
|
||||
/* This shouldn't happen, because higher levels should
|
||||
* disallow having the booted deployment not in the active
|
||||
* deployment list, but let's be extra safe. */
|
||||
if (stbuf.st_dev == self->root_device &&
|
||||
stbuf.st_ino == self->root_inode)
|
||||
return TRUE;
|
||||
|
||||
/* This deployment wasn't referenced, so delete it */
|
||||
if (!_ostree_linuxfs_fd_alter_immutable_flag (deployment_fd, FALSE,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, origin_relpath, cancellable, error))
|
||||
return FALSE;
|
||||
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* As the bootloader configuration changes, we will have leftover deployments
|
||||
* on disk. This function deletes all deployments which aren't actively
|
||||
* referenced.
|
||||
@@ -279,36 +317,12 @@ cleanup_old_deployments (OstreeSysroot *self,
|
||||
{
|
||||
OstreeDeployment *deployment = all_deployment_dirs->pdata[i];
|
||||
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
|
||||
g_autofree char *origin_relpath = ostree_deployment_get_origin_relpath (deployment);
|
||||
|
||||
if (!g_hash_table_lookup (active_deployment_dirs, deployment_path))
|
||||
{
|
||||
struct stat stbuf;
|
||||
glnx_autofd int deployment_fd = -1;
|
||||
if (g_hash_table_lookup (active_deployment_dirs, deployment_path))
|
||||
continue;
|
||||
|
||||
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE,
|
||||
&deployment_fd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_fstat (deployment_fd, &stbuf, error))
|
||||
return FALSE;
|
||||
|
||||
/* This shouldn't happen, because higher levels should
|
||||
* disallow having the booted deployment not in the active
|
||||
* deployment list, but let's be extra safe. */
|
||||
if (stbuf.st_dev == root_stbuf.st_dev &&
|
||||
stbuf.st_ino == root_stbuf.st_ino)
|
||||
continue;
|
||||
|
||||
/* This deployment wasn't referenced, so delete it */
|
||||
if (!_ostree_linuxfs_fd_alter_immutable_flag (deployment_fd, FALSE,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, origin_relpath, cancellable, error))
|
||||
return FALSE;
|
||||
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
if (!_ostree_sysroot_rmrf_deployment (self, deployment, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Clean up boot directories */
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -50,8 +50,7 @@ struct OstreeSysroot {
|
||||
GLnxLockFile lock;
|
||||
|
||||
gboolean loaded;
|
||||
gboolean ostree_booted;
|
||||
gboolean root_is_sysroot; /* TRUE if sysroot_fd is pointed to rootfs "/" */
|
||||
gboolean root_is_ostree_booted; /* TRUE if sysroot is / and we are booted via ostree */
|
||||
/* The device/inode for /, used to detect booted deployment */
|
||||
dev_t root_device;
|
||||
ino_t root_inode;
|
||||
@@ -61,6 +60,8 @@ struct OstreeSysroot {
|
||||
int bootversion;
|
||||
int subbootversion;
|
||||
OstreeDeployment *booted_deployment;
|
||||
OstreeDeployment *staged_deployment;
|
||||
GVariant *staged_deployment_data;
|
||||
struct timespec loaded_ts;
|
||||
|
||||
/* Only access through ostree_sysroot_[_get]repo() */
|
||||
@@ -71,6 +72,7 @@ struct OstreeSysroot {
|
||||
|
||||
#define OSTREE_SYSROOT_LOCKFILE "ostree/lock"
|
||||
/* We keep some transient state in /run */
|
||||
#define _OSTREE_SYSROOT_RUNSTATE_STAGED "/run/ostree/staged-deployment"
|
||||
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/"
|
||||
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development"
|
||||
|
||||
@@ -105,6 +107,22 @@ _ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
void
|
||||
_ostree_deployment_set_bootconfig_from_kargs (OstreeDeployment *deployment,
|
||||
char **override_kernel_argv);
|
||||
|
||||
gboolean
|
||||
_ostree_sysroot_reload_staged (OstreeSysroot *self, GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_sysroot_finalize_staged (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
OstreeDeployment *
|
||||
_ostree_sysroot_deserialize_deployment_from_variant (GVariant *v,
|
||||
GError **error);
|
||||
|
||||
char *
|
||||
_ostree_sysroot_get_origin_relpath (GFile *path,
|
||||
guint32 *out_device,
|
||||
@@ -112,6 +130,14 @@ _ostree_sysroot_get_origin_relpath (GFile *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_sysroot_rmrf_deployment (OstreeSysroot *sysroot,
|
||||
OstreeDeployment *deployment,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
char * _ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const char *key);
|
||||
|
||||
char *_ostree_sysroot_join_lines (GPtrArray *lines);
|
||||
|
||||
gboolean _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
|
||||
|
||||
@@ -644,21 +644,37 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(OstreeDeployment) new_deployment = NULL;
|
||||
if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname,
|
||||
self->new_revision,
|
||||
self->origin,
|
||||
self->merge_deployment,
|
||||
NULL,
|
||||
&new_deployment,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname,
|
||||
new_deployment,
|
||||
self->merge_deployment,
|
||||
0,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
/* Experimental flag to enable staging */
|
||||
if (getenv ("OSTREE_EX_STAGE_DEPLOYMENTS"))
|
||||
{
|
||||
if (!ostree_sysroot_stage_tree (self->sysroot, self->osname,
|
||||
self->new_revision,
|
||||
self->origin,
|
||||
self->merge_deployment,
|
||||
NULL,
|
||||
&new_deployment,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname,
|
||||
self->new_revision,
|
||||
self->origin,
|
||||
self->merge_deployment,
|
||||
NULL,
|
||||
&new_deployment,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname,
|
||||
new_deployment,
|
||||
self->merge_deployment,
|
||||
0,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+124
-35
@@ -82,6 +82,8 @@ ostree_sysroot_finalize (GObject *object)
|
||||
g_clear_object (&self->repo);
|
||||
g_clear_pointer (&self->deployments, g_ptr_array_unref);
|
||||
g_clear_object (&self->booted_deployment);
|
||||
g_clear_object (&self->staged_deployment);
|
||||
g_clear_pointer (&self->staged_deployment_data, (GDestroyNotify)g_variant_unref);
|
||||
|
||||
glnx_release_lock_file (&self->lock);
|
||||
|
||||
@@ -525,32 +527,30 @@ read_current_bootversion (OstreeSysroot *self,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_origin (OstreeSysroot *self,
|
||||
int deployment_dfd,
|
||||
const char *deployment_name,
|
||||
GKeyFile **out_origin,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
load_origin (OstreeSysroot *self,
|
||||
OstreeDeployment *deployment,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *origin_path = g_strconcat ("../", deployment_name, ".origin", NULL);
|
||||
g_autoptr(GKeyFile) ret_origin = g_key_file_new ();
|
||||
g_autofree char *origin_path = ostree_deployment_get_origin_relpath (deployment);
|
||||
|
||||
struct stat stbuf;
|
||||
if (!glnx_fstatat_allow_noent (deployment_dfd, origin_path, &stbuf, 0, error))
|
||||
glnx_autofd int fd = -1;
|
||||
if (!ot_openat_ignore_enoent (self->sysroot_fd, origin_path, &fd, error))
|
||||
return FALSE;
|
||||
if (errno == 0)
|
||||
if (fd >= 0)
|
||||
{
|
||||
g_autofree char *origin_contents =
|
||||
glnx_file_get_contents_utf8_at (deployment_dfd, origin_path,
|
||||
NULL, cancellable, error);
|
||||
glnx_fd_readall_utf8 (fd, NULL, cancellable, error);
|
||||
if (!origin_contents)
|
||||
return FALSE;
|
||||
|
||||
if (!g_key_file_load_from_data (ret_origin, origin_contents, -1, 0, error))
|
||||
g_autoptr(GKeyFile) origin = g_key_file_new ();
|
||||
if (!g_key_file_load_from_data (origin, origin_contents, -1, 0, error))
|
||||
return glnx_prefix_error (error, "Parsing %s", origin_path);
|
||||
|
||||
ostree_deployment_set_origin (deployment, origin);
|
||||
}
|
||||
|
||||
ot_transfer_out_value(out_origin, &ret_origin);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -584,14 +584,14 @@ parse_bootlink (const char *bootlink,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_unlocked_development_path (OstreeDeployment *deployment)
|
||||
char *
|
||||
_ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const char *key)
|
||||
{
|
||||
return g_strdup_printf ("%s%s.%d/%s",
|
||||
_OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR,
|
||||
ostree_deployment_get_csum (deployment),
|
||||
ostree_deployment_get_deployserial (deployment),
|
||||
_OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
|
||||
key);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -637,8 +637,7 @@ parse_deployment (OstreeSysroot *self,
|
||||
|
||||
/* See if this is the booted deployment */
|
||||
const gboolean looking_for_booted_deployment =
|
||||
(self->ostree_booted && self->root_is_sysroot &&
|
||||
!self->booted_deployment);
|
||||
(self->root_is_ostree_booted && !self->booted_deployment);
|
||||
gboolean is_booted_deployment = FALSE;
|
||||
if (looking_for_booted_deployment)
|
||||
{
|
||||
@@ -653,26 +652,23 @@ parse_deployment (OstreeSysroot *self,
|
||||
stbuf.st_ino == self->root_inode);
|
||||
}
|
||||
|
||||
g_autoptr(GKeyFile) origin = NULL;
|
||||
if (!parse_origin (self, deployment_dfd, deploy_basename, &origin,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(OstreeDeployment) ret_deployment
|
||||
= ostree_deployment_new (-1, osname, treecsum, deployserial,
|
||||
bootcsum, treebootserial);
|
||||
if (origin)
|
||||
ostree_deployment_set_origin (ret_deployment, origin);
|
||||
if (!load_origin (self, ret_deployment, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE;
|
||||
g_autofree char *unlocked_development_path = get_unlocked_development_path (ret_deployment);
|
||||
g_autofree char *unlocked_development_path =
|
||||
_ostree_sysroot_get_runstate_path (ret_deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
|
||||
struct stat stbuf;
|
||||
if (lstat (unlocked_development_path, &stbuf) == 0)
|
||||
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
|
||||
else
|
||||
{
|
||||
g_autofree char *existing_unlocked_state =
|
||||
g_key_file_get_string (origin, "origin", "unlocked", NULL);
|
||||
GKeyFile *origin = ostree_deployment_get_origin (ret_deployment);
|
||||
g_autofree char *existing_unlocked_state = origin ?
|
||||
g_key_file_get_string (origin, "origin", "unlocked", NULL) : NULL;
|
||||
|
||||
if (g_strcmp0 (existing_unlocked_state, "hotfix") == 0)
|
||||
{
|
||||
@@ -742,6 +738,15 @@ compare_deployments_by_boot_loader_version_reversed (gconstpointer a_pp,
|
||||
OstreeBootconfigParser *a_bootconfig = ostree_deployment_get_bootconfig (a);
|
||||
OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b);
|
||||
|
||||
/* Staged deployments are always first */
|
||||
if (ostree_deployment_is_staged (a))
|
||||
{
|
||||
g_assert (!ostree_deployment_is_staged (b));
|
||||
return -1;
|
||||
}
|
||||
else if (ostree_deployment_is_staged (b))
|
||||
return 1;
|
||||
|
||||
return compare_boot_loader_configs (a_bootconfig, b_bootconfig);
|
||||
}
|
||||
|
||||
@@ -789,6 +794,63 @@ ensure_repo (OstreeSysroot *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Reload the staged deployment from the file in /run */
|
||||
gboolean
|
||||
_ostree_sysroot_reload_staged (OstreeSysroot *self,
|
||||
GError **error)
|
||||
{
|
||||
GLNX_AUTO_PREFIX_ERROR ("Loading staged deployment", error);
|
||||
if (!self->root_is_ostree_booted)
|
||||
return TRUE; /* Note early return */
|
||||
|
||||
g_assert (self->booted_deployment);
|
||||
|
||||
g_clear_object (&self->staged_deployment);
|
||||
g_clear_pointer (&self->staged_deployment_data, (GDestroyNotify)g_variant_unref);
|
||||
|
||||
/* Read the staged state from disk */
|
||||
glnx_autofd int fd = -1;
|
||||
if (!ot_openat_ignore_enoent (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, &fd, error))
|
||||
return FALSE;
|
||||
if (fd != -1)
|
||||
{
|
||||
g_autoptr(GBytes) contents = ot_fd_readall_or_mmap (fd, 0, error);
|
||||
if (!contents)
|
||||
return FALSE;
|
||||
g_autoptr(GVariant) staged_deployment_data =
|
||||
g_variant_new_from_bytes ((GVariantType*)"a{sv}", contents, TRUE);
|
||||
g_autoptr(GVariantDict) staged_deployment_dict =
|
||||
g_variant_dict_new (staged_deployment_data);
|
||||
|
||||
/* Parse it */
|
||||
g_autoptr(GVariant) target = NULL;
|
||||
g_autofree char **kargs = NULL;
|
||||
g_variant_dict_lookup (staged_deployment_dict, "target", "@a{sv}", &target);
|
||||
g_variant_dict_lookup (staged_deployment_dict, "kargs", "^a&s", &kargs);
|
||||
if (target)
|
||||
{
|
||||
g_autoptr(OstreeDeployment) staged =
|
||||
_ostree_sysroot_deserialize_deployment_from_variant (target, error);
|
||||
if (!staged)
|
||||
return FALSE;
|
||||
|
||||
_ostree_deployment_set_bootconfig_from_kargs (staged, kargs);
|
||||
if (!load_origin (self, staged, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
self->staged_deployment = g_steal_pointer (&staged);
|
||||
self->staged_deployment_data = g_steal_pointer (&staged_deployment_data);
|
||||
/* We set this flag for ostree_deployment_is_staged() because that API
|
||||
* doesn't have access to the sysroot, which currently has the
|
||||
* canonical "staged_deployment" reference.
|
||||
*/
|
||||
self->staged_deployment->staged = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
gboolean *out_changed,
|
||||
@@ -813,7 +875,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
{
|
||||
if (!glnx_fstatat_allow_noent (AT_FDCWD, "/run/ostree-booted", NULL, 0, error))
|
||||
return FALSE;
|
||||
self->ostree_booted = (errno == 0);
|
||||
const gboolean ostree_booted = (errno == 0);
|
||||
|
||||
{ struct stat root_stbuf;
|
||||
if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error))
|
||||
@@ -826,9 +888,11 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
if (!glnx_fstat (self->sysroot_fd, &self_stbuf, error))
|
||||
return FALSE;
|
||||
|
||||
self->root_is_sysroot =
|
||||
const gboolean root_is_sysroot =
|
||||
(self->root_device == self_stbuf.st_dev &&
|
||||
self->root_inode == self_stbuf.st_ino);
|
||||
|
||||
self->root_is_ostree_booted = (ostree_booted && root_is_sysroot);
|
||||
}
|
||||
|
||||
int bootversion = 0;
|
||||
@@ -857,6 +921,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
|
||||
g_clear_pointer (&self->deployments, g_ptr_array_unref);
|
||||
g_clear_object (&self->booted_deployment);
|
||||
g_clear_object (&self->staged_deployment);
|
||||
self->bootversion = -1;
|
||||
self->subbootversion = -1;
|
||||
|
||||
@@ -880,11 +945,20 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
}
|
||||
}
|
||||
|
||||
if (self->ostree_booted && self->root_is_sysroot
|
||||
&& !self->booted_deployment)
|
||||
if (self->root_is_ostree_booted && !self->booted_deployment)
|
||||
return glnx_throw (error, "Unexpected state: /run/ostree-booted found and in / sysroot but not in a booted deployment");
|
||||
|
||||
if (!_ostree_sysroot_reload_staged (self, error))
|
||||
return FALSE;
|
||||
|
||||
/* Ensure the entires are sorted */
|
||||
g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed);
|
||||
|
||||
/* Staged shows up first */
|
||||
if (self->staged_deployment)
|
||||
g_ptr_array_insert (deployments, 0, g_object_ref (self->staged_deployment));
|
||||
|
||||
/* And then set their index variables */
|
||||
for (guint i = 0; i < deployments->len; i++)
|
||||
{
|
||||
OstreeDeployment *deployment = deployments->pdata[i];
|
||||
@@ -949,6 +1023,20 @@ ostree_sysroot_get_booted_deployment (OstreeSysroot *self)
|
||||
return self->booted_deployment;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_sysroot_get_staged_deployment:
|
||||
* @self: Sysroot
|
||||
*
|
||||
* Returns: (transfer none): The currently staged deployment, or %NULL if none
|
||||
*/
|
||||
OstreeDeployment *
|
||||
ostree_sysroot_get_staged_deployment (OstreeSysroot *self)
|
||||
{
|
||||
g_return_val_if_fail (self->loaded, NULL);
|
||||
|
||||
return self->staged_deployment;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_sysroot_get_deployments:
|
||||
* @self: Sysroot
|
||||
@@ -1769,7 +1857,8 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
break;
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
|
||||
{
|
||||
g_autofree char *devpath = get_unlocked_development_path (deployment);
|
||||
g_autofree char *devpath =
|
||||
_ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
|
||||
g_autofree char *devpath_parent = dirname (g_strdup (devpath));
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, devpath_parent, 0755, cancellable, error))
|
||||
|
||||
@@ -74,6 +74,8 @@ _OSTREE_PUBLIC
|
||||
GPtrArray *ostree_sysroot_get_deployments (OstreeSysroot *self);
|
||||
_OSTREE_PUBLIC
|
||||
OstreeDeployment *ostree_sysroot_get_booted_deployment (OstreeSysroot *self);
|
||||
_OSTREE_PUBLIC
|
||||
OstreeDeployment *ostree_sysroot_get_staged_deployment (OstreeSysroot *self);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
GFile *ostree_sysroot_get_deployment_directory (OstreeSysroot *self,
|
||||
@@ -174,6 +176,17 @@ gboolean ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_sysroot_stage_tree (OstreeSysroot *self,
|
||||
const char *osname,
|
||||
const char *revision,
|
||||
GKeyFile *origin,
|
||||
OstreeDeployment *merge_deployment,
|
||||
char **override_kernel_argv,
|
||||
OstreeDeployment **out_new_deployment,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
|
||||
OstreeDeployment *deployment,
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_RELEASE_VERSION (4)
|
||||
#define OSTREE_RELEASE_VERSION (5)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION
|
||||
@@ -52,7 +52,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_VERSION (2018.4)
|
||||
#define OSTREE_VERSION (2018.5)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION_S:
|
||||
@@ -62,7 +62,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_VERSION_S "2018.4"
|
||||
#define OSTREE_VERSION_S "2018.5"
|
||||
|
||||
#define OSTREE_ENCODE_VERSION(year,release) \
|
||||
((year) << 16 | (release))
|
||||
|
||||
Reference in new issue
Block a user