core: INCOMPATIBLE CHANGE: Split archive files in two parts (meta and content)
This will allow us to have hardlink checkouts of archives. A key use case here is an archive repo of an OS (with root-owned files etc.) where we want to do builds in a user tree. A positive side effect of doing things this way is that now the SHA256 checksums for a given file should be identical regardless of whether it's stored in an archive or bare repository.
This commit is contained in:
parent
ecbffd4915
commit
9a71ab187d
|
|
@ -245,6 +245,8 @@ ostree_checksum_file_from_input (GFileInfo *file_info,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
|
||||||
|
{
|
||||||
ostree_checksum_update_stat (ret_checksum,
|
ostree_checksum_update_stat (ret_checksum,
|
||||||
g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
|
g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
|
||||||
g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
|
g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
|
||||||
|
|
@ -252,6 +254,7 @@ ostree_checksum_file_from_input (GFileInfo *file_info,
|
||||||
/* FIXME - ensure empty xattrs are the same as NULL xattrs */
|
/* FIXME - ensure empty xattrs are the same as NULL xattrs */
|
||||||
if (xattrs)
|
if (xattrs)
|
||||||
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
||||||
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
ot_transfer_out_value (out_checksum, &ret_checksum);
|
ot_transfer_out_value (out_checksum, &ret_checksum);
|
||||||
|
|
@ -291,7 +294,7 @@ ostree_checksum_file (GFile *f,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!OSTREE_OBJECT_TYPE_IS_META(objtype))
|
if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE)
|
||||||
{
|
{
|
||||||
xattrs = ostree_get_xattrs_for_file (f, error);
|
xattrs = ostree_get_xattrs_for_file (f, error);
|
||||||
if (!xattrs)
|
if (!xattrs)
|
||||||
|
|
@ -444,35 +447,34 @@ ostree_set_xattrs (GFile *f,
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
ostree_parse_metadata_file (GFile *file,
|
ostree_map_metadata_file (GFile *file,
|
||||||
OstreeObjectType *out_type,
|
OstreeObjectType expected_type,
|
||||||
GVariant **out_variant,
|
GVariant **out_variant,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GVariant *ret_variant = NULL;
|
GVariant *ret_variant = NULL;
|
||||||
GVariant *container = NULL;
|
GVariant *container = NULL;
|
||||||
guint32 ret_type;
|
guint32 actual_type;
|
||||||
|
|
||||||
if (!ot_util_variant_map (file, G_VARIANT_TYPE (OSTREE_SERIALIZED_VARIANT_FORMAT),
|
if (!ot_util_variant_map (file, OSTREE_SERIALIZED_VARIANT_FORMAT,
|
||||||
&container, error))
|
&container, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
g_variant_get (container, "(uv)",
|
g_variant_get (container, "(uv)",
|
||||||
&ret_type, &ret_variant);
|
&actual_type, &ret_variant);
|
||||||
ret_type = GUINT32_FROM_BE (ret_type);
|
ot_util_variant_take_ref (ret_variant);
|
||||||
if (!OSTREE_OBJECT_TYPE_IS_META (ret_type))
|
actual_type = GUINT32_FROM_BE (actual_type);
|
||||||
|
if (actual_type != expected_type)
|
||||||
{
|
{
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
"Corrupted metadata object '%s'; invalid type %d",
|
"Corrupted metadata object '%s'; found type %u, expected %u",
|
||||||
ot_gfile_get_path_cached (file), ret_type);
|
ot_gfile_get_path_cached (file),
|
||||||
|
actual_type, (guint32)expected_type);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
ot_util_variant_take_ref (ret_variant);
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
if (out_type)
|
|
||||||
*out_type = ret_type;
|
|
||||||
ot_transfer_out_value(out_variant, &ret_variant);
|
ot_transfer_out_value(out_variant, &ret_variant);
|
||||||
out:
|
out:
|
||||||
ot_clear_gvariant (&ret_variant);
|
ot_clear_gvariant (&ret_variant);
|
||||||
|
|
@ -541,201 +543,66 @@ ostree_get_relative_object_path (const char *checksum,
|
||||||
return g_string_free (path, FALSE);
|
return g_string_free (path, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
GVariant *
|
||||||
ostree_archive_file_for_input (GOutputStream *output,
|
ostree_create_archive_file_metadata (GFileInfo *finfo,
|
||||||
GFileInfo *finfo,
|
GVariant *xattrs)
|
||||||
GInputStream *instream,
|
|
||||||
GVariant *xattrs,
|
|
||||||
GChecksum **out_checksum,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
guint32 uid, gid, mode, rdev;
|
||||||
guint32 uid, gid, mode;
|
|
||||||
guint32 device = 0;
|
|
||||||
guint32 metadata_size_be;
|
|
||||||
const char *target = NULL;
|
|
||||||
guint64 object_size;
|
|
||||||
gboolean pack_builder_initialized = FALSE;
|
|
||||||
GVariantBuilder pack_builder;
|
GVariantBuilder pack_builder;
|
||||||
GVariant *pack_variant = NULL;
|
GVariant *ret = NULL;
|
||||||
gsize bytes_written;
|
|
||||||
GChecksum *ret_checksum = NULL;
|
|
||||||
|
|
||||||
uid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_UID);
|
uid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_UID);
|
||||||
gid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_GID);
|
gid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_GID);
|
||||||
mode = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_MODE);
|
mode = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_MODE);
|
||||||
|
rdev = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_RDEV);
|
||||||
|
|
||||||
g_variant_builder_init (&pack_builder, G_VARIANT_TYPE (OSTREE_ARCHIVED_FILE_VARIANT_FORMAT));
|
g_variant_builder_init (&pack_builder, OSTREE_ARCHIVED_FILE_VARIANT_FORMAT);
|
||||||
pack_builder_initialized = TRUE;
|
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (0)); /* Version */
|
||||||
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (0));
|
|
||||||
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (uid));
|
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (uid));
|
||||||
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (gid));
|
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (gid));
|
||||||
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (mode));
|
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (mode));
|
||||||
|
g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (rdev));
|
||||||
|
if (S_ISLNK (mode))
|
||||||
|
g_variant_builder_add (&pack_builder, "s", g_file_info_get_symlink_target (finfo));
|
||||||
|
else
|
||||||
|
g_variant_builder_add (&pack_builder, "s", "");
|
||||||
|
|
||||||
g_variant_builder_add (&pack_builder, "@a(ayay)", xattrs ? xattrs : g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0));
|
g_variant_builder_add (&pack_builder, "@a(ayay)", xattrs ? xattrs : g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0));
|
||||||
|
|
||||||
if (S_ISREG (mode))
|
ret = g_variant_builder_end (&pack_builder);
|
||||||
{
|
g_variant_ref_sink (ret);
|
||||||
object_size = (guint64)g_file_info_get_size (finfo);
|
|
||||||
}
|
|
||||||
else if (S_ISLNK (mode))
|
|
||||||
{
|
|
||||||
target = g_file_info_get_attribute_byte_string (finfo, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
|
|
||||||
object_size = strlen (target);
|
|
||||||
}
|
|
||||||
else if (S_ISBLK (mode) || S_ISCHR (mode))
|
|
||||||
{
|
|
||||||
device = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_RDEV);
|
|
||||||
object_size = 4;
|
|
||||||
}
|
|
||||||
else if (S_ISFIFO (mode))
|
|
||||||
{
|
|
||||||
object_size = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Invalid mode %u", mode);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_variant_builder_add (&pack_builder, "t", GUINT64_TO_BE (object_size));
|
|
||||||
pack_variant = g_variant_builder_end (&pack_builder);
|
|
||||||
pack_builder_initialized = FALSE;
|
|
||||||
|
|
||||||
metadata_size_be = GUINT32_TO_BE (g_variant_get_size (pack_variant));
|
|
||||||
|
|
||||||
if (!g_output_stream_write_all (output, &metadata_size_be, 4,
|
|
||||||
&bytes_written, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
g_assert (bytes_written == 4);
|
|
||||||
|
|
||||||
if (!g_output_stream_write_all (output, g_variant_get_data (pack_variant), g_variant_get_size (pack_variant),
|
|
||||||
&bytes_written, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (S_ISREG (mode))
|
|
||||||
{
|
|
||||||
if (!ot_gio_splice_and_checksum (output, (GInputStream*)instream,
|
|
||||||
out_checksum ? &ret_checksum : NULL,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else if (S_ISLNK (mode))
|
|
||||||
{
|
|
||||||
if (out_checksum)
|
|
||||||
{
|
|
||||||
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
|
||||||
g_checksum_update (ret_checksum, (guint8*)target, object_size);
|
|
||||||
}
|
|
||||||
if (!g_output_stream_write_all (output, target, object_size,
|
|
||||||
&bytes_written, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else if (S_ISBLK (mode) || S_ISCHR (mode))
|
|
||||||
{
|
|
||||||
guint32 device_be = GUINT32_TO_BE (device);
|
|
||||||
g_assert (object_size == 4);
|
|
||||||
if (out_checksum)
|
|
||||||
{
|
|
||||||
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
|
||||||
g_checksum_update (ret_checksum, (guint8*)&device_be, 4);
|
|
||||||
}
|
|
||||||
if (!g_output_stream_write_all (output, &device_be, object_size,
|
|
||||||
&bytes_written, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
g_assert (bytes_written == 4);
|
|
||||||
}
|
|
||||||
else if (S_ISFIFO (mode))
|
|
||||||
{
|
|
||||||
if (out_checksum)
|
|
||||||
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
g_assert_not_reached ();
|
|
||||||
|
|
||||||
if (ret_checksum)
|
|
||||||
{
|
|
||||||
ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
|
|
||||||
if (xattrs)
|
|
||||||
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
ot_transfer_out_value(out_checksum, &ret_checksum);
|
|
||||||
out:
|
|
||||||
if (pack_builder_initialized)
|
|
||||||
g_variant_builder_clear (&pack_builder);
|
|
||||||
ot_clear_gvariant (&pack_variant);
|
|
||||||
ot_clear_checksum (&ret_checksum);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
ostree_parse_archived_file (GFile *file,
|
ostree_parse_archived_file_meta (GVariant *metadata,
|
||||||
GFileInfo **out_file_info,
|
GFileInfo **out_file_info,
|
||||||
GVariant **out_xattrs,
|
GVariant **out_xattrs,
|
||||||
GInputStream **out_content,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
char *metadata_buf = NULL;
|
|
||||||
GVariant *metadata = NULL;
|
|
||||||
GFileInfo *ret_file_info = NULL;
|
GFileInfo *ret_file_info = NULL;
|
||||||
GVariant *ret_xattrs = NULL;
|
GVariant *ret_xattrs = NULL;
|
||||||
GInputStream *in = NULL;
|
guint32 version, uid, gid, mode, rdev;
|
||||||
guint32 metadata_len;
|
const char *symlink_target;
|
||||||
guint32 version, uid, gid, mode;
|
|
||||||
guint64 content_len;
|
|
||||||
gsize bytes_read;
|
|
||||||
|
|
||||||
in = (GInputStream*)g_file_read (file, NULL, error);
|
g_variant_get (metadata, "(uuuuu&s@a(ayay))",
|
||||||
if (!in)
|
&version, &uid, &gid, &mode, &rdev,
|
||||||
goto out;
|
&symlink_target, &ret_xattrs);
|
||||||
|
version = GUINT32_FROM_BE (version);
|
||||||
|
|
||||||
if (!g_input_stream_read_all (in, &metadata_len, 4, &bytes_read, NULL, error))
|
if (version != 0)
|
||||||
goto out;
|
|
||||||
if (bytes_read != 4)
|
|
||||||
{
|
{
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
"Corrupted archive file; too short while reading metadata length");
|
"Invalid version %d in archived file metadata", version);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata_len = GUINT32_FROM_BE (metadata_len);
|
|
||||||
if (metadata_len > OSTREE_MAX_METADATA_SIZE)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Corrupted archive file; metadata length %u is larger than maximum %u",
|
|
||||||
metadata_len, OSTREE_MAX_METADATA_SIZE);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
metadata_buf = g_malloc (metadata_len);
|
|
||||||
|
|
||||||
if (!g_input_stream_read_all (in, metadata_buf, metadata_len, &bytes_read, NULL, error))
|
|
||||||
goto out;
|
|
||||||
if (bytes_read != metadata_len)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Corrupted archive file; too short while reading metadata");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_ARCHIVED_FILE_VARIANT_FORMAT),
|
|
||||||
metadata_buf, metadata_len, FALSE,
|
|
||||||
(GDestroyNotify)g_free,
|
|
||||||
metadata_buf);
|
|
||||||
metadata_buf = NULL;
|
|
||||||
|
|
||||||
g_variant_get (metadata, "(uuuu@a(ayay)t)",
|
|
||||||
&version, &uid, &gid, &mode,
|
|
||||||
&ret_xattrs, &content_len);
|
|
||||||
uid = GUINT32_FROM_BE (uid);
|
uid = GUINT32_FROM_BE (uid);
|
||||||
gid = GUINT32_FROM_BE (gid);
|
gid = GUINT32_FROM_BE (gid);
|
||||||
mode = GUINT32_FROM_BE (mode);
|
mode = GUINT32_FROM_BE (mode);
|
||||||
content_len = GUINT64_FROM_BE (content_len);
|
rdev = GUINT32_FROM_BE (rdev);
|
||||||
|
|
||||||
ret_file_info = g_file_info_new ();
|
ret_file_info = g_file_info_new ();
|
||||||
g_file_info_set_attribute_uint32 (ret_file_info, "standard::type", ot_gfile_type_for_mode (mode));
|
g_file_info_set_attribute_uint32 (ret_file_info, "standard::type", ot_gfile_type_for_mode (mode));
|
||||||
|
|
@ -743,46 +610,22 @@ ostree_parse_archived_file (GFile *file,
|
||||||
g_file_info_set_attribute_uint32 (ret_file_info, "unix::uid", uid);
|
g_file_info_set_attribute_uint32 (ret_file_info, "unix::uid", uid);
|
||||||
g_file_info_set_attribute_uint32 (ret_file_info, "unix::gid", gid);
|
g_file_info_set_attribute_uint32 (ret_file_info, "unix::gid", gid);
|
||||||
g_file_info_set_attribute_uint32 (ret_file_info, "unix::mode", mode);
|
g_file_info_set_attribute_uint32 (ret_file_info, "unix::mode", mode);
|
||||||
g_file_info_set_attribute_uint64 (ret_file_info, "standard::size", content_len);
|
|
||||||
|
|
||||||
if (S_ISREG (mode))
|
if (S_ISREG (mode))
|
||||||
{
|
{
|
||||||
g_file_info_set_attribute_uint64 (ret_file_info, "standard::size", content_len);
|
;
|
||||||
}
|
}
|
||||||
else if (S_ISLNK (mode))
|
else if (S_ISLNK (mode))
|
||||||
{
|
{
|
||||||
char target[PATH_MAX+1];
|
g_file_info_set_attribute_byte_string (ret_file_info, "standard::symlink-target", symlink_target);
|
||||||
if (!g_input_stream_read_all (in, target, sizeof(target)-1, &bytes_read, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
target[bytes_read] = '\0';
|
|
||||||
|
|
||||||
g_file_info_set_attribute_boolean (ret_file_info, "standard::is-symlink", TRUE);
|
|
||||||
g_file_info_set_attribute_byte_string (ret_file_info, "standard::symlink-target", target);
|
|
||||||
|
|
||||||
g_input_stream_close (in, cancellable, error);
|
|
||||||
g_clear_object (&in);
|
|
||||||
}
|
}
|
||||||
else if (S_ISCHR (mode) || S_ISBLK (mode))
|
else if (S_ISCHR (mode) || S_ISBLK (mode))
|
||||||
{
|
{
|
||||||
guint32 dev;
|
g_file_info_set_attribute_uint32 (ret_file_info, "unix::rdev", rdev);
|
||||||
|
|
||||||
if (!g_input_stream_read_all (in, &dev, 4, &bytes_read, NULL, error))
|
|
||||||
goto out;
|
|
||||||
if (bytes_read != 4)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Corrupted archive file; too short while reading device id");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
dev = GUINT32_FROM_BE (dev);
|
|
||||||
g_file_info_set_attribute_uint32 (ret_file_info, "unix::rdev", dev);
|
|
||||||
g_input_stream_close (in, cancellable, error);
|
|
||||||
g_clear_object (&in);
|
|
||||||
}
|
}
|
||||||
else if (S_ISFIFO (mode))
|
else if (S_ISFIFO (mode))
|
||||||
{
|
{
|
||||||
g_input_stream_close (in, cancellable, error);
|
;
|
||||||
g_clear_object (&in);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -794,12 +637,9 @@ ostree_parse_archived_file (GFile *file,
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
ot_transfer_out_value(out_file_info, &ret_file_info);
|
ot_transfer_out_value(out_file_info, &ret_file_info);
|
||||||
ot_transfer_out_value(out_xattrs, &ret_xattrs);
|
ot_transfer_out_value(out_xattrs, &ret_xattrs);
|
||||||
ot_transfer_out_value(out_content, &in);
|
|
||||||
out:
|
out:
|
||||||
g_clear_object (&ret_file_info);
|
g_clear_object (&ret_file_info);
|
||||||
ot_clear_gvariant (&ret_xattrs);
|
ot_clear_gvariant (&ret_xattrs);
|
||||||
g_clear_object (&in);
|
|
||||||
ot_clear_gvariant (&metadata);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -818,7 +658,11 @@ ostree_create_file_from_input (GFile *dest_file,
|
||||||
GFileOutputStream *out = NULL;
|
GFileOutputStream *out = NULL;
|
||||||
guint32 uid, gid, mode;
|
guint32 uid, gid, mode;
|
||||||
GChecksum *ret_checksum = NULL;
|
GChecksum *ret_checksum = NULL;
|
||||||
gboolean is_meta = OSTREE_OBJECT_TYPE_IS_META (objtype);
|
gboolean is_meta;
|
||||||
|
gboolean is_archived_content;
|
||||||
|
|
||||||
|
is_meta = OSTREE_OBJECT_TYPE_IS_META (objtype);
|
||||||
|
is_archived_content = objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT;
|
||||||
|
|
||||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
@ -829,14 +673,13 @@ ostree_create_file_from_input (GFile *dest_file,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mode = S_IFREG | 0666;
|
mode = S_IFREG | 0664;
|
||||||
}
|
}
|
||||||
dest_path = ot_gfile_get_path_cached (dest_file);
|
dest_path = ot_gfile_get_path_cached (dest_file);
|
||||||
|
|
||||||
if (S_ISDIR (mode))
|
if (S_ISDIR (mode))
|
||||||
{
|
{
|
||||||
if (mkdir (ot_gfile_get_path_cached (dest_file),
|
if (mkdir (ot_gfile_get_path_cached (dest_file), mode) < 0)
|
||||||
g_file_info_get_attribute_uint32 (finfo, "unix::mode")) < 0)
|
|
||||||
{
|
{
|
||||||
ot_util_set_error_from_errno (error, errno);
|
ot_util_set_error_from_errno (error, errno);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -907,7 +750,7 @@ ostree_create_file_from_input (GFile *dest_file,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finfo != NULL)
|
if (finfo != NULL && !is_meta && !is_archived_content)
|
||||||
{
|
{
|
||||||
uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
|
uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
|
||||||
gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
|
gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
|
||||||
|
|
@ -918,11 +761,6 @@ ostree_create_file_from_input (GFile *dest_file,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
uid = geteuid ();
|
|
||||||
gid = getegid ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!S_ISLNK (mode))
|
if (!S_ISLNK (mode))
|
||||||
{
|
{
|
||||||
|
|
@ -940,9 +778,14 @@ ostree_create_file_from_input (GFile *dest_file,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret_checksum && !is_meta)
|
if (ret_checksum && !is_meta && !is_archived_content)
|
||||||
{
|
{
|
||||||
ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
|
g_assert (finfo != NULL);
|
||||||
|
|
||||||
|
ostree_checksum_update_stat (ret_checksum,
|
||||||
|
g_file_info_get_attribute_uint32 (finfo, "unix::uid"),
|
||||||
|
g_file_info_get_attribute_uint32 (finfo, "unix::gid"),
|
||||||
|
mode);
|
||||||
if (xattrs)
|
if (xattrs)
|
||||||
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
||||||
}
|
}
|
||||||
|
|
@ -965,14 +808,14 @@ create_tmp_string (const char *dirpath,
|
||||||
GString *tmp_name = NULL;
|
GString *tmp_name = NULL;
|
||||||
|
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
prefix = "tmp-";
|
prefix = "tmp";
|
||||||
if (!suffix)
|
if (!suffix)
|
||||||
suffix = ".tmp";
|
suffix = "tmp";
|
||||||
|
|
||||||
tmp_name = g_string_new (dirpath);
|
tmp_name = g_string_new (dirpath);
|
||||||
g_string_append_c (tmp_name, '/');
|
g_string_append_c (tmp_name, '/');
|
||||||
g_string_append (tmp_name, prefix);
|
g_string_append (tmp_name, prefix);
|
||||||
g_string_append (tmp_name, "XXXXXX");
|
g_string_append (tmp_name, "-XXXXXXXXXXXX.");
|
||||||
g_string_append (tmp_name, suffix);
|
g_string_append (tmp_name, suffix);
|
||||||
|
|
||||||
return tmp_name;
|
return tmp_name;
|
||||||
|
|
|
||||||
|
|
@ -33,16 +33,17 @@ G_BEGIN_DECLS
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OSTREE_OBJECT_TYPE_RAW_FILE = 1, /* .raw */
|
OSTREE_OBJECT_TYPE_RAW_FILE = 1, /* .raw */
|
||||||
OSTREE_OBJECT_TYPE_ARCHIVED_FILE = 2, /* .archive */
|
OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT = 2, /* .archive-content */
|
||||||
OSTREE_OBJECT_TYPE_DIR_TREE = 3, /* .dirtree */
|
OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META = 3, /* .archive-meta */
|
||||||
OSTREE_OBJECT_TYPE_DIR_META = 4, /* .dirmeta */
|
OSTREE_OBJECT_TYPE_DIR_TREE = 4, /* .dirtree */
|
||||||
OSTREE_OBJECT_TYPE_COMMIT = 5 /* .commit */
|
OSTREE_OBJECT_TYPE_DIR_META = 5, /* .dirmeta */
|
||||||
|
OSTREE_OBJECT_TYPE_COMMIT = 6 /* .commit */
|
||||||
} OstreeObjectType;
|
} OstreeObjectType;
|
||||||
|
|
||||||
#define OSTREE_OBJECT_TYPE_IS_META(t) (t >= 3 && t <= 5)
|
#define OSTREE_OBJECT_TYPE_IS_META(t) (t >= 3 && t <= 6)
|
||||||
#define OSTREE_OBJECT_TYPE_LAST OSTREE_OBJECT_TYPE_COMMIT
|
#define OSTREE_OBJECT_TYPE_LAST OSTREE_OBJECT_TYPE_COMMIT
|
||||||
|
|
||||||
#define OSTREE_SERIALIZED_VARIANT_FORMAT "(uv)"
|
#define OSTREE_SERIALIZED_VARIANT_FORMAT G_VARIANT_TYPE("(uv)")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xattr objects:
|
* xattr objects:
|
||||||
|
|
@ -116,8 +117,8 @@ GVariant *ostree_wrap_metadata_variant (OstreeObjectType type, GVariant *metadat
|
||||||
gboolean ostree_set_xattrs (GFile *f, GVariant *xattrs,
|
gboolean ostree_set_xattrs (GFile *f, GVariant *xattrs,
|
||||||
GCancellable *cancellable, GError **error);
|
GCancellable *cancellable, GError **error);
|
||||||
|
|
||||||
gboolean ostree_parse_metadata_file (GFile *file,
|
gboolean ostree_map_metadata_file (GFile *file,
|
||||||
OstreeObjectType *out_type,
|
OstreeObjectType expected_type,
|
||||||
GVariant **out_variant,
|
GVariant **out_variant,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
|
@ -150,32 +151,6 @@ gboolean ostree_checksum_file_async_finish (GFile *f,
|
||||||
GVariant *ostree_create_directory_metadata (GFileInfo *dir_info,
|
GVariant *ostree_create_directory_metadata (GFileInfo *dir_info,
|
||||||
GVariant *xattrs);
|
GVariant *xattrs);
|
||||||
|
|
||||||
/* Archived files:
|
|
||||||
*
|
|
||||||
* guint32 metadata_length [metadata gvariant] [content]
|
|
||||||
*
|
|
||||||
* metadata variant:
|
|
||||||
* u - Version
|
|
||||||
* u - uid
|
|
||||||
* u - gid
|
|
||||||
* u - mode
|
|
||||||
* a(ayay) - xattrs
|
|
||||||
* t - content length
|
|
||||||
*
|
|
||||||
* And then following the end of the variant is the content. If
|
|
||||||
* symlink, then this is the target; if device, then device ID as
|
|
||||||
* network byte order uint32.
|
|
||||||
*/
|
|
||||||
#define OSTREE_ARCHIVED_FILE_VARIANT_FORMAT "(uuuua(ayay)t)"
|
|
||||||
|
|
||||||
gboolean ostree_archive_file_for_input (GOutputStream *output,
|
|
||||||
GFileInfo *finfo,
|
|
||||||
GInputStream *input,
|
|
||||||
GVariant *xattrs,
|
|
||||||
GChecksum **out_checksum,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
gboolean ostree_create_file_from_input (GFile *file,
|
gboolean ostree_create_file_from_input (GFile *file,
|
||||||
GFileInfo *finfo,
|
GFileInfo *finfo,
|
||||||
GVariant *xattrs,
|
GVariant *xattrs,
|
||||||
|
|
@ -205,17 +180,12 @@ gboolean ostree_create_temp_regular_file (GFile *dir,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
gboolean ostree_parse_archived_file (GFile *file,
|
GVariant *ostree_create_archive_file_metadata (GFileInfo *file_info,
|
||||||
|
GVariant *xattrs);
|
||||||
|
|
||||||
|
gboolean ostree_parse_archived_file_meta (GVariant *data,
|
||||||
GFileInfo **out_file_info,
|
GFileInfo **out_file_info,
|
||||||
GVariant **out_xattrs,
|
GVariant **out_xattrs,
|
||||||
GInputStream **out_content,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
gboolean ostree_unpack_object (GFile *file,
|
|
||||||
OstreeObjectType objtype,
|
|
||||||
GFile *dest,
|
|
||||||
GChecksum **out_checksum,
|
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,7 @@ _ostree_repo_file_get_xattrs (OstreeRepoFile *self,
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GVariant *ret_xattrs = NULL;
|
GVariant *ret_xattrs = NULL;
|
||||||
|
GVariant *metadata = NULL;
|
||||||
GFile *local_file = NULL;
|
GFile *local_file = NULL;
|
||||||
|
|
||||||
if (!_ostree_repo_file_ensure_resolved (self, error))
|
if (!_ostree_repo_file_ensure_resolved (self, error))
|
||||||
|
|
@ -317,7 +318,12 @@ _ostree_repo_file_get_xattrs (OstreeRepoFile *self,
|
||||||
else if (ostree_repo_get_mode (self->repo) == OSTREE_REPO_MODE_ARCHIVE)
|
else if (ostree_repo_get_mode (self->repo) == OSTREE_REPO_MODE_ARCHIVE)
|
||||||
{
|
{
|
||||||
local_file = _ostree_repo_file_nontree_get_local (self);
|
local_file = _ostree_repo_file_nontree_get_local (self);
|
||||||
if (!ostree_parse_archived_file (local_file, NULL, &ret_xattrs, NULL, cancellable, error))
|
|
||||||
|
if (!ostree_map_metadata_file (local_file, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
|
||||||
|
&metadata, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_parse_archived_file_meta (metadata, NULL, &ret_xattrs, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -330,6 +336,7 @@ _ostree_repo_file_get_xattrs (OstreeRepoFile *self,
|
||||||
ot_transfer_out_value(out_xattrs, &ret_xattrs);
|
ot_transfer_out_value(out_xattrs, &ret_xattrs);
|
||||||
out:
|
out:
|
||||||
ot_clear_gvariant (&ret_xattrs);
|
ot_clear_gvariant (&ret_xattrs);
|
||||||
|
ot_clear_gvariant (&metadata);
|
||||||
g_clear_object (&local_file);
|
g_clear_object (&local_file);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -1002,6 +1009,7 @@ _ostree_repo_file_tree_query_child (OstreeRepoFile *self,
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GFileInfo *ret_info = NULL;
|
GFileInfo *ret_info = NULL;
|
||||||
|
GVariant *archive_metadata = NULL;
|
||||||
GVariant *files_variant = NULL;
|
GVariant *files_variant = NULL;
|
||||||
GVariant *dirs_variant = NULL;
|
GVariant *dirs_variant = NULL;
|
||||||
GVariant *tree_child_metadata = NULL;
|
GVariant *tree_child_metadata = NULL;
|
||||||
|
|
@ -1030,7 +1038,10 @@ _ostree_repo_file_tree_query_child (OstreeRepoFile *self,
|
||||||
|
|
||||||
if (ostree_repo_get_mode (self->repo) == OSTREE_REPO_MODE_ARCHIVE)
|
if (ostree_repo_get_mode (self->repo) == OSTREE_REPO_MODE_ARCHIVE)
|
||||||
{
|
{
|
||||||
if (!ostree_parse_archived_file (local_child, &ret_info, NULL, NULL, cancellable, error))
|
if (!ostree_map_metadata_file (local_child, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
|
||||||
|
&archive_metadata, error))
|
||||||
|
goto out;
|
||||||
|
if (!ostree_parse_archived_file_meta (archive_metadata, &ret_info, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1086,6 +1097,7 @@ _ostree_repo_file_tree_query_child (OstreeRepoFile *self,
|
||||||
g_clear_object (&local_child);
|
g_clear_object (&local_child);
|
||||||
if (matcher)
|
if (matcher)
|
||||||
g_file_attribute_matcher_unref (matcher);
|
g_file_attribute_matcher_unref (matcher);
|
||||||
|
ot_clear_gvariant (&archive_metadata);
|
||||||
ot_clear_gvariant (&tree_child_metadata);
|
ot_clear_gvariant (&tree_child_metadata);
|
||||||
ot_clear_gvariant (&files_variant);
|
ot_clear_gvariant (&files_variant);
|
||||||
ot_clear_gvariant (&dirs_variant);
|
ot_clear_gvariant (&dirs_variant);
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,12 @@ struct _OstreeRepoPrivate {
|
||||||
char *config_path;
|
char *config_path;
|
||||||
|
|
||||||
gboolean inited;
|
gboolean inited;
|
||||||
|
gboolean in_transaction;
|
||||||
|
|
||||||
GKeyFile *config;
|
GKeyFile *config;
|
||||||
OstreeRepoMode mode;
|
OstreeRepoMode mode;
|
||||||
|
|
||||||
|
GHashTable *pending_transaction_tmpfiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -78,6 +81,7 @@ ostree_repo_finalize (GObject *object)
|
||||||
g_clear_object (&priv->remote_heads_dir);
|
g_clear_object (&priv->remote_heads_dir);
|
||||||
g_free (priv->objects_path);
|
g_free (priv->objects_path);
|
||||||
g_free (priv->config_path);
|
g_free (priv->config_path);
|
||||||
|
g_hash_table_destroy (priv->pending_transaction_tmpfiles);
|
||||||
if (priv->config)
|
if (priv->config)
|
||||||
g_key_file_free (priv->config);
|
g_key_file_free (priv->config);
|
||||||
|
|
||||||
|
|
@ -175,6 +179,11 @@ ostree_repo_class_init (OstreeRepoClass *klass)
|
||||||
static void
|
static void
|
||||||
ostree_repo_init (OstreeRepo *self)
|
ostree_repo_init (OstreeRepo *self)
|
||||||
{
|
{
|
||||||
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
|
|
||||||
|
priv->pending_transaction_tmpfiles = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
|
g_free,
|
||||||
|
g_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
OstreeRepo*
|
OstreeRepo*
|
||||||
|
|
@ -647,7 +656,7 @@ get_objtype_for_repo_file (OstreeRepo *self)
|
||||||
{
|
{
|
||||||
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
if (priv->mode == OSTREE_REPO_MODE_ARCHIVE)
|
if (priv->mode == OSTREE_REPO_MODE_ARCHIVE)
|
||||||
return OSTREE_OBJECT_TYPE_ARCHIVED_FILE;
|
return OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META;
|
||||||
else
|
else
|
||||||
return OSTREE_OBJECT_TYPE_RAW_FILE;
|
return OSTREE_OBJECT_TYPE_RAW_FILE;
|
||||||
}
|
}
|
||||||
|
|
@ -659,41 +668,219 @@ ostree_repo_get_file_object_path (OstreeRepo *self,
|
||||||
return ostree_repo_get_object_path (self, checksum, get_objtype_for_repo_file (self));
|
return ostree_repo_get_object_path (self, checksum, get_objtype_for_repo_file (self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
create_checksum_and_objtype (const char *checksum,
|
||||||
|
OstreeObjectType objtype)
|
||||||
|
{
|
||||||
|
return g_strconcat (checksum, ".", ostree_object_type_to_string (objtype), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_repo_has_object (OstreeRepo *self,
|
||||||
|
OstreeObjectType objtype,
|
||||||
|
const char *checksum,
|
||||||
|
gboolean *out_have_object,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
|
char *tmp_key = NULL;
|
||||||
|
GFile *object_path = NULL;
|
||||||
|
|
||||||
|
tmp_key = create_checksum_and_objtype (checksum, objtype);
|
||||||
|
|
||||||
|
if (g_hash_table_lookup (priv->pending_transaction_tmpfiles, tmp_key))
|
||||||
|
{
|
||||||
|
*out_have_object = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
object_path = ostree_repo_get_object_path (self, checksum, objtype);
|
||||||
|
|
||||||
|
*out_have_object = g_file_query_exists (object_path, cancellable);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
/* out: */
|
||||||
|
g_free (tmp_key);
|
||||||
|
g_clear_object (&object_path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GFileInfo *
|
||||||
|
dup_file_info_owned_by_me (GFileInfo *file_info)
|
||||||
|
{
|
||||||
|
GFileInfo *ret = g_file_info_dup (file_info);
|
||||||
|
|
||||||
|
g_file_info_set_attribute_uint32 (ret, "unix::uid", geteuid ());
|
||||||
|
g_file_info_set_attribute_uint32 (ret, "unix::gid", getegid ());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ostree_repo_stage_object (OstreeRepo *self,
|
stage_object (OstreeRepo *self,
|
||||||
OstreeObjectType objtype,
|
OstreeObjectType objtype,
|
||||||
GFileInfo *file_info,
|
GFileInfo *file_info,
|
||||||
GVariant *xattrs,
|
GVariant *xattrs,
|
||||||
GInputStream *input,
|
GInputStream *input,
|
||||||
GFile **out_tmpname,
|
const char *expected_checksum,
|
||||||
|
GChecksum **out_checksum,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
impl_stage_archive_file_object_from_raw (OstreeRepo *self,
|
||||||
|
GFileInfo *file_info,
|
||||||
|
GVariant *xattrs,
|
||||||
|
GInputStream *input,
|
||||||
|
const char *expected_checksum,
|
||||||
GChecksum **out_checksum,
|
GChecksum **out_checksum,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
GOutputStream *temp_out = NULL;
|
|
||||||
GChecksum *ret_checksum = NULL;
|
GChecksum *ret_checksum = NULL;
|
||||||
|
GVariant *archive_metadata = NULL;
|
||||||
|
GFileInfo *temp_info = NULL;
|
||||||
|
GFile *meta_temp_file = NULL;
|
||||||
|
GFile *content_temp_file = NULL;
|
||||||
|
GVariant *serialized = NULL;
|
||||||
|
GInputStream *mem = NULL;
|
||||||
|
const char *actual_checksum;
|
||||||
|
|
||||||
|
archive_metadata = ostree_create_archive_file_metadata (file_info, xattrs);
|
||||||
|
|
||||||
|
serialized = ostree_wrap_metadata_variant (OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, archive_metadata);
|
||||||
|
mem = g_memory_input_stream_new_from_data (g_variant_get_data (serialized),
|
||||||
|
g_variant_get_size (serialized),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!ostree_create_temp_file_from_input (priv->tmp_dir,
|
||||||
|
"archive-tmp-", NULL,
|
||||||
|
NULL, NULL, mem,
|
||||||
|
OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
|
||||||
|
&meta_temp_file,
|
||||||
|
NULL,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
temp_info = dup_file_info_owned_by_me (file_info);
|
||||||
|
if (!ostree_create_temp_file_from_input (priv->tmp_dir,
|
||||||
|
"archive-tmp-", NULL,
|
||||||
|
temp_info, NULL, input,
|
||||||
|
OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT,
|
||||||
|
&content_temp_file,
|
||||||
|
out_checksum ? &ret_checksum : NULL,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (ret_checksum)
|
||||||
|
{
|
||||||
|
ostree_checksum_update_stat (ret_checksum,
|
||||||
|
g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
|
||||||
|
g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
|
||||||
|
g_file_info_get_attribute_uint32 (file_info, "unix::mode"));
|
||||||
|
/* FIXME - ensure empty xattrs are the same as NULL xattrs */
|
||||||
|
if (xattrs)
|
||||||
|
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expected_checksum)
|
||||||
|
{
|
||||||
|
if (strcmp (g_checksum_get_string (ret_checksum), expected_checksum) != 0)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Corrupted %s object %s (actual checksum is %s)",
|
||||||
|
ostree_object_type_to_string (OSTREE_OBJECT_TYPE_RAW_FILE),
|
||||||
|
expected_checksum, g_checksum_get_string (ret_checksum));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
actual_checksum = expected_checksum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
actual_checksum = g_checksum_get_string (ret_checksum);
|
||||||
|
|
||||||
|
g_hash_table_insert (priv->pending_transaction_tmpfiles,
|
||||||
|
create_checksum_and_objtype (actual_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT),
|
||||||
|
g_strdup (ot_gfile_get_basename_cached (content_temp_file)));
|
||||||
|
g_hash_table_insert (priv->pending_transaction_tmpfiles,
|
||||||
|
create_checksum_and_objtype (actual_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META),
|
||||||
|
g_strdup (ot_gfile_get_basename_cached (meta_temp_file)));
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
ot_transfer_out_value (out_checksum, &ret_checksum);
|
||||||
|
out:
|
||||||
|
ot_clear_gvariant (&serialized);
|
||||||
|
ot_clear_gvariant (&archive_metadata);
|
||||||
|
g_clear_object (&mem);
|
||||||
|
g_clear_object (&temp_info);
|
||||||
|
g_clear_object (&meta_temp_file);
|
||||||
|
g_clear_object (&content_temp_file);
|
||||||
|
ot_clear_checksum (&ret_checksum);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
stage_object (OstreeRepo *self,
|
||||||
|
OstreeObjectType objtype,
|
||||||
|
GFileInfo *file_info,
|
||||||
|
GVariant *xattrs,
|
||||||
|
GInputStream *input,
|
||||||
|
const char *expected_checksum,
|
||||||
|
GChecksum **out_checksum,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
|
GChecksum *ret_checksum = NULL;
|
||||||
|
GFileInfo *temp_info = NULL;
|
||||||
GFile *temp_file = NULL;
|
GFile *temp_file = NULL;
|
||||||
GFile *ret_tmpname = NULL;
|
gboolean already_exists;
|
||||||
|
const char *actual_checksum;
|
||||||
|
|
||||||
|
g_return_val_if_fail (priv->in_transaction, FALSE);
|
||||||
|
|
||||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (!OSTREE_OBJECT_TYPE_IS_META(objtype) && priv->mode == OSTREE_REPO_MODE_ARCHIVE)
|
g_assert (expected_checksum || out_checksum);
|
||||||
|
|
||||||
|
if (expected_checksum)
|
||||||
{
|
{
|
||||||
if (!ostree_create_temp_regular_file (priv->tmp_dir,
|
if (!ostree_repo_has_object (self, objtype, expected_checksum, &already_exists, cancellable, error))
|
||||||
"archive-tmp-", NULL,
|
goto out;
|
||||||
&temp_file, &temp_out,
|
}
|
||||||
|
else
|
||||||
|
already_exists = FALSE;
|
||||||
|
|
||||||
|
g_assert (objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
|
||||||
|
g_assert (objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META);
|
||||||
|
|
||||||
|
if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE)
|
||||||
|
{
|
||||||
|
g_assert (file_info != NULL);
|
||||||
|
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
||||||
|
g_assert (input != NULL);
|
||||||
|
}
|
||||||
|
else if (OSTREE_OBJECT_TYPE_IS_META (objtype))
|
||||||
|
{
|
||||||
|
g_assert (xattrs == NULL);
|
||||||
|
g_assert (input != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!already_exists)
|
||||||
|
{
|
||||||
|
if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE && priv->mode == OSTREE_REPO_MODE_ARCHIVE)
|
||||||
|
{
|
||||||
|
if (!impl_stage_archive_file_object_from_raw (self, file_info, xattrs, input,
|
||||||
|
expected_checksum,
|
||||||
|
out_checksum ? &ret_checksum : NULL,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!ostree_archive_file_for_input (temp_out, file_info, input, xattrs,
|
|
||||||
&ret_checksum, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!g_output_stream_close (temp_out, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -701,22 +888,40 @@ ostree_repo_stage_object (OstreeRepo *self,
|
||||||
"store-tmp-", NULL,
|
"store-tmp-", NULL,
|
||||||
file_info, xattrs, input,
|
file_info, xattrs, input,
|
||||||
objtype,
|
objtype,
|
||||||
&temp_file, &ret_checksum,
|
&temp_file,
|
||||||
|
out_checksum ? &ret_checksum : NULL,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (!ret_checksum)
|
||||||
|
actual_checksum = expected_checksum;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actual_checksum = g_checksum_get_string (ret_checksum);
|
||||||
|
if (expected_checksum && strcmp (actual_checksum, expected_checksum) != 0)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Corrupted %s object %s (actual checksum is %s)",
|
||||||
|
ostree_object_type_to_string (objtype),
|
||||||
|
expected_checksum, actual_checksum);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret_tmpname = g_object_ref (temp_file);
|
g_hash_table_insert (priv->pending_transaction_tmpfiles,
|
||||||
|
create_checksum_and_objtype (actual_checksum, objtype),
|
||||||
|
g_strdup (ot_gfile_get_basename_cached (temp_file)));
|
||||||
g_clear_object (&temp_file);
|
g_clear_object (&temp_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
ot_transfer_out_value(out_checksum, &ret_checksum);
|
ot_transfer_out_value(out_checksum, &ret_checksum);
|
||||||
ot_transfer_out_value(out_tmpname, &ret_tmpname);
|
|
||||||
out:
|
out:
|
||||||
if (temp_file)
|
if (temp_file)
|
||||||
(void) unlink (ot_gfile_get_path_cached (temp_file));
|
(void) unlink (ot_gfile_get_path_cached (temp_file));
|
||||||
g_clear_object (&temp_file);
|
g_clear_object (&temp_file);
|
||||||
g_clear_object (&temp_out);
|
g_clear_object (&temp_info);
|
||||||
ot_clear_checksum (&ret_checksum);
|
ot_clear_checksum (&ret_checksum);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -726,7 +931,6 @@ commit_staged_file (OstreeRepo *self,
|
||||||
GFile *file,
|
GFile *file,
|
||||||
const char *checksum,
|
const char *checksum,
|
||||||
OstreeObjectType objtype,
|
OstreeObjectType objtype,
|
||||||
gboolean *did_exist,
|
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
|
|
@ -740,12 +944,9 @@ commit_staged_file (OstreeRepo *self,
|
||||||
if (!ot_gfile_ensure_directory (checksum_dir, FALSE, error))
|
if (!ot_gfile_ensure_directory (checksum_dir, FALSE, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
*did_exist = FALSE;
|
|
||||||
if (link (ot_gfile_get_path_cached (file), ot_gfile_get_path_cached (dest_file)) < 0)
|
if (link (ot_gfile_get_path_cached (file), ot_gfile_get_path_cached (dest_file)) < 0)
|
||||||
{
|
{
|
||||||
if (errno == EEXIST)
|
if (errno != EEXIST)
|
||||||
*did_exist = TRUE;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ot_util_set_error_from_errno (error, errno);
|
ot_util_set_error_from_errno (error, errno);
|
||||||
g_prefix_error (error, "Storing file '%s': ",
|
g_prefix_error (error, "Storing file '%s': ",
|
||||||
|
|
@ -762,109 +963,68 @@ commit_staged_file (OstreeRepo *self,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
gboolean
|
||||||
stage_and_commit_from_input (OstreeRepo *self,
|
ostree_repo_prepare_transaction (OstreeRepo *self,
|
||||||
OstreeObjectType objtype,
|
|
||||||
GFileInfo *file_info,
|
|
||||||
GVariant *xattrs,
|
|
||||||
GInputStream *input,
|
|
||||||
GChecksum **out_checksum,
|
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
GFile *tmp_file = NULL;
|
|
||||||
GChecksum *ret_checksum = NULL;
|
|
||||||
gboolean did_exist;
|
|
||||||
|
|
||||||
if (!ostree_repo_stage_object (self, objtype,
|
g_return_val_if_fail (priv->in_transaction == FALSE, FALSE);
|
||||||
file_info, xattrs, input,
|
|
||||||
&tmp_file, &ret_checksum,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!commit_staged_file (self, tmp_file, g_checksum_get_string (ret_checksum),
|
priv->in_transaction = TRUE;
|
||||||
objtype, &did_exist, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
g_clear_object (&tmp_file);
|
|
||||||
|
|
||||||
ret = TRUE;
|
return TRUE;
|
||||||
ot_transfer_out_value(out_checksum, &ret_checksum);
|
|
||||||
out:
|
|
||||||
if (tmp_file)
|
|
||||||
(void) unlink (ot_gfile_get_path_cached (tmp_file));
|
|
||||||
g_clear_object (&tmp_file);
|
|
||||||
ot_clear_checksum (&ret_checksum);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
gboolean
|
||||||
commit_file (OstreeRepo *self,
|
ostree_repo_commit_transaction (OstreeRepo *self,
|
||||||
GFile *file,
|
|
||||||
const char *expected_checksum,
|
|
||||||
GChecksum **out_checksum,
|
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GFileInfo *file_info = NULL;
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
GVariant *xattrs = NULL;
|
GFile *f = NULL;
|
||||||
GInputStream *input = NULL;
|
GHashTableIter iter;
|
||||||
GFile *tmp_file = NULL;
|
gpointer key, value;
|
||||||
GChecksum *ret_checksum = NULL;
|
char *checksum = NULL;
|
||||||
gboolean did_exist;
|
|
||||||
|
g_return_val_if_fail (priv->in_transaction == TRUE, FALSE);
|
||||||
|
|
||||||
|
priv->in_transaction = FALSE;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, priv->pending_transaction_tmpfiles);
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||||
|
{
|
||||||
|
const char *checksum_and_type = key;
|
||||||
|
const char *filename = value;
|
||||||
|
const char *type_str;
|
||||||
OstreeObjectType objtype;
|
OstreeObjectType objtype;
|
||||||
|
|
||||||
g_assert (expected_checksum || out_checksum);
|
type_str = strrchr (checksum_and_type, '.');
|
||||||
|
g_assert (type_str);
|
||||||
|
g_free (checksum);
|
||||||
|
checksum = g_strndup (checksum_and_type, type_str - checksum_and_type);
|
||||||
|
|
||||||
file_info = g_file_query_info (file, OSTREE_GIO_FAST_QUERYINFO,
|
objtype = ostree_object_type_from_string (type_str + 1);
|
||||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
|
||||||
cancellable, error);
|
|
||||||
if (!file_info)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
xattrs = ostree_get_xattrs_for_file (file, error);
|
g_clear_object (&f);
|
||||||
if (!xattrs)
|
f = g_file_get_child (priv->tmp_dir, filename);
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
if (!commit_staged_file (self, f, checksum, objtype, cancellable, error))
|
||||||
{
|
|
||||||
input = (GInputStream*)g_file_read (file, cancellable, error);
|
|
||||||
if (!input)
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
objtype = get_objtype_for_repo_file (self);
|
|
||||||
|
|
||||||
if (!ostree_repo_stage_object (self, objtype,
|
|
||||||
file_info, xattrs, input,
|
|
||||||
&tmp_file, out_checksum ? &ret_checksum : NULL,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (expected_checksum == NULL)
|
|
||||||
expected_checksum = g_checksum_get_string (ret_checksum);
|
|
||||||
|
|
||||||
if (!commit_staged_file (self, tmp_file, expected_checksum, objtype,
|
|
||||||
&did_exist, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
g_clear_object (&tmp_file);
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
ot_transfer_out_value(out_checksum, &ret_checksum);
|
|
||||||
out:
|
out:
|
||||||
if (tmp_file)
|
g_free (checksum);
|
||||||
(void) unlink (ot_gfile_get_path_cached (tmp_file));
|
g_hash_table_remove_all (priv->pending_transaction_tmpfiles);
|
||||||
g_clear_object (&tmp_file);
|
g_clear_object (&f);
|
||||||
g_clear_object (&file_info);
|
|
||||||
ot_clear_gvariant (&xattrs);
|
|
||||||
g_clear_object (&input);
|
|
||||||
ot_clear_checksum (&ret_checksum);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
import_gvariant_object (OstreeRepo *self,
|
stage_gvariant_object (OstreeRepo *self,
|
||||||
OstreeObjectType type,
|
OstreeObjectType type,
|
||||||
GVariant *variant,
|
GVariant *variant,
|
||||||
GChecksum **out_checksum,
|
GChecksum **out_checksum,
|
||||||
|
|
@ -881,10 +1041,9 @@ import_gvariant_object (OstreeRepo *self,
|
||||||
g_variant_get_size (serialized),
|
g_variant_get_size (serialized),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (!stage_and_commit_from_input (self, type,
|
if (!stage_object (self, type,
|
||||||
NULL, NULL, mem,
|
NULL, NULL, mem,
|
||||||
&ret_checksum,
|
NULL, &ret_checksum, cancellable, error))
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
|
@ -904,35 +1063,41 @@ ostree_repo_load_variant (OstreeRepo *self,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
OstreeObjectType type;
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
GFile *object_path = NULL;
|
GFile *object_path = NULL;
|
||||||
|
GFile *tmpfile = NULL;
|
||||||
GVariant *ret_variant = NULL;
|
GVariant *ret_variant = NULL;
|
||||||
|
char *pending_key = NULL;
|
||||||
|
const char *pending_tmpfile;
|
||||||
|
|
||||||
g_return_val_if_fail (OSTREE_OBJECT_TYPE_IS_META (expected_type), FALSE);
|
g_return_val_if_fail (OSTREE_OBJECT_TYPE_IS_META (expected_type), FALSE);
|
||||||
|
|
||||||
object_path = ostree_repo_get_object_path (self, sha256, expected_type);
|
pending_key = create_checksum_and_objtype (sha256, expected_type);
|
||||||
|
if ((pending_tmpfile = g_hash_table_lookup (priv->pending_transaction_tmpfiles, pending_key)) != NULL)
|
||||||
if (!ostree_parse_metadata_file (object_path, &type, &ret_variant, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (type != expected_type)
|
|
||||||
{
|
{
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
tmpfile = g_file_get_child (priv->tmp_dir, pending_tmpfile);
|
||||||
"Corrupted metadata object '%s'; found type %u, expected %u", sha256,
|
if (!ostree_map_metadata_file (tmpfile, expected_type, &ret_variant, error))
|
||||||
type, (guint32)expected_type);
|
goto out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
object_path = ostree_repo_get_object_path (self, sha256, expected_type);
|
||||||
|
if (!ostree_map_metadata_file (object_path, expected_type, &ret_variant, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
ot_transfer_out_value(out_variant, &ret_variant);
|
ot_transfer_out_value (out_variant, &ret_variant);
|
||||||
out:
|
out:
|
||||||
g_clear_object (&object_path);
|
g_clear_object (&object_path);
|
||||||
|
g_clear_object (&tmpfile);
|
||||||
|
g_free (pending_key);
|
||||||
ot_clear_gvariant (&ret_variant);
|
ot_clear_gvariant (&ret_variant);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
import_directory_meta (OstreeRepo *self,
|
stage_directory_meta (OstreeRepo *self,
|
||||||
GFileInfo *file_info,
|
GFileInfo *file_info,
|
||||||
GVariant *xattrs,
|
GVariant *xattrs,
|
||||||
GChecksum **out_checksum,
|
GChecksum **out_checksum,
|
||||||
|
|
@ -948,7 +1113,7 @@ import_directory_meta (OstreeRepo *self,
|
||||||
|
|
||||||
dirmeta = ostree_create_directory_metadata (file_info, xattrs);
|
dirmeta = ostree_create_directory_metadata (file_info, xattrs);
|
||||||
|
|
||||||
if (!import_gvariant_object (self, OSTREE_OBJECT_TYPE_DIR_META,
|
if (!stage_gvariant_object (self, OSTREE_OBJECT_TYPE_DIR_META,
|
||||||
dirmeta, &ret_checksum, cancellable, error))
|
dirmeta, &ret_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -981,107 +1146,40 @@ ostree_repo_get_object_path (OstreeRepo *self,
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
ostree_repo_store_object_trusted (OstreeRepo *self,
|
ostree_repo_store_object_trusted (OstreeRepo *self,
|
||||||
GFile *file,
|
|
||||||
const char *checksum,
|
|
||||||
OstreeObjectType objtype,
|
OstreeObjectType objtype,
|
||||||
|
const char *checksum,
|
||||||
|
GFileInfo *file_info,
|
||||||
|
GVariant *xattrs,
|
||||||
|
GInputStream *input,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return stage_object (self, objtype,
|
||||||
|
file_info, xattrs, input,
|
||||||
|
checksum, NULL, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_repo_store_object (OstreeRepo *self,
|
||||||
|
OstreeObjectType objtype,
|
||||||
|
const char *expected_checksum,
|
||||||
|
GFileInfo *file_info,
|
||||||
|
GVariant *xattrs,
|
||||||
|
GInputStream *input,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GFile *local_object = NULL;
|
GChecksum *actual_checksum = NULL;
|
||||||
GInputStream *input = NULL;
|
|
||||||
|
|
||||||
local_object = ostree_repo_get_object_path (self, checksum, objtype);
|
if (!stage_object (self, objtype,
|
||||||
|
|
||||||
if (!g_file_query_exists (local_object, cancellable))
|
|
||||||
{
|
|
||||||
if (!OSTREE_OBJECT_TYPE_IS_META (objtype))
|
|
||||||
{
|
|
||||||
if (!commit_file (self, file, checksum, NULL, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
input = (GInputStream*)g_file_read (file, cancellable, error);
|
|
||||||
if (!input)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!stage_and_commit_from_input (self, objtype,
|
|
||||||
NULL, NULL, input,
|
|
||||||
NULL, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
g_clear_object (&input);
|
|
||||||
g_clear_object (&local_object);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
ostree_repo_store_archived_file (OstreeRepo *self,
|
|
||||||
const char *expected_checksum,
|
|
||||||
const char *path,
|
|
||||||
OstreeObjectType objtype,
|
|
||||||
gboolean *did_exist,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
GChecksum *checksum = NULL;
|
|
||||||
GFileInfo *file_info = NULL;
|
|
||||||
GFile *tmp_file = NULL;
|
|
||||||
GFile *src = NULL;
|
|
||||||
GInputStream *input = NULL;
|
|
||||||
GVariant *xattrs = NULL;
|
|
||||||
OstreeObjectType dest_objtype;
|
|
||||||
|
|
||||||
src = ot_gfile_new_for_path (path);
|
|
||||||
|
|
||||||
if (OSTREE_OBJECT_TYPE_IS_META(objtype))
|
|
||||||
{
|
|
||||||
dest_objtype = objtype;
|
|
||||||
input = (GInputStream*)g_file_read (src, NULL, error);
|
|
||||||
if (!input)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Ensure we convert archived files to bare, or vice versa */
|
|
||||||
dest_objtype = get_objtype_for_repo_file (self);
|
|
||||||
if (!ostree_parse_archived_file (src, &file_info, &xattrs, &input, NULL, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ostree_repo_stage_object (self, dest_objtype,
|
|
||||||
file_info, xattrs, input,
|
file_info, xattrs, input,
|
||||||
&tmp_file, &checksum, NULL, error))
|
expected_checksum, &actual_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (strcmp (g_checksum_get_string (checksum), expected_checksum) != 0)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Corrupted object %s (actual checksum is %s)",
|
|
||||||
expected_checksum, g_checksum_get_string (checksum));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!commit_staged_file (self, tmp_file, g_checksum_get_string (checksum),
|
|
||||||
dest_objtype, did_exist, NULL, error))
|
|
||||||
goto out;
|
|
||||||
g_clear_object (&tmp_file);
|
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
if (tmp_file)
|
ot_clear_checksum (&actual_checksum);
|
||||||
(void) unlink (ot_gfile_get_path_cached (tmp_file));
|
|
||||||
g_clear_object (&tmp_file);
|
|
||||||
g_clear_object (&src);
|
|
||||||
g_clear_object (&file_info);
|
|
||||||
ot_clear_gvariant (&xattrs);
|
|
||||||
g_clear_object (&input);
|
|
||||||
ot_clear_checksum (&checksum);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1124,7 +1222,7 @@ ostree_repo_write_ref (OstreeRepo *self,
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
import_commit (OstreeRepo *self,
|
do_commit_write_ref (OstreeRepo *self,
|
||||||
const char *branch,
|
const char *branch,
|
||||||
const char *parent,
|
const char *parent,
|
||||||
const char *subject,
|
const char *subject,
|
||||||
|
|
@ -1133,6 +1231,7 @@ import_commit (OstreeRepo *self,
|
||||||
const char *root_contents_checksum,
|
const char *root_contents_checksum,
|
||||||
const char *root_metadata_checksum,
|
const char *root_metadata_checksum,
|
||||||
GChecksum **out_commit,
|
GChecksum **out_commit,
|
||||||
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
|
|
@ -1153,10 +1252,13 @@ import_commit (OstreeRepo *self,
|
||||||
root_contents_checksum,
|
root_contents_checksum,
|
||||||
root_metadata_checksum);
|
root_metadata_checksum);
|
||||||
g_variant_ref_sink (commit);
|
g_variant_ref_sink (commit);
|
||||||
if (!import_gvariant_object (self, OSTREE_OBJECT_TYPE_COMMIT,
|
if (!stage_gvariant_object (self, OSTREE_OBJECT_TYPE_COMMIT,
|
||||||
commit, &ret_commit, NULL, error))
|
commit, &ret_commit, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_repo_commit_transaction (self, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!ostree_repo_write_ref (self, NULL, branch, g_checksum_get_string (ret_commit), error))
|
if (!ostree_repo_write_ref (self, NULL, branch, g_checksum_get_string (ret_commit), error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -1240,7 +1342,7 @@ create_tree_variant_from_hashes (GHashTable *file_checksums,
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
import_directory_recurse (OstreeRepo *self,
|
stage_directory_recurse (OstreeRepo *self,
|
||||||
GFile *base,
|
GFile *base,
|
||||||
GFile *dir,
|
GFile *dir,
|
||||||
GChecksum **out_contents_checksum,
|
GChecksum **out_contents_checksum,
|
||||||
|
|
@ -1273,7 +1375,8 @@ import_directory_recurse (OstreeRepo *self,
|
||||||
if (!xattrs)
|
if (!xattrs)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!import_directory_meta (self, child_info, xattrs, &ret_metadata_checksum, cancellable, error))
|
if (!stage_directory_meta (self, child_info, xattrs, &ret_metadata_checksum,
|
||||||
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
g_clear_object (&child_info);
|
g_clear_object (&child_info);
|
||||||
|
|
@ -1304,7 +1407,7 @@ import_directory_recurse (OstreeRepo *self,
|
||||||
GChecksum *child_dir_metadata_checksum = NULL;
|
GChecksum *child_dir_metadata_checksum = NULL;
|
||||||
GChecksum *child_dir_contents_checksum = NULL;
|
GChecksum *child_dir_contents_checksum = NULL;
|
||||||
|
|
||||||
if (!import_directory_recurse (self, base, child, &child_dir_contents_checksum,
|
if (!stage_directory_recurse (self, base, child, &child_dir_contents_checksum,
|
||||||
&child_dir_metadata_checksum, cancellable, error))
|
&child_dir_metadata_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -1332,8 +1435,8 @@ import_directory_recurse (OstreeRepo *self,
|
||||||
if (!xattrs)
|
if (!xattrs)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!stage_and_commit_from_input (self, get_objtype_for_repo_file (self),
|
if (!stage_object (self, OSTREE_OBJECT_TYPE_RAW_FILE,
|
||||||
child_info, xattrs, file_input,
|
child_info, xattrs, file_input, NULL,
|
||||||
&child_file_checksum, cancellable, error))
|
&child_file_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -1353,7 +1456,7 @@ import_directory_recurse (OstreeRepo *self,
|
||||||
dir_contents_checksums,
|
dir_contents_checksums,
|
||||||
dir_metadata_checksums);
|
dir_metadata_checksums);
|
||||||
|
|
||||||
if (!import_gvariant_object (self, OSTREE_OBJECT_TYPE_DIR_TREE,
|
if (!stage_gvariant_object (self, OSTREE_OBJECT_TYPE_DIR_TREE,
|
||||||
serialized_tree, &ret_contents_checksum,
|
serialized_tree, &ret_contents_checksum,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -1405,19 +1508,22 @@ ostree_repo_commit_directory (OstreeRepo *self,
|
||||||
g_return_val_if_fail (subject != NULL, FALSE);
|
g_return_val_if_fail (subject != NULL, FALSE);
|
||||||
g_return_val_if_fail (metadata == NULL || g_variant_is_of_type (metadata, G_VARIANT_TYPE ("a{sv}")), FALSE);
|
g_return_val_if_fail (metadata == NULL || g_variant_is_of_type (metadata, G_VARIANT_TYPE ("a{sv}")), FALSE);
|
||||||
|
|
||||||
|
if (!ostree_repo_prepare_transaction (self, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (parent == NULL)
|
if (parent == NULL)
|
||||||
parent = branch;
|
parent = branch;
|
||||||
|
|
||||||
if (!ostree_repo_resolve_rev (self, parent, TRUE, ¤t_head, error))
|
if (!ostree_repo_resolve_rev (self, parent, TRUE, ¤t_head, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!import_directory_recurse (self, dir, dir, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
if (!stage_directory_recurse (self, dir, dir, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!import_commit (self, branch, current_head, subject, body, metadata,
|
if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
|
||||||
g_checksum_get_string (root_contents_checksum),
|
g_checksum_get_string (root_contents_checksum),
|
||||||
g_checksum_get_string (root_metadata_checksum),
|
g_checksum_get_string (root_metadata_checksum),
|
||||||
&ret_commit_checksum, error))
|
&ret_commit_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
|
@ -1491,9 +1597,10 @@ import_libarchive_entry_file (OstreeRepo *self,
|
||||||
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
||||||
archive_stream = ostree_libarchive_input_stream_new (a);
|
archive_stream = ostree_libarchive_input_stream_new (a);
|
||||||
|
|
||||||
if (!stage_and_commit_from_input (self, get_objtype_for_repo_file (self),
|
if (!stage_object (self, OSTREE_OBJECT_TYPE_RAW_FILE,
|
||||||
file_info, NULL, archive_stream,
|
file_info, NULL, archive_stream,
|
||||||
&ret_checksum, cancellable, error))
|
NULL, &ret_checksum,
|
||||||
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
|
@ -1611,7 +1718,7 @@ file_tree_import_recurse (OstreeRepo *self,
|
||||||
dir_contents_checksums,
|
dir_contents_checksums,
|
||||||
dir_metadata_checksums);
|
dir_metadata_checksums);
|
||||||
|
|
||||||
if (!import_gvariant_object (self, OSTREE_OBJECT_TYPE_DIR_TREE,
|
if (!stage_gvariant_object (self, OSTREE_OBJECT_TYPE_DIR_TREE,
|
||||||
serialized_tree, &ret_contents_checksum_obj,
|
serialized_tree, &ret_contents_checksum_obj,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -1772,7 +1879,7 @@ import_libarchive (OstreeRepo *self,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!import_directory_meta (self, file_info, NULL, &tmp_checksum, cancellable, error))
|
if (!stage_directory_meta (self, file_info, NULL, &tmp_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (parent == NULL)
|
if (parent == NULL)
|
||||||
|
|
@ -1879,6 +1986,9 @@ ostree_repo_commit_tarfile (OstreeRepo *self,
|
||||||
g_return_val_if_fail (subject != NULL, FALSE);
|
g_return_val_if_fail (subject != NULL, FALSE);
|
||||||
g_return_val_if_fail (metadata == NULL || g_variant_is_of_type (metadata, G_VARIANT_TYPE ("a{sv}")), FALSE);
|
g_return_val_if_fail (metadata == NULL || g_variant_is_of_type (metadata, G_VARIANT_TYPE ("a{sv}")), FALSE);
|
||||||
|
|
||||||
|
if (!ostree_repo_prepare_transaction (self, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (parent == NULL)
|
if (parent == NULL)
|
||||||
parent = branch;
|
parent = branch;
|
||||||
|
|
||||||
|
|
@ -1888,8 +1998,9 @@ ostree_repo_commit_tarfile (OstreeRepo *self,
|
||||||
if (!import_libarchive (self, path, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
if (!import_libarchive (self, path, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!import_commit (self, branch, current_head, subject, body, metadata,
|
if (!do_commit_write_ref (self, branch, current_head, subject, body, metadata,
|
||||||
root_contents_checksum, root_metadata_checksum, &ret_commit_checksum, error))
|
root_contents_checksum, root_metadata_checksum, &ret_commit_checksum,
|
||||||
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
|
@ -1947,8 +2058,10 @@ iter_object_dir (OstreeRepo *self,
|
||||||
|
|
||||||
if (g_str_has_suffix (name, ".file"))
|
if (g_str_has_suffix (name, ".file"))
|
||||||
objtype = OSTREE_OBJECT_TYPE_RAW_FILE;
|
objtype = OSTREE_OBJECT_TYPE_RAW_FILE;
|
||||||
else if (g_str_has_suffix (name, ".archive"))
|
else if (g_str_has_suffix (name, ".archive-meta"))
|
||||||
objtype = OSTREE_OBJECT_TYPE_ARCHIVED_FILE;
|
objtype = OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META;
|
||||||
|
else if (g_str_has_suffix (name, ".archive-content"))
|
||||||
|
objtype = OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT;
|
||||||
else if (g_str_has_suffix (name, ".dirtree"))
|
else if (g_str_has_suffix (name, ".dirtree"))
|
||||||
objtype = OSTREE_OBJECT_TYPE_DIR_TREE;
|
objtype = OSTREE_OBJECT_TYPE_DIR_TREE;
|
||||||
else if (g_str_has_suffix (name, ".dirmeta"))
|
else if (g_str_has_suffix (name, ".dirmeta"))
|
||||||
|
|
@ -2098,13 +2211,15 @@ checkout_tree (OstreeRepo *self,
|
||||||
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
OstreeRepoPrivate *priv = GET_PRIVATE (self);
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GError *temp_error = NULL;
|
GError *temp_error = NULL;
|
||||||
|
GVariant *archive_metadata = NULL;
|
||||||
GFileInfo *file_info = NULL;
|
GFileInfo *file_info = NULL;
|
||||||
GInputStream *packed_input = NULL;
|
|
||||||
GVariant *xattrs = NULL;
|
GVariant *xattrs = NULL;
|
||||||
GFileEnumerator *dir_enum = NULL;
|
GFileEnumerator *dir_enum = NULL;
|
||||||
GFile *src_child = NULL;
|
GFile *src_child = NULL;
|
||||||
GFile *dest_path = NULL;
|
GFile *dest_path = NULL;
|
||||||
GFile *object_path = NULL;
|
GFile *object_path = NULL;
|
||||||
|
GFile *content_object_path = NULL;
|
||||||
|
GInputStream *content_input = NULL;
|
||||||
|
|
||||||
if (!_ostree_repo_file_get_xattrs (source, &xattrs, NULL, error))
|
if (!_ostree_repo_file_get_xattrs (source, &xattrs, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -2131,7 +2246,10 @@ checkout_tree (OstreeRepo *self,
|
||||||
name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
|
name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
|
||||||
type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
|
type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
|
||||||
|
|
||||||
|
g_clear_object (&dest_path);
|
||||||
dest_path = g_file_get_child (destination, name);
|
dest_path = g_file_get_child (destination, name);
|
||||||
|
|
||||||
|
g_clear_object (&src_child);
|
||||||
src_child = g_file_get_child ((GFile*)source, name);
|
src_child = g_file_get_child ((GFile*)source, name);
|
||||||
|
|
||||||
if (type == G_FILE_TYPE_DIRECTORY)
|
if (type == G_FILE_TYPE_DIRECTORY)
|
||||||
|
|
@ -2143,20 +2261,36 @@ checkout_tree (OstreeRepo *self,
|
||||||
{
|
{
|
||||||
const char *checksum = _ostree_repo_file_get_checksum ((OstreeRepoFile*)src_child);
|
const char *checksum = _ostree_repo_file_get_checksum ((OstreeRepoFile*)src_child);
|
||||||
|
|
||||||
object_path = ostree_repo_get_object_path (self, checksum, get_objtype_for_repo_file (self));
|
g_clear_object (&object_path);
|
||||||
|
|
||||||
if (priv->mode == OSTREE_REPO_MODE_ARCHIVE)
|
if (priv->mode == OSTREE_REPO_MODE_ARCHIVE)
|
||||||
{
|
{
|
||||||
if (!ostree_parse_archived_file (object_path, NULL, &xattrs, &packed_input,
|
if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, checksum, &archive_metadata, error))
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
ot_clear_gvariant (&xattrs);
|
||||||
|
if (!ostree_parse_archived_file_meta (archive_metadata, NULL, &xattrs, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_clear_object (&content_object_path);
|
||||||
|
content_object_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
|
||||||
|
|
||||||
|
g_clear_object (&content_input);
|
||||||
|
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
||||||
|
{
|
||||||
|
content_input = (GInputStream*)g_file_read (content_object_path, cancellable, error);
|
||||||
|
if (!content_input)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (!checkout_file_from_input (dest_path, mode, file_info, xattrs,
|
if (!checkout_file_from_input (dest_path, mode, file_info, xattrs,
|
||||||
packed_input, cancellable, error))
|
content_input, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
object_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_RAW_FILE);
|
||||||
|
|
||||||
if (link (ot_gfile_get_path_cached (object_path), ot_gfile_get_path_cached (dest_path)) < 0)
|
if (link (ot_gfile_get_path_cached (object_path), ot_gfile_get_path_cached (dest_path)) < 0)
|
||||||
{
|
{
|
||||||
ot_util_set_error_from_errno (error, errno);
|
ot_util_set_error_from_errno (error, errno);
|
||||||
|
|
@ -2165,12 +2299,7 @@ checkout_tree (OstreeRepo *self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_clear_object (&object_path);
|
|
||||||
g_clear_object (&dest_path);
|
|
||||||
g_clear_object (&file_info);
|
g_clear_object (&file_info);
|
||||||
g_clear_object (&src_child);
|
|
||||||
g_clear_object (&packed_input);
|
|
||||||
ot_clear_gvariant (&xattrs);
|
|
||||||
}
|
}
|
||||||
if (file_info == NULL && temp_error != NULL)
|
if (file_info == NULL && temp_error != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -2182,10 +2311,12 @@ checkout_tree (OstreeRepo *self,
|
||||||
out:
|
out:
|
||||||
g_clear_object (&dir_enum);
|
g_clear_object (&dir_enum);
|
||||||
g_clear_object (&file_info);
|
g_clear_object (&file_info);
|
||||||
g_clear_object (&packed_input);
|
|
||||||
ot_clear_gvariant (&xattrs);
|
ot_clear_gvariant (&xattrs);
|
||||||
|
ot_clear_gvariant (&archive_metadata);
|
||||||
g_clear_object (&src_child);
|
g_clear_object (&src_child);
|
||||||
g_clear_object (&object_path);
|
g_clear_object (&object_path);
|
||||||
|
g_clear_object (&content_object_path);
|
||||||
|
g_clear_object (&content_input);
|
||||||
g_clear_object (&dest_path);
|
g_clear_object (&dest_path);
|
||||||
g_free (dest_path);
|
g_free (dest_path);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -79,17 +79,36 @@ GFile * ostree_repo_get_object_path (OstreeRepo *self,
|
||||||
GFile * ostree_repo_get_file_object_path (OstreeRepo *self,
|
GFile * ostree_repo_get_file_object_path (OstreeRepo *self,
|
||||||
const char *object);
|
const char *object);
|
||||||
|
|
||||||
gboolean ostree_repo_store_archived_file (OstreeRepo *self,
|
gboolean ostree_repo_prepare_transaction (OstreeRepo *self,
|
||||||
const char *expected_checksum,
|
GCancellable *cancellable,
|
||||||
const char *path,
|
GError **error);
|
||||||
|
|
||||||
|
gboolean ostree_repo_commit_transaction (OstreeRepo *self,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean ostree_repo_has_object (OstreeRepo *self,
|
||||||
OstreeObjectType objtype,
|
OstreeObjectType objtype,
|
||||||
gboolean *did_exist,
|
const char *checksum,
|
||||||
|
gboolean *out_have_object,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean ostree_repo_store_object (OstreeRepo *self,
|
||||||
|
OstreeObjectType objtype,
|
||||||
|
const char *expected_checksum,
|
||||||
|
GFileInfo *file_info,
|
||||||
|
GVariant *xattrs,
|
||||||
|
GInputStream *content,
|
||||||
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
gboolean ostree_repo_store_object_trusted (OstreeRepo *self,
|
gboolean ostree_repo_store_object_trusted (OstreeRepo *self,
|
||||||
GFile *file,
|
|
||||||
const char *checksum,
|
|
||||||
OstreeObjectType objtype,
|
OstreeObjectType objtype,
|
||||||
|
const char *checksum,
|
||||||
|
GFileInfo *file_info,
|
||||||
|
GVariant *xattrs,
|
||||||
|
GInputStream *content,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,17 +58,18 @@ static gboolean
|
||||||
fetch_uri (OstreeRepo *repo,
|
fetch_uri (OstreeRepo *repo,
|
||||||
SoupSession *soup,
|
SoupSession *soup,
|
||||||
SoupURI *uri,
|
SoupURI *uri,
|
||||||
char **temp_filename,
|
const char *tmp_prefix,
|
||||||
|
GFile **out_temp_filename,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
SoupMessage *msg = NULL;
|
SoupMessage *msg = NULL;
|
||||||
guint response;
|
guint response;
|
||||||
char *template = NULL;
|
|
||||||
int fd;
|
|
||||||
SoupBuffer *buf = NULL;
|
SoupBuffer *buf = NULL;
|
||||||
GFile *tempf = NULL;
|
|
||||||
char *uri_string = NULL;
|
char *uri_string = NULL;
|
||||||
|
GFile *ret_temp_filename = NULL;
|
||||||
|
GOutputStream *output_stream = NULL;
|
||||||
|
gsize bytes_written;
|
||||||
|
|
||||||
uri_string = soup_uri_to_string (uri, FALSE);
|
uri_string = soup_uri_to_string (uri, FALSE);
|
||||||
log_verbose ("Fetching %s", uri_string);
|
log_verbose ("Fetching %s", uri_string);
|
||||||
|
|
@ -83,31 +84,78 @@ fetch_uri (OstreeRepo *repo,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template = g_strdup_printf ("%s/tmp-fetchXXXXXX", ostree_repo_get_path (repo));
|
if (!ostree_create_temp_regular_file (ostree_repo_get_tmpdir (repo),
|
||||||
|
tmp_prefix, NULL,
|
||||||
fd = g_mkstemp (template);
|
&ret_temp_filename,
|
||||||
if (fd < 0)
|
&output_stream,
|
||||||
{
|
NULL, error))
|
||||||
ot_util_set_error_from_errno (error, errno);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
close (fd);
|
|
||||||
tempf = ot_gfile_new_for_path (template);
|
|
||||||
|
|
||||||
buf = soup_message_body_flatten (msg->response_body);
|
buf = soup_message_body_flatten (msg->response_body);
|
||||||
|
|
||||||
if (!g_file_replace_contents (tempf, buf->data, buf->length, NULL, FALSE, 0, NULL, NULL, error))
|
if (!g_output_stream_write_all (output_stream, buf->data, buf->length,
|
||||||
|
&bytes_written, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
*temp_filename = template;
|
if (!g_output_stream_close (output_stream, NULL, error))
|
||||||
template = NULL;
|
goto out;
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
ot_transfer_out_value (out_temp_filename, &ret_temp_filename);
|
||||||
out:
|
out:
|
||||||
|
if (ret_temp_filename)
|
||||||
|
(void) unlink (ot_gfile_get_path_cached (ret_temp_filename));
|
||||||
|
g_clear_object (&ret_temp_filename);
|
||||||
g_free (uri_string);
|
g_free (uri_string);
|
||||||
g_free (template);
|
|
||||||
g_clear_object (&msg);
|
g_clear_object (&msg);
|
||||||
g_clear_object (&tempf);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fetch_object (OstreeRepo *repo,
|
||||||
|
SoupSession *soup,
|
||||||
|
SoupURI *baseuri,
|
||||||
|
const char *checksum,
|
||||||
|
OstreeObjectType objtype,
|
||||||
|
gboolean *did_exist,
|
||||||
|
GFile **out_file,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
GFile *ret_file = NULL;
|
||||||
|
char *objpath = NULL;
|
||||||
|
char *relpath = NULL;
|
||||||
|
SoupURI *obj_uri = NULL;
|
||||||
|
gboolean exists;
|
||||||
|
|
||||||
|
g_assert (objtype != OSTREE_OBJECT_TYPE_RAW_FILE);
|
||||||
|
|
||||||
|
if (!ostree_repo_has_object (repo, objtype, checksum, &exists, NULL, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!exists)
|
||||||
|
{
|
||||||
|
objpath = ostree_get_relative_object_path (checksum, objtype);
|
||||||
|
obj_uri = soup_uri_copy (baseuri);
|
||||||
|
relpath = g_build_filename (soup_uri_get_path (obj_uri), objpath, NULL);
|
||||||
|
soup_uri_set_path (obj_uri, relpath);
|
||||||
|
|
||||||
|
if (!fetch_uri (repo, soup, obj_uri, ostree_object_type_to_string (objtype), &ret_file, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
*did_exist = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*did_exist = TRUE;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
ot_transfer_out_value (out_file, &ret_file);
|
||||||
|
out:
|
||||||
|
if (obj_uri)
|
||||||
|
soup_uri_free (obj_uri);
|
||||||
|
g_clear_object (&ret_file);
|
||||||
|
g_free (objpath);
|
||||||
|
g_free (relpath);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,39 +163,40 @@ static gboolean
|
||||||
store_object (OstreeRepo *repo,
|
store_object (OstreeRepo *repo,
|
||||||
SoupSession *soup,
|
SoupSession *soup,
|
||||||
SoupURI *baseuri,
|
SoupURI *baseuri,
|
||||||
const char *object,
|
const char *checksum,
|
||||||
OstreeObjectType objtype,
|
OstreeObjectType objtype,
|
||||||
gboolean *did_exist,
|
gboolean *did_exist,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
char *filename = NULL;
|
GFile *filename = NULL;
|
||||||
char *objpath = NULL;
|
GFileInfo *file_info = NULL;
|
||||||
char *relpath = NULL;
|
GInputStream *input = NULL;
|
||||||
SoupURI *obj_uri = NULL;
|
|
||||||
|
|
||||||
g_assert (objtype != OSTREE_OBJECT_TYPE_RAW_FILE);
|
if (!fetch_object (repo, soup, baseuri, checksum, objtype, did_exist, &filename, error))
|
||||||
|
|
||||||
objpath = ostree_get_relative_object_path (object, objtype);
|
|
||||||
obj_uri = soup_uri_copy (baseuri);
|
|
||||||
relpath = g_build_filename (soup_uri_get_path (obj_uri), objpath, NULL);
|
|
||||||
soup_uri_set_path (obj_uri, relpath);
|
|
||||||
|
|
||||||
if (!fetch_uri (repo, soup, obj_uri, &filename, error))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!ostree_repo_store_archived_file (repo, object, filename, objtype, did_exist, error))
|
if (!*did_exist)
|
||||||
|
{
|
||||||
|
file_info = g_file_query_info (filename, OSTREE_GIO_FAST_QUERYINFO,
|
||||||
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, error);
|
||||||
|
if (!file_info)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
input = (GInputStream*)g_file_read (filename, NULL, error);
|
||||||
|
if (!input)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_repo_store_object (repo, objtype, checksum, file_info, NULL, input, NULL, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
out:
|
out:
|
||||||
if (obj_uri)
|
|
||||||
soup_uri_free (obj_uri);
|
|
||||||
if (filename)
|
if (filename)
|
||||||
(void) unlink (filename);
|
(void) unlink (ot_gfile_get_path_cached (filename));
|
||||||
g_free (filename);
|
g_clear_object (&file_info);
|
||||||
g_free (objpath);
|
g_clear_object (&input);
|
||||||
g_free (relpath);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,6 +213,12 @@ store_tree_recurse (OstreeRepo *repo,
|
||||||
GVariant *dirs_variant = NULL;
|
GVariant *dirs_variant = NULL;
|
||||||
gboolean did_exist;
|
gboolean did_exist;
|
||||||
int i, n;
|
int i, n;
|
||||||
|
GVariant *archive_metadata = NULL;
|
||||||
|
GFileInfo *archive_file_info = NULL;
|
||||||
|
GVariant *archive_xattrs = NULL;
|
||||||
|
GFile *meta_file = NULL;
|
||||||
|
GFile *content_file = NULL;
|
||||||
|
GInputStream *input = NULL;
|
||||||
|
|
||||||
if (!store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_DIR_TREE, &did_exist, error))
|
if (!store_object (repo, soup, base_uri, rev, OSTREE_OBJECT_TYPE_DIR_TREE, &did_exist, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -187,7 +242,41 @@ store_tree_recurse (OstreeRepo *repo,
|
||||||
|
|
||||||
g_variant_get_child (files_variant, i, "(&s&s)", &filename, &checksum);
|
g_variant_get_child (files_variant, i, "(&s&s)", &filename, &checksum);
|
||||||
|
|
||||||
if (!store_object (repo, soup, base_uri, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE, &did_exist, error))
|
g_clear_object (&meta_file);
|
||||||
|
|
||||||
|
if (!fetch_object (repo, soup, base_uri, checksum,
|
||||||
|
OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
|
||||||
|
&did_exist,
|
||||||
|
&meta_file,
|
||||||
|
error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_clear_object (&content_file);
|
||||||
|
if (!fetch_object (repo, soup, base_uri, checksum,
|
||||||
|
OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT,
|
||||||
|
&did_exist,
|
||||||
|
&content_file,
|
||||||
|
error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_map_metadata_file (meta_file, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META,
|
||||||
|
&archive_metadata, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_parse_archived_file_meta (archive_metadata, &archive_file_info, &archive_xattrs, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (g_file_info_get_file_type (archive_file_info) == G_FILE_TYPE_REGULAR)
|
||||||
|
{
|
||||||
|
input = (GInputStream*)g_file_read (content_file, NULL, error);
|
||||||
|
if (!input)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ostree_repo_store_object (repo, OSTREE_OBJECT_TYPE_RAW_FILE,
|
||||||
|
checksum,
|
||||||
|
archive_file_info, archive_xattrs, input,
|
||||||
|
NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,6 +303,10 @@ store_tree_recurse (OstreeRepo *repo,
|
||||||
ot_clear_gvariant (&tree);
|
ot_clear_gvariant (&tree);
|
||||||
ot_clear_gvariant (&files_variant);
|
ot_clear_gvariant (&files_variant);
|
||||||
ot_clear_gvariant (&dirs_variant);
|
ot_clear_gvariant (&dirs_variant);
|
||||||
|
ot_clear_gvariant (&archive_metadata);
|
||||||
|
ot_clear_gvariant (&archive_xattrs);
|
||||||
|
g_clear_object (&archive_file_info);
|
||||||
|
g_clear_object (&input);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,7 +362,6 @@ ostree_builtin_pull (int argc, char **argv, const char *repo_path, GError **erro
|
||||||
char *key = NULL;
|
char *key = NULL;
|
||||||
char *baseurl = NULL;
|
char *baseurl = NULL;
|
||||||
char *refpath = NULL;
|
char *refpath = NULL;
|
||||||
char *temppath = NULL;
|
|
||||||
GFile *tempf = NULL;
|
GFile *tempf = NULL;
|
||||||
char *remote_ref = NULL;
|
char *remote_ref = NULL;
|
||||||
char *original_rev = NULL;
|
char *original_rev = NULL;
|
||||||
|
|
@ -326,9 +418,8 @@ ostree_builtin_pull (int argc, char **argv, const char *repo_path, GError **erro
|
||||||
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
|
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
|
||||||
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
|
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_COOKIE_JAR,
|
||||||
NULL);
|
NULL);
|
||||||
if (!fetch_uri (repo, soup, target_uri, &temppath, error))
|
if (!fetch_uri (repo, soup, target_uri, "ref-", &tempf, error))
|
||||||
goto out;
|
goto out;
|
||||||
tempf = ot_gfile_new_for_path (temppath);
|
|
||||||
|
|
||||||
if (!ot_gfile_load_contents_utf8 (tempf, &rev, NULL, NULL, error))
|
if (!ot_gfile_load_contents_utf8 (tempf, &rev, NULL, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -343,9 +434,15 @@ ostree_builtin_pull (int argc, char **argv, const char *repo_path, GError **erro
|
||||||
if (!ostree_validate_checksum_string (rev, error))
|
if (!ostree_validate_checksum_string (rev, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_repo_prepare_transaction (repo, NULL, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!store_commit_recurse (repo, soup, base_uri, rev, error))
|
if (!store_commit_recurse (repo, soup, base_uri, rev, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_repo_commit_transaction (repo, NULL, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!ostree_repo_write_ref (repo, remote, branch, rev, error))
|
if (!ostree_repo_write_ref (repo, remote, branch, rev, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -356,9 +453,9 @@ ostree_builtin_pull (int argc, char **argv, const char *repo_path, GError **erro
|
||||||
out:
|
out:
|
||||||
if (context)
|
if (context)
|
||||||
g_option_context_free (context);
|
g_option_context_free (context);
|
||||||
if (temppath)
|
if (tempf)
|
||||||
(void) unlink (temppath);
|
(void) unlink (ot_gfile_get_path_cached (tempf));
|
||||||
g_free (temppath);
|
g_clear_object (&tempf);
|
||||||
g_free (key);
|
g_free (key);
|
||||||
g_free (rev);
|
g_free (rev);
|
||||||
g_free (remote_ref);
|
g_free (remote_ref);
|
||||||
|
|
|
||||||
|
|
@ -35,37 +35,53 @@ static GOptionEntry options[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
OstreeRepo *repo;
|
||||||
guint n_objects;
|
guint n_objects;
|
||||||
gboolean had_error;
|
gboolean had_error;
|
||||||
} OtFsckData;
|
} OtFsckData;
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
checksum_archived_file (OtFsckData *data,
|
checksum_archived_file (OtFsckData *data,
|
||||||
|
const char *exp_checksum,
|
||||||
GFile *file,
|
GFile *file,
|
||||||
GChecksum **out_checksum,
|
GChecksum **out_checksum,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GChecksum *ret_checksum = NULL;
|
GChecksum *ret_checksum = NULL;
|
||||||
GInputStream *in = NULL;
|
GVariant *archive_metadata = NULL;
|
||||||
GVariant *xattrs = NULL;
|
GVariant *xattrs = NULL;
|
||||||
|
GFile *content_path = NULL;
|
||||||
|
GInputStream *content_input = NULL;
|
||||||
GFileInfo *file_info = NULL;
|
GFileInfo *file_info = NULL;
|
||||||
char buf[8192];
|
char buf[8192];
|
||||||
gsize bytes_read;
|
gsize bytes_read;
|
||||||
guint32 mode;
|
guint32 mode;
|
||||||
|
|
||||||
if (!ostree_parse_archived_file (file, &file_info, &xattrs, &in, NULL, error))
|
if (!ostree_map_metadata_file (file, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, &archive_metadata, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_parse_archived_file_meta (archive_metadata, &file_info, &xattrs, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
content_path = ostree_repo_get_object_path (data->repo, exp_checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
|
||||||
|
|
||||||
|
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
||||||
|
{
|
||||||
|
content_input = (GInputStream*)g_file_read (content_path, NULL, error);
|
||||||
|
if (!content_input)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||||
|
|
||||||
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
|
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
|
||||||
if (S_ISREG (mode))
|
if (S_ISREG (mode))
|
||||||
{
|
{
|
||||||
g_assert (in != NULL);
|
g_assert (content_input != NULL);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, NULL, error))
|
if (!g_input_stream_read_all (content_input, buf, sizeof(buf), &bytes_read, NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
g_checksum_update (ret_checksum, (guint8*)buf, bytes_read);
|
g_checksum_update (ret_checksum, (guint8*)buf, bytes_read);
|
||||||
}
|
}
|
||||||
|
|
@ -97,9 +113,11 @@ checksum_archived_file (OtFsckData *data,
|
||||||
ot_transfer_out_value (out_checksum, &ret_checksum);
|
ot_transfer_out_value (out_checksum, &ret_checksum);
|
||||||
out:
|
out:
|
||||||
ot_clear_checksum (&ret_checksum);
|
ot_clear_checksum (&ret_checksum);
|
||||||
g_clear_object (&in);
|
|
||||||
g_clear_object (&file_info);
|
g_clear_object (&file_info);
|
||||||
ot_clear_gvariant (&xattrs);
|
ot_clear_gvariant (&xattrs);
|
||||||
|
ot_clear_gvariant (&archive_metadata);
|
||||||
|
g_clear_object (&content_path);
|
||||||
|
g_clear_object (&content_input);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,40 +130,38 @@ object_iter_callback (OstreeRepo *repo,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
OtFsckData *data = user_data;
|
OtFsckData *data = user_data;
|
||||||
const char *path = NULL;
|
|
||||||
GChecksum *real_checksum = NULL;
|
GChecksum *real_checksum = NULL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
path = ot_gfile_get_path_cached (objf);
|
|
||||||
|
|
||||||
/* nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink");
|
/* nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink");
|
||||||
if (nlinks < 2 && !quiet)
|
if (nlinks < 2 && !quiet)
|
||||||
g_printerr ("note: floating object: %s\n", path); */
|
g_printerr ("note: floating object: %s\n", path); */
|
||||||
|
|
||||||
if (ostree_repo_get_mode (repo) == OSTREE_REPO_MODE_ARCHIVE
|
if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
|
||||||
&& !OSTREE_OBJECT_TYPE_IS_META (objtype))
|
|
||||||
{
|
{
|
||||||
if (!g_str_has_suffix (path, ".archive"))
|
if (!g_str_has_suffix (ot_gfile_get_path_cached (objf), ".archive-meta"))
|
||||||
{
|
{
|
||||||
g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
"Invalid archive filename '%s'",
|
"Invalid archive filename '%s'",
|
||||||
path);
|
ot_gfile_get_path_cached (objf));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!checksum_archived_file (data, objf, &real_checksum, &error))
|
if (!checksum_archived_file (data, exp_checksum, objf, &real_checksum, &error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
|
||||||
|
; /* Handled above */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ostree_checksum_file (objf, objtype, &real_checksum, NULL, &error))
|
if (!ostree_checksum_file (objf, objtype, &real_checksum, NULL, &error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp (exp_checksum, g_checksum_get_string (real_checksum)) != 0)
|
if (real_checksum && strcmp (exp_checksum, g_checksum_get_string (real_checksum)) != 0)
|
||||||
{
|
{
|
||||||
data->had_error = TRUE;
|
data->had_error = TRUE;
|
||||||
g_printerr ("ERROR: corrupted object '%s' expected checksum: %s\n",
|
g_printerr ("ERROR: corrupted object '%s'; actual checksum: %s\n",
|
||||||
exp_checksum, g_checksum_get_string (real_checksum));
|
ot_gfile_get_path_cached (objf), g_checksum_get_string (real_checksum));
|
||||||
}
|
}
|
||||||
|
|
||||||
data->n_objects++;
|
data->n_objects++;
|
||||||
|
|
@ -173,13 +189,14 @@ ostree_builtin_fsck (int argc, char **argv, const char *repo_path, GError **erro
|
||||||
if (!g_option_context_parse (context, &argc, &argv, error))
|
if (!g_option_context_parse (context, &argc, &argv, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
data.n_objects = 0;
|
|
||||||
data.had_error = FALSE;
|
|
||||||
|
|
||||||
repo = ostree_repo_new (repo_path);
|
repo = ostree_repo_new (repo_path);
|
||||||
if (!ostree_repo_check (repo, error))
|
if (!ostree_repo_check (repo, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
data.repo = repo;
|
||||||
|
data.n_objects = 0;
|
||||||
|
data.had_error = FALSE;
|
||||||
|
|
||||||
if (!ostree_repo_iter_objects (repo, object_iter_callback, &data, error))
|
if (!ostree_repo_iter_objects (repo, object_iter_callback, &data, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@
|
||||||
#include "ot-builtins.h"
|
#include "ot-builtins.h"
|
||||||
#include "ostree.h"
|
#include "ostree.h"
|
||||||
|
|
||||||
#include <glib/gi18n.h>
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
static GOptionEntry options[] = {
|
static GOptionEntry options[] = {
|
||||||
{ NULL }
|
{ NULL }
|
||||||
|
|
@ -94,34 +95,67 @@ object_iter_callback (OstreeRepo *repo,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
OtLocalCloneData *data = user_data;
|
OtLocalCloneData *data = user_data;
|
||||||
GError *error = NULL;
|
GError *real_error = NULL;
|
||||||
gboolean did_exist;
|
GError **error = &real_error;
|
||||||
|
GFile *content_path = NULL;
|
||||||
|
GFileInfo *archive_info = NULL;
|
||||||
|
GVariant *archive_metadata = NULL;
|
||||||
|
GVariant *xattrs = NULL;
|
||||||
|
GInputStream *input = NULL;
|
||||||
|
|
||||||
if (ostree_repo_get_mode (data->src_repo) == OSTREE_REPO_MODE_ARCHIVE)
|
if (objtype == OSTREE_OBJECT_TYPE_RAW_FILE)
|
||||||
|
xattrs = ostree_get_xattrs_for_file (objfile, error);
|
||||||
|
|
||||||
|
if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
|
||||||
|
;
|
||||||
|
else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META)
|
||||||
{
|
{
|
||||||
if (!ostree_repo_store_archived_file (data->dest_repo, checksum,
|
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_META, checksum, &archive_metadata, error))
|
||||||
ot_gfile_get_path_cached (objfile),
|
goto out;
|
||||||
objtype,
|
|
||||||
&did_exist,
|
if (!ostree_parse_archived_file_meta (archive_metadata, &archive_info, &xattrs, error))
|
||||||
&error))
|
goto out;
|
||||||
|
|
||||||
|
content_path = ostree_repo_get_object_path (repo, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
|
||||||
|
|
||||||
|
if (g_file_info_get_file_type (archive_info) == G_FILE_TYPE_REGULAR)
|
||||||
|
{
|
||||||
|
input = (GInputStream*)g_file_read (content_path, NULL, error);
|
||||||
|
if (!input)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ostree_repo_store_object_trusted (data->dest_repo, OSTREE_OBJECT_TYPE_RAW_FILE, checksum,
|
||||||
|
archive_info, xattrs, input,
|
||||||
|
NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ostree_repo_store_object_trusted (data->dest_repo,
|
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
||||||
objfile,
|
{
|
||||||
checksum,
|
input = (GInputStream*)g_file_read (objfile, NULL, error);
|
||||||
objtype,
|
if (!input)
|
||||||
NULL,
|
goto out;
|
||||||
&error))
|
}
|
||||||
|
|
||||||
|
if (!ostree_repo_store_object_trusted (data->dest_repo, objtype, checksum,
|
||||||
|
file_info, xattrs, input,
|
||||||
|
NULL, error))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (error != NULL)
|
ot_clear_gvariant (&archive_metadata);
|
||||||
|
ot_clear_gvariant (&xattrs);
|
||||||
|
g_clear_object (&archive_info);
|
||||||
|
g_clear_object (&input);
|
||||||
|
g_clear_object (&content_path);
|
||||||
|
if (real_error != NULL)
|
||||||
{
|
{
|
||||||
g_printerr ("%s\n", error->message);
|
g_printerr ("%s\n", real_error->message);
|
||||||
g_clear_error (&error);
|
g_clear_error (error);
|
||||||
|
exit (1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,9 +217,15 @@ ostree_builtin_local_clone (int argc, char **argv, const char *repo_path, GError
|
||||||
|
|
||||||
data.uids_differ = g_file_info_get_attribute_uint32 (src_info, "unix::uid") != g_file_info_get_attribute_uint32 (dest_info, "unix::uid");
|
data.uids_differ = g_file_info_get_attribute_uint32 (src_info, "unix::uid") != g_file_info_get_attribute_uint32 (dest_info, "unix::uid");
|
||||||
|
|
||||||
|
if (!ostree_repo_prepare_transaction (data.dest_repo, NULL, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!ostree_repo_iter_objects (data.src_repo, object_iter_callback, &data, error))
|
if (!ostree_repo_iter_objects (data.src_repo, object_iter_callback, &data, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_repo_commit_transaction (data.dest_repo, NULL, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
src_dir = g_file_resolve_relative_path (src_repo_dir, "refs/heads");
|
src_dir = g_file_resolve_relative_path (src_repo_dir, "refs/heads");
|
||||||
dest_dir = g_file_resolve_relative_path (dest_repo_dir, "refs/heads");
|
dest_dir = g_file_resolve_relative_path (dest_repo_dir, "refs/heads");
|
||||||
if (!copy_dir_contents (src_dir, dest_dir, NULL, error))
|
if (!copy_dir_contents (src_dir, dest_dir, NULL, error))
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ ostree_builtin_log (int argc, char **argv, const char *repo_path, GError **error
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
OstreeObjectType type;
|
|
||||||
char *formatted = NULL;
|
char *formatted = NULL;
|
||||||
guint32 version;
|
guint32 version;
|
||||||
const char *parent;
|
const char *parent;
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ show_repo_meta (OstreeRepo *repo,
|
||||||
g_print ("%s", buf);
|
g_print ("%s", buf);
|
||||||
} while (bytes_read > 0);
|
} while (bytes_read > 0);
|
||||||
}
|
}
|
||||||
else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE)
|
else if (objtype == OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
|
||||||
{
|
{
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||||
"Can't show archived files yet");
|
"Can't show archived files yet");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue