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:
Colin Walters 2011-12-15 13:11:47 -05:00
parent ecbffd4915
commit 9a71ab187d
10 changed files with 806 additions and 678 deletions

View File

@ -245,13 +245,16 @@ ostree_checksum_file_from_input (GFileInfo *file_info,
goto out; goto out;
} }
ostree_checksum_update_stat (ret_checksum, if (objtype != OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT)
g_file_info_get_attribute_uint32 (file_info, "unix::uid"), {
g_file_info_get_attribute_uint32 (file_info, "unix::gid"), ostree_checksum_update_stat (ret_checksum,
g_file_info_get_attribute_uint32 (file_info, "unix::mode")); g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
/* FIXME - ensure empty xattrs are the same as NULL xattrs */ g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
if (xattrs) g_file_info_get_attribute_uint32 (file_info, "unix::mode"));
g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs)); /* 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));
}
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, GError **error)
GCancellable *cancellable,
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))
goto out;
if (bytes_read != 4)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Corrupted archive file; too short while reading metadata length");
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)) if (version != 0)
goto out;
if (bytes_read != metadata_len)
{ {
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"); "Invalid version %d in archived file metadata", version);
goto out; 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;

View File

@ -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,10 +117,10 @@ 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);
gboolean ostree_checksum_file_from_input (GFileInfo *file_info, gboolean ostree_checksum_file_from_input (GFileInfo *file_info,
GVariant *xattrs, GVariant *xattrs,
@ -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,18 +180,13 @@ 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,
GFileInfo **out_file_info, GVariant *xattrs);
GVariant **out_xattrs,
GInputStream **out_content,
GCancellable *cancellable,
GError **error);
gboolean ostree_unpack_object (GFile *file, gboolean ostree_parse_archived_file_meta (GVariant *data,
OstreeObjectType objtype, GFileInfo **out_file_info,
GFile *dest, GVariant **out_xattrs,
GChecksum **out_checksum, GError **error);
GError **error);
#endif /* _OSTREE_REPO */ #endif /* _OSTREE_REPO */

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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);
OstreeObjectType objtype,
gboolean *did_exist, gboolean ostree_repo_commit_transaction (OstreeRepo *self,
GError **error); GCancellable *cancellable,
GError **error);
gboolean ostree_repo_has_object (OstreeRepo *self,
OstreeObjectType objtype,
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);
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);

View File

@ -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;
if (!g_output_stream_close (output_stream, NULL, error))
goto out; goto out;
*temp_filename = template; ret = TRUE;
template = NULL; ot_transfer_out_value (out_temp_filename, &ret_temp_filename);
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_clear_object (&msg);
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; ret = TRUE;
ot_transfer_out_value (out_file, &ret_file);
out: out:
g_free (uri_string); if (obj_uri)
g_free (template); soup_uri_free (obj_uri);
g_clear_object (&msg); g_clear_object (&ret_file);
g_clear_object (&tempf); 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)
goto out; {
file_info = g_file_query_info (filename, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, error);
if (!file_info)
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;
@ -342,9 +433,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);

View File

@ -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;

View File

@ -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,8 +217,14 @@ 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");

View File

@ -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;

View File

@ -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");