diff options
-rw-r--r-- | src/libostree/ostree-repo.c | 175 | ||||
-rw-r--r-- | src/libostree/ostree-repo.h | 7 | ||||
-rw-r--r-- | src/ostree/ot-builtin-pull-local.c | 68 |
3 files changed, 186 insertions, 64 deletions
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 7069d01d..0d24a967 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1632,6 +1632,181 @@ ostree_repo_delete_object (OstreeRepo *self, return ret; } +static gboolean +copy_detached_metadata (OstreeRepo *self, + OstreeRepo *source, + const char *checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gs_unref_variant GVariant *detached_meta = NULL; + + if (!ostree_repo_read_commit_detached_metadata (source, + checksum, &detached_meta, + cancellable, error)) + goto out; + + if (detached_meta) + { + if (!ostree_repo_write_commit_detached_metadata (self, + checksum, detached_meta, + cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +import_one_object_copy (OstreeRepo *self, + OstreeRepo *source, + const char *checksum, + OstreeObjectType objtype, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + guint64 length; + gs_unref_object GInputStream *object = NULL; + + if (!ostree_repo_load_object_stream (source, objtype, checksum, + &object, &length, + cancellable, error)) + goto out; + + if (objtype == OSTREE_OBJECT_TYPE_FILE) + { + if (!ostree_repo_write_content_trusted (self, checksum, + object, length, + cancellable, error)) + goto out; + } + else + { + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + if (!copy_detached_metadata (self, source, checksum, cancellable, error)) + goto out; + } + if (!ostree_repo_write_metadata_stream_trusted (self, objtype, + checksum, object, length, + cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +import_one_object_link (OstreeRepo *self, + OstreeRepo *source, + const char *checksum, + OstreeObjectType objtype, + gboolean *out_was_supported, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + + _ostree_loose_path (loose_path_buf, checksum, objtype, self->mode); + + if (!_ostree_repo_ensure_loose_objdir_at (self->objects_dir_fd, loose_path_buf, cancellable, error)) + goto out; + + *out_was_supported = TRUE; + if (linkat (source->objects_dir_fd, loose_path_buf, self->objects_dir_fd, loose_path_buf, 0) != 0) + { + if (errno == EEXIST) + { + ret = TRUE; + } + else if (errno == EMLINK || errno == EXDEV || errno == EPERM) + { + /* EMLINK, EXDEV and EPERM shouldn't be fatal; we just can't do the + * optimization of hardlinking instead of copying. + */ + *out_was_supported = FALSE; + ret = TRUE; + } + else + ot_util_set_error_from_errno (error, errno); + + goto out; + } + + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + if (!copy_detached_metadata (self, source, checksum, cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} + +/** + * ostree_repo_import_object_from: + * @self: Destination repo + * @source: Source repo + * @objtype: Object type + * @checksum: checksum + * @cancellable: Cancellable + * @error: Error + * + * Copy object named by @objtype and @checksum into @self from the + * source repository @source. If both repositories are of the same + * type and on the same filesystem, this will simply be a fast Unix + * hard link operation. + * + * Otherwise, a copy will be performed. + */ +gboolean +ostree_repo_import_object_from (OstreeRepo *self, + OstreeRepo *source, + OstreeObjectType objtype, + const char *checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gboolean hardlink_was_supported = FALSE; + + if (self->mode == source->mode) + { + if (!import_one_object_link (self, source, checksum, objtype, + &hardlink_was_supported, + cancellable, error)) + goto out; + } + + if (!hardlink_was_supported) + { + gboolean has_object; + + if (!ostree_repo_has_object (self, objtype, checksum, &has_object, + cancellable, error)) + goto out; + + if (!has_object) + { + if (!import_one_object_copy (self, source, checksum, objtype, + cancellable, error)) + goto out; + } + } + + ret = TRUE; + out: + return ret; +} + /** * ostree_repo_query_object_storage_size: * @self: Repo diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index de38ce43..856b764a 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -265,6 +265,13 @@ gboolean ostree_repo_query_object_storage_size (OstreeRepo *self, GCancellable *cancellable, GError **error); +gboolean ostree_repo_import_object_from (OstreeRepo *self, + OstreeRepo *source, + OstreeObjectType objtype, + const char *sha256, + GCancellable *cancellable, + GError **error); + gboolean ostree_repo_delete_object (OstreeRepo *self, OstreeObjectType objtype, const char *sha256, diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c index 50b05a6f..bd9773b7 100644 --- a/src/ostree/ot-builtin-pull-local.c +++ b/src/ostree/ot-builtin-pull-local.c @@ -55,61 +55,6 @@ termination_condition (OtLocalCloneData *self) return g_atomic_int_get (&self->n_objects_checked) == self->n_objects_to_check; } -static gboolean -import_one_object (OtLocalCloneData *data, - const char *checksum, - OstreeObjectType objtype, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - guint64 length; - gs_unref_object GInputStream *object = NULL; - - if (!ostree_repo_load_object_stream (data->src_repo, objtype, checksum, - &object, &length, - cancellable, error)) - goto out; - - if (objtype == OSTREE_OBJECT_TYPE_FILE) - { - if (!ostree_repo_write_content_trusted (data->dest_repo, checksum, - object, length, - cancellable, error)) - goto out; - } - else - { - if (objtype == OSTREE_OBJECT_TYPE_COMMIT) - { - gs_unref_variant GVariant *detached_meta = NULL; - - if (!ostree_repo_read_commit_detached_metadata (data->src_repo, - checksum, &detached_meta, - cancellable, error)) - goto out; - - if (detached_meta) - { - if (!ostree_repo_write_commit_detached_metadata (data->dest_repo, - checksum, detached_meta, - cancellable, error)) - goto out; - } - } - if (!ostree_repo_write_metadata_stream_trusted (data->dest_repo, objtype, - checksum, object, length, - cancellable, error)) - goto out; - } - - g_atomic_int_inc (&data->n_objects_copied); - - ret = TRUE; - out: - return ret; -} - static void import_one_object_thread (gpointer object, gpointer user_data) @@ -120,21 +65,16 @@ import_one_object_thread (gpointer object, GError **error = &local_error; const char *checksum; OstreeObjectType objtype; - gboolean has_object; GCancellable *cancellable = NULL; ostree_object_name_deserialize (serialized_key, &checksum, &objtype); - if (!ostree_repo_has_object (data->dest_repo, objtype, checksum, &has_object, - cancellable, error)) + if (!ostree_repo_import_object_from (data->dest_repo, data->src_repo, + objtype, checksum, cancellable, error)) goto out; + + g_atomic_int_inc (&data->n_objects_copied); - if (!has_object) - { - if (!import_one_object (data, checksum, objtype, cancellable, error)) - goto out; - } - out: g_atomic_int_add (&data->n_objects_checked, 1); if (termination_condition (data)) |