deltas: Flesh out the open/write/close opcodes

Refactor open-splice-and-close to call open/close.  We can't just call
write as that would require duplicating the object size parameter.
This commit is contained in:
Colin Walters 2015-01-29 22:32:44 -05:00
parent 96181da26a
commit 7900c82a36
1 changed files with 123 additions and 62 deletions

View File

@ -54,6 +54,16 @@ typedef struct {
GError **async_error; GError **async_error;
OstreeObjectType output_objtype; OstreeObjectType output_objtype;
OstreeRepoTrustedContentBareCommit barecommitstate;
guint64 content_size;
GOutputStream *content_out;
char checksum[65];
gboolean have_obj;
guint32 uid;
guint32 gid;
guint32 mode;
GVariant *xattrs;
const guint8 *output_target; const guint8 *output_target;
const guint8 *input_target_csum; const guint8 *input_target_csum;
@ -113,7 +123,6 @@ open_output_target (StaticDeltaExecutionState *state,
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
guint8 *objcsum; guint8 *objcsum;
char checksum[65];
g_assert (state->checksums != NULL); g_assert (state->checksums != NULL);
g_assert (state->output_target == NULL); g_assert (state->output_target == NULL);
@ -127,7 +136,7 @@ open_output_target (StaticDeltaExecutionState *state,
state->output_objtype = (OstreeObjectType) *objcsum; state->output_objtype = (OstreeObjectType) *objcsum;
state->output_target = objcsum + 1; state->output_target = objcsum + 1;
ostree_checksum_inplace_from_bytes (state->output_target, checksum); ostree_checksum_inplace_from_bytes (state->output_target, state->checksum);
ret = TRUE; ret = TRUE;
out: out:
@ -438,6 +447,38 @@ validate_ofs (StaticDeltaExecutionState *state,
return TRUE; return TRUE;
} }
static gboolean
do_content_open_generic (OstreeRepo *repo,
StaticDeltaExecutionState *state,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
gs_unref_variant GVariant *modev;
guint64 mode_offset;
guint64 xattr_offset;
guint32 uid, gid, mode;
if (!read_varuint64 (state, &mode_offset, error))
goto out;
if (!read_varuint64 (state, &xattr_offset, error))
goto out;
state->barecommitstate.fd = -1;
modev = g_variant_get_child_value (state->mode_dict, mode_offset);
g_variant_get (modev, "(uuu)", &uid, &gid, &mode);
state->uid = GUINT32_FROM_BE (uid);
state->gid = GUINT32_FROM_BE (gid);
state->mode = GUINT32_FROM_BE (mode);
state->xattrs = g_variant_get_child_value (state->xattr_dict, xattr_offset);
ret = TRUE;
out:
return ret;
}
static gboolean static gboolean
dispatch_open_splice_and_close (OstreeRepo *repo, dispatch_open_splice_and_close (OstreeRepo *repo,
StaticDeltaExecutionState *state, StaticDeltaExecutionState *state,
@ -445,13 +486,10 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
GError **error) GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
char checksum[65];
if (!open_output_target (state, cancellable, error)) if (!open_output_target (state, cancellable, error))
goto out; goto out;
ostree_checksum_inplace_from_bytes (state->output_target, checksum);
if (OSTREE_OBJECT_TYPE_IS_META (state->output_objtype)) if (OSTREE_OBJECT_TYPE_IS_META (state->output_objtype))
{ {
gs_unref_variant GVariant *metadata = NULL; gs_unref_variant GVariant *metadata = NULL;
@ -469,7 +507,7 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
state->payload_data + offset, length, TRUE, NULL, NULL); state->payload_data + offset, length, TRUE, NULL, NULL);
if (!ostree_repo_write_metadata_trusted (state->repo, state->output_objtype, if (!ostree_repo_write_metadata_trusted (state->repo, state->output_objtype,
checksum, state->checksum,
metadata, metadata,
cancellable, cancellable,
error)) error))
@ -477,81 +515,54 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
} }
else else
{ {
guint64 mode_offset;
guint64 xattr_offset;
guint64 content_size;
guint64 content_offset; guint64 content_offset;
guint64 objlen; guint64 objlen;
guint64 content_size;
gsize bytes_written;
gs_unref_object GInputStream *object_input = NULL; gs_unref_object GInputStream *object_input = NULL;
gs_unref_object GInputStream *memin = NULL; gs_unref_object GInputStream *memin = NULL;
gs_unref_variant GVariant *xattrs_buf = NULL;
GVariant *modev; if (!do_content_open_generic (repo, state, cancellable, error))
GVariant *xattrs; goto out;
guint32 uid, gid, mode;
if (!read_varuint64 (state, &mode_offset, error))
goto out;
if (!read_varuint64 (state, &xattr_offset, error))
goto out;
if (!read_varuint64 (state, &content_size, error)) if (!read_varuint64 (state, &content_size, error))
goto out; goto out;
if (!read_varuint64 (state, &content_offset, error)) if (!read_varuint64 (state, &content_offset, error))
goto out; goto out;
if (!validate_ofs (state, content_offset, content_size, error)) if (!validate_ofs (state, content_offset, content_size, error))
goto out; goto out;
modev = g_variant_get_child_value (state->mode_dict, mode_offset);
g_variant_get (modev, "(uuu)", &uid, &gid, &mode);
uid = GUINT32_FROM_BE (uid);
gid = GUINT32_FROM_BE (gid);
mode = GUINT32_FROM_BE (mode);
xattrs = g_variant_get_child_value (state->xattr_dict, xattr_offset);
/* Fast path for regular files to bare repositories */ /* Fast path for regular files to bare repositories */
if (S_ISREG (mode) && if (S_ISREG (state->mode) &&
(repo->mode == OSTREE_REPO_MODE_BARE || (repo->mode == OSTREE_REPO_MODE_BARE ||
repo->mode == OSTREE_REPO_MODE_BARE_USER)) repo->mode == OSTREE_REPO_MODE_BARE_USER))
{ {
OstreeRepoTrustedContentBareCommit barecommitstate = { -1 }; if (!_ostree_repo_open_trusted_content_bare (repo, state->checksum,
gs_unref_object GOutputStream *outstream = NULL; state->content_size,
gsize bytes_written; &state->barecommitstate,
gboolean have_obj; &state->content_out,
&state->have_obj,
if (!_ostree_repo_open_trusted_content_bare (repo, checksum,
content_size,
&barecommitstate,
&outstream,
&have_obj,
cancellable, error)) cancellable, error))
goto out; goto out;
if (!have_obj) if (!state->have_obj)
{ {
if (!g_output_stream_write_all (outstream, state->payload_data + content_offset, if (!g_output_stream_write_all (state->content_out,
state->payload_data + content_offset,
content_size, content_size,
&bytes_written, &bytes_written,
cancellable, error)) cancellable, error))
goto out; goto out;
if (!g_output_stream_flush (outstream, cancellable, error))
goto out;
} }
if (!_ostree_repo_commit_trusted_content_bare (repo, checksum, &barecommitstate,
uid, gid, mode, xattrs,
cancellable, error))
goto out;
} }
else else
{ {
/* Slower path, for symlinks and unpacking deltas into archive-z2 */ /* Slower path, for symlinks and unpacking deltas into archive-z2 */
gs_unref_object GFileInfo *finfo = NULL; gs_unref_object GFileInfo *finfo = NULL;
finfo = _ostree_header_gfile_info_new (mode, uid, gid); finfo = _ostree_header_gfile_info_new (state->mode, state->uid, state->gid);
if (S_ISLNK (mode)) if (S_ISLNK (state->mode))
{ {
gs_free char *nulterminated_target = gs_free char *nulterminated_target =
g_strndup ((char*)state->payload_data + content_offset, content_size); g_strndup ((char*)state->payload_data + content_offset, content_size);
@ -559,18 +570,18 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
} }
else else
{ {
g_assert (S_ISREG (mode)); g_assert (S_ISREG (state->mode));
g_file_info_set_size (finfo, content_size); g_file_info_set_size (finfo, content_size);
memin = g_memory_input_stream_new_from_data (state->payload_data + content_offset, content_size, NULL); memin = g_memory_input_stream_new_from_data (state->payload_data + content_offset, content_size, NULL);
} }
if (!ostree_raw_file_to_content_stream (memin, finfo, xattrs, if (!ostree_raw_file_to_content_stream (memin, finfo, state->xattrs,
&object_input, &objlen, &object_input, &objlen,
cancellable, error)) cancellable, error))
goto out; goto out;
if (!ostree_repo_write_content_trusted (state->repo, if (!ostree_repo_write_content_trusted (state->repo,
checksum, state->checksum,
object_input, object_input,
objlen, objlen,
cancellable, cancellable,
@ -579,8 +590,8 @@ dispatch_open_splice_and_close (OstreeRepo *repo,
} }
} }
state->checksum_index++; if (!dispatch_close (repo, state, cancellable, error))
state->output_target = NULL; goto out;
ret = TRUE; ret = TRUE;
out: out:
@ -597,9 +608,25 @@ dispatch_open (OstreeRepo *repo,
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
g_assert (state->output_target == NULL);
/* FIXME - lift this restriction */
g_assert (repo->mode == OSTREE_REPO_MODE_BARE ||
repo->mode == OSTREE_REPO_MODE_BARE_USER);
if (!open_output_target (state, cancellable, error)) if (!open_output_target (state, cancellable, error))
goto out; goto out;
if (!do_content_open_generic (repo, state, cancellable, error))
goto out;
if (!_ostree_repo_open_trusted_content_bare (repo, state->checksum,
state->content_size,
&state->barecommitstate,
&state->content_out,
&state->have_obj,
cancellable, error))
goto out;
ret = TRUE; ret = TRUE;
out: out:
if (!ret) if (!ret)
@ -614,11 +641,29 @@ dispatch_write (OstreeRepo *repo,
GError **error) GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
guint64 content_size;
guint64 content_offset;
gsize bytes_written;
if (!read_varuint64 (state, &content_size, error))
goto out;
if (!read_varuint64 (state, &content_offset, error))
goto out;
if (!validate_ofs (state, content_offset, content_size, error))
goto out;
g_assert_not_reached (); if (!state->have_obj)
{
if (!g_output_stream_write_all (state->content_out,
state->payload_data + content_offset,
content_size,
&bytes_written,
cancellable, error))
goto out;
}
ret = TRUE; ret = TRUE;
/* out: */ out:
if (!ret) if (!ret)
g_prefix_error (error, "opcode open-splice-and-close: "); g_prefix_error (error, "opcode open-splice-and-close: ");
return ret; return ret;
@ -648,11 +693,27 @@ dispatch_close (OstreeRepo *repo,
GError **error) GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
g_assert_not_reached ();
if (state->content_out)
{
if (!g_output_stream_flush (state->content_out, cancellable, error))
goto out;
if (!_ostree_repo_commit_trusted_content_bare (repo, state->checksum, &state->barecommitstate,
state->uid, state->gid, state->mode,
state->xattrs,
cancellable, error))
goto out;
}
g_clear_pointer (&state->xattrs, g_variant_unref);
g_clear_object (&state->content_out);
state->checksum_index++;
state->output_target = NULL;
ret = TRUE; ret = TRUE;
/* out: */ out:
if (!ret) if (!ret)
g_prefix_error (error, "opcode open-splice-and-close: "); g_prefix_error (error, "opcode open-splice-and-close: ");
return ret; return ret;