core: Clean up staging API and internals

Cleanly separate metadata/content APIs, rather than defaulting to
raw streams.  This helps most use cases.

Also, drop support for staging content without knowing the total
length.  This complicated the code, and for things like streaming
HTTP, we should be able to figure this out from Content-Length.
This commit is contained in:
Colin Walters 2012-09-23 16:44:12 -04:00
parent 2a0601efc7
commit 34c49f0411
4 changed files with 177 additions and 202 deletions

View File

@ -824,22 +824,17 @@ commit_loose_object_trusted (OstreeRepo *self,
return ret; return ret;
} }
typedef enum {
OSTREE_REPO_STAGE_FLAGS_LENGTH_VALID = (1<<0)
} OstreeRepoStageFlags;
static gboolean static gboolean
stage_object_internal (OstreeRepo *self, stage_object (OstreeRepo *self,
OstreeRepoStageFlags flags, OstreeObjectType objtype,
OstreeObjectType objtype, const char *expected_checksum,
GInputStream *input, GInputStream *input,
guint64 file_object_length, guint64 file_object_length,
const char *expected_checksum, guchar **out_csum,
guchar **out_csum, GCancellable *cancellable,
GCancellable *cancellable, GError **error)
GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
const char *actual_checksum; const char *actual_checksum;
gboolean do_commit; gboolean do_commit;
ot_lobj GFileInfo *temp_info = NULL; ot_lobj GFileInfo *temp_info = NULL;
@ -854,6 +849,20 @@ stage_object_internal (OstreeRepo *self,
gboolean staged_archive_file = FALSE; gboolean staged_archive_file = FALSE;
gboolean temp_file_is_regular; gboolean temp_file_is_regular;
g_return_val_if_fail (self->in_transaction, FALSE);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
g_assert (expected_checksum || out_csum);
if (expected_checksum)
{
if (!repo_find_object (self, objtype, expected_checksum, &stored_path,
cancellable, error))
goto out;
}
if (out_csum) if (out_csum)
{ {
checksum = g_checksum_new (G_CHECKSUM_SHA256); checksum = g_checksum_new (G_CHECKSUM_SHA256);
@ -861,8 +870,7 @@ stage_object_internal (OstreeRepo *self,
checksum_input = ostree_checksum_input_stream_new (input, checksum); checksum_input = ostree_checksum_input_stream_new (input, checksum);
} }
if (objtype == OSTREE_OBJECT_TYPE_FILE if (objtype == OSTREE_OBJECT_TYPE_FILE)
&& (flags & OSTREE_REPO_STAGE_FLAGS_LENGTH_VALID) > 0)
{ {
ot_lobj GInputStream *file_input = NULL; ot_lobj GInputStream *file_input = NULL;
ot_lobj GFileInfo *file_info = NULL; ot_lobj GFileInfo *file_info = NULL;
@ -1038,50 +1046,6 @@ stage_object_internal (OstreeRepo *self,
return ret; return ret;
} }
static gboolean
stage_object (OstreeRepo *self,
OstreeRepoStageFlags flags,
OstreeObjectType objtype,
GInputStream *input,
guint64 file_object_length,
const char *expected_checksum,
guchar **out_csum,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
ot_lobj GFile *stored_path = NULL;
ot_lfree guchar *ret_csum = NULL;
g_return_val_if_fail (self->in_transaction, FALSE);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
g_assert (expected_checksum || out_csum);
if (expected_checksum)
{
if (!repo_find_object (self, objtype, expected_checksum, &stored_path,
cancellable, error))
goto out;
}
if (stored_path == NULL)
{
if (!stage_object_internal (self, flags, objtype, input,
file_object_length, expected_checksum,
out_csum ? &ret_csum : NULL,
cancellable, error))
goto out;
}
ret = TRUE;
ot_transfer_out_value(out_csum, &ret_csum);
out:
return ret;
}
static gboolean static gboolean
get_loose_object_dirs (OstreeRepo *self, get_loose_object_dirs (OstreeRepo *self,
GPtrArray **out_object_dirs, GPtrArray **out_object_dirs,
@ -1322,26 +1286,56 @@ ostree_repo_abort_transaction (OstreeRepo *self,
return ret; return ret;
} }
static gboolean /**
stage_metadata_object (OstreeRepo *self, * ostree_repo_stage_metadata:
OstreeObjectType type, *
GVariant *variant, * Store the metadata object @variant. Return the checksum
guchar **out_csum, * as @out_csum.
GCancellable *cancellable, *
GError **error) * If @expected_checksum is not %NULL, verify it against the
* computed checksum.
*/
gboolean
ostree_repo_stage_metadata (OstreeRepo *self,
OstreeObjectType type,
const char *expected_checksum,
GVariant *variant,
guchar **out_csum,
GCancellable *cancellable,
GError **error)
{ {
gboolean ret = FALSE;
ot_lobj GInputStream *input = NULL; ot_lobj GInputStream *input = NULL;
ot_lvariant GVariant *normalized = NULL;
input = ot_variant_read (variant); normalized = g_variant_get_normal_form (variant);
input = ot_variant_read (normalized);
if (!stage_object (self, 0, type, input, 0, NULL, return stage_object (self, type, expected_checksum, input, 0, out_csum,
out_csum, cancellable, error)) cancellable, error);
goto out; }
ret = TRUE; /**
out: * ostree_repo_stage_metadata_trusted:
return ret; *
* Store the metadata object @variant; the provided @checksum
* is trusted.
*/
gboolean
ostree_repo_stage_metadata_trusted (OstreeRepo *self,
OstreeObjectType type,
const char *checksum,
GVariant *variant,
GCancellable *cancellable,
GError **error)
{
ot_lobj GInputStream *input = NULL;
ot_lvariant GVariant *normalized = NULL;
normalized = g_variant_get_normal_form (variant);
input = ot_variant_read (normalized);
return stage_object (self, type, checksum, input, 0, NULL,
cancellable, error);
} }
static gboolean static gboolean
@ -1352,7 +1346,6 @@ stage_directory_meta (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
gboolean ret = FALSE;
ot_lvariant GVariant *dirmeta = NULL; ot_lvariant GVariant *dirmeta = NULL;
if (g_cancellable_set_error_if_cancelled (cancellable, error)) if (g_cancellable_set_error_if_cancelled (cancellable, error))
@ -1360,13 +1353,8 @@ stage_directory_meta (OstreeRepo *self,
dirmeta = ostree_create_directory_metadata (file_info, xattrs); dirmeta = ostree_create_directory_metadata (file_info, xattrs);
if (!stage_metadata_object (self, OSTREE_OBJECT_TYPE_DIR_META, return ostree_repo_stage_metadata (self, OSTREE_OBJECT_TYPE_DIR_META, NULL,
dirmeta, out_csum, cancellable, error)) dirmeta, out_csum, cancellable, error);
goto out;
ret = TRUE;
out:
return ret;
} }
GFile * GFile *
@ -1384,77 +1372,49 @@ ostree_repo_get_object_path (OstreeRepo *self,
return ret; return ret;
} }
/**
* ostree_repo_stage_content_trusted:
*
* Store the content object streamed as @object_input, with total
* length @length. The given @checksum will be treated as trusted.
*
* This function should be used when importing file objects from local
* disk, for example.
*/
gboolean gboolean
ostree_repo_stage_object_trusted (OstreeRepo *self, ostree_repo_stage_content_trusted (OstreeRepo *self,
OstreeObjectType objtype, const char *checksum,
const char *checksum, GInputStream *object_input,
GInputStream *object_input, guint64 length,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
int flags = 0; return stage_object (self, OSTREE_OBJECT_TYPE_FILE, checksum,
return stage_object (self, flags, objtype, object_input, length, NULL,
object_input, 0, checksum, NULL,
cancellable, error); cancellable, error);
} }
/**
* ostree_repo_stage_content:
*
* Store the content object streamed as @object_input,
* with total length @length. The actual checksum will
* be returned as @out_csum.
*/
gboolean gboolean
ostree_repo_stage_object (OstreeRepo *self, ostree_repo_stage_content (OstreeRepo *self,
OstreeObjectType objtype, const char *expected_checksum,
const char *expected_checksum, GInputStream *object_input,
GInputStream *object_input, guint64 length,
GCancellable *cancellable, guchar **out_csum,
GError **error) GCancellable *cancellable,
GError **error)
{ {
gboolean ret = FALSE; return stage_object (self, OSTREE_OBJECT_TYPE_FILE, expected_checksum,
ot_lfree guchar *actual_csum = NULL; object_input, length, out_csum,
if (!stage_object (self, 0, objtype,
object_input, 0, expected_checksum, &actual_csum,
cancellable, error))
goto out;
ret = TRUE;
out:
return ret;
}
gboolean
ostree_repo_stage_file_object_trusted (OstreeRepo *self,
const char *checksum,
GInputStream *object_input,
guint64 length,
GCancellable *cancellable,
GError **error)
{
int flags = OSTREE_REPO_STAGE_FLAGS_LENGTH_VALID;
return stage_object (self, flags, OSTREE_OBJECT_TYPE_FILE,
object_input, length, checksum, NULL,
cancellable, error); cancellable, error);
} }
gboolean
ostree_repo_stage_file_object (OstreeRepo *self,
const char *expected_checksum,
GInputStream *object_input,
guint64 length,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
int flags = OSTREE_REPO_STAGE_FLAGS_LENGTH_VALID;
ot_lfree guchar *actual_csum = NULL;
if (!stage_object (self, flags, OSTREE_OBJECT_TYPE_FILE,
object_input, length, expected_checksum, &actual_csum,
cancellable, error))
goto out;
ret = TRUE;
out:
return ret;
}
static GVariant * static GVariant *
create_empty_gvariant_dict (void) create_empty_gvariant_dict (void)
{ {
@ -1658,8 +1618,9 @@ ostree_repo_stage_commit (OstreeRepo *self,
ostree_checksum_to_bytes_v (root_contents_checksum), ostree_checksum_to_bytes_v (root_contents_checksum),
ostree_checksum_to_bytes_v (root_metadata_checksum)); ostree_checksum_to_bytes_v (root_metadata_checksum));
g_variant_ref_sink (commit); g_variant_ref_sink (commit);
if (!stage_metadata_object (self, OSTREE_OBJECT_TYPE_COMMIT, if (!ostree_repo_stage_metadata (self, OSTREE_OBJECT_TYPE_COMMIT, NULL,
commit, &commit_csum, cancellable, error)) commit, &commit_csum,
cancellable, error))
goto out; goto out;
ret_commit = ostree_checksum_from_bytes (commit_csum); ret_commit = ostree_checksum_from_bytes (commit_csum);
@ -1932,9 +1893,8 @@ stage_directory_to_mtree_internal (OstreeRepo *self,
&file_object_input, &file_obj_length, &file_object_input, &file_obj_length,
cancellable, error)) cancellable, error))
goto out; goto out;
if (!stage_object (self, OSTREE_REPO_STAGE_FLAGS_LENGTH_VALID, if (!ostree_repo_stage_content (self, NULL, file_object_input, file_obj_length,
OSTREE_OBJECT_TYPE_FILE, file_object_input, file_obj_length, &child_file_csum, cancellable, error))
NULL, &child_file_csum, cancellable, error))
goto out; goto out;
g_free (tmp_checksum); g_free (tmp_checksum);
@ -2041,9 +2001,9 @@ ostree_repo_stage_mtree (OstreeRepo *self,
dir_contents_checksums, dir_contents_checksums,
dir_metadata_checksums); dir_metadata_checksums);
if (!stage_metadata_object (self, OSTREE_OBJECT_TYPE_DIR_TREE, if (!ostree_repo_stage_metadata (self, OSTREE_OBJECT_TYPE_DIR_TREE, NULL,
serialized_tree, &contents_csum, serialized_tree, &contents_csum,
cancellable, error)) cancellable, error))
goto out; goto out;
ret_contents_checksum = ostree_checksum_from_bytes (contents_csum); ret_contents_checksum = ostree_checksum_from_bytes (contents_csum);
} }
@ -2140,9 +2100,8 @@ import_libarchive_entry_file (OstreeRepo *self,
&file_object_input, &length, cancellable, error)) &file_object_input, &length, cancellable, error))
goto out; goto out;
if (!stage_object (self, OSTREE_REPO_STAGE_FLAGS_LENGTH_VALID, OSTREE_OBJECT_TYPE_FILE, if (!ostree_repo_stage_content (self, NULL, file_object_input, length, out_csum,
file_object_input, length, NULL, out_csum, cancellable, error))
cancellable, error))
goto out; goto out;
ret = TRUE; ret = TRUE;

View File

@ -94,33 +94,35 @@ gboolean ostree_repo_has_object (OstreeRepo *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
gboolean ostree_repo_stage_object (OstreeRepo *self, gboolean ostree_repo_stage_metadata (OstreeRepo *self,
OstreeObjectType objtype, OstreeObjectType objtype,
const char *expected_checksum, const char *expected_checksum,
GInputStream *content, GVariant *object,
GCancellable *cancellable, guchar **out_csum,
GError **error); GCancellable *cancellable,
GError **error);
gboolean ostree_repo_stage_file_object (OstreeRepo *self, gboolean ostree_repo_stage_content (OstreeRepo *self,
const char *expected_checksum, const char *expected_checksum,
GInputStream *content, GInputStream *content,
guint64 content_length, guint64 content_length,
GCancellable *cancellable, guchar **out_csum,
GError **error); GCancellable *cancellable,
GError **error);
gboolean ostree_repo_stage_object_trusted (OstreeRepo *self, gboolean ostree_repo_stage_metadata_trusted (OstreeRepo *self,
OstreeObjectType objtype, OstreeObjectType objtype,
const char *checksum, const char *checksum,
GInputStream *content, GVariant *object,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
gboolean ostree_repo_stage_file_object_trusted (OstreeRepo *self, gboolean ostree_repo_stage_content_trusted (OstreeRepo *self,
const char *checksum, const char *checksum,
GInputStream *content, GInputStream *content,
guint64 content_length, guint64 content_length,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
gboolean ostree_repo_resolve_rev (OstreeRepo *self, gboolean ostree_repo_resolve_rev (OstreeRepo *self,
const char *rev, const char *rev,

View File

@ -359,7 +359,6 @@ fetch_and_store_metadata (OtPullData *pull_data,
gboolean is_stored; gboolean is_stored;
ot_lvariant GVariant *ret_variant = NULL; ot_lvariant GVariant *ret_variant = NULL;
ot_lobj GFile *temp_path = NULL; ot_lobj GFile *temp_path = NULL;
ot_lobj GInputStream *input = NULL;
ot_lvariant GVariant *metadata = NULL; ot_lvariant GVariant *metadata = NULL;
g_assert (OSTREE_OBJECT_TYPE_IS_META (objtype)); g_assert (OSTREE_OBJECT_TYPE_IS_META (objtype));
@ -370,15 +369,32 @@ fetch_and_store_metadata (OtPullData *pull_data,
if (!is_stored) if (!is_stored)
{ {
ot_lvariant GVariant *tmp_metadata = NULL;
const GVariantType *vtype;
if (!fetch_loose_object (pull_data, checksum, objtype, &temp_path, cancellable, error)) if (!fetch_loose_object (pull_data, checksum, objtype, &temp_path, cancellable, error))
goto out; goto out;
input = (GInputStream*)g_file_read (temp_path, cancellable, error); switch (objtype)
if (!input) {
case OSTREE_OBJECT_TYPE_DIR_TREE:
vtype = OSTREE_TREE_GVARIANT_FORMAT;
break;
case OSTREE_OBJECT_TYPE_DIR_META:
vtype = OSTREE_DIRMETA_GVARIANT_FORMAT;
break;
case OSTREE_OBJECT_TYPE_COMMIT:
vtype = OSTREE_COMMIT_GVARIANT_FORMAT;
break;
default:
g_assert_not_reached ();
}
if (!ot_util_variant_map (temp_path, vtype, FALSE, &tmp_metadata, error))
goto out; goto out;
if (!ostree_repo_stage_object (pull_data->repo, objtype, checksum, input, if (!ostree_repo_stage_metadata (pull_data->repo, objtype, checksum, tmp_metadata, NULL,
cancellable, error)) cancellable, error))
goto out; goto out;
} }
@ -664,9 +680,9 @@ content_fetch_on_checksum_complete (GObject *object,
goto out; goto out;
} }
if (!ostree_repo_stage_file_object_trusted (data->pull_data->repo, checksum, if (!ostree_repo_stage_content_trusted (data->pull_data->repo, checksum,
file_object_input, length, file_object_input, length,
cancellable, error)) cancellable, error))
goto out; goto out;
out: out:

View File

@ -45,17 +45,16 @@ import_one_object (OtLocalCloneData *data,
GError **error) GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
ot_lobj GFileInfo *file_info = NULL;
ot_lobj GFile *content_path = NULL; ot_lobj GFile *content_path = NULL;
ot_lobj GFileInfo *archive_info = NULL; ot_lobj GFileInfo *archive_info = NULL;
ot_lvariant GVariant *metadata = NULL;
ot_lvariant GVariant *xattrs = NULL;
ot_lobj GInputStream *input = NULL;
if (objtype == OSTREE_OBJECT_TYPE_FILE) if (objtype == OSTREE_OBJECT_TYPE_FILE)
{ {
ot_lobj GInputStream *file_object = NULL;
guint64 length; guint64 length;
ot_lobj GInputStream *file_object = NULL;
ot_lobj GInputStream *input = NULL;
ot_lobj GFileInfo *file_info = NULL;
ot_lvariant GVariant *xattrs = NULL;
if (!ostree_repo_load_file (data->src_repo, checksum, if (!ostree_repo_load_file (data->src_repo, checksum,
&input, &file_info, &xattrs, &input, &file_info, &xattrs,
@ -67,22 +66,21 @@ import_one_object (OtLocalCloneData *data,
cancellable, error)) cancellable, error))
goto out; goto out;
if (!ostree_repo_stage_file_object_trusted (data->dest_repo, checksum, if (!ostree_repo_stage_content_trusted (data->dest_repo, checksum,
file_object, length, file_object, length,
cancellable, error)) cancellable, error))
goto out; goto out;
} }
else else
{ {
ot_lvariant GVariant *metadata = NULL;
if (!ostree_repo_load_variant (data->src_repo, objtype, checksum, &metadata, if (!ostree_repo_load_variant (data->src_repo, objtype, checksum, &metadata,
error)) error))
goto out; goto out;
input = ot_variant_read (metadata); if (!ostree_repo_stage_metadata_trusted (data->dest_repo, objtype, checksum, metadata,
cancellable, error))
if (!ostree_repo_stage_object_trusted (data->dest_repo, objtype,
checksum, input,
cancellable, error))
goto out; goto out;
} }